add LuaBridge
[ardour.git] / libs / lua / LuaBridge / detail / CFunctions.h
1 //------------------------------------------------------------------------------
2 /*
3   https://github.com/vinniefalco/LuaBridge
4   
5   Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
6
7   License: The MIT License (http://www.opensource.org/licenses/mit-license.php)
8
9   Permission is hereby granted, free of charge, to any person obtaining a copy
10   of this software and associated documentation files (the "Software"), to deal
11   in the Software without restriction, including without limitation the rights
12   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13   copies of the Software, and to permit persons to whom the Software is
14   furnished to do so, subject to the following conditions:
15
16   The above copyright notice and this permission notice shall be included in all
17   copies or substantial portions of the Software.
18
19   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25   SOFTWARE.
26 */
27 //==============================================================================
28
29 // We use a structure so we can define everything in the header.
30 //
31 struct CFunc
32 {
33   //----------------------------------------------------------------------------
34   /**
35       __index metamethod for a namespace or class static members.
36
37       This handles:
38         Retrieving functions and class static methods, stored in the metatable.
39         Reading global and class static data, stored in the __propget table.
40         Reading global and class properties, stored in the __propget table.
41   */
42   static int indexMetaMethod (lua_State* L)
43   {
44     int result = 0;
45     lua_getmetatable (L, 1);                // push metatable of arg1
46     for (;;)
47     {
48       lua_pushvalue (L, 2);                 // push key arg2
49       lua_rawget (L, -2);                   // lookup key in metatable
50       if (lua_isnil (L, -1))                // not found
51       {
52         lua_pop (L, 1);                     // discard nil
53         rawgetfield (L, -1, "__propget");   // lookup __propget in metatable
54         lua_pushvalue (L, 2);               // push key arg2
55         lua_rawget (L, -2);                 // lookup key in __propget
56         lua_remove (L, -2);                 // discard __propget
57         if (lua_iscfunction (L, -1))
58         {
59           lua_remove (L, -2);               // discard metatable
60           lua_pushvalue (L, 1);             // push arg1
61           lua_call (L, 1, 1);               // call cfunction
62           result = 1;
63           break;
64         }
65         else
66         {
67           assert (lua_isnil (L, -1));
68           lua_pop (L, 1);                   // discard nil and fall through
69         }
70       }
71       else
72       {
73         assert (lua_istable (L, -1) || lua_iscfunction (L, -1));
74         lua_remove (L, -2);
75         result = 1;
76         break;
77       }
78
79       rawgetfield (L, -1, "__parent");
80       if (lua_istable (L, -1))
81       {
82         // Remove metatable and repeat the search in __parent.
83         lua_remove (L, -2);
84       }
85       else
86       {
87         // Discard metatable and return nil.
88         assert (lua_isnil (L, -1));
89         lua_remove (L, -2);
90         result = 1;
91         break;
92       }
93     }
94
95     return result;
96   }
97
98   //----------------------------------------------------------------------------
99   /**
100       __newindex metamethod for a namespace or class static members.
101
102       The __propset table stores proxy functions for assignment to:
103         Global and class static data.
104         Global and class properties.
105   */
106   static int newindexMetaMethod (lua_State* L)
107   {
108     int result = 0;
109     lua_getmetatable (L, 1);                // push metatable of arg1
110     for (;;)
111     {
112       rawgetfield (L, -1, "__propset");     // lookup __propset in metatable
113       assert (lua_istable (L, -1));
114       lua_pushvalue (L, 2);                 // push key arg2
115       lua_rawget (L, -2);                   // lookup key in __propset
116       lua_remove (L, -2);                   // discard __propset
117       if (lua_iscfunction (L, -1))          // ensure value is a cfunction
118       {
119         lua_remove (L, -2);                 // discard metatable
120         lua_pushvalue (L, 3);               // push new value arg3
121         lua_call (L, 1, 0);                 // call cfunction
122         result = 0;
123         break;
124       }
125       else
126       {
127         assert (lua_isnil (L, -1));
128         lua_pop (L, 1);
129       }
130
131       rawgetfield (L, -1, "__parent");
132       if (lua_istable (L, -1))
133       {
134         // Remove metatable and repeat the search in __parent.
135         lua_remove (L, -2);
136       }
137       else
138       {
139         assert (lua_isnil (L, -1));
140         lua_pop (L, 2);
141         result = luaL_error (L,"no writable variable '%s'", lua_tostring (L, 2));
142       }
143     }
144
145     return result;
146   }
147
148   //----------------------------------------------------------------------------
149   /**
150       lua_CFunction to report an error writing to a read-only value.
151
152       The name of the variable is in the first upvalue.
153   */
154   static int readOnlyError (lua_State* L)
155   {
156     std::string s;
157     
158     s = s + "'" + lua_tostring (L, lua_upvalueindex (1)) + "' is read-only";
159
160     return luaL_error (L, s.c_str ());
161   }
162   
163   //----------------------------------------------------------------------------
164   /**
165       lua_CFunction to get a variable.
166
167       This is used for global variables or class static data members.
168
169       The pointer to the data is in the first upvalue.
170   */
171   template <class T>
172   static int getVariable (lua_State* L)
173   {
174     assert (lua_islightuserdata (L, lua_upvalueindex (1)));
175     T const* ptr = static_cast <T const*> (lua_touserdata (L, lua_upvalueindex (1)));
176     assert (ptr != 0);
177     Stack <T>::push (L, *ptr);
178     return 1;
179   }
180
181   //----------------------------------------------------------------------------
182   /**
183       lua_CFunction to set a variable.
184
185       This is used for global variables or class static data members.
186
187       The pointer to the data is in the first upvalue.
188   */
189   template <class T>
190   static int setVariable (lua_State* L)
191   {
192     assert (lua_islightuserdata (L, lua_upvalueindex (1)));
193     T* ptr = static_cast <T*> (lua_touserdata (L, lua_upvalueindex (1)));
194     assert (ptr != 0);
195     *ptr = Stack <T>::get (L, 1);
196     return 0;
197   }
198
199   //----------------------------------------------------------------------------
200   /**
201       lua_CFunction to call a function with a return value.
202
203       This is used for global functions, global properties, class static methods,
204       and class static properties.
205
206       The function pointer is in the first upvalue.
207   */
208   template <class FnPtr,
209             class ReturnType = typename FuncTraits <FnPtr>::ReturnType>
210   struct Call
211   {
212     typedef typename FuncTraits <FnPtr>::Params Params;
213     static int f (lua_State* L)
214     {
215       assert (isfulluserdata (L, lua_upvalueindex (1)));
216       FnPtr const& fnptr = *static_cast <FnPtr const*> (lua_touserdata (L, lua_upvalueindex (1)));
217       assert (fnptr != 0);
218       ArgList <Params> args (L);
219       Stack <typename FuncTraits <FnPtr>::ReturnType>::push (L, FuncTraits <FnPtr>::call (fnptr, args));
220       return 1;
221     }
222   };
223
224   //----------------------------------------------------------------------------
225   /**
226       lua_CFunction to call a function with no return value.
227
228       This is used for global functions, global properties, class static methods,
229       and class static properties.
230
231       The function pointer is in the first upvalue.
232   */
233   template <class FnPtr>
234   struct Call <FnPtr, void>
235   {
236     typedef typename FuncTraits <FnPtr>::Params Params;
237     static int f (lua_State* L)
238     {
239       assert (isfulluserdata (L, lua_upvalueindex (1)));
240       FnPtr const& fnptr = *static_cast <FnPtr const*> (lua_touserdata (L, lua_upvalueindex (1)));
241       assert (fnptr != 0);
242       ArgList <Params> args (L);
243       FuncTraits <FnPtr>::call (fnptr, args);
244       return 0;
245     }
246   };
247
248   //----------------------------------------------------------------------------
249   /**
250       lua_CFunction to call a class member function with a return value.
251
252       The member function pointer is in the first upvalue.
253       The class userdata object is at the top of the Lua stack.
254   */
255   template <class MemFnPtr,
256             class ReturnType = typename FuncTraits <MemFnPtr>::ReturnType>
257   struct CallMember
258   {
259     typedef typename FuncTraits <MemFnPtr>::ClassType T;
260     typedef typename FuncTraits <MemFnPtr>::Params Params;
261
262     static int f (lua_State* L)
263     {
264       assert (isfulluserdata (L, lua_upvalueindex (1)));
265       T* const t = Userdata::get <T> (L, 1, false);
266       MemFnPtr const& fnptr = *static_cast <MemFnPtr const*> (lua_touserdata (L, lua_upvalueindex (1)));
267       assert (fnptr != 0);
268       ArgList <Params, 2> args (L);
269       Stack <ReturnType>::push (L, FuncTraits <MemFnPtr>::call (t, fnptr, args));
270       return 1;
271     }
272   };
273
274   template <class MemFnPtr,
275             class ReturnType = typename FuncTraits <MemFnPtr>::ReturnType>
276   struct CallConstMember
277   {
278     typedef typename FuncTraits <MemFnPtr>::ClassType T;
279     typedef typename FuncTraits <MemFnPtr>::Params Params;
280
281     static int f (lua_State* L)
282     {
283       assert (isfulluserdata (L, lua_upvalueindex (1)));
284       T const* const t = Userdata::get <T> (L, 1, true);
285       MemFnPtr const& fnptr = *static_cast <MemFnPtr const*> (lua_touserdata (L, lua_upvalueindex (1)));
286       assert (fnptr != 0);
287       ArgList <Params, 2> args(L);
288       Stack <ReturnType>::push (L, FuncTraits <MemFnPtr>::call (t, fnptr, args));
289       return 1;
290     }
291   };
292
293   //----------------------------------------------------------------------------
294   /**
295       lua_CFunction to call a class member function with no return value.
296
297       The member function pointer is in the first upvalue.
298       The class userdata object is at the top of the Lua stack.
299   */
300   template <class MemFnPtr>
301   struct CallMember <MemFnPtr, void>
302   {
303     typedef typename FuncTraits <MemFnPtr>::ClassType T;
304     typedef typename FuncTraits <MemFnPtr>::Params Params;
305
306     static int f (lua_State* L)
307     {
308       assert (isfulluserdata (L, lua_upvalueindex (1)));
309       T* const t = Userdata::get <T> (L, 1, false);
310       MemFnPtr const& fnptr = *static_cast <MemFnPtr const*> (lua_touserdata (L, lua_upvalueindex (1)));
311       assert (fnptr != 0);
312       ArgList <Params, 2> args (L);
313       FuncTraits <MemFnPtr>::call (t, fnptr, args);
314       return 0;
315     }
316   };
317
318   template <class MemFnPtr>
319   struct CallConstMember <MemFnPtr, void>
320   {
321     typedef typename FuncTraits <MemFnPtr>::ClassType T;
322     typedef typename FuncTraits <MemFnPtr>::Params Params;
323
324     static int f (lua_State* L)
325     {
326       assert (isfulluserdata (L, lua_upvalueindex (1)));
327       T const* const t = Userdata::get <T> (L, 1, true);
328       MemFnPtr const& fnptr = *static_cast <MemFnPtr const*> (lua_touserdata (L, lua_upvalueindex (1)));
329       assert (fnptr != 0);
330       ArgList <Params, 2> args (L);
331       FuncTraits <MemFnPtr>::call (t, fnptr, args);
332       return 0;
333     }
334   };
335
336   //--------------------------------------------------------------------------
337   /**
338       lua_CFunction to call a class member lua_CFunction.
339
340       The member function pointer is in the first upvalue.
341       The class userdata object is at the top of the Lua stack.
342   */
343   template <class T>
344   struct CallMemberCFunction
345   {
346     static int f (lua_State* L)
347     {
348       assert (isfulluserdata (L, lua_upvalueindex (1)));
349       typedef int (T::*MFP)(lua_State* L);
350       T* const t = Userdata::get <T> (L, 1, false);
351       MFP const& fnptr = *static_cast <MFP const*> (lua_touserdata (L, lua_upvalueindex (1)));
352       assert (fnptr != 0);
353       return (t->*fnptr) (L);
354     }
355   };
356
357   template <class T>
358   struct CallConstMemberCFunction
359   {
360     static int f (lua_State* L)
361     {
362       assert (isfulluserdata (L, lua_upvalueindex (1)));
363       typedef int (T::*MFP)(lua_State* L);
364       T const* const t = Userdata::get <T> (L, 1, true);
365       MFP const& fnptr = *static_cast <MFP const*> (lua_touserdata (L, lua_upvalueindex (1)));
366       assert (fnptr != 0);
367       return (t->*fnptr) (L);
368     }
369   };
370
371   //--------------------------------------------------------------------------
372
373   // SFINAE Helpers
374
375   template <class MemFnPtr, bool isConst>
376   struct CallMemberFunctionHelper
377   {
378     static void add (lua_State* L, char const* name, MemFnPtr mf)
379     {
380       new (lua_newuserdata (L, sizeof (MemFnPtr))) MemFnPtr (mf);
381       lua_pushcclosure (L, &CallConstMember <MemFnPtr>::f, 1);
382       lua_pushvalue (L, -1);
383       rawsetfield (L, -5, name); // const table
384       rawsetfield (L, -3, name); // class table
385     }
386   };
387
388   template <class MemFnPtr>
389   struct CallMemberFunctionHelper <MemFnPtr, false>
390   {
391     static void add (lua_State* L, char const* name, MemFnPtr mf)
392     {
393       new (lua_newuserdata (L, sizeof (MemFnPtr))) MemFnPtr (mf);
394       lua_pushcclosure (L, &CallMember <MemFnPtr>::f, 1);
395       rawsetfield (L, -3, name); // class table
396     }
397   };
398
399   //--------------------------------------------------------------------------
400   /**
401       __gc metamethod for a class.
402   */
403   template <class C>
404   static int gcMetaMethod (lua_State* L)
405   {
406     Userdata* const ud = Userdata::getExact <C> (L, 1);
407     ud->~Userdata ();
408     return 0;
409   }
410
411   //--------------------------------------------------------------------------
412   /**
413       lua_CFunction to get a class data member.
414
415       The pointer-to-member is in the first upvalue.
416       The class userdata object is at the top of the Lua stack.
417   */
418   template <class C, typename T>
419   static int getProperty (lua_State* L)
420   {
421     C const* const c = Userdata::get <C> (L, 1, true);
422     T C::** mp = static_cast <T C::**> (lua_touserdata (L, lua_upvalueindex (1)));
423     Stack <T>::push (L, c->**mp);
424     return 1;
425   }
426
427   //--------------------------------------------------------------------------
428   /**
429       lua_CFunction to set a class data member.
430
431       The pointer-to-member is in the first upvalue.
432       The class userdata object is at the top of the Lua stack.
433   */
434   template <class C, typename T>
435   static int setProperty (lua_State* L)
436   {
437     C* const c = Userdata::get <C> (L, 1, false);
438     T C::** mp = static_cast <T C::**> (lua_touserdata (L, lua_upvalueindex (1)));
439     c->**mp = Stack <T>::get (L, 2);
440     return 0;
441   }
442 };