Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to create value_object binding with optional fields? #6226

Open
mean-ui-thread opened this issue Feb 11, 2018 · 3 comments
Open

How to create value_object binding with optional fields? #6226

mean-ui-thread opened this issue Feb 11, 2018 · 3 comments
Labels

Comments

@mean-ui-thread
Copy link

mean-ui-thread commented Feb 11, 2018

consider the following example:

struct Rectangle {
   int x = 0;
   int y = 0;
   int width = 100;
   int height = 100;
   int color = 0xFF000000;
};

class Shape {
public: 
    Shape(Rectangle rect);  
};

EMSCRIPTEN_BINDINGS(shapes) {

value_object<Rectangle>("Rectangle")
    .field("x", &Rectangle::x)
    .field("y", &Rectangle::y)
    .field("width", &Rectangle::width)
    .field("height", &Rectangle::height)
    .field("color", &Rectangle::color);

class_<Shape>("Shape")
    .constructor<Rectangle>();

}

Then works flawlessly when I do this in Javascript:

var rect = new Module.Shape( {x: 50, y: 60, width:250, height:10, color: 0xFF000000} )

However, if I just want to only provide the fields I want to override and leave the other fields to their default value like so:

var rect = new Module.Shape( {x: 50, y: 60, width:250, height:10} )

then I get the following error:

Uncaught TypeError: Missing field

How do we make optional fields with embind's value_object? Thanks!

@mean-ui-thread
Copy link
Author

mean-ui-thread commented Feb 11, 2018

I think I figured out a quick work around: I manually modified emsdk-portable/emscripten/1.37.33/src/embind/embind.js
from:

            'toWireType': function(destructors, o) {
                // todo: Here we have an opportunity for -O3 level "unsafe" optimizations:
                // assume all fields are present without checking.
                for (var fieldName in fields) {
                    if (!(fieldName in o)) {
                        throw new TypeError('Missing field');
                    }
                }
                var ptr = rawConstructor();
                for (fieldName in fields) {
                    fields[fieldName].write(ptr, o[fieldName]);
                }
                if (destructors !== null) {
                    destructors.push(rawDestructor, ptr);
                }
                return ptr;
            },

to

            'toWireType': function(destructors, o) {
                var ptr = rawConstructor();
                for (fieldName in fields) {
                    if (fieldName in o) {
                        fields[fieldName].write(ptr, o[fieldName]);
                    }
                }
                if (destructors !== null) {
                    destructors.push(rawDestructor, ptr);
                }
                return ptr;
            },

and I think it works now.

@blockspacer
Copy link

You can use emscripten::val && hasOwnProperty(width)

===

You can use emscripten::val && hasOwnProperty to create overloaded constructors.

We can call native constructor based on properties && typeof:

    .constructor<emscripten::val>( select_overload<ClassNameHere(emscripten::val)>([](emscripten::val c) {
       std::cout << "int constructor wrapped with emscripten::val" << std::endl;
       if (c.typeof().as<std::string>() == "string") {
           return ClassNameHere("1");
       } else if (c.typeof().as<std::string>() == "boolean") {
           return ClassNameHere(true);
       }
       return ClassNameHere(1);
    }))

typeof(emscripten::val) === string -> call string contructor
typeof(emscripten::val) === boolean -> call bool contructor
e.t.c.


template<typename T> 
class TemplatedConstructor {
private:
    T value;
    int p1;
    int p2;
    std::string str;

public:
    TemplatedConstructor() {};
    TemplatedConstructor(T val) : value(val) {};
    TemplatedConstructor(std::string val) : str(val) {
        //std::cout << "TemplatedConstructor(std::string val) called" << std::endl;
    };
    TemplatedConstructor(int a1, int a2) { p1 = a1; p2 = a2; };

    void set(T val) {
        value = val;
        str = std::to_string(value);
    }

    T get() {
        std::cout << "str:" << str << std::endl;
        std::cout << "p1:" << p1 << std::endl;
        std::cout << "p2:" << p2 << std::endl;
        return value;
    }
};

//......

EMSCRIPTEN_BINDINGS(my_module) {
class_<TemplatedConstructor<int>>("TemplatedConstructor")
    .constructor<>()
    .constructor<int>()
 // cant use
    //.constructor<std::string>()
 // cant use
    //.constructor<std::string>(select_overload<void(std::string)>(&TemplatedConstructor<std::string>::TemplatedConstructor<std::string>))
    .constructor<int, int>()
 // change it to accept one argument
    // Idea: use emscripten::val && hasOwnProperty to create overloaded constructors. We can call native constructor based on properties
    .constructor<std::string>( select_overload<TemplatedConstructor<int>(std::string, std::string, emscripten::val)>([](std::string a, std::string b, emscripten::val c) {
       std::cout << "wrap constructor in lambda 1" << std::endl;
       std::cout << "c.typeof().as<std::string>() is " << c.typeof().as<std::string>() << std::endl;
       if (c.hasOwnProperty("isStr")){
           std::cout << "hasOwnProperty isStr" << std::endl;
           std::cout << "c[\"isStr\"].typeof().as<std::string>() is " << c["isStr"].typeof().as<std::string>() << std::endl;
           std::cout << "c[\"value\"].typeof().as<std::string>() is " << c["value"].typeof().as<std::string>() << std::endl;
           //emscripten::val strVal = c["isStr"];
           //std::string getVal;
           std::cout << "strVal: " << c["value"].as<std::string>() << std::endl;
           
           return TemplatedConstructor<int>(c["value"].as<std::string>());
       }
       if (c.hasOwnProperty("isNumber")){
           std::cout << "hasOwnProperty isNumber" << std::endl;
           return TemplatedConstructor<int>("wrapped constructor");
       }
       return TemplatedConstructor<int>("wrapped constructor");
    }))
    .function("set", &TemplatedConstructor<int>::set)
    .function("get", &TemplatedConstructor<int>::get);
}

@stale
Copy link

stale bot commented Nov 9, 2019

This issue has been automatically marked as stale because there has been no activity in the past year. It will be closed automatically if no further activity occurs in the next 7 days. Feel free to re-open at any time if this issue is still relevant.

@stale stale bot added the wontfix label Nov 9, 2019
@stale stale bot closed this as completed Nov 16, 2019
@brendandahl brendandahl reopened this Aug 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants