export c++ class to duktape

前端 未结 1 1977
Happy的楠姐
Happy的楠姐 2020-12-31 18:00

say I have a c++ class Point

class Point {
public:
    Point();
    Point(float x, float y);
    ~Point();

    float X;
    float Y;

};

I

1条回答
  •  隐瞒了意图╮
    2020-12-31 18:46

    My personal advice is to create C++ bindings for it just like you would do in JavaScript.

    The only need, is to save the real C++ object in the JavaScript object, we use internal properties for that purpose.

    You need to create a function that will be called from JavaScript as a constructor function, then you just have to fill its prototype and set a finalizer. It's not hard but it required lot of code so you basically want to create wrapper to make them easier.

    #include 
    
    #include "duktape.h"
    
    class Point {
    public:
        float x;
        float y;
    };
    
    /*
     * This is the point destructor
     */
    duk_ret_t js_Point_dtor(duk_context *ctx)
    {
        // The object to delete is passed as first argument instead
        duk_get_prop_string(ctx, 0, "\xff""\xff""deleted");
    
        bool deleted = duk_to_boolean(ctx, -1);
        duk_pop(ctx);
    
        if (!deleted) {
            duk_get_prop_string(ctx, 0, "\xff""\xff""data");
            delete static_cast(duk_to_pointer(ctx, -1));
            duk_pop(ctx);
    
            // Mark as deleted
            duk_push_boolean(ctx, true);
            duk_put_prop_string(ctx, 0, "\xff""\xff""deleted");
        }
    
        return 0;
    }
    
    /*
     * This is Point function, constructor. Note that it can be called
     * as a standard function call, you may need to check for
     * duk_is_constructor_call to be sure that it is constructed
     * as a "new" statement.
     */
    duk_ret_t js_Point_ctor(duk_context *ctx)
    {
        // Get arguments
        float x = duk_require_number(ctx, 0);
        float y = duk_require_number(ctx, 1);
    
        // Push special this binding to the function being constructed
        duk_push_this(ctx);
    
        // Store the underlying object
        duk_push_pointer(ctx, new Point{x, y});
        duk_put_prop_string(ctx, -2, "\xff""\xff""data");
    
        // Store a boolean flag to mark the object as deleted because the destructor may be called several times
        duk_push_boolean(ctx, false);
        duk_put_prop_string(ctx, -2, "\xff""\xff""deleted");
    
        // Store the function destructor
        duk_push_c_function(ctx, js_Point_dtor, 1);
        duk_set_finalizer(ctx, -2);
    
        return 0;
    }
    
    /*
     * Basic toString method
     */
    duk_ret_t js_Point_toString(duk_context *ctx)
    {
        duk_push_this(ctx);
        duk_get_prop_string(ctx, -1, "\xff""\xff""data");
        Point *point = static_cast(duk_to_pointer(ctx, -1));
        duk_pop(ctx);
        duk_push_sprintf(ctx, "%f, %f", point->x, point->y);
    
        return 1;
    }
    
    // methods, add more here
    const duk_function_list_entry methods[] = {
        { "toString",   js_Point_toString,  0   },
        { nullptr,  nullptr,        0   }
    };
    
    int main(void)
    {
        duk_context *ctx = duk_create_heap_default();
    
        // Create Point function
        duk_push_c_function(ctx, js_Point_ctor, 2);
    
        // Create a prototype with toString and all other functions
        duk_push_object(ctx);
        duk_put_function_list(ctx, -1, methods);
        duk_put_prop_string(ctx, -2, "prototype");
    
        // Now store the Point function as a global
        duk_put_global_string(ctx, "Point");
    
        if (duk_peval_string(ctx, "p = new Point(20, 40); print(p)") != 0) {
            std::cerr << "error: " << duk_to_string(ctx, -1) << std::endl;
            std::exit(1);
        }
    
        return 0;
    }
    

    0 讨论(0)
提交回复
热议问题