diff --git a/src/dawn_node/interop/Core.cpp b/src/dawn_node/interop/Core.cpp index 7c505ca065..8ee22cf90f 100644 --- a/src/dawn_node/interop/Core.cpp +++ b/src/dawn_node/interop/Core.cpp @@ -16,136 +16,142 @@ namespace wgpu { namespace interop { - bool Converter::FromJS(Napi::Env env, Napi::Value value, bool& out) { + Result Success; + + Result Error(std::string msg) { + return {msg}; + } + + Result Converter::FromJS(Napi::Env env, Napi::Value value, bool& out) { if (value.IsBoolean()) { out = value.ToBoolean(); - return true; + return Success; } - return false; + return Error("value is not a boolean"); } Napi::Value Converter::ToJS(Napi::Env env, bool value) { return Napi::Value::From(env, value); } - bool Converter::FromJS(Napi::Env env, Napi::Value value, std::string& out) { + Result Converter::FromJS(Napi::Env env, Napi::Value value, std::string& out) { if (value.IsString()) { out = value.ToString(); - return true; + return Success; } - return false; + return Error("value is not a string"); } Napi::Value Converter::ToJS(Napi::Env env, std::string value) { return Napi::Value::From(env, value); } - bool Converter::FromJS(Napi::Env env, Napi::Value value, int8_t& out) { + Result Converter::FromJS(Napi::Env env, Napi::Value value, int8_t& out) { if (value.IsNumber()) { out = value.ToNumber().Int32Value(); - return true; + return Success; } - return false; + return Error("value is not a number"); } Napi::Value Converter::ToJS(Napi::Env env, int8_t value) { return Napi::Value::From(env, value); } - bool Converter::FromJS(Napi::Env env, Napi::Value value, uint8_t& out) { + Result Converter::FromJS(Napi::Env env, Napi::Value value, uint8_t& out) { if (value.IsNumber()) { out = value.ToNumber().Uint32Value(); - return true; + return Success; } - return false; + return Error("value is not a number"); } Napi::Value Converter::ToJS(Napi::Env env, uint8_t value) { return Napi::Value::From(env, value); } - bool Converter::FromJS(Napi::Env env, Napi::Value value, int16_t& out) { + Result Converter::FromJS(Napi::Env env, Napi::Value value, int16_t& out) { if (value.IsNumber()) { out = value.ToNumber().Int32Value(); - return true; + return Success; } - return false; + return Error("value is not a number"); } Napi::Value Converter::ToJS(Napi::Env env, int16_t value) { return Napi::Value::From(env, value); } - bool Converter::FromJS(Napi::Env env, Napi::Value value, uint16_t& out) { + Result Converter::FromJS(Napi::Env env, Napi::Value value, uint16_t& out) { if (value.IsNumber()) { out = value.ToNumber().Uint32Value(); - return true; + return Success; } - return false; + return Error("value is not a number"); } Napi::Value Converter::ToJS(Napi::Env env, uint16_t value) { return Napi::Value::From(env, value); } - bool Converter::FromJS(Napi::Env env, Napi::Value value, int32_t& out) { + Result Converter::FromJS(Napi::Env env, Napi::Value value, int32_t& out) { if (value.IsNumber()) { out = value.ToNumber().Int32Value(); - return true; + return Success; } - return false; + return Error("value is not a number"); } Napi::Value Converter::ToJS(Napi::Env env, int32_t value) { return Napi::Value::From(env, value); } - bool Converter::FromJS(Napi::Env env, Napi::Value value, uint32_t& out) { + Result Converter::FromJS(Napi::Env env, Napi::Value value, uint32_t& out) { if (value.IsNumber()) { out = value.ToNumber().Uint32Value(); - return true; + return Success; } - return false; + return Error("value is not a number"); } Napi::Value Converter::ToJS(Napi::Env env, uint32_t value) { return Napi::Value::From(env, value); } - bool Converter::FromJS(Napi::Env env, Napi::Value value, int64_t& out) { + Result Converter::FromJS(Napi::Env env, Napi::Value value, int64_t& out) { if (value.IsNumber()) { out = value.ToNumber().Int64Value(); - return true; + return Success; } - return false; + return Error("value is not a number"); } Napi::Value Converter::ToJS(Napi::Env env, int64_t value) { return Napi::Value::From(env, value); } - bool Converter::FromJS(Napi::Env env, Napi::Value value, uint64_t& out) { + Result Converter::FromJS(Napi::Env env, Napi::Value value, uint64_t& out) { if (value.IsNumber()) { // Note that the JS Number type only stores doubles, so the max integer // range of values without precision loss is -2^53 to 2^53 (52 bit mantissa // with 1 implicit bit). This is why there's no UInt64Value() function. out = static_cast(value.ToNumber().Int64Value()); - return true; + return Success; } - return false; + return Error("value is not a number"); } Napi::Value Converter::ToJS(Napi::Env env, uint64_t value) { return Napi::Value::From(env, value); } - bool Converter::FromJS(Napi::Env env, Napi::Value value, float& out) { + Result Converter::FromJS(Napi::Env env, Napi::Value value, float& out) { if (value.IsNumber()) { out = value.ToNumber().FloatValue(); - return true; + return Success; } - return false; + return Error("value is not a number"); } Napi::Value Converter::ToJS(Napi::Env env, float value) { return Napi::Value::From(env, value); } - bool Converter::FromJS(Napi::Env env, Napi::Value value, double& out) { + Result Converter::FromJS(Napi::Env env, Napi::Value value, double& out) { if (value.IsNumber()) { out = value.ToNumber().DoubleValue(); - return true; + return Success; } - return false; + return Error("value is not a number"); } Napi::Value Converter::ToJS(Napi::Env env, double value) { return Napi::Value::From(env, value); diff --git a/src/dawn_node/interop/Core.h b/src/dawn_node/interop/Core.h index e05f0b19b8..ff26930959 100644 --- a/src/dawn_node/interop/Core.h +++ b/src/dawn_node/interop/Core.h @@ -58,6 +58,42 @@ namespace wgpu { namespace interop { template using FrozenArray = std::vector; + //////////////////////////////////////////////////////////////////////////////// + // Result + //////////////////////////////////////////////////////////////////////////////// + + // Result is used to hold an success / error state by functions that perform JS <-> C++ + // conversion + struct [[nodiscard]] Result { + // Returns true if the operation succeeded, false if there was an error + inline operator bool() const { + return error.empty(); + } + + // If Result is an error, then a new Error is returned with the + // stringified values append to the error message. + // If Result is a success, then a success Result is returned. + template + Result Append(VALUES && ... values) { + if (*this) { + return *this; + } + std::stringstream ss; + ss << error << "\n"; + utils::Write(ss, std::forward(values)...); + return {ss.str()}; + } + + // The error message, if the operation failed. + std::string error; + }; + + // A successful result + extern Result Success; + + // Returns a Result with the given error message + Result Error(std::string msg); + //////////////////////////////////////////////////////////////////////////////// // Interface //////////////////////////////////////////////////////////////////////////////// @@ -200,8 +236,7 @@ namespace wgpu { namespace interop { // with the signatures: // // // FromJS() converts the JavaScript value 'in' to the C++ value 'out'. - // // Returns true on success, false on failure. - // static bool FromJS(Napi::Env, Napi::Value in, T& out); + // static Result FromJS(Napi::Env, Napi::Value in, T& out); // // // ToJS() converts the C++ value 'in' to a JavaScript value, and returns // // this value. @@ -212,12 +247,12 @@ namespace wgpu { namespace interop { template <> class Converter { public: - static inline bool FromJS(Napi::Env, Napi::Value value, Napi::Object& out) { + static inline Result FromJS(Napi::Env, Napi::Value value, Napi::Object& out) { if (value.IsObject()) { out = value.ToObject(); - return true; + return Success; } - return false; + return Error("value is not an object"); } static inline Napi::Value ToJS(Napi::Env, Napi::Object value) { return value; @@ -227,12 +262,12 @@ namespace wgpu { namespace interop { template <> class Converter { public: - static inline bool FromJS(Napi::Env, Napi::Value value, ArrayBuffer& out) { + static inline Result FromJS(Napi::Env, Napi::Value value, ArrayBuffer& out) { if (value.IsArrayBuffer()) { out = value.As(); - return true; + return Success; } - return false; + return Error("value is not a ArrayBuffer"); }; static inline Napi::Value ToJS(Napi::Env, ArrayBuffer value) { return value; @@ -242,12 +277,12 @@ namespace wgpu { namespace interop { template <> class Converter { public: - static inline bool FromJS(Napi::Env, Napi::Value value, Napi::TypedArray& out) { + static inline Result FromJS(Napi::Env, Napi::Value value, Napi::TypedArray& out) { if (value.IsTypedArray()) { out = value.As(); - return true; + return Success; } - return false; + return Error("value is not a TypedArray"); }; static inline Napi::Value ToJS(Napi::Env, ArrayBuffer value) { return value; @@ -274,15 +309,16 @@ namespace wgpu { namespace interop { // clang-format on static_assert(static_cast(element_type) >= 0, "unsupported T type for Napi::TypedArrayOf"); - static inline bool FromJS(Napi::Env, Napi::Value value, Napi::TypedArrayOf& out) { + static inline Result FromJS(Napi::Env, Napi::Value value, Napi::TypedArrayOf& out) { if (value.IsTypedArray()) { auto arr = value.As>(); if (arr.TypedArrayType() == element_type) { out = arr; - return true; + return Success; } + return Error("value is not a TypedArray of the correct element type"); } - return false; + return Error("value is not a TypedArray"); }; static inline Napi::Value ToJS(Napi::Env, ArrayBuffer value) { return value; @@ -292,99 +328,100 @@ namespace wgpu { namespace interop { template <> class Converter { public: - static bool FromJS(Napi::Env, Napi::Value, std::string&); + static Result FromJS(Napi::Env, Napi::Value, std::string&); static Napi::Value ToJS(Napi::Env, std::string); }; template <> class Converter { public: - static bool FromJS(Napi::Env, Napi::Value, bool&); + static Result FromJS(Napi::Env, Napi::Value, bool&); static Napi::Value ToJS(Napi::Env, bool); }; template <> class Converter { public: - static bool FromJS(Napi::Env, Napi::Value, int8_t&); + static Result FromJS(Napi::Env, Napi::Value, int8_t&); static Napi::Value ToJS(Napi::Env, int8_t); }; template <> class Converter { public: - static bool FromJS(Napi::Env, Napi::Value, uint8_t&); + static Result FromJS(Napi::Env, Napi::Value, uint8_t&); static Napi::Value ToJS(Napi::Env, uint8_t); }; template <> class Converter { public: - static bool FromJS(Napi::Env, Napi::Value, int16_t&); + static Result FromJS(Napi::Env, Napi::Value, int16_t&); static Napi::Value ToJS(Napi::Env, int16_t); }; template <> class Converter { public: - static bool FromJS(Napi::Env, Napi::Value, uint16_t&); + static Result FromJS(Napi::Env, Napi::Value, uint16_t&); static Napi::Value ToJS(Napi::Env, uint16_t); }; template <> class Converter { public: - static bool FromJS(Napi::Env, Napi::Value, int32_t&); + static Result FromJS(Napi::Env, Napi::Value, int32_t&); static Napi::Value ToJS(Napi::Env, int32_t); }; template <> class Converter { public: - static bool FromJS(Napi::Env, Napi::Value, uint32_t&); + static Result FromJS(Napi::Env, Napi::Value, uint32_t&); static Napi::Value ToJS(Napi::Env, uint32_t); }; template <> class Converter { public: - static bool FromJS(Napi::Env, Napi::Value, int64_t&); + static Result FromJS(Napi::Env, Napi::Value, int64_t&); static Napi::Value ToJS(Napi::Env, int64_t); }; template <> class Converter { public: - static bool FromJS(Napi::Env, Napi::Value, uint64_t&); + static Result FromJS(Napi::Env, Napi::Value, uint64_t&); static Napi::Value ToJS(Napi::Env, uint64_t); }; template <> class Converter { public: - static bool FromJS(Napi::Env, Napi::Value, float&); + static Result FromJS(Napi::Env, Napi::Value, float&); static Napi::Value ToJS(Napi::Env, float); }; template <> class Converter { public: - static bool FromJS(Napi::Env, Napi::Value, double&); + static Result FromJS(Napi::Env, Napi::Value, double&); static Napi::Value ToJS(Napi::Env, double); }; template class Converter> { public: - static bool FromJS(Napi::Env env, Napi::Value value, Interface& out) { - if (value.IsObject()) { - auto obj = value.As(); - if (T::Unwrap(obj)) { - out = Interface(obj); - return true; - } + static Result FromJS(Napi::Env env, Napi::Value value, Interface& out) { + if (!value.IsObject()) { + return Error("value is not object"); } - return false; + auto obj = value.As(); + if (!T::Unwrap(obj)) { + return Error("object is not of the correct interface type"); + } + out = Interface(obj); + return Success; } static Napi::Value ToJS(Napi::Env env, const Interface& value) { return {env, value}; @@ -394,17 +431,18 @@ namespace wgpu { namespace interop { template class Converter> { public: - static bool FromJS(Napi::Env env, Napi::Value value, std::optional& out) { + static Result FromJS(Napi::Env env, Napi::Value value, std::optional& out) { if (value.IsNull() || value.IsUndefined()) { out.reset(); - return true; + return Success; } T v{}; - if (!Converter::FromJS(env, value, v)) { - return false; + auto res = Converter::FromJS(env, value, v); + if (!res) { + return res; } out = std::move(v); - return true; + return Success; } static Napi::Value ToJS(Napi::Env env, std::optional value) { if (value.has_value()) { @@ -417,19 +455,20 @@ namespace wgpu { namespace interop { template class Converter> { public: - static inline bool FromJS(Napi::Env env, Napi::Value value, std::vector& out) { + static inline Result FromJS(Napi::Env env, Napi::Value value, std::vector& out) { if (!value.IsArray()) { - return false; + return Error("value is not an array"); } auto arr = value.As(); std::vector vec(arr.Length()); for (size_t i = 0; i < vec.size(); i++) { - if (!Converter::FromJS(env, arr[static_cast(i)], vec[i])) { - return false; + auto res = Converter::FromJS(env, arr[i], vec[i]); + if (!res) { + return res.Append("for array element ", i); } } out = std::move(vec); - return true; + return Success; } static inline Napi::Value ToJS(Napi::Env env, const std::vector& vec) { auto arr = Napi::Array::New(env, vec.size()); @@ -443,9 +482,11 @@ namespace wgpu { namespace interop { template class Converter> { public: - static inline bool FromJS(Napi::Env env, Napi::Value value, std::unordered_map& out) { + static inline Result FromJS(Napi::Env env, + Napi::Value value, + std::unordered_map& out) { if (!value.IsObject()) { - return false; + return Error("value is not an object"); } auto obj = value.ToObject(); auto keys = obj.GetPropertyNames(); @@ -453,14 +494,18 @@ namespace wgpu { namespace interop { for (uint32_t i = 0; i < static_cast(map.size()); i++) { K key{}; V value{}; - if (!Converter::FromJS(env, keys[i], key) || - !Converter::FromJS(env, obj.Get(keys[i]), value)) { - return false; + auto key_res = Converter::FromJS(env, keys[i], key); + if (!key_res) { + return key_res.Append("for object key"); + } + auto value_res = Converter::FromJS(env, obj.Get(keys[i]), value); + if (!value_res) { + return value_res.Append("for object value of key: ", key); } map[key] = value; } out = std::move(map); - return true; + return Success; } static inline Napi::Value ToJS(Napi::Env env, std::unordered_map value) { auto obj = Napi::Object::New(env); @@ -474,29 +519,30 @@ namespace wgpu { namespace interop { template class Converter> { template - static inline bool TryFromJS(Napi::Env env, - Napi::Value value, - std::variant& out) { + static inline Result TryFromJS(Napi::Env env, + Napi::Value value, + std::variant& out) { TY v{}; - if (Converter::FromJS(env, value, v)) { - out = std::move(v); - return true; + auto res = Converter::FromJS(env, value, v); + if (!res) { + return Error("no possible types matched"); } - return false; + out = std::move(v); + return Success; } template - static inline bool TryFromJS(Napi::Env env, - Napi::Value value, - std::variant& out) { + static inline Result TryFromJS(Napi::Env env, + Napi::Value value, + std::variant& out) { if (TryFromJS(env, value, out)) { - return true; + return Success; } return TryFromJS(env, value, out); } public: - static inline bool FromJS(Napi::Env env, Napi::Value value, std::variant& out) { + static inline Result FromJS(Napi::Env env, Napi::Value value, std::variant& out) { return TryFromJS(env, value, out); } static inline Napi::Value ToJS(Napi::Env env, std::variant value) { @@ -512,7 +558,7 @@ namespace wgpu { namespace interop { template class Converter> { public: - static inline bool FromJS(Napi::Env, Napi::Value, Promise&) { + static inline Result FromJS(Napi::Env, Napi::Value, Promise&) { UNIMPLEMENTED(); } static inline Napi::Value ToJS(Napi::Env, Promise promise) { @@ -527,18 +573,16 @@ namespace wgpu { namespace interop { // FromJS() is a helper function which delegates to // Converter::FromJS() template - inline bool FromJS(Napi::Env env, Napi::Value value, T& out) { + inline Result FromJS(Napi::Env env, Napi::Value value, T& out) { return Converter::FromJS(env, value, out); } // FromJSOptional() is similar to FromJS(), but if 'value' is either null - // or undefined then FromJSOptional() returns true and 'out' is left - // unassigned. - // Returns true on success, false on failure. + // or undefined then 'out' is left unassigned. template - inline bool FromJSOptional(Napi::Env env, Napi::Value value, T& out) { + inline Result FromJSOptional(Napi::Env env, Napi::Value value, T& out) { if (value.IsNull() || value.IsUndefined()) { - return true; + return Success; } return Converter::FromJS(env, value, out); } @@ -580,9 +624,8 @@ namespace wgpu { namespace interop { // PARAM_TYPES is a std::tuple<> describing the C++ function parameter types. // Parameters may be of the templated DefaultedParameter type, in which case // the parameter will default to the default-value if omitted. - // Returns true on success, false on failure. template - inline bool FromJS(const Napi::CallbackInfo& info, PARAM_TYPES& args) { + inline Result FromJS(const Napi::CallbackInfo& info, PARAM_TYPES& args) { if constexpr (BASE_INDEX < std::tuple_size_v) { using T = std::tuple_element_t; auto& value = info[BASE_INDEX]; @@ -593,20 +636,24 @@ namespace wgpu { namespace interop { if (value.IsNull() || value.IsUndefined()) { // Use default value for this parameter out.value = out.default_value; - } else if (!FromJS(info.Env(), value, out.value)) { - // Argument was provided, but failed to convert. - return false; + } else { + // Argument was provided + auto res = FromJS(info.Env(), value, out.value); + if (!res) { + return res; + } } } else { // Parameter does not have a default value. - if (!FromJS(info.Env(), value, out)) { - return false; + auto res = FromJS(info.Env(), value, out); + if (!res) { + return res; } } // Convert the rest of the arguments return FromJS(info, args); } else { - return true; + return Success; } } diff --git a/src/dawn_node/interop/WebGPU.cpp.tmpl b/src/dawn_node/interop/WebGPU.cpp.tmpl index 9ec75c0a7d..22f5f414c8 100644 --- a/src/dawn_node/interop/WebGPU.cpp.tmpl +++ b/src/dawn_node/interop/WebGPU.cpp.tmpl @@ -164,10 +164,11 @@ Wrappers* Wrappers::instance = nullptr; {{ if $s := SetlikeOf $}} Napi::Value has(const Napi::CallbackInfo& info) { std::tuple<{{template "Type" $s.Elem}}> args; - if (FromJS(info, args)) { + auto res = FromJS(info, args); + if (res) { return ToJS(info.Env(), impl->has(info.Env(), std::get<0>(args))); } - Napi::Error::New(info.Env(), "invalid arguments to has()").ThrowAsJavaScriptException(); + Napi::Error::New(info.Env(), res.error).ThrowAsJavaScriptException(); return {}; } Napi::Value keys(const Napi::CallbackInfo& info) { @@ -176,8 +177,10 @@ Wrappers* Wrappers::instance = nullptr; {{- end}} {{- range $m := MethodsOf $}} Napi::Value {{$m.Name}}(const Napi::CallbackInfo& info) { + std::string error; {{- range $overload_idx, $o := $m.Overloads}} - { // Overload {{$overload_idx}} +{{- $overloaded := gt (len $m.Overloads) 1}} + { {{if $overloaded}}// Overload {{$overload_idx}}{{end}} std::tuple< {{- range $i, $p := $o.Parameters}} {{- if $i}}, {{end}} @@ -193,7 +196,8 @@ Wrappers* Wrappers::instance = nullptr; {{- end}} {{- end}} - if (FromJS(info, args)) { + auto res = FromJS(info, args); + if (res) { {{/* indent */}}INTEROP_LOG( {{- range $i, $p := $o.Parameters}} {{- if $i}}, ", {{$p.Name}}: "{{else}}"{{$p.Name}}: "{{end}}, std::get<{{$i}}>(args) @@ -206,9 +210,10 @@ Wrappers* Wrappers::instance = nullptr; {{- else }}return ToJS(info.Env(), result); {{- end }} } + error = {{if $overloaded}}"\noverload {{$overload_idx}} failed to match:\n" + {{end}}res.error; } {{- end}} - Napi::Error::New(info.Env(), "invalid arguments to {{$m.Name}}").ThrowAsJavaScriptException(); + Napi::Error::New(info.Env(), "no overload matched for {{$m.Name}}:\n" + error).ThrowAsJavaScriptException(); return {}; } {{- end}} @@ -220,10 +225,12 @@ Wrappers* Wrappers::instance = nullptr; {{- if not $a.Readonly}} void set{{Title $a.Name}}(const Napi::CallbackInfo& info, const Napi::Value& value) { {{template "Type" $a.Type}} v{}; - if (FromJS(info.Env(), value, v)) { + auto res = FromJS(info.Env(), value, v); + if (res) { impl->set{{Title $a.Name}}(info.Env(), std::move(v)); } else { - Napi::Error::New(info.Env(), "invalid value to {{$a.Name}}").ThrowAsJavaScriptException(); + res = res.Append("invalid value to {{$a.Name}}"); + Napi::Error::New(info.Env(), res.error).ThrowAsJavaScriptException(); } } {{- end }} @@ -239,9 +246,11 @@ Wrappers* Wrappers::instance = nullptr; -------------------------------------------------------------------------------- */ -}} {{- define "Dictionary"}} -bool Converter<{{$.Name}}>::FromJS(Napi::Env env, Napi::Value value, {{$.Name}}& out) { +Result Converter<{{$.Name}}>::FromJS(Napi::Env env, Napi::Value value, {{$.Name}}& out) { auto object = value.ToObject(); - return true{{template "DictionaryMembersFromJS" $}}; + Result res; +{{- template "DictionaryMembersFromJS" $}}; + return Success; } Napi::Value Converter<{{$.Name}}>::ToJS(Napi::Env env, {{$.Name}} value) { @@ -265,18 +274,21 @@ std::ostream& operator<<(std::ostream& o, const {{$.Name}}& dict) { {{- /* -------------------------------------------------------------------------------- -- DictionaryMembersFromJS emits the C++ logic to convert each of the --- dictionary ast.Member fields from JavaScript to C++. Each call to FromJS() is --- prefixed with '&&' so that the combined expression is true iff all members --- are converted succesfully +-- dictionary ast.Member fields from JavaScript to C++. Each call to ToJS() is +-- emitted as a separate statement, and requires a 'Result res' local to be +-- declared -------------------------------------------------------------------------------- */ -}} {{- define "DictionaryMembersFromJS"}} {{- if $.Inherits}}{{template "DictionaryMembersFromJS" (Lookup $.Inherits)}}{{end}} -{{- range $i, $m := $.Members}} && - {{/* indent */}} -{{- if $m.Init }}interop::FromJSOptional(env, object.Get("{{$m.Name}}"), out.{{$m.Name}}) -{{- else }}interop::FromJS(env, object.Get("{{$m.Name}}"), out.{{$m.Name}}) +{{- range $i, $m := $.Members}} + {{/* indent */}} +{{- if $m.Init }}res = interop::FromJSOptional(env, object.Get("{{$m.Name}}"), out.{{$m.Name}}); +{{- else }}res = interop::FromJS(env, object.Get("{{$m.Name}}"), out.{{$m.Name}}); {{- end }} + if (!res) { + return res.Append("while converting member '{{$.Name}}'"); + } {{- end}} {{- end}} @@ -353,8 +365,12 @@ const char* Converter<{{$.Name}}>::ToString({{$.Name}} value) { return nullptr; } -bool Converter<{{$.Name}}>::FromJS(Napi::Env env, Napi::Value value, {{$.Name}}& out) { - return FromString(value.ToString(), out); +Result Converter<{{$.Name}}>::FromJS(Napi::Env env, Napi::Value value, {{$.Name}}& out) { + std::string str = value.ToString(); + if (FromString(str, out)) { + return Success; + } + return Error(str + " is not a valid enum value of {{$.Name}}"); } Napi::Value Converter<{{$.Name}}>::ToJS(Napi::Env env, {{$.Name}} value) { diff --git a/src/dawn_node/interop/WebGPU.h.tmpl b/src/dawn_node/interop/WebGPU.h.tmpl index e23be0cd49..5fbb0ae55c 100644 --- a/src/dawn_node/interop/WebGPU.h.tmpl +++ b/src/dawn_node/interop/WebGPU.h.tmpl @@ -76,7 +76,7 @@ public: template<> class Converter<{{$.Name}}> { public: - static bool FromJS(Napi::Env, Napi::Value, {{$.Name}}&); + static Result FromJS(Napi::Env, Napi::Value, {{$.Name}}&); static Napi::Value ToJS(Napi::Env, {{$.Name}}); }; @@ -166,7 +166,7 @@ enum class {{$.Name}} { template<> class Converter<{{$.Name}}> { public: - static bool FromJS(Napi::Env, Napi::Value, {{$.Name}}&); + static Result FromJS(Napi::Env, Napi::Value, {{$.Name}}&); static Napi::Value ToJS(Napi::Env, {{$.Name}}); static bool FromString(std::string, {{$.Name}}&); static const char* ToString({{$.Name}});