From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Jeremy Apthorp Date: Wed, 1 Apr 2020 01:06:45 +0000 Subject: gin: forward args when dispatching This allows passing arguments with move-only semantics. Change-Id: I852eb343398e6f763abfe2a44e623f28353d79a5 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2129029 Commit-Queue: Jeremy Apthorp Reviewed-by: Jeremy Roman Auto-Submit: Jeremy Apthorp Cr-Commit-Position: refs/heads/master@{#755196} diff --git a/gin/converter_unittest.cc b/gin/converter_unittest.cc index 6f9205f06a3e4747e70149c440c4548e54045001..162572385bdd8a54612eb64414fe80e0f9d619d1 100644 --- a/gin/converter_unittest.cc +++ b/gin/converter_unittest.cc @@ -12,6 +12,7 @@ #include "base/stl_util.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" +#include "gin/function_template.h" #include "gin/handle.h" #include "gin/public/isolate_holder.h" #include "gin/test/v8_test.h" @@ -224,4 +225,45 @@ TEST_F(ConverterTest, VectorOfWrappables) { EXPECT_THAT(out_value2, testing::ContainerEq(vector)); } +namespace { + +class MoveOnlyObject { + public: + MoveOnlyObject() = default; + MoveOnlyObject(const MoveOnlyObject&) = delete; + MoveOnlyObject& operator=(const MoveOnlyObject&) = delete; + + MoveOnlyObject(MoveOnlyObject&&) noexcept = default; + MoveOnlyObject& operator=(MoveOnlyObject&&) noexcept = default; +}; + +} // namespace + +template <> +struct Converter { + static v8::Local ToV8(v8::Isolate* isolate, MoveOnlyObject in) { + return v8::Undefined(isolate); + } + static bool FromV8(v8::Isolate* isolate, + v8::Local val, + MoveOnlyObject* out) { + *out = MoveOnlyObject(); + return true; + } +}; + +TEST_F(ConverterTest, MoveOnlyParameters) { + v8::Isolate* isolate = instance_->isolate(); + v8::HandleScope handle_scope(isolate); + + auto receives_move_only_obj = [](MoveOnlyObject obj) {}; + auto func_templ = gin::CreateFunctionTemplate( + isolate, base::BindRepeating(receives_move_only_obj)); + + v8::Local context = instance_->isolate()->GetCurrentContext(); + auto func = func_templ->GetFunction(context).ToLocalChecked(); + v8::Local argv[] = {v8::Undefined(isolate)}; + func->Call(context, v8::Undefined(isolate), 1, argv).ToLocalChecked(); +} + } // namespace gin diff --git a/gin/function_template.h b/gin/function_template.h index 7edcc9e20dfa6367dde5f58237cca5f4ca637f7a..8c641d934fdeebb9a90f6eb49960e4fe06217913 100644 --- a/gin/function_template.h +++ b/gin/function_template.h @@ -166,14 +166,15 @@ class Invoker, ArgTypes...> template void DispatchToCallback( base::RepeatingCallback callback) { - args_->Return(callback.Run(ArgumentHolder::value...)); + args_->Return( + callback.Run(std::move(ArgumentHolder::value)...)); } // In C++, you can declare the function foo(void), but you can't pass a void // expression to foo. As a result, we must specialize the case of Callbacks // that have the void return type. void DispatchToCallback(base::RepeatingCallback callback) { - callback.Run(ArgumentHolder::value...); + callback.Run(std::move(ArgumentHolder::value)...); } private: