Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Conversion of std::tuple types #148

Merged
merged 4 commits into from
Mar 7, 2021
Merged
Changes from 1 commit
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
Next Next commit
Support for tuple conversion to/from v8
wflohry committed Feb 28, 2021
commit 263a7158455886592ccb6236ce363da1d425f507
23 changes: 23 additions & 0 deletions test/test.hpp
Original file line number Diff line number Diff line change
@@ -96,6 +96,29 @@ void check_eq(std::string msg, T actual, U expected)
}
}

template <typename ... Ts>
void check_eq(std::string msg, const std::tuple<Ts...>& actual, const std::tuple<Ts...>& expected)
{
if (actual != expected)
{
std::stringstream ss;
auto get_string_item = []<typename T>(const T& item){
using U = std::decay_t<T>;
if constexpr (std::is_same_v<U, std::string>){
return item;
} else {
return std::to_string(item);
}
};
auto get_string = [&get_string_item](const std::tuple<Ts...> &value){
std::string out = (get_string_item(std::get<Ts>(value)).append(", ") + ... + "");
return out;
};
ss << msg << " expected: '" << get_string(expected) << "' actual: '" << get_string(actual) << "'";
check(ss.str(), false);
}
}

template<typename Ex, typename F>
void check_ex(std::string msg, F&& f)
{
21 changes: 21 additions & 0 deletions test/test_convert.cpp
Original file line number Diff line number Diff line change
@@ -171,4 +171,25 @@ void test_convert()
person p;
p.name = "Al"; p.age = 33;
test_conv(isolate, p);


std::tuple<size_t, bool> tuple_1{2, true};
test_conv(isolate, tuple_1);

std::tuple<size_t, bool, std::string> tuple_2{2, true, "test"};
test_conv(isolate, tuple_2);

check_ex<std::runtime_error>("wrong array length", [isolate, &tuple_1]()
{
// incorrect number of elements
v8::Local<v8::Array> tuple_1_ = v8pp::to_v8(isolate, tuple_1);
v8pp::from_v8<std::tuple<size_t, bool, std::string>>(isolate, tuple_1_);
});

check_ex<v8pp::invalid_argument>("String", [isolate, &tuple_1]()
{
// wrong types
v8::Local<v8::Array> tuple_1_ = v8pp::to_v8(isolate, tuple_1);
v8pp::from_v8<std::tuple<size_t, std::string>>(isolate, tuple_1_);
});
}
56 changes: 56 additions & 0 deletions v8pp/convert.hpp
Original file line number Diff line number Diff line change
@@ -304,6 +304,53 @@ struct convert<T, typename std::enable_if<std::is_floating_point<T>::value>::typ
}
};

template <typename ... Ts>
struct convert<std::tuple<Ts...>>
{
using from_type = std::tuple<Ts...>;
using to_type = v8::Local<v8::Array>;
static constexpr size_t N = sizeof ... (Ts);
static bool is_valid(v8::Isolate*, v8::Local<v8::Value> value)
{
return !value.IsEmpty() && value->IsArray();
}

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

v8::HandleScope scope(isolate);
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Array> array = value.As<v8::Array>();

if (array->Length() != N)
{
throw std::runtime_error("Invalid array length: expected "
+ std::to_string(N) + " actual "
+ std::to_string(array->Length()));
}

return [isolate, &context, &array]<std::size_t ... Is>(std::index_sequence<Is...>&&) -> from_type{
return std::tuple<Ts...>{v8pp::convert<Ts>::from_v8(isolate, array->Get(context, Is).ToLocalChecked())...};
}(std::make_index_sequence<N>{});
}

static to_type to_v8(v8::Isolate * isolate, from_type const& value)
{
v8::EscapableHandleScope scope(isolate);
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Array> result = v8::Array::New(isolate, N);
[isolate, &context, &result, &value]<std::size_t ... Is>(std::index_sequence<Is...> &&) -> void {
(result->Set(context, Is, convert<Ts>::to_v8(isolate, std::get<Is>(value))).FromJust(), ...);
}(std::make_index_sequence<N>{});

return scope.Escape(result);
}
};

// convert Array <-> std::array
template<typename T, size_t N>
struct convert<std::array<T, N>>
@@ -487,6 +534,9 @@ struct is_wrapped_class<v8::Global<T>> : std::false_type {};
template<typename Char, typename Traits, typename Alloc>
struct is_wrapped_class<std::basic_string<Char, Traits, Alloc>> : std::false_type {};

template<typename ... Ts>
struct is_wrapped_class<std::tuple<Ts...>> : std::false_type{};

template<typename T, size_t N>
struct is_wrapped_class<std::array<T, N>> : std::false_type{};

@@ -701,6 +751,12 @@ v8::Local<v8::Array> to_v8(v8::Isolate* isolate, Iterator begin, Iterator end)
return scope.Escape(result);
}

template <typename ... Ts>
v8::Local<v8::Array> to_v8(v8::Isolate* isolate, std::tuple<Ts...> const& value)
{
return convert<std::tuple<Ts...>>::to_v8(isolate, value);
}

template<typename T>
v8::Local<v8::Array> to_v8(v8::Isolate* isolate, std::initializer_list<T> const& init)
{