• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1$$ This is a pump file for generating file templates.  Pump is a python
2$$ script that is part of the Google Test suite of utilities.  Description
3$$ can be found here:
4$$
5$$ http://code.google.com/p/googletest/wiki/PumpManual
6$$
7
8#ifndef GIN_FUNCTION_TEMPLATE_H_
9#define GIN_FUNCTION_TEMPLATE_H_
10
11$var MAX_ARITY = 6
12
13// Copyright 2013 The Chromium Authors. All rights reserved.
14// Use of this source code is governed by a BSD-style license that can be
15// found in the LICENSE file.
16
17#include "base/callback.h"
18#include "base/logging.h"
19#include "gin/arguments.h"
20#include "gin/converter.h"
21#include "gin/gin_export.h"
22#include "v8/include/v8.h"
23
24namespace gin {
25
26class PerIsolateData;
27
28enum CreateFunctionTemplateFlags {
29  HolderIsFirstArgument = 1 << 0,
30};
31
32namespace internal {
33
34template<typename T>
35struct CallbackParamTraits {
36  typedef T LocalType;
37};
38template<typename T>
39struct CallbackParamTraits<const T&> {
40  typedef T LocalType;
41};
42template<typename T>
43struct CallbackParamTraits<const T*> {
44  typedef T* LocalType;
45};
46
47
48// CallbackHolder and CallbackHolderBase are used to pass a base::Callback from
49// CreateFunctionTemplate through v8 (via v8::FunctionTemplate) to
50// DispatchToCallback, where it is invoked.
51
52// This simple base class is used so that we can share a single object template
53// among every CallbackHolder instance.
54class GIN_EXPORT CallbackHolderBase {
55 public:
56  v8::Handle<v8::External> GetHandle(v8::Isolate* isolate);
57
58 protected:
59  explicit CallbackHolderBase(v8::Isolate* isolate);
60  virtual ~CallbackHolderBase();
61
62 private:
63  static void WeakCallback(
64      const v8::WeakCallbackData<v8::External, CallbackHolderBase>& data);
65
66  v8::Persistent<v8::External> v8_ref_;
67
68  DISALLOW_COPY_AND_ASSIGN(CallbackHolderBase);
69};
70
71template<typename Sig>
72class CallbackHolder : public CallbackHolderBase {
73 public:
74  CallbackHolder(v8::Isolate* isolate,
75                 const base::Callback<Sig>& callback,
76                 int flags)
77      : CallbackHolderBase(isolate), callback(callback), flags(flags) {}
78  base::Callback<Sig> callback;
79  int flags;
80 private:
81  virtual ~CallbackHolder() {}
82
83  DISALLOW_COPY_AND_ASSIGN(CallbackHolder);
84};
85
86
87// This set of templates invokes a base::Callback, converts the return type to a
88// JavaScript value, and returns that value to script via the provided
89// gin::Arguments object.
90//
91// In C++, you can declare the function foo(void), but you can't pass a void
92// expression to foo. As a result, we must specialize the case of Callbacks that
93// have the void return type.
94
95$range ARITY 0..MAX_ARITY
96$for ARITY [[
97$var INV_ARITY = MAX_ARITY - ARITY
98$range ARG 1..INV_ARITY
99$range VOID INV_ARITY+1..MAX_ARITY
100
101$if ARITY == 0 [[
102template<typename R$for ARG [[, typename P$(ARG) = void]]>
103struct Invoker {
104]] $else [[
105template<typename R$for ARG [[, typename P$(ARG)]]>
106struct Invoker<R$for ARG [[, P$(ARG)]]$for VOID [[, void]]> {
107]]
108
109  inline static void Go(
110      Arguments* args,
111      const base::Callback<R($for ARG , [[P$(ARG)]])>& callback$for ARG [[,
112      const P$(ARG)& a$(ARG)]]) {
113    args->Return(callback.Run($for ARG, [[a$(ARG)]]));
114  }
115};
116template<$for ARG , [[typename P$(ARG)]]>
117struct Invoker<void$for ARG [[, P$(ARG)]]$for VOID [[, void]]> {
118  inline static void Go(
119      Arguments* args,
120      const base::Callback<void($for ARG , [[P$(ARG)]])>& callback$for ARG [[,
121      const P$(ARG)& a$(ARG)]]) {
122    callback.Run($for ARG, [[a$(ARG)]]);
123  }
124};
125
126
127]]
128
129template<typename T>
130bool GetNextArgument(Arguments* args, int create_flags, bool is_first,
131                     T* result) {
132  if (is_first && (create_flags & HolderIsFirstArgument) != 0) {
133    return args->GetHolder(result);
134  } else {
135    return args->GetNext(result);
136  }
137}
138
139// For advanced use cases, we allow callers to request the unparsed Arguments
140// object and poke around in it directly.
141inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first,
142                            Arguments* result) {
143  *result = *args;
144  return true;
145}
146inline bool GetNextArgument(Arguments* args, int create_flags, bool is_first,
147                            Arguments** result) {
148  *result = args;
149  return true;
150}
151
152// It's common for clients to just need the isolate, so we make that easy.
153inline bool GetNextArgument(Arguments* args, int create_flags,
154                            bool is_first, v8::Isolate** result) {
155  *result = args->isolate();
156  return true;
157}
158
159
160// DispatchToCallback converts all the JavaScript arguments to C++ types and
161// invokes the base::Callback.
162template<typename Sig>
163struct Dispatcher {
164};
165
166$range ARITY 0..MAX_ARITY
167$for ARITY [[
168$range ARG 1..ARITY
169
170template<typename R$for ARG [[, typename P$(ARG)]]>
171struct Dispatcher<R($for ARG , [[P$(ARG)]])> {
172  static void DispatchToCallback(
173      const v8::FunctionCallbackInfo<v8::Value>& info) {
174    Arguments args(info);
175    v8::Handle<v8::External> v8_holder;
176    CHECK(args.GetData(&v8_holder));
177    CallbackHolderBase* holder_base = reinterpret_cast<CallbackHolderBase*>(
178        v8_holder->Value());
179
180    typedef CallbackHolder<R($for ARG , [[P$(ARG)]])> HolderT;
181    HolderT* holder = static_cast<HolderT*>(holder_base);
182
183$if ARITY != 0 [[
184
185
186$for ARG [[    typename CallbackParamTraits<P$(ARG)>::LocalType a$(ARG);
187
188]]
189    if ($for ARG  ||
190        [[!GetNextArgument(&args, holder->flags, $if ARG == 1 [[true]] $else [[false]], &a$(ARG))]]) {
191      args.ThrowError();
192      return;
193    }
194
195]]
196
197    Invoker<R$for ARG [[, P$(ARG)]]>::Go(&args, holder->callback$for ARG [[, a$(ARG)]]);
198  }
199};
200
201]]
202
203}  // namespace internal
204
205
206// CreateFunctionTemplate creates a v8::FunctionTemplate that will create
207// JavaScript functions that execute a provided C++ function or base::Callback.
208// JavaScript arguments are automatically converted via gin::Converter, as is
209// the return value of the C++ function, if any.
210template<typename Sig>
211v8::Local<v8::FunctionTemplate> CreateFunctionTemplate(
212    v8::Isolate* isolate, const base::Callback<Sig> callback,
213    int callback_flags = 0) {
214  typedef internal::CallbackHolder<Sig> HolderT;
215  HolderT* holder = new HolderT(isolate, callback, callback_flags);
216
217  return v8::FunctionTemplate::New(
218      isolate,
219      &internal::Dispatcher<Sig>::DispatchToCallback,
220      ConvertToV8<v8::Handle<v8::External> >(isolate,
221                                             holder->GetHandle(isolate)));
222}
223
224// CreateFunctionHandler installs a CallAsFunction handler on the given
225// object template that forwards to a provided C++ function or base::Callback.
226template<typename Sig>
227void CreateFunctionHandler(v8::Isolate* isolate,
228                           v8::Local<v8::ObjectTemplate> tmpl,
229                           const base::Callback<Sig> callback,
230                           int callback_flags = 0) {
231  typedef internal::CallbackHolder<Sig> HolderT;
232  HolderT* holder = new HolderT(isolate, callback, callback_flags);
233  tmpl->SetCallAsFunctionHandler(&internal::Dispatcher<Sig>::DispatchToCallback,
234                                 ConvertToV8<v8::Handle<v8::External> >(
235                                     isolate, holder->GetHandle(isolate)));
236}
237
238}  // namespace gin
239
240#endif  // GIN_FUNCTION_TEMPLATE_H_
241