diff --git a/v8pp/call_from_v8.hpp b/v8pp/call_from_v8.hpp index 013cc6a3..065dedcb 100644 --- a/v8pp/call_from_v8.hpp +++ b/v8pp/call_from_v8.hpp @@ -11,12 +11,29 @@ namespace v8pp { namespace detail { +template +struct optional_count_impl; + +template +struct optional_count_impl> +{ + constexpr static std::size_t count = + (0 + ... + (is_optional::value ? 1 : 0)); +}; + +template +constexpr auto optional_count() -> std::size_t +{ + return optional_count_impl::count; +} + template struct call_from_v8_traits { static constexpr size_t offset = Offset; static constexpr bool is_mem_fun = std::is_member_function_pointer::value; using arguments = typename function_traits::arguments; + static constexpr size_t optional_arg_count = optional_count(); static constexpr size_t arg_count = std::tuple_size::value - is_mem_fun - offset; @@ -91,7 +108,7 @@ decltype(auto) call_from_v8(F&& func, v8::FunctionCallbackInfo const& using call_traits = call_from_v8_traits; using indices = std::make_index_sequence; - if (args.Length() != call_traits::arg_count) + if (args.Length() > call_traits::arg_count || args.Length() < call_traits::arg_count - call_traits::optional_arg_count) { throw std::runtime_error( "Argument count does not match function definition. Expected " + diff --git a/v8pp/convert.hpp b/v8pp/convert.hpp index 06970dfa..fa2c288d 100644 --- a/v8pp/convert.hpp +++ b/v8pp/convert.hpp @@ -125,6 +125,33 @@ struct convert : convert> #endif // converter specializations for primitive types +template<> +struct convert +{ + using from_type = std::monostate; + using to_type = v8::Local; + + static bool is_valid(v8::Isolate*, v8::Local value) + { + return value.IsEmpty() || value->IsNullOrUndefined(); + } + + static from_type from_v8(v8::Isolate* isolate, v8::Local value) + { + if (!is_valid(isolate, value)) + { + throw invalid_argument(isolate, value, "Undefined"); + } + + return from_type{}; + } + + static to_type to_v8(v8::Isolate* isolate, from_type value) + { + return v8::Undefined(isolate); + } +}; + template<> struct convert { @@ -265,6 +292,41 @@ struct convert::value>::typ } }; +// convert std::optional <-> value or undefined +template +struct convert> +{ + using from_type = std::optional; + using to_type = typename convert::to_type; + + static bool is_valid(v8::Isolate* isolate, v8::Local value) + { + return convert::is_valid(isolate, value); + } + + static from_type from_v8(v8::Isolate* isolate, v8::Local value) + { + if (!is_valid(isolate, value)) + { + return from_type{}; + } + + return convert::from_v8(isolate, value); + } + + static to_type to_v8(v8::Isolate* isolate, from_type const& value) + { + if (value.has_value()) + { + return convert::to_v8(isolate, value.value()); + } + else + { + return to_type::Cast(v8::Undefined(isolate)); + } + } +}; + // convert std::tuple <-> Array template struct convert> @@ -373,6 +435,10 @@ struct convert> return alternate(isolate, value); } } + else if (value->IsNullOrUndefined()) + { + return alternate(isolate, value); + } else { return alternate(isolate, value); @@ -392,6 +458,9 @@ struct convert> template using is_bool = std::is_same; + template + using is_monostate = std::is_same; + template using is_integral_not_bool = std::bool_constant::value && !is_bool::value>; @@ -427,7 +496,14 @@ struct convert> template static bool try_as(v8::Isolate* isolate, v8::Local value, std::optional& result) { - if constexpr (detail::is_shared_ptr::value) + if constexpr (std::is_same::value) + { + if(v8pp::convert::is_valid(isolate, value)) + { + result = std::monostate{}; + } + } + else if constexpr (detail::is_shared_ptr::value) { using U = typename T::element_type; if (auto obj = v8pp::class_::unwrap_object(isolate, value)) @@ -635,7 +711,8 @@ struct is_wrapped_class : std::conjunction< std::negation>, std::negation>, std::negation>, - std::negation>> + std::negation>, + std::negation>> { }; @@ -857,6 +934,15 @@ v8::Local to_v8(v8::Isolate* isolate, } #endif +template +auto to_v8(v8::Isolate* isolate, std::optional const& value) -> v8::Local +{ + if (value.has_value()) + return convert::to_v8(isolate, value.value()); + else + return v8::Undefined(isolate); +} + template auto to_v8(v8::Isolate* isolate, T const& value) { diff --git a/v8pp/utility.hpp b/v8pp/utility.hpp index c1d2f4a8..195c65cc 100644 --- a/v8pp/utility.hpp +++ b/v8pp/utility.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include namespace v8pp { namespace detail { @@ -158,6 +159,20 @@ struct is_shared_ptr> : std::true_type { }; +///////////////////////////////////////////////////////////////////////////// +// +// is_optional +// +template +struct is_optional : std::false_type +{ +}; + +template +struct is_optional> : std::true_type +{ +}; + ///////////////////////////////////////////////////////////////////////////// // // Function traits