Help with wrapping CivetWeb in haxe error C2664

Hi

I am trying to convert my haxe apps from hashlink/weblink to haxecpp and CivetWeb

So far I’ve been successfull with:
calling from haxe/cpp initialization code.
calling from cpp handler a haxe static method.
initializing the civetweb threads with the haxe GC.

Now I am trying to kep an array of handlers and dispatch the correct handler

static var handlers=new Map<String,RequestInfo->String>();
static function respond(conn:Star<Connection>){
        var handler;
        var req_info=mg_get_request_info(conn);
        for (k=>v in handlers){
            if (req_info.request_uri.toString().startsWith(k)){
                return v(req_info);
            }
        }
        return "404 not found from haxe";
    }
@:structAccess
@:native("mg_request_info")
@:include("../../civetweb/include/civetweb.h")
extern class RequestInfo {
    public var request_method:cpp.ConstCharStar;   
    public var request_uri:cpp.ConstCharStar;   
}

I receive the follwing erros that I am unable to interpret

Error: Main_Fields_.cpp
./src/_Main/Main_Fields_.cpp(46): error C2664: 'String _Main::Main_Fields__obj::main::_hx_Closure_0::_hx_run(mg_request_info)': cannot convert argument 1 from 'ELEM_' to 'mg_request_info'
        with
        [
            ELEM_=Dynamic
        ]
./src/_Main/Main_Fields_.cpp(46): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
./src/_Main/Main_Fields_.cpp(42): note: see declaration of '_Main::Main_Fields__obj::main::_hx_Closure_0::_hx_run'
./src/_Main/Main_Fields_.cpp(46): error C2664: 'String _Main::Main_Fields__obj::main::_hx_Closure_0::_hx_run(mg_request_info)': cannot convert argument 1 from 'const Dynamic' to 'mg_request_info'
./src/_Main/Main_Fields_.cpp(46): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
./src/_Main/Main_Fields_.cpp(42): note: see declaration of '_Main::Main_Fields__obj::main::_hx_Closure_0::_hx_run'
./src/_Main/Main_Fields_.cpp(53): error C2664: 'String _Main::Main_Fields__obj::main::_hx_Closure_1::_hx_run(mg_request_info)': cannot convert argument 1 from 'ELEM_' to 'mg_request_info'
        with
        [
            ELEM_=Dynamic
        ]
./src/_Main/Main_Fields_.cpp(53): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
./src/_Main/Main_Fields_.cpp(49): note: see declaration of '_Main::Main_Fields__obj::main::_hx_Closure_1::_hx_run'
./src/_Main/Main_Fields_.cpp(53): error C2664: 'String _Main::Main_Fields__obj::main::_hx_Closure_1::_hx_run(mg_request_info)': cannot convert argument 1 from 'const Dynamic' to 'mg_request_info'
./src/_Main/Main_Fields_.cpp(53): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
./src/_Main/Main_Fields_.cpp(49): note: see declaration of '_Main::Main_Fields__obj::main::_hx_Closure_1::_hx_run'

Error: Build failed

Can anyone point how to get past the error?
What is ELEM_ why is it dynamic?

The problem comes from trying to use RequestInfo in a closure. For hxcpp all types in a closure must be convertible to and from Dynamic.

One solution to this is to wrap that externed struct in a cpp::Struct which gives Dynamic compatibility (hxcpp/test/native/tests/TestPtr.hx at 7665c67a830f38d6c214bb18cb9a2c180952fdef · HaxeFoundation/hxcpp · GitHub).

Another is to create a wrapper class which holds all your extern gubbins and use that everywhere instead of the raw struct.

Thanks, the first seems to be less code changes, while the second seems cleaner.

Going with the first I am having issues with an assinments

HXLINE(  40)		 cpp::Struct<mg_request_info> * req_info = mg_get_request_info(conn);

Is producing the following error

./src/CivetC.cpp(87): error C2440: 'initializing': cannot convert from 'const mg_request_info *' to 'cpp::Struct<mg_request_info,cpp::DefaultStructHandler> *'

I would like to study the cpp::Struct source to understand how it works, and how it would manage cast assignment and field access, in the haxe source it seems to be a simple typedef.

Also I wonder isn’t this a huge performance issue? would it be recommanded to stop using closures and instead rely on polymorphism e. g. mmake a base handler class and subclass for the operation details, or use an interface?

I have here an incentive of learning haxecpp, but performance is also a big incentive, my hashlink processes are running with gigabytes of ram, wereas my intial tests with haxecpp/civetweb server 4krps with 10MB of ram on windows, and 12krps on linux, which is enough for my usecase, but I hope I will not bump into edge cases where haxecpp will be much slower than nodejs. (nodejs had issues with GC, and being single threaded, and webworkers being too selfiish)
Another thing I do like about the haxecpp is the ability to inspect the generated code, and sense how to optimize.

Turned out that I had to remove @:structAccess from the RequestInfo class

I would appriciate any insights about the perofrmance.

I’m guessing mg_get_request_info returns a pointer, not a struct, based on the generated code line you pasted so it would probably be more appropriate to have the RequestInfo extern be wrapped in the pointer helper for dynamic compatibility.

You can do this by changing the native meta to @:native ("::cpp::Pointer<mg_request_info>") or changing the return type of the externed mg_get_request_info function to cpp.Pointer<RequestInfo>.

You can find some info on the different pointer types here code-cookbook/assets/content/cookbook/Other/hxcpp-pointers.md at master · HaxeFoundation/code-cookbook · GitHub

I can’t speak to performance as I don’t know anything about your project or your approach to externing the library you’re using. Profile and find out!