// Copyright (c) 2019 GitHub, Inc. All rights reserved. // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. #ifndef SHELL_COMMON_NATIVE_MATE_CONVERTERS_ONCE_CALLBACK_H_ #define SHELL_COMMON_NATIVE_MATE_CONVERTERS_ONCE_CALLBACK_H_ #include <utility> #include "shell/common/native_mate_converters/callback.h" namespace mate { namespace internal { // Manages the OnceCallback with ref-couting. template <typename Sig> class RefCountedOnceCallback : public base::RefCounted<RefCountedOnceCallback<Sig>> { public: explicit RefCountedOnceCallback(base::OnceCallback<Sig> callback) : callback_(std::move(callback)) {} base::OnceCallback<Sig> GetCallback() { return std::move(callback_); } private: friend class base::RefCounted<RefCountedOnceCallback<Sig>>; ~RefCountedOnceCallback() = default; base::OnceCallback<Sig> callback_; }; // Invokes the OnceCallback. template <typename Sig> struct InvokeOnceCallback {}; template <typename... ArgTypes> struct InvokeOnceCallback<void(ArgTypes...)> { static void Go( scoped_refptr<RefCountedOnceCallback<void(ArgTypes...)>> holder, ArgTypes... args) { base::OnceCallback<void(ArgTypes...)> callback = holder->GetCallback(); DCHECK(!callback.is_null()); std::move(callback).Run(std::move(args)...); } }; template <typename ReturnType, typename... ArgTypes> struct InvokeOnceCallback<ReturnType(ArgTypes...)> { static ReturnType Go( scoped_refptr<RefCountedOnceCallback<ReturnType(ArgTypes...)>> holder, ArgTypes... args) { base::OnceCallback<void(ArgTypes...)> callback = holder->GetCallback(); DCHECK(!callback.is_null()); return std::move(callback).Run(std::move(args)...); } }; } // namespace internal template <typename Sig> struct Converter<base::OnceCallback<Sig>> { static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, base::OnceCallback<Sig> val) { // Reuse the converter of base::RepeatingCallback by storing the callback // with a RefCounted. auto holder = base::MakeRefCounted<internal::RefCountedOnceCallback<Sig>>( std::move(val)); return Converter<base::RepeatingCallback<Sig>>::ToV8( isolate, base::BindRepeating(&internal::InvokeOnceCallback<Sig>::Go, holder)); } static bool FromV8(v8::Isolate* isolate, v8::Local<v8::Value> val, base::OnceCallback<Sig>* out) { if (!val->IsFunction()) return false; *out = base::BindOnce(&internal::V8FunctionInvoker<Sig>::Go, isolate, internal::SafeV8Function(isolate, val)); return true; } }; } // namespace mate #endif // SHELL_COMMON_NATIVE_MATE_CONVERTERS_ONCE_CALLBACK_H_