OLD | NEW |
| (Empty) |
1 // Copyright 2010 The Ginsu Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can | |
3 // be found in the LICENSE file. | |
4 | |
5 #ifndef C_SALT_CALLBACK_H_ | |
6 #define C_SALT_CALLBACK_H_ | |
7 | |
8 #include "boost/function.hpp" | |
9 #include "boost/bind.hpp" | |
10 #include "boost/shared_ptr.hpp" | |
11 #include "boost/type_traits/remove_const.hpp" | |
12 #include "boost/type_traits/remove_reference.hpp" | |
13 #include "c_salt/variant_ptrs.h" | |
14 #include "c_salt/variant.h" | |
15 | |
16 namespace c_salt { | |
17 namespace c_salt_private { | |
18 // VariantToArgConverter is a small helper class for converting c_salt Variants | |
19 // in to a given type, to allow them to be used as parameters. | |
20 // For most types, just call Variant::GetValue<> function and let it do the | |
21 // work. | |
22 // TODO(dmichael): Is there a nicer way to support passing c_salt::Variant as | |
23 // a parameter? Or is this a good way... it is certainly extensible. It also | |
24 // allows us to pass the Variant through without copying. | |
25 template <class T> | |
26 struct VariantToArgConverter { | |
27 static T Get(const c_salt::SharedVariant& var) { | |
28 return var->GetValue<T>(); | |
29 } | |
30 }; | |
31 // If the argument is a c_salt::SharedVariant, just pass it through. | |
32 template <> | |
33 struct VariantToArgConverter<c_salt::SharedVariant> { | |
34 static const c_salt::SharedVariant& Get(const c_salt::SharedVariant& var) { | |
35 return var; | |
36 } | |
37 }; | |
38 // If the argument is a c_salt::Variant, just dereference the shared_ptr. | |
39 template <> | |
40 struct VariantToArgConverter<c_salt::Variant> { | |
41 static const c_salt::Variant& Get(const c_salt::SharedVariant& var) { | |
42 return *var; | |
43 } | |
44 }; | |
45 } // namespace c_salt_private | |
46 | |
47 // Pure virtual class that provides the interface for invoking a method given | |
48 // c_salt::Variant arguments. Clients should generally not use this interface | |
49 // directly; it simply allows c_salt code to invoke methods generically. See | |
50 // MethodCallbackExecutorImpl (and related classes) below for further | |
51 // details on how this is achieved. | |
52 class MethodCallbackExecutor { | |
53 public: | |
54 virtual ~MethodCallbackExecutor() {} | |
55 | |
56 virtual bool Execute(const SharedVariant* params_begin, | |
57 const SharedVariant* params_end, | |
58 SharedVariant* return_value_var) = 0; | |
59 }; | |
60 typedef boost::shared_ptr<MethodCallbackExecutor> SharedMethodCallbackExecutor; | |
61 | |
62 // Templates used to support method call-backs when a method or property is | |
63 // accessed from the browser code. | |
64 | |
65 // FunctionInvoker is a class template which holds a boost::function and | |
66 // provides a means for invoking that boost::function by providing a sequence | |
67 // of c_salt::Variant parameters. Its purpose is to allow turning scripting | |
68 // invocations in to a more natural C++ form. For example, it can be used to | |
69 // convert an NPAPI method invocation in to a conventional C++ function call, | |
70 // or similarly for PPAPI, SRPC, etc, by mapping the parameters to a sequence of | |
71 // c_salt::Variants. | |
72 // | |
73 // This is the default implementation of FunctionInvoker. Its methods are not | |
74 // implemented; it is left here for documentation purposes only. Any real usage | |
75 // of FunctionInvoker must match one of the specializations defined later. If | |
76 // a match is not found, it is likely because the user is attempting to create | |
77 // a function invoker with more arguments than we currently support. | |
78 template <class Signature> | |
79 class FunctionInvoker { | |
80 // Constructor for member functions that binds the target object to the | |
81 // FunctionInvoker's stored boost::function. | |
82 template <class T> | |
83 FunctionInvoker(T* target_object, Signature method); | |
84 | |
85 // Convert the given parameters (taken as a sequence of c_salt::Variants) in | |
86 // to the C++ types required by the bound function. Then, invoke the | |
87 // boost::function owned by this FunctionInvoker, passing the arguments. | |
88 // Convert the return value to a c_salt::Variant. | |
89 // params_begin and params_end are pointers treated as forward iterators for a | |
90 // sequence that contains the arguments to be sent to the function. Note that | |
91 // we could just pass a vector, but this keeps STL dependencies to more of a | |
92 // minimum in the interface between client-compiled code (i.e., the template) | |
93 // and the Google-provided library (c_salt). | |
94 // return_val is an out-parameter. The caller must provide a valid pointer | |
95 // to a c_salt::Variant. | |
96 bool Invoke(const SharedVariant* begin, | |
97 const SharedVariant* end, | |
98 SharedVariant* return_value); | |
99 }; | |
100 | |
101 // Define some macros temporarily so that we can generate code succinctly for | |
102 // our FunctionInvoker classes. We need one specialization of FunctionInvoker | |
103 // for each number of arguments, and they are largely the same. The macros | |
104 // abstract out the repetive parts and allow us to only duplicate the parts that | |
105 // are unique. | |
106 // | |
107 // Here is an example of what the code looks like after the preprocessor is | |
108 // finished with it, in this case for 2 arguments: | |
109 #if 0 | |
110 template <class T, class RetType, class Arg1, class Arg2> | |
111 class FunctionInvoker<RetType(T::*)(Arg1, Arg2)> { | |
112 public: | |
113 typedef RetType ReturnType; | |
114 typedef ReturnType (T::*MemFunSignature) (Arg1, Arg2); | |
115 typedef ReturnType (*Signature) (Arg1, Arg2); | |
116 typedef boost::function<ReturnType (Arg1, Arg2)> FunctionType; | |
117 | |
118 FunctionInvoker(T* target_object, MemFunSignature method) | |
119 : function_(boost::bind(method, target_object, _1, _2)) {} | |
120 bool Invoke(const SharedVariant* params_begin, | |
121 const SharedVariant* params_end, | |
122 SharedVariant* return_value_var) { | |
123 // Declare a local instance of the argument type. If it's a const-ref | |
124 // parameter, remove the const-ref part of the type so we can make a local | |
125 // argument on the stack to pass. | |
126 typedef typename boost::remove_reference<Arg1>::type NoRef1; | |
127 typedef typename boost::remove_const<NoRef1>::type NoConstRef1; | |
128 NoConstRef1 arg1; | |
129 // See if we've run out of arguments. If so, that's an error, so return | |
130 // false. | |
131 if (params_begin == params_end) return false; | |
132 // Get the value from the c_salt::Variant, which handles conversions for us. | |
133 NoConstRef1 arg1(::c_salt::c_salt_private:: | |
134 VariantToArgConverter<NoConstRef1>::Get(*params_begin)); | |
135 // Advance to the next parameter. | |
136 ++params_begin; | |
137 typedef typename boost::remove_reference<Arg2>::type NoRef2; | |
138 typedef typename boost::remove_const<NoRef2>::type NoConstRef2; | |
139 if (params_begin == params_end) return false; | |
140 NoConstRef2 arg2(::c_salt::c_salt_private:: | |
141 VariantToArgConverter<NoConstRef2>::Get(*params_begin)); | |
142 ++params_begin; | |
143 NoConstRef2 arg2; | |
144 | |
145 // Call the function and capture the return value (note, this does not | |
146 // currently support void returns). | |
147 ReturnType retval = function_(arg1, arg2); | |
148 // Create a Variant using the appropriate constructor. | |
149 *return_value_var = SharedVariant(retval); | |
150 return true; | |
151 } | |
152 private: | |
153 FunctionType function_; | |
154 }; | |
155 #endif | |
156 // A macro that fills in the beginning of the class definition, including | |
157 // typedefs that we (or our clients) might find useful. | |
158 #define FUNCTIONINVOKER_CLASS_DEFINITION_BEGIN(ARGLIST) \ | |
159 class FunctionInvoker<RetType(T::*) ARGLIST> {\ | |
160 public:\ | |
161 typedef RetType ReturnType;\ | |
162 typedef ReturnType (T::*MemFunSignature) ARGLIST;\ | |
163 typedef ReturnType (*Signature) ARGLIST;\ | |
164 typedef boost::function<ReturnType ARGLIST> FunctionType;\ | |
165 | |
166 // A macro for the constructor. BIND_ARGLIST is of the form: | |
167 // (method, target_object ...) | |
168 // where the ... is a list of 0 or more bind placeholders (, _1, _2, etc). | |
169 #define FUNCTIONINVOKER_CONSTRUCTOR(BIND_ARGLIST) \ | |
170 FunctionInvoker(T* target_object, MemFunSignature method) : \ | |
171 function_(boost::bind BIND_ARGLIST ) {} | |
172 // end FUNCTIONINVOKER_CONSTRUCTOR | |
173 | |
174 // A macro for the beginning of the Invoke function. | |
175 #define FUNCTIONINVOKER_INVOKE_BEGIN() \ | |
176 bool Invoke(const ::c_salt::SharedVariant* params_begin, \ | |
177 const ::c_salt::SharedVariant* params_end, \ | |
178 ::c_salt::SharedVariant* return_value_var) { | |
179 // end FUNCTIONINVOKER_INVOKE_BEGIN | |
180 | |
181 // A portion of the invoker function that converts 1 argument, returning | |
182 // false if that conversion fails. NUM is a positive integer. | |
183 #define FUNCTIONINVOKER_INVOKE_CONVERT_ARG(NUM) \ | |
184 typedef typename boost::remove_reference<Arg ## NUM>::type NoRef ## NUM; \ | |
185 typedef typename boost::remove_const<NoRef ## NUM>::type NoConstRef ## NUM;\ | |
186 if (params_begin == params_end) return false; \ | |
187 NoConstRef##NUM arg##NUM(::c_salt::c_salt_private:: \ | |
188 VariantToArgConverter<NoConstRef##NUM>::Get(*params_begin)); \ | |
189 ++params_begin; | |
190 // end FUNCTIONINVOKER_INVOKE_CONVERT_ARG | |
191 | |
192 // A macro for the end of the Invoke function. | |
193 #define FUNCTIONINVOKER_INVOKE_END(ARGLIST) \ | |
194 ReturnType retval = function_ ARGLIST; \ | |
195 return_value_var->reset(new ::c_salt::Variant(retval)); \ | |
196 return true;\ | |
197 } | |
198 // end FUNCTIONINVOKER_INVOKE_END | |
199 | |
200 // A macro for the end of the FunctionInvoker class. | |
201 #define FUNCTIONINVOKER_CLASS_DEFINITION_END() \ | |
202 private: \ | |
203 FunctionType function_;\ | |
204 }; | |
205 // end FUNCTIONINVOKER_CLASS_DEFINITION_END | |
206 | |
207 // Now we use the above macros to define FunctionInvoker partial specializations | |
208 // for each number of arguments which we want to support. | |
209 // 0 Args. Note the lack of semicolons. These macros are not written to allow | |
210 // for semicolons. | |
211 template <class T, class RetType> | |
212 FUNCTIONINVOKER_CLASS_DEFINITION_BEGIN(()) | |
213 // Note that the parameter list here (and in INVOKE_END) must have additional | |
214 // parens around it. This makes it appear as 1 argument to the preprocessor, | |
215 // and places the entire parameter list in the resultant code. | |
216 FUNCTIONINVOKER_CONSTRUCTOR((method, target_object)) | |
217 FUNCTIONINVOKER_INVOKE_BEGIN() | |
218 FUNCTIONINVOKER_INVOKE_END(()) | |
219 FUNCTIONINVOKER_CLASS_DEFINITION_END() | |
220 // 1 Args. | |
221 template <class T, class RetType, class Arg1> | |
222 FUNCTIONINVOKER_CLASS_DEFINITION_BEGIN((Arg1)) | |
223 FUNCTIONINVOKER_CONSTRUCTOR((method, target_object, _1)) | |
224 FUNCTIONINVOKER_INVOKE_BEGIN() | |
225 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(1) | |
226 FUNCTIONINVOKER_INVOKE_END((arg1)) | |
227 FUNCTIONINVOKER_CLASS_DEFINITION_END() | |
228 // 2 Args. | |
229 template <class T, class RetType, class Arg1, class Arg2> | |
230 FUNCTIONINVOKER_CLASS_DEFINITION_BEGIN((Arg1, Arg2)) | |
231 FUNCTIONINVOKER_CONSTRUCTOR((method, target_object, _1, _2)) | |
232 FUNCTIONINVOKER_INVOKE_BEGIN() | |
233 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(1) | |
234 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(2) | |
235 FUNCTIONINVOKER_INVOKE_END((arg1, arg2)) | |
236 FUNCTIONINVOKER_CLASS_DEFINITION_END() | |
237 // 3 Args. | |
238 template <class T, class RetType, class Arg1, class Arg2, class Arg3> | |
239 FUNCTIONINVOKER_CLASS_DEFINITION_BEGIN((Arg1, Arg2, Arg3)) | |
240 FUNCTIONINVOKER_CONSTRUCTOR((method, target_object, _1, _2, _3)) | |
241 FUNCTIONINVOKER_INVOKE_BEGIN() | |
242 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(1) | |
243 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(2) | |
244 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(3) | |
245 FUNCTIONINVOKER_INVOKE_END((arg1, arg2, arg3)) | |
246 FUNCTIONINVOKER_CLASS_DEFINITION_END() | |
247 // 4 Args. | |
248 template <class T, class RetType, class Arg1, class Arg2, class Arg3 | |
249 , class Arg4> | |
250 FUNCTIONINVOKER_CLASS_DEFINITION_BEGIN((Arg1, Arg2, Arg3, Arg4)) | |
251 FUNCTIONINVOKER_CONSTRUCTOR((method, target_object, _1, _2, _3, _4)) | |
252 FUNCTIONINVOKER_INVOKE_BEGIN() | |
253 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(1) | |
254 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(2) | |
255 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(3) | |
256 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(4) | |
257 FUNCTIONINVOKER_INVOKE_END((arg1, arg2, arg3, arg4)) | |
258 FUNCTIONINVOKER_CLASS_DEFINITION_END() | |
259 // 5 Args. | |
260 template <class T, class RetType, class Arg1, class Arg2, class Arg3 | |
261 , class Arg4, class Arg5> | |
262 FUNCTIONINVOKER_CLASS_DEFINITION_BEGIN((Arg1, Arg2, Arg3, Arg4, Arg5)) | |
263 FUNCTIONINVOKER_CONSTRUCTOR((method, target_object, _1, _2, _3, _4, _5)) | |
264 FUNCTIONINVOKER_INVOKE_BEGIN() | |
265 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(1) | |
266 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(2) | |
267 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(3) | |
268 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(4) | |
269 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(5) | |
270 FUNCTIONINVOKER_INVOKE_END((arg1, arg2, arg3, arg4, arg5)) | |
271 FUNCTIONINVOKER_CLASS_DEFINITION_END() | |
272 // 6 Args. | |
273 template <class T, class RetType, class Arg1, class Arg2, class Arg3 | |
274 , class Arg4, class Arg5, class Arg6> | |
275 FUNCTIONINVOKER_CLASS_DEFINITION_BEGIN((Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)) | |
276 FUNCTIONINVOKER_CONSTRUCTOR((method, target_object, _1, _2, _3, _4, _5, _6)) | |
277 FUNCTIONINVOKER_INVOKE_BEGIN() | |
278 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(1) | |
279 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(2) | |
280 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(3) | |
281 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(4) | |
282 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(5) | |
283 FUNCTIONINVOKER_INVOKE_CONVERT_ARG(6) | |
284 FUNCTIONINVOKER_INVOKE_END((arg1, arg2, arg3, arg4, arg5, arg6)) | |
285 FUNCTIONINVOKER_CLASS_DEFINITION_END() | |
286 | |
287 // Now clean up so these macros aren't exported outside this .h file. | |
288 #undef FUNCTIONINVOKER_CLASS_DEFINITION_BEGIN | |
289 #undef FUNCTIONINVOKER_CONSTRUCTOR | |
290 #undef FUNCTIONINVOKER_INVOKE_BEGIN | |
291 #undef FUNCTIONINVOKER_INVOKE_CONVERT_ARG | |
292 #undef FUNCTIONINVOKER_INVOKE_END | |
293 #undef FUNCTIONINVOKER_CLASS_DEFINITION_END | |
294 | |
295 // MethodCallbackExecutorImpl is a class template that implements the | |
296 // MethodCallbackExecutor interface by calling an arbitrary boost::function | |
297 // and automatically handling marshalling/unmarshalling of the arguments and | |
298 // return type to bridge the gap between the method invocation and the | |
299 // invocation of a real C++ method on a client-defined class. | |
300 template <class Signature> | |
301 class MethodCallbackExecutorImpl : public MethodCallbackExecutor { | |
302 public: | |
303 typedef typename ::c_salt::FunctionInvoker<Signature> FunctionInvokerType; | |
304 | |
305 template <class T> | |
306 MethodCallbackExecutorImpl(T* instance, Signature method) | |
307 : function_invoker_(instance, method) {} | |
308 virtual ~MethodCallbackExecutorImpl() {} | |
309 | |
310 virtual bool Execute(const SharedVariant* params_begin, | |
311 const SharedVariant* params_end, | |
312 SharedVariant* return_value_var) { | |
313 return function_invoker_.Invoke(params_begin, | |
314 params_end, | |
315 return_value_var); | |
316 } | |
317 private: | |
318 FunctionInvokerType function_invoker_; | |
319 }; | |
320 | |
321 } // namespace c_salt | |
322 | |
323 #endif // C_SALT_CALLBACK_H_ | |
OLD | NEW |