diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-06 06:55:25 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-06 06:55:25 +0000 |
commit | bf3dd3cc6b32fd98b82f5e22a9ab1fddbe38f8d9 (patch) | |
tree | a5f3d7b91e1b0f5a70660ab80d6c4c1d8f5a33c8 /gin | |
parent | c80725d518df535f6e08e61d5bab47600046a646 (diff) | |
download | chromium_src-bf3dd3cc6b32fd98b82f5e22a9ab1fddbe38f8d9.zip chromium_src-bf3dd3cc6b32fd98b82f5e22a9ab1fddbe38f8d9.tar.gz chromium_src-bf3dd3cc6b32fd98b82f5e22a9ab1fddbe38f8d9.tar.bz2 |
Gin: Add support for binding JS methods to C++ instance methods.
Also:
- Added support for computed properties to ObjectTemplateBuilder
- Realized it was possible for CreateFunctionTemplate to be just one template
BUG=
R=abarth@chromium.org, jyasskin@chromium.org
Review URL: https://codereview.chromium.org/103703002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@239126 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gin')
-rw-r--r-- | gin/arguments.cc | 6 | ||||
-rw-r--r-- | gin/arguments.h | 6 | ||||
-rw-r--r-- | gin/function_template.h | 293 | ||||
-rw-r--r-- | gin/function_template.h.pump | 104 | ||||
-rw-r--r-- | gin/object_template_builder.cc | 8 | ||||
-rw-r--r-- | gin/object_template_builder.h | 79 | ||||
-rw-r--r-- | gin/try_catch.cc | 5 | ||||
-rw-r--r-- | gin/wrappable.cc | 2 | ||||
-rw-r--r-- | gin/wrappable.h | 2 | ||||
-rw-r--r-- | gin/wrappable_unittest.cc | 39 |
10 files changed, 306 insertions, 238 deletions
diff --git a/gin/arguments.cc b/gin/arguments.cc index 2844514..ee57897 100644 --- a/gin/arguments.cc +++ b/gin/arguments.cc @@ -45,10 +45,4 @@ void Arguments::ThrowTypeError(const std::string& message) { StringToV8(isolate_, message))); } -template<> -bool Arguments::GetNext<Arguments>(Arguments* out) { - *out = *this; - return true; -} - } // namespace gin diff --git a/gin/arguments.h b/gin/arguments.h index 8be9bc3..1461dc8 100644 --- a/gin/arguments.h +++ b/gin/arguments.h @@ -20,8 +20,7 @@ class Arguments { ~Arguments(); template<typename T> - // TODO(aa): Rename GetHolder(). - bool Holder(T* out) { + bool GetHolder(T* out) { return ConvertFromV8(isolate_, info_->Holder(), out); } @@ -75,9 +74,6 @@ class Arguments { bool insufficient_arguments_; }; -template<> -bool Arguments::GetNext<Arguments>(Arguments* out); - } // namespace gin #endif // GIN_ARGUMENTS_H_ diff --git a/gin/function_template.h b/gin/function_template.h index 6431317..b2badfa 100644 --- a/gin/function_template.h +++ b/gin/function_template.h @@ -26,15 +26,23 @@ namespace gin { class PerIsolateData; +enum CreateFunctionTemplateFlags { + HolderIsFirstArgument = 1 << 0, +}; + namespace internal { template<typename T> -struct RemoveConstRef { - typedef T Type; +struct CallbackParamTraits { + typedef T LocalType; +}; +template<typename T> +struct CallbackParamTraits<const T&> { + typedef T LocalType; }; template<typename T> -struct RemoveConstRef<const T&> { - typedef T Type; +struct CallbackParamTraits<const T*> { + typedef T* LocalType; }; @@ -58,9 +66,10 @@ class CallbackHolderBase : public Wrappable { template<typename Sig> class CallbackHolder : public CallbackHolderBase { public: - CallbackHolder(const base::Callback<Sig>& callback) - : callback(callback) {} + CallbackHolder(const base::Callback<Sig>& callback, int flags) + : callback(callback), flags(flags) {} base::Callback<Sig> callback; + int flags; private: virtual ~CallbackHolder() {} }; @@ -180,108 +189,141 @@ struct Invoker<void, void, void, void, void> { }; +template<typename T> +bool GetNextArgument(Arguments* args, int create_flags, bool is_first, + T* result) { + if (is_first && (create_flags & HolderIsFirstArgument) != 0) { + return args->GetHolder(result); + } else { + return args->GetNext(result); + } +} + +// For advanced use cases, we allow callers to request the unparsed Arguments +// object and poke around in it directly. +inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first, + Arguments* result) { + *result = *args; + return true; +} + + // DispatchToCallback converts all the JavaScript arguments to C++ types and // invokes the base::Callback. +template<typename Sig> +struct Dispatcher { +}; + template<typename R> -static void DispatchToCallback( - const v8::FunctionCallbackInfo<v8::Value>& info) { - Arguments args(info); - CallbackHolderBase* holder_base = NULL; - CHECK(args.GetData(&holder_base)); +struct Dispatcher<R()> { + static void DispatchToCallback( + const v8::FunctionCallbackInfo<v8::Value>& info) { + Arguments args(info); + CallbackHolderBase* holder_base = NULL; + CHECK(args.GetData(&holder_base)); - typedef CallbackHolder<R()> HolderT; - HolderT* holder = static_cast<HolderT*>(holder_base); + typedef CallbackHolder<R()> HolderT; + HolderT* holder = static_cast<HolderT*>(holder_base); - Invoker<R>::Go(&args, holder->callback); -} + Invoker<R>::Go(&args, holder->callback); + } +}; template<typename R, typename P1> -static void DispatchToCallback( - const v8::FunctionCallbackInfo<v8::Value>& info) { - Arguments args(info); - CallbackHolderBase* holder_base = NULL; - CHECK(args.GetData(&holder_base)); - - typedef CallbackHolder<R(P1)> HolderT; - HolderT* holder = static_cast<HolderT*>(holder_base); - - typename RemoveConstRef<P1>::Type a1; - if (!args.GetNext(&a1)) { - args.ThrowError(); - return; +struct Dispatcher<R(P1)> { + static void DispatchToCallback( + const v8::FunctionCallbackInfo<v8::Value>& info) { + Arguments args(info); + CallbackHolderBase* holder_base = NULL; + CHECK(args.GetData(&holder_base)); + + typedef CallbackHolder<R(P1)> HolderT; + HolderT* holder = static_cast<HolderT*>(holder_base); + + typename CallbackParamTraits<P1>::LocalType a1; + if (!GetNextArgument(&args, holder->flags, true, &a1)) { + args.ThrowError(); + return; + } + + Invoker<R, P1>::Go(&args, holder->callback, a1); } - - Invoker<R, P1>::Go(&args, holder->callback, a1); -} +}; template<typename R, typename P1, typename P2> -static void DispatchToCallback( - const v8::FunctionCallbackInfo<v8::Value>& info) { - Arguments args(info); - CallbackHolderBase* holder_base = NULL; - CHECK(args.GetData(&holder_base)); - - typedef CallbackHolder<R(P1, P2)> HolderT; - HolderT* holder = static_cast<HolderT*>(holder_base); - - typename RemoveConstRef<P1>::Type a1; - typename RemoveConstRef<P2>::Type a2; - if (!args.GetNext(&a1) || - !args.GetNext(&a2)) { - args.ThrowError(); - return; +struct Dispatcher<R(P1, P2)> { + static void DispatchToCallback( + const v8::FunctionCallbackInfo<v8::Value>& info) { + Arguments args(info); + CallbackHolderBase* holder_base = NULL; + CHECK(args.GetData(&holder_base)); + + typedef CallbackHolder<R(P1, P2)> HolderT; + HolderT* holder = static_cast<HolderT*>(holder_base); + + typename CallbackParamTraits<P1>::LocalType a1; + typename CallbackParamTraits<P2>::LocalType a2; + if (!GetNextArgument(&args, holder->flags, true, &a1) || + !GetNextArgument(&args, holder->flags, false, &a2)) { + args.ThrowError(); + return; + } + + Invoker<R, P1, P2>::Go(&args, holder->callback, a1, a2); } - - Invoker<R, P1, P2>::Go(&args, holder->callback, a1, a2); -} +}; template<typename R, typename P1, typename P2, typename P3> -static void DispatchToCallback( - const v8::FunctionCallbackInfo<v8::Value>& info) { - Arguments args(info); - CallbackHolderBase* holder_base = NULL; - CHECK(args.GetData(&holder_base)); - - typedef CallbackHolder<R(P1, P2, P3)> HolderT; - HolderT* holder = static_cast<HolderT*>(holder_base); - - typename RemoveConstRef<P1>::Type a1; - typename RemoveConstRef<P2>::Type a2; - typename RemoveConstRef<P3>::Type a3; - if (!args.GetNext(&a1) || - !args.GetNext(&a2) || - !args.GetNext(&a3)) { - args.ThrowError(); - return; +struct Dispatcher<R(P1, P2, P3)> { + static void DispatchToCallback( + const v8::FunctionCallbackInfo<v8::Value>& info) { + Arguments args(info); + CallbackHolderBase* holder_base = NULL; + CHECK(args.GetData(&holder_base)); + + typedef CallbackHolder<R(P1, P2, P3)> HolderT; + HolderT* holder = static_cast<HolderT*>(holder_base); + + typename CallbackParamTraits<P1>::LocalType a1; + typename CallbackParamTraits<P2>::LocalType a2; + typename CallbackParamTraits<P3>::LocalType a3; + if (!GetNextArgument(&args, holder->flags, true, &a1) || + !GetNextArgument(&args, holder->flags, false, &a2) || + !GetNextArgument(&args, holder->flags, false, &a3)) { + args.ThrowError(); + return; + } + + Invoker<R, P1, P2, P3>::Go(&args, holder->callback, a1, a2, a3); } - - Invoker<R, P1, P2, P3>::Go(&args, holder->callback, a1, a2, a3); -} +}; template<typename R, typename P1, typename P2, typename P3, typename P4> -static void DispatchToCallback( - const v8::FunctionCallbackInfo<v8::Value>& info) { - Arguments args(info); - CallbackHolderBase* holder_base = NULL; - CHECK(args.GetData(&holder_base)); - - typedef CallbackHolder<R(P1, P2, P3, P4)> HolderT; - HolderT* holder = static_cast<HolderT*>(holder_base); - - typename RemoveConstRef<P1>::Type a1; - typename RemoveConstRef<P2>::Type a2; - typename RemoveConstRef<P3>::Type a3; - typename RemoveConstRef<P4>::Type a4; - if (!args.GetNext(&a1) || - !args.GetNext(&a2) || - !args.GetNext(&a3) || - !args.GetNext(&a4)) { - args.ThrowError(); - return; +struct Dispatcher<R(P1, P2, P3, P4)> { + static void DispatchToCallback( + const v8::FunctionCallbackInfo<v8::Value>& info) { + Arguments args(info); + CallbackHolderBase* holder_base = NULL; + CHECK(args.GetData(&holder_base)); + + typedef CallbackHolder<R(P1, P2, P3, P4)> HolderT; + HolderT* holder = static_cast<HolderT*>(holder_base); + + typename CallbackParamTraits<P1>::LocalType a1; + typename CallbackParamTraits<P2>::LocalType a2; + typename CallbackParamTraits<P3>::LocalType a3; + typename CallbackParamTraits<P4>::LocalType a4; + if (!GetNextArgument(&args, holder->flags, true, &a1) || + !GetNextArgument(&args, holder->flags, false, &a2) || + !GetNextArgument(&args, holder->flags, false, &a3) || + !GetNextArgument(&args, holder->flags, false, &a4)) { + args.ThrowError(); + return; + } + + Invoker<R, P1, P2, P3, P4>::Go(&args, holder->callback, a1, a2, a3, a4); } - - Invoker<R, P1, P2, P3, P4>::Go(&args, holder->callback, a1, a2, a3, a4); -} +}; } // namespace internal @@ -299,66 +341,19 @@ struct Converter<internal::CallbackHolderBase*> : public WrappableConverter<internal::CallbackHolderBase> {}; -// Creates a v8::FunctionTemplate that will run the provided base::Callback each -// time it is called. JavaScript arguments and return values are converted via -// gin::Converter. -template<typename R> -v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( - v8::Isolate* isolate, - const base::Callback<R()> callback) { - typedef internal::CallbackHolder<R()> HolderT; - gin::Handle<HolderT> holder = CreateHandle(isolate, new HolderT(callback)); - return v8::FunctionTemplate::New( - isolate, - &internal::DispatchToCallback<R>, - ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get())); -} - -template<typename R, typename P1> -v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( - v8::Isolate* isolate, - const base::Callback<R(P1)> callback) { - typedef internal::CallbackHolder<R(P1)> HolderT; - gin::Handle<HolderT> holder = CreateHandle(isolate, new HolderT(callback)); - return v8::FunctionTemplate::New( - isolate, - &internal::DispatchToCallback<R, P1>, - ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get())); -} - -template<typename R, typename P1, typename P2> -v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( - v8::Isolate* isolate, - const base::Callback<R(P1, P2)> callback) { - typedef internal::CallbackHolder<R(P1, P2)> HolderT; - gin::Handle<HolderT> holder = CreateHandle(isolate, new HolderT(callback)); - return v8::FunctionTemplate::New( - isolate, - &internal::DispatchToCallback<R, P1, P2>, - ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get())); -} - -template<typename R, typename P1, typename P2, typename P3> -v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( - v8::Isolate* isolate, - const base::Callback<R(P1, P2, P3)> callback) { - typedef internal::CallbackHolder<R(P1, P2, P3)> HolderT; - gin::Handle<HolderT> holder = CreateHandle(isolate, new HolderT(callback)); - return v8::FunctionTemplate::New( - isolate, - &internal::DispatchToCallback<R, P1, P2, P3>, - ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get())); -} - -template<typename R, typename P1, typename P2, typename P3, typename P4> +// CreateFunctionTemplate creates a v8::FunctionTemplate that will create +// JavaScript functions that execute a provided C++ function or base::Callback. +// JavaScript arguments are automatically converted via gin::Converter, as is +// the return value of the C++ function, if any. +template<typename Sig> v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( - v8::Isolate* isolate, - const base::Callback<R(P1, P2, P3, P4)> callback) { - typedef internal::CallbackHolder<R(P1, P2, P3, P4)> HolderT; - gin::Handle<HolderT> holder = CreateHandle(isolate, new HolderT(callback)); + v8::Isolate* isolate, const base::Callback<Sig> callback, + int callback_flags = 0) { + typedef internal::CallbackHolder<Sig> HolderT; + gin::Handle<HolderT> holder = CreateHandle( + isolate, new HolderT(callback, callback_flags)); return v8::FunctionTemplate::New( - isolate, - &internal::DispatchToCallback<R, P1, P2, P3, P4>, + &internal::Dispatcher<Sig>::DispatchToCallback, ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get())); } diff --git a/gin/function_template.h.pump b/gin/function_template.h.pump index 7324db8..d3ae98b 100644 --- a/gin/function_template.h.pump +++ b/gin/function_template.h.pump @@ -29,15 +29,23 @@ namespace gin { class PerIsolateData; +enum CreateFunctionTemplateFlags { + HolderIsFirstArgument = 1 << 0, +}; + namespace internal { template<typename T> -struct RemoveConstRef { - typedef T Type; +struct CallbackParamTraits { + typedef T LocalType; +}; +template<typename T> +struct CallbackParamTraits<const T&> { + typedef T LocalType; }; template<typename T> -struct RemoveConstRef<const T&> { - typedef T Type; +struct CallbackParamTraits<const T*> { + typedef T* LocalType; }; @@ -61,9 +69,10 @@ class CallbackHolderBase : public Wrappable { template<typename Sig> class CallbackHolder : public CallbackHolderBase { public: - CallbackHolder(const base::Callback<Sig>& callback) - : callback(callback) {} + CallbackHolder(const base::Callback<Sig>& callback, int flags) + : callback(callback), flags(flags) {} base::Callback<Sig> callback; + int flags; private: virtual ~CallbackHolder() {} }; @@ -111,39 +120,63 @@ struct Invoker<void$for ARG [[, P$(ARG)]]$for VOID [[, void]]> { ]] +template<typename T> +bool GetNextArgument(Arguments* args, int create_flags, bool is_first, + T* result) { + if (is_first && (create_flags & HolderIsFirstArgument) != 0) { + return args->GetHolder(result); + } else { + return args->GetNext(result); + } +} + +// For advanced use cases, we allow callers to request the unparsed Arguments +// object and poke around in it directly. +inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first, + Arguments* result) { + *result = *args; + return true; +} + + // DispatchToCallback converts all the JavaScript arguments to C++ types and // invokes the base::Callback. +template<typename Sig> +struct Dispatcher { +}; + $range ARITY 0..MAX_ARITY $for ARITY [[ $range ARG 1..ARITY template<typename R$for ARG [[, typename P$(ARG)]]> -static void DispatchToCallback( - const v8::FunctionCallbackInfo<v8::Value>& info) { - Arguments args(info); - CallbackHolderBase* holder_base = NULL; - CHECK(args.GetData(&holder_base)); +struct Dispatcher<R($for ARG , [[P$(ARG)]])> { + static void DispatchToCallback( + const v8::FunctionCallbackInfo<v8::Value>& info) { + Arguments args(info); + CallbackHolderBase* holder_base = NULL; + CHECK(args.GetData(&holder_base)); - typedef CallbackHolder<R($for ARG , [[P$(ARG)]])> HolderT; - HolderT* holder = static_cast<HolderT*>(holder_base); + typedef CallbackHolder<R($for ARG , [[P$(ARG)]])> HolderT; + HolderT* holder = static_cast<HolderT*>(holder_base); $if ARITY != 0 [[ -$for ARG [[ typename RemoveConstRef<P$(ARG)>::Type a$(ARG); +$for ARG [[ typename CallbackParamTraits<P$(ARG)>::LocalType a$(ARG); ]] - if ( -$for ARG || - [[!args.GetNext(&a$(ARG))]]) { - args.ThrowError(); - return; - } + if ($for ARG || + [[!GetNextArgument(&args, holder->flags, $if ARG == 1 [[true]] $else [[false]], &a$(ARG))]]) { + args.ThrowError(); + return; + } ]] - Invoker<R$for ARG [[, P$(ARG)]]>::Go(&args, holder->callback$for ARG [[, a$(ARG)]]); -} + Invoker<R$for ARG [[, P$(ARG)]]>::Go(&args, holder->callback$for ARG [[, a$(ARG)]]); + } +}; ]] @@ -163,27 +196,22 @@ struct Converter<internal::CallbackHolderBase*> : public WrappableConverter<internal::CallbackHolderBase> {}; -// Creates a v8::FunctionTemplate that will run the provided base::Callback each -// time it is called. JavaScript arguments and return values are converted via -// gin::Converter. -$range ARITY 0..MAX_ARITY -$for ARITY [[ -$range ARG 1..ARITY - -template<typename R$for ARG [[, typename P$(ARG)]]> +// CreateFunctionTemplate creates a v8::FunctionTemplate that will create +// JavaScript functions that execute a provided C++ function or base::Callback. +// JavaScript arguments are automatically converted via gin::Converter, as is +// the return value of the C++ function, if any. +template<typename Sig> v8::Local<v8::FunctionTemplate> CreateFunctionTemplate( - v8::Isolate* isolate, - const base::Callback<R($for ARG , [[P$(ARG)]])> callback) { - typedef internal::CallbackHolder<R($for ARG , [[P$(ARG)]])> HolderT; - gin::Handle<HolderT> holder = CreateHandle(isolate, new HolderT(callback)); + v8::Isolate* isolate, const base::Callback<Sig> callback, + int callback_flags = 0) { + typedef internal::CallbackHolder<Sig> HolderT; + gin::Handle<HolderT> holder = CreateHandle( + isolate, new HolderT(callback, callback_flags)); return v8::FunctionTemplate::New( - isolate, - &internal::DispatchToCallback<R$for ARG [[, P$(ARG)]]>, + &internal::Dispatcher<Sig>::DispatchToCallback, ConvertToV8<internal::CallbackHolderBase*>(isolate, holder.get())); } -]] - } // namespace gin #endif // GIN_FUNCTION_TEMPLATE_H_ diff --git a/gin/object_template_builder.cc b/gin/object_template_builder.cc index 3a148e7..6dc6d2f 100644 --- a/gin/object_template_builder.cc +++ b/gin/object_template_builder.cc @@ -19,6 +19,14 @@ ObjectTemplateBuilder& ObjectTemplateBuilder::SetImpl( return *this; } +ObjectTemplateBuilder& ObjectTemplateBuilder::SetPropertyImpl( + const base::StringPiece& name, v8::Handle<v8::FunctionTemplate> getter, + v8::Handle<v8::FunctionTemplate> setter) { + template_->SetAccessorProperty(StringToSymbol(isolate_, name), getter, + setter); + return *this; +} + v8::Local<v8::ObjectTemplate> ObjectTemplateBuilder::Build() { v8::Local<v8::ObjectTemplate> result = template_; template_.Clear(); diff --git a/gin/object_template_builder.h b/gin/object_template_builder.h index 87e2633..9af5e4f 100644 --- a/gin/object_template_builder.h +++ b/gin/object_template_builder.h @@ -6,13 +6,64 @@ #define GIN_OBJECT_TEMPLATE_BUILDER_H_ #include "base/bind.h" +#include "base/callback.h" #include "base/strings/string_piece.h" +#include "base/template_util.h" #include "gin/converter.h" #include "gin/function_template.h" #include "v8/include/v8.h" namespace gin { +namespace { + +// Base template - used only for non-member function pointers. Other types +// either go to one of the below specializations, or go here and fail to compile +// because of base::Bind(). +template<typename T, typename Enable = void> +struct CallbackTraits { + static v8::Handle<v8::FunctionTemplate> CreateTemplate(v8::Isolate* isolate, + T callback) { + return CreateFunctionTemplate(isolate, base::Bind(callback)); + } +}; + +// Specialization for base::Callback. +template<typename T> +struct CallbackTraits<base::Callback<T> > { + static v8::Handle<v8::FunctionTemplate> CreateTemplate( + v8::Isolate* isolate, const base::Callback<T>& callback) { + return CreateFunctionTemplate(isolate, callback); + } +}; + +// Specialization for member function pointers. We need to handle this case +// specially because the first parameter for callbacks to MFP should typically +// come from the the JavaScript "this" object the function was called on, not +// from the first normal parameter. +template<typename T> +struct CallbackTraits<T, typename base::enable_if< + base::is_member_function_pointer<T>::value >::type> { + static v8::Handle<v8::FunctionTemplate> CreateTemplate(v8::Isolate* isolate, + T callback) { + return CreateFunctionTemplate(isolate, base::Bind(callback), + HolderIsFirstArgument); + } +}; + +// This specialization allows people to construct function templates directly if +// they need to do fancier stuff. +template<> +struct CallbackTraits<v8::Handle<v8::FunctionTemplate> > { + static v8::Handle<v8::FunctionTemplate> CreateTemplate( + v8::Handle<v8::FunctionTemplate> templ) { + return templ; + } +}; + +} // namespace + + // ObjectTemplateBuilder provides a handy interface to creating // v8::ObjectTemplate instances with various sorts of properties. class ObjectTemplateBuilder { @@ -28,15 +79,28 @@ class ObjectTemplateBuilder { return SetImpl(name, ConvertToV8(isolate_, val)); } + // In the following methods, T and U can be function pointer, member function + // pointer, base::Callback, or v8::FunctionTemplate. Most clients will want to + // use one of the first two options. Also see gin::CreateFunctionTemplate() + // for creating raw function templates. template<typename T> - ObjectTemplateBuilder& SetMethod(const base::StringPiece& name, T val) { - return SetMethod(name, base::Bind(val)); + ObjectTemplateBuilder& SetMethod(const base::StringPiece& name, + const T& callback) { + return SetImpl(name, CallbackTraits<T>::CreateTemplate(isolate_, callback)); } - template<typename T> - ObjectTemplateBuilder& SetMethod(const base::StringPiece& name, - const base::Callback<T>& callback) { - return SetImpl(name, CreateFunctionTemplate(isolate_, callback)); + ObjectTemplateBuilder& SetProperty(const base::StringPiece& name, + const T& getter) { + return SetPropertyImpl(name, + CallbackTraits<T>::CreateTemplate(isolate_, getter), + v8::Local<v8::FunctionTemplate>()); + } + template<typename T, typename U> + ObjectTemplateBuilder& SetProperty(const base::StringPiece& name, + const T& getter, const U& setter) { + return SetPropertyImpl(name, + CallbackTraits<T>::CreateTemplate(isolate_, getter), + CallbackTraits<U>::CreateTemplate(isolate_, setter)); } v8::Local<v8::ObjectTemplate> Build(); @@ -44,6 +108,9 @@ class ObjectTemplateBuilder { private: ObjectTemplateBuilder& SetImpl(const base::StringPiece& name, v8::Handle<v8::Data> val); + ObjectTemplateBuilder& SetPropertyImpl( + const base::StringPiece& name, v8::Handle<v8::FunctionTemplate> getter, + v8::Handle<v8::FunctionTemplate> setter); v8::Isolate* isolate_; diff --git a/gin/try_catch.cc b/gin/try_catch.cc index 89a969f..a44e28e 100644 --- a/gin/try_catch.cc +++ b/gin/try_catch.cc @@ -6,7 +6,6 @@ #include <sstream> -#include "base/logging.h" #include "gin/converter.h" namespace gin { @@ -22,6 +21,10 @@ bool TryCatch::HasCaught() { } std::string TryCatch::GetStackTrace() { + if (!HasCaught()) { + return ""; + } + std::stringstream ss; v8::Handle<v8::Message> message = try_catch_.Message(); ss << V8ToString(message->Get()) << std::endl diff --git a/gin/wrappable.cc b/gin/wrappable.cc index cb652d6..e9217ba 100644 --- a/gin/wrappable.cc +++ b/gin/wrappable.cc @@ -34,7 +34,7 @@ v8::Handle<v8::Object> Wrappable::CreateWrapper(v8::Isolate* isolate) { PerIsolateData* data = PerIsolateData::From(isolate); v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate(info); CHECK(!templ.IsEmpty()); // Don't forget to register an object template. - CHECK(templ->InternalFieldCount() == kNumberOfInternalFields); + CHECK_EQ(kNumberOfInternalFields, templ->InternalFieldCount()); v8::Handle<v8::Object> wrapper = templ->NewInstance(); wrapper->SetAlignedPointerInInternalField(kWrapperInfoIndex, info); wrapper->SetAlignedPointerInInternalField(kEncodedValueIndex, this); diff --git a/gin/wrappable.h b/gin/wrappable.h index 333a31c..0fa3697 100644 --- a/gin/wrappable.h +++ b/gin/wrappable.h @@ -78,7 +78,7 @@ struct WrappableConverter { return Converter<Wrappable*>::ToV8(isolate, val); } static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val, T** out) { - Wrappable* wrappable = 0; + Wrappable* wrappable = NULL; if (!Converter<Wrappable*>::FromV8(isolate, val, &wrappable) || wrappable->GetWrapperInfo() != &T::kWrapperInfo) return false; diff --git a/gin/wrappable_unittest.cc b/gin/wrappable_unittest.cc index ad47e28..d6ec19e 100644 --- a/gin/wrappable_unittest.cc +++ b/gin/wrappable_unittest.cc @@ -5,9 +5,11 @@ #include "base/logging.h" #include "gin/arguments.h" #include "gin/handle.h" +#include "gin/object_template_builder.h" #include "gin/per_isolate_data.h" #include "gin/public/isolate_holder.h" #include "gin/test/v8_test.h" +#include "gin/try_catch.h" #include "gin/wrappable.h" #include "testing/gtest/include/gtest/gtest.h" @@ -48,41 +50,14 @@ struct Converter<MyObject*> : public WrappableConverter<MyObject> {}; namespace { -// TODO(abarth): This is too much typing. - -void MyObjectGetValue(const v8::FunctionCallbackInfo<v8::Value>& info) { - Arguments args(info); - - MyObject* obj = 0; - CHECK(args.Holder(&obj)); - - args.Return(obj->value()); -} - -void MyObjectSetValue(const v8::FunctionCallbackInfo<v8::Value>& info) { - Arguments args(info); - - MyObject* obj = 0; - CHECK(args.Holder(&obj)); - - int val = 0; - if (!args.GetNext(&val)) - return args.ThrowError(); - - obj->set_value(val); -} - void RegisterTemplate(v8::Isolate* isolate) { PerIsolateData* data = PerIsolateData::From(isolate); DCHECK(data->GetObjectTemplate(&MyObject::kWrapperInfo).IsEmpty()); - v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate); + v8::Handle<v8::ObjectTemplate> templ = ObjectTemplateBuilder(isolate) + .SetProperty("value", &MyObject::value, &MyObject::set_value) + .Build(); templ->SetInternalFieldCount(kNumberOfInternalFields); - templ->SetAccessorProperty( - StringToSymbol(isolate, "value"), - v8::FunctionTemplate::New(isolate, MyObjectGetValue), - v8::FunctionTemplate::New(isolate, MyObjectSetValue)); - data->SetObjectTemplate(&MyObject::kWrapperInfo, templ); } @@ -119,7 +94,7 @@ TEST_F(WrappableTest, GetAndSetProperty) { " else obj.value = 191; })"); EXPECT_FALSE(source.IsEmpty()); - v8::TryCatch try_catch; + gin::TryCatch try_catch; v8::Handle<v8::Script> script = v8::Script::New(source); EXPECT_FALSE(script.IsEmpty()); v8::Handle<v8::Value> val = script->Run(); @@ -130,6 +105,8 @@ TEST_F(WrappableTest, GetAndSetProperty) { ConvertToV8(isolate, obj.get()), }; func->Call(v8::Undefined(isolate), 1, argv); + EXPECT_FALSE(try_catch.HasCaught()); + EXPECT_EQ("", try_catch.GetStackTrace()); EXPECT_EQ(191, obj->value()); } |