Skip to content

Enhance Support for std::optional and Empty std::variant #214

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion v8pp/call_from_v8.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,29 @@

namespace v8pp { namespace detail {

template<typename>
struct optional_count_impl;

template<typename... Ts>
struct optional_count_impl<std::tuple<Ts...>>
{
constexpr static std::size_t count =
(0 + ... + (is_optional<Ts>::value ? 1 : 0));
};

template<typename Tuple>
constexpr auto optional_count() -> std::size_t
{
return optional_count_impl<Tuple>::count;
}

template<typename F, size_t Offset = 0>
struct call_from_v8_traits
{
static constexpr size_t offset = Offset;
static constexpr bool is_mem_fun = std::is_member_function_pointer<F>::value;
using arguments = typename function_traits<F>::arguments;
static constexpr size_t optional_arg_count = optional_count<arguments>();

static constexpr size_t arg_count =
std::tuple_size<arguments>::value - is_mem_fun - offset;
Expand Down Expand Up @@ -91,7 +108,7 @@ decltype(auto) call_from_v8(F&& func, v8::FunctionCallbackInfo<v8::Value> const&
using call_traits = call_from_v8_traits<F, with_isolate>;
using indices = std::make_index_sequence<call_traits::arg_count>;

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 " +
Expand Down
90 changes: 88 additions & 2 deletions v8pp/convert.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,33 @@ struct convert<wchar_t const*> : convert<std::basic_string_view<wchar_t>>
#endif

// converter specializations for primitive types
template<>
struct convert<std::monostate>
{
using from_type = std::monostate;
using to_type = v8::Local<v8::Primitive>;

static bool is_valid(v8::Isolate*, v8::Local<v8::Value> value)
{
return value.IsEmpty() || value->IsNullOrUndefined();
}

static from_type from_v8(v8::Isolate* isolate, v8::Local<v8::Value> 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<bool>
{
Expand Down Expand Up @@ -265,6 +292,41 @@ struct convert<T, typename std::enable_if<std::is_floating_point<T>::value>::typ
}
};

// convert std::optional <-> value or undefined
template<typename T>
struct convert<std::optional<T>>
{
using from_type = std::optional<T>;
using to_type = typename convert<T>::to_type;

static bool is_valid(v8::Isolate* isolate, v8::Local<v8::Value> value)
{
return convert<T>::is_valid(isolate, value);
}

static from_type from_v8(v8::Isolate* isolate, v8::Local<v8::Value> value)
{
if (!is_valid(isolate, value))
{
return from_type{};
}

return convert<T>::from_v8(isolate, value);
}

static to_type to_v8(v8::Isolate* isolate, from_type const& value)
{
if (value.has_value())
{
return convert<T>::to_v8(isolate, value.value());
}
else
{
return to_type::Cast(v8::Undefined(isolate));
}
}
};

// convert std::tuple <-> Array
template<typename... Ts>
struct convert<std::tuple<Ts...>>
Expand Down Expand Up @@ -373,6 +435,10 @@ struct convert<std::variant<Ts...>>
return alternate<is_wrapped_class, detail::is_shared_ptr>(isolate, value);
}
}
else if (value->IsNullOrUndefined())
{
return alternate<is_monostate>(isolate, value);
}
else
{
return alternate<is_any>(isolate, value);
Expand All @@ -392,6 +458,9 @@ struct convert<std::variant<Ts...>>
template<typename T>
using is_bool = std::is_same<T, bool>;

template<typename T>
using is_monostate = std::is_same<T, std::monostate>;

template<typename T>
using is_integral_not_bool = std::bool_constant<std::is_integral<T>::value && !is_bool<T>::value>;

Expand Down Expand Up @@ -427,7 +496,14 @@ struct convert<std::variant<Ts...>>
template<typename T>
static bool try_as(v8::Isolate* isolate, v8::Local<v8::Value> value, std::optional<from_type>& result)
{
if constexpr (detail::is_shared_ptr<T>::value)
if constexpr (std::is_same<T, std::monostate>::value)
{
if(v8pp::convert<std::monostate>::is_valid(isolate, value))
{
result = std::monostate{};
}
}
else if constexpr (detail::is_shared_ptr<T>::value)
{
using U = typename T::element_type;
if (auto obj = v8pp::class_<U, v8pp::shared_ptr_traits>::unwrap_object(isolate, value))
Expand Down Expand Up @@ -635,7 +711,8 @@ struct is_wrapped_class : std::conjunction<
std::negation<detail::is_sequence<T>>,
std::negation<detail::is_array<T>>,
std::negation<detail::is_tuple<T>>,
std::negation<detail::is_shared_ptr<T>>>
std::negation<detail::is_shared_ptr<T>>,
std::negation<detail::is_optional<T>>>
{
};

Expand Down Expand Up @@ -857,6 +934,15 @@ v8::Local<v8::String> to_v8(v8::Isolate* isolate,
}
#endif

template<typename T>
auto to_v8(v8::Isolate* isolate, std::optional<T> const& value) -> v8::Local<v8::Value>
{
if (value.has_value())
return convert<T>::to_v8(isolate, value.value());
else
return v8::Undefined(isolate);
}

template<typename T>
auto to_v8(v8::Isolate* isolate, T const& value)
{
Expand Down
15 changes: 15 additions & 0 deletions v8pp/utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <memory>
#include <string_view>
#include <tuple>
#include <optional>
#include <type_traits>

namespace v8pp { namespace detail {
Expand Down Expand Up @@ -158,6 +159,20 @@ struct is_shared_ptr<std::shared_ptr<T>> : std::true_type
{
};

/////////////////////////////////////////////////////////////////////////////
//
// is_optional<T>
//
template<typename T>
struct is_optional : std::false_type
{
};

template<typename T>
struct is_optional<std::optional<T>> : std::true_type
{
};

/////////////////////////////////////////////////////////////////////////////
//
// Function traits
Expand Down
Loading