1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef GIN_OBJECT_TEMPLATE_BUILDER_H_
6#define GIN_OBJECT_TEMPLATE_BUILDER_H_
7
8#include "base/bind.h"
9#include "base/callback.h"
10#include "base/strings/string_piece.h"
11#include "base/template_util.h"
12#include "gin/converter.h"
13#include "gin/function_template.h"
14#include "gin/gin_export.h"
15#include "v8/include/v8.h"
16
17namespace gin {
18
19namespace {
20
21// Base template - used only for non-member function pointers. Other types
22// either go to one of the below specializations, or go here and fail to compile
23// because of base::Bind().
24template<typename T, typename Enable = void>
25struct CallbackTraits {
26  static v8::Handle<v8::FunctionTemplate> CreateTemplate(v8::Isolate* isolate,
27                                                         T callback) {
28    return CreateFunctionTemplate(isolate, base::Bind(callback));
29  }
30  static void SetAsFunctionHandler(v8::Isolate* isolate,
31                                   v8::Local<v8::ObjectTemplate> tmpl,
32                                   T callback) {
33    CreateFunctionHandler(isolate, tmpl, base::Bind(callback));
34  }
35};
36
37// Specialization for base::Callback.
38template<typename T>
39struct CallbackTraits<base::Callback<T> > {
40  static v8::Handle<v8::FunctionTemplate> CreateTemplate(
41      v8::Isolate* isolate, const base::Callback<T>& callback) {
42    return CreateFunctionTemplate(isolate, callback);
43  }
44  static void SetAsFunctionHandler(v8::Isolate* isolate,
45                                   v8::Local<v8::ObjectTemplate> tmpl,
46                                   const base::Callback<T>& callback) {
47    CreateFunctionHandler(isolate, tmpl, callback);
48  }
49};
50
51// Specialization for member function pointers. We need to handle this case
52// specially because the first parameter for callbacks to MFP should typically
53// come from the the JavaScript "this" object the function was called on, not
54// from the first normal parameter.
55template<typename T>
56struct CallbackTraits<T, typename base::enable_if<
57                           base::is_member_function_pointer<T>::value>::type> {
58  static v8::Handle<v8::FunctionTemplate> CreateTemplate(v8::Isolate* isolate,
59                                                         T callback) {
60    return CreateFunctionTemplate(isolate, base::Bind(callback),
61                                  HolderIsFirstArgument);
62  }
63  static void SetAsFunctionHandler(v8::Isolate* isolate,
64                                   v8::Local<v8::ObjectTemplate> tmpl,
65                                   T callback) {
66    CreateFunctionHandler(
67        isolate, tmpl, base::Bind(callback), HolderIsFirstArgument);
68  }
69};
70
71// This specialization allows people to construct function templates directly if
72// they need to do fancier stuff.
73template<>
74struct GIN_EXPORT CallbackTraits<v8::Handle<v8::FunctionTemplate> > {
75  static v8::Handle<v8::FunctionTemplate> CreateTemplate(
76      v8::Handle<v8::FunctionTemplate> templ) {
77    return templ;
78  }
79};
80
81}  // namespace
82
83
84// ObjectTemplateBuilder provides a handy interface to creating
85// v8::ObjectTemplate instances with various sorts of properties.
86class GIN_EXPORT ObjectTemplateBuilder {
87 public:
88  explicit ObjectTemplateBuilder(v8::Isolate* isolate);
89  ~ObjectTemplateBuilder();
90
91  // It's against Google C++ style to return a non-const ref, but we take some
92  // poetic license here in order that all calls to Set() can be via the '.'
93  // operator and line up nicely.
94  template<typename T>
95  ObjectTemplateBuilder& SetValue(const base::StringPiece& name, T val) {
96    return SetImpl(name, ConvertToV8(isolate_, val));
97  }
98
99  // In the following methods, T and U can be function pointer, member function
100  // pointer, base::Callback, or v8::FunctionTemplate. Most clients will want to
101  // use one of the first two options. Also see gin::CreateFunctionTemplate()
102  // for creating raw function templates.
103  template<typename T>
104  ObjectTemplateBuilder& SetMethod(const base::StringPiece& name,
105                                   const T& callback) {
106    return SetImpl(name, CallbackTraits<T>::CreateTemplate(isolate_, callback));
107  }
108  template<typename T>
109  ObjectTemplateBuilder& SetProperty(const base::StringPiece& name,
110                                     const T& getter) {
111    return SetPropertyImpl(name,
112                           CallbackTraits<T>::CreateTemplate(isolate_, getter),
113                           v8::Local<v8::FunctionTemplate>());
114  }
115  template<typename T, typename U>
116  ObjectTemplateBuilder& SetProperty(const base::StringPiece& name,
117                                     const T& getter, const U& setter) {
118    return SetPropertyImpl(name,
119                           CallbackTraits<T>::CreateTemplate(isolate_, getter),
120                           CallbackTraits<U>::CreateTemplate(isolate_, setter));
121  }
122  template<typename T>
123  ObjectTemplateBuilder& SetCallAsFunctionHandler(const T& callback) {
124    CallbackTraits<T>::SetAsFunctionHandler(isolate_, template_, callback);
125    return *this;
126  }
127  ObjectTemplateBuilder& AddNamedPropertyInterceptor();
128  ObjectTemplateBuilder& AddIndexedPropertyInterceptor();
129
130  v8::Local<v8::ObjectTemplate> Build();
131
132 private:
133  ObjectTemplateBuilder& SetImpl(const base::StringPiece& name,
134                                 v8::Handle<v8::Data> val);
135  ObjectTemplateBuilder& SetPropertyImpl(
136      const base::StringPiece& name, v8::Handle<v8::FunctionTemplate> getter,
137      v8::Handle<v8::FunctionTemplate> setter);
138
139  v8::Isolate* isolate_;
140
141  // ObjectTemplateBuilder should only be used on the stack.
142  v8::Local<v8::ObjectTemplate> template_;
143};
144
145}  // namespace gin
146
147#endif  // GIN_OBJECT_TEMPLATE_BUILDER_H_
148