quickjspp icon indicating copy to clipboard operation
quickjspp copied to clipboard

How to implement a variadic (const) compound type for List and Map

Open CncGpp opened this issue 4 years ago • 0 comments

Hi, I'm developing a scripting-capable utility. I now use successfully wren-lang with wrenbind17 but I would like to try QuickJS.

However, I was unable to define a generic (variadic) datatype that allows me to call C++ functions from JS with compound objects such as Lists/Arrays or Map. Is it possible to do such a thing?

namespace js {
    struct List {
        // ??? DATA
        template <typename T> T get(const size_t ix) const;
        size_t size() const;
    };

    struct Map {
        // ??? DATA
        template <typename K, typename V> V get(const K key) const;
        size_t size() const;       
    };


    using Variant = std::variant<std::nullptr_t, bool, int, double, std::string, js::List, js::Map>;
    struct any :  public Variant {
        using Variant::variant;
        using Variant::operator=;

        enum class Type : int {
            null_t = 0, bool_t, int_t, double_t, string_t, list_t, map_t
        };

        any(const Variant& p) : Variant(p) {}

        Type type() const { return (Type)this->index(); }

        template <class T> bool is() const {
            const Type t = type();

            if constexpr (std::is_same<T, std::nullptr_t>::value)
                return t == Type::null_t;

            if constexpr (std::is_same<T, bool>::value)
                return t == Type::bool_t;

            if constexpr (std::is_same<T, int>::value)
                return t == Type::int_t;

            if constexpr (std::is_same<T, double>::value)
                return t == Type::double_t;

            if constexpr (std::is_same<T, std::string>::value)
                return t == Type::string_t;

            if constexpr (std::is_same<T, js::List>::value)
                return t == Type::list_t;

            if constexpr (std::is_same<T, js::Map>::value)
                return t == Type::map_t;

            return false;
        }

        template <class T> T as() const { return std::get<T>(*this); }
    };
}

So js::List is just a list/array of js::any and js::Map is a map of <std::string, js::any> .

I'd like to do something like this:

/* C++ function definition*/
void f(std::string s, js::any a){
   if(a.is<js::Map>()){
       // Code for accessing map elements  for example convert to nlohmann_json
  } else if(a.is<js::List>()){
    auto v = a.as<js::list>().get(0);          //v is also a js::any.
  } else { ... }
}
/* JS function call*/
module.f("~/example.dat", {
     "parms" : {"hello":"HI!"},
     "array" : [false, "str1", true, "str2"],
     "id" : 38,
});

Is it possible to do this in quickjspp?

CncGpp avatar Sep 20 '21 09:09 CncGpp