From 75f062fa25595854e8de94ae36b9e1cabb1e984a Mon Sep 17 00:00:00 2001 From: MangelSpec Date: Mon, 4 Apr 2022 18:45:42 +0200 Subject: [PATCH 1/3] added std::optional handling with v8::Undefined if empty --- v8pp/convert.hpp | 38 +++++++++++++++++++++++++++++++++++++- v8pp/utility.hpp | 15 +++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/v8pp/convert.hpp b/v8pp/convert.hpp index 6ba88001..cadc8c34 100644 --- a/v8pp/convert.hpp +++ b/v8pp/convert.hpp @@ -265,6 +265,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; // v8::Local; + + 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)) + { + throw invalid_argument(isolate, value, "Optional"); + } + + 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> @@ -637,7 +672,8 @@ struct is_wrapped_class : std::conjunction< std::negation>, std::negation>, std::negation>, - std::negation>> + std::negation>, + std::negation>> { }; 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 From ee56198b17d6e2f6210145700a8df6aaa28dbb72 Mon Sep 17 00:00:00 2001 From: MangelSpec Date: Fri, 8 Apr 2022 17:59:52 +0200 Subject: [PATCH 2/3] add optional args support to call_from_v8 improve convert --- v8pp/call_from_v8.hpp | 19 ++++++++++++++++++- v8pp/convert.hpp | 13 +++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/v8pp/call_from_v8.hpp b/v8pp/call_from_v8.hpp index 92acb629..de05873e 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"); } diff --git a/v8pp/convert.hpp b/v8pp/convert.hpp index cadc8c34..d4421e5c 100644 --- a/v8pp/convert.hpp +++ b/v8pp/convert.hpp @@ -270,7 +270,7 @@ template struct convert> { using from_type = std::optional; - using to_type = typename convert::to_type; // v8::Local; + using to_type = typename convert::to_type; static bool is_valid(v8::Isolate* isolate, v8::Local value) { @@ -281,7 +281,7 @@ struct convert> { if (!is_valid(isolate, value)) { - throw invalid_argument(isolate, value, "Optional"); + return from_type{}; } return convert::from_v8(isolate, value); @@ -895,6 +895,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) { From 4d2818686d941348e1f2912ce00e428de299b246 Mon Sep 17 00:00:00 2001 From: mangelspec Date: Thu, 29 Dec 2022 17:15:21 +0100 Subject: [PATCH 3/3] add monostate support to variant for undefined types --- v8pp/convert.hpp | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/v8pp/convert.hpp b/v8pp/convert.hpp index d4421e5c..b0b5295e 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 { @@ -408,6 +435,10 @@ struct convert> return alternate(isolate, value); } } + else if (value->IsNullOrUndefined()) + { + return alternate(isolate, value); + } else { return alternate(isolate, value); @@ -427,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>; @@ -464,7 +498,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))