refine Lua Binding Documentation
[ardour.git] / libs / lua / LuaBridge / detail / Userdata.h
1 //------------------------------------------------------------------------------
2 /*
3   https://github.com/vinniefalco/LuaBridge
4
5   Copyright 2016, Robin Gareus <robin@gareus.org>
6   Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
7
8   License: The MIT License (http://www.opensource.org/licenses/mit-license.php)
9
10   Permission is hereby granted, free of charge, to any person obtaining a copy
11   of this software and associated documentation files (the "Software"), to deal
12   in the Software without restriction, including without limitation the rights
13   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14   copies of the Software, and to permit persons to whom the Software is
15   furnished to do so, subject to the following conditions:
16
17   The above copyright notice and this permission notice shall be included in all
18   copies or substantial portions of the Software.
19
20   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26   SOFTWARE.
27 */
28 //==============================================================================
29
30 //==============================================================================
31 /**
32   Return the identity pointer for our lightuserdata tokens.
33
34   LuaBridge metatables are tagged with a security "token." The token is a
35   lightuserdata created from the identity pointer, used as a key in the
36   metatable. The value is a boolean = true, although any value could have been
37   used.
38
39   Because of Lua's dynamic typing and our improvised system of imposing C++
40   class structure, there is the possibility that executing scripts may
41   knowingly or unknowingly cause invalid data to get passed to the C functions
42   created by LuaBridge. In particular, our security model addresses the
43   following:
44
45   Notes:
46     1. Scripts cannot create a userdata (ignoring the debug lib).
47     2. Scripts cannot create a lightuserdata (ignoring the debug lib).
48     3. Scripts cannot set the metatable on a userdata.
49     4. Our identity key is a unique pointer in the process.
50     5. Our metatables have a lightuserdata identity key / value pair.
51     6. Our metatables have "__metatable" set to a boolean = false.
52     7. Our lightuserdata is unique.
53 */
54 inline void* getIdentityKey ()
55 {
56   static char value;
57   return &value;
58 }
59
60 /**
61   Interface to a class pointer retrievable from a userdata.
62 */
63 class Userdata
64 {
65 protected:
66   void* m_p; // subclasses must set this
67
68   //--------------------------------------------------------------------------
69   /**
70     Get an untyped pointer to the contained class.
71   */
72   inline void* getPointer () const
73   {
74     return m_p;
75   }
76
77 private:
78   //--------------------------------------------------------------------------
79   /**
80     Validate and retrieve a Userdata on the stack.
81
82     The Userdata must exactly match the corresponding class table or
83     const table, or else a Lua error is raised. This is used for the
84     __gc metamethod.
85   */
86   static Userdata* getExactClass (lua_State* L,
87                                   int narg,
88                                   void const* classKey)
89   {
90     Userdata* ud = 0;
91     int const index = lua_absindex (L, narg);
92
93     bool mismatch = false;
94     char const* got = 0;
95
96     lua_rawgetp (L, LUA_REGISTRYINDEX, classKey);
97     assert (lua_istable (L, -1));
98
99     // Make sure we have a userdata.
100     if (!lua_isuserdata (L, index))
101       mismatch = true;
102
103     // Make sure it's metatable is ours.
104     if (!mismatch)
105     {
106       lua_getmetatable (L, index);
107       lua_rawgetp (L, -1, getIdentityKey ());
108       if (lua_isboolean (L, -1))
109       {
110         lua_pop (L, 1);
111       }
112       else
113       {
114         lua_pop (L, 2);
115         mismatch = true;
116       }
117     }
118
119     if (!mismatch)
120     {
121       if (lua_rawequal (L, -1, -2))
122       {
123         // Matches class table.
124         lua_pop (L, 2);
125         ud = static_cast <Userdata*> (lua_touserdata (L, index));
126       }
127       else
128       {
129         rawgetfield (L, -2, "__const");
130         if (lua_rawequal (L, -1, -2))
131         {
132           // Matches const table
133           lua_pop (L, 3);
134           ud = static_cast <Userdata*> (lua_touserdata (L, index));
135         }
136         else
137         {
138           // Mismatch, but its one of ours so get a type name.
139           rawgetfield (L, -2, "__type");
140           lua_insert (L, -4);
141           lua_pop (L, 2);
142           got = lua_tostring (L, -2);
143           mismatch = true;
144         }
145       }
146     }
147
148     if (mismatch)
149     {
150       rawgetfield (L, -1, "__type");
151       assert (lua_type (L, -1) == LUA_TSTRING);
152       char const* const expected = lua_tostring (L, -1);
153
154       if (got == 0)
155         got = lua_typename (L, lua_type (L, index));
156
157       char const* const msg = lua_pushfstring (
158         L, "%s expected, got %s", expected, got);
159
160       if (narg > 0)
161         luaL_argerror (L, narg, msg);
162       else
163         lua_error (L);
164     }
165
166     return ud;
167   }
168
169   //--------------------------------------------------------------------------
170   /**
171     Validate and retrieve a Userdata on the stack.
172
173     The Userdata must be derived from or the same as the given base class,
174     identified by the key. If canBeConst is false, generates an error if
175     the resulting Userdata represents to a const object. We do the type check
176     first so that the error message is informative.
177   */
178   static Userdata* getClass (lua_State* L,
179                              int index,
180                              void const* baseClassKey,
181                              bool canBeConst)
182   {
183     assert (index > 0);
184     Userdata* ud = 0;
185
186     bool mismatch = false;
187     char const* got = 0;
188
189     lua_rawgetp (L, LUA_REGISTRYINDEX, baseClassKey);
190     assert (lua_istable (L, -1));
191
192     // Make sure we have a userdata.
193     if (lua_isuserdata (L, index))
194     {
195       // Make sure it's metatable is ours.
196       lua_getmetatable (L, index);
197       lua_rawgetp (L, -1, getIdentityKey ());
198       if (lua_isboolean (L, -1))
199       {
200         lua_pop (L, 1);
201
202         // If __const is present, object is NOT const.
203         rawgetfield (L, -1, "__const");
204         assert (lua_istable (L, -1) || lua_isnil (L, -1));
205         bool const isConst = lua_isnil (L, -1);
206         lua_pop (L, 1);
207
208         // Replace the class table with the const table if needed.
209         if (isConst)
210         {
211           rawgetfield (L, -2, "__const");
212           assert (lua_istable (L, -1));
213           lua_replace (L, -3);
214         }
215
216         for (;;)
217         {
218           if (lua_rawequal (L, -1, -2))
219           {
220             lua_pop (L, 2);
221
222             // Match, now check const-ness.
223             if (isConst && !canBeConst)
224             {
225               luaL_argerror (L, index, "cannot be const");
226             }
227             else
228             {
229               ud = static_cast <Userdata*> (lua_touserdata (L, index));
230               break;
231             }
232           }
233           else
234           {
235             // Replace current metatable with it's base class.
236             rawgetfield (L, -1, "__parent");
237 /*
238 ud
239 class metatable
240 ud metatable
241 ud __parent (nil)
242 */
243
244             if (lua_isnil (L, -1))
245             {
246               lua_remove (L, -1);
247               // Mismatch, but its one of ours so get a type name.
248               rawgetfield (L, -1, "__type");
249               lua_insert (L, -3);
250               lua_pop (L, 1);
251               got = lua_tostring (L, -2);
252               mismatch = true;
253               break;
254             }
255             else
256             {
257               lua_remove (L, -2);
258             }
259           }
260         }
261       }
262       else
263       {
264         lua_pop (L, 2);
265         mismatch = true;
266       }
267     }
268     else
269     {
270       mismatch = true;
271     }
272
273     if (mismatch)
274     {
275       assert (lua_type (L, -1) == LUA_TTABLE);
276       rawgetfield (L, -1, "__type");
277       assert (lua_type (L, -1) == LUA_TSTRING);
278       char const* const expected = lua_tostring (L, -1);
279
280       if (got == 0)
281         got = lua_typename (L, lua_type (L, index));
282
283       char const* const msg = lua_pushfstring (
284         L, "%s expected, got %s", expected, got);
285
286       luaL_argerror (L, index, msg);
287     }
288
289     return ud;
290   }
291
292 public:
293   virtual ~Userdata () { }
294
295   //--------------------------------------------------------------------------
296   /**
297     Returns the Userdata* if the class on the Lua stack matches.
298
299     If the class does not match, a Lua error is raised.
300   */
301   template <class T>
302   static inline Userdata* getExact (lua_State* L, int index)
303   {
304     return getExactClass (L, index, ClassInfo <T>::getClassKey ());
305   }
306
307   //--------------------------------------------------------------------------
308   /**
309     Get a pointer to the class from the Lua stack.
310
311     If the object is not the class or a subclass, or it violates the
312     const-ness, a Lua error is raised.
313   */
314   template <class T>
315   static inline T* get (lua_State* L, int index, bool canBeConst)
316   {
317     if (lua_isnil (L, index))
318       return 0;
319     else
320       return static_cast <T*> (getClass (L, index,
321         ClassInfo <T>::getClassKey (), canBeConst)->getPointer ());
322   }
323 };
324
325 //----------------------------------------------------------------------------
326 /**
327   Wraps a class object stored in a Lua userdata.
328
329   The lifetime of the object is managed by Lua. The object is constructed
330   inside the userdata using placement new.
331 */
332 template <class T>
333 class UserdataValue : public Userdata
334 {
335 private:
336   UserdataValue <T> (UserdataValue <T> const&);
337   UserdataValue <T> operator= (UserdataValue <T> const&);
338
339   char m_storage [sizeof (T)];
340
341   inline T* getObject ()
342   {
343     // If this fails to compile it means you forgot to provide
344     // a Container specialization for your container!
345     //
346     return reinterpret_cast <T*> (&m_storage [0]);
347   }
348
349 private:
350   /**
351     Used for placement construction.
352   */
353   UserdataValue ()
354   {
355     m_p = getObject ();
356   }
357
358   ~UserdataValue ()
359   {
360     getObject ()->~T ();
361   }
362
363 public:
364   /**
365     Push a T via placement new.
366
367     The caller is responsible for calling placement new using the
368     returned uninitialized storage.
369   */
370   static void* place (lua_State* const L)
371   {
372     UserdataValue <T>* const ud = new (
373       lua_newuserdata (L, sizeof (UserdataValue <T>))) UserdataValue <T> ();
374     lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getClassKey ());
375     // If this goes off it means you forgot to register the class!
376     assert (lua_istable (L, -1));
377     lua_setmetatable (L, -2);
378     return ud->getPointer ();
379   }
380
381   /**
382     Push T via copy construction from U.
383   */
384   template <class U>
385   static inline void push (lua_State* const L, U const& u)
386   {
387     new (place (L)) U (u);
388   }
389 };
390
391 //----------------------------------------------------------------------------
392 /**
393   Wraps a pointer to a class object inside a Lua userdata.
394
395   The lifetime of the object is managed by C++.
396 */
397 class UserdataPtr : public Userdata
398 {
399 private:
400   UserdataPtr (UserdataPtr const&);
401   UserdataPtr operator= (UserdataPtr const&);
402
403 private:
404   /** Push non-const pointer to object using metatable key.
405   */
406   static void push (lua_State* L, void* const p, void const* const key)
407   {
408     if (p)
409     {
410       new (lua_newuserdata (L, sizeof (UserdataPtr))) UserdataPtr (p);
411       lua_rawgetp (L, LUA_REGISTRYINDEX, key);
412       // If this goes off it means you forgot to register the class!
413       assert (lua_istable (L, -1));
414       lua_setmetatable (L, -2);
415     }
416     else
417     {
418       lua_pushnil (L);
419     }
420   }
421
422   /** Push const pointer to object using metatable key.
423   */
424   static void push (lua_State* L, void const* const p, void const* const key)
425   {
426     if (p)
427     {
428       new (lua_newuserdata (L, sizeof (UserdataPtr)))
429         UserdataPtr (const_cast <void*> (p));
430       lua_rawgetp (L, LUA_REGISTRYINDEX, key);
431       // If this goes off it means you forgot to register the class!
432       assert (lua_istable (L, -1));
433       lua_setmetatable (L, -2);
434     }
435     else
436     {
437       lua_pushnil (L);
438     }
439   }
440
441   explicit UserdataPtr (void* const p)
442   {
443     m_p = p;
444
445     // Can't construct with a null pointer!
446     //
447     assert (m_p != 0);
448   }
449
450 public:
451   /** Push non-const pointer to object.
452   */
453   template <class T>
454   static inline void push (lua_State* const L, T* const p)
455   {
456     if (p)
457       push (L, p, ClassInfo <T>::getClassKey ());
458     else
459       lua_pushnil (L);
460   }
461
462   /** Push const pointer to object.
463   */
464   template <class T>
465   static inline void push (lua_State* const L, T const* const p)
466   {
467     if (p)
468       push (L, p, ClassInfo <T>::getConstKey ());
469     else
470       lua_pushnil (L);
471   }
472 };
473
474 //============================================================================
475 /**
476   Wraps a container thet references a class object.
477
478   The template argument C is the container type, ContainerTraits must be
479   specialized on C or else a compile error will result.
480 */
481 template <class C>
482 class UserdataShared : public Userdata
483 {
484 private:
485   UserdataShared (UserdataShared <C> const&);
486   UserdataShared <C>& operator= (UserdataShared <C> const&);
487
488   typedef typename TypeTraits::removeConst <
489     typename ContainerTraits <C>::Type>::Type T;
490
491   C m_c;
492
493 private:
494   ~UserdataShared ()
495   {
496   }
497
498 public:
499   /**
500     Construct from a container to the class or a derived class.
501   */
502   template <class U>
503   explicit UserdataShared (U const& u) : m_c (u)
504   {
505     m_p = const_cast <void*> (reinterpret_cast <void const*> (
506         (ContainerTraits <C>::get (m_c))));
507   }
508
509   /**
510     Construct from a pointer to the class or a derived class.
511   */
512   template <class U>
513   explicit UserdataShared (U* u) : m_c (u)
514   {
515     m_p = const_cast <void*> (reinterpret_cast <void const*> (
516         (ContainerTraits <C>::get (m_c))));
517   }
518 };
519
520 //----------------------------------------------------------------------------
521 //
522 // SFINAE helpers.
523 //
524
525 // non-const objects
526 template <class C, bool makeObjectConst>
527 struct UserdataSharedHelper
528 {
529   typedef typename TypeTraits::removeConst <
530     typename ContainerTraits <C>::Type>::Type T;
531
532   static void push (lua_State* L, C const& c)
533   {
534     if (ContainerTraits <C>::get (c) != 0)
535     {
536       new (lua_newuserdata (L, sizeof (UserdataShared <C>))) UserdataShared <C> (c);
537       lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getClassKey ());
538       // If this goes off it means the class T is unregistered!
539       assert (lua_istable (L, -1));
540       lua_setmetatable (L, -2);
541     }
542     else
543     {
544       lua_pushnil (L);
545     }
546   }
547
548   static void push (lua_State* L, T* const t)
549   {
550     if (t)
551     {
552       new (lua_newuserdata (L, sizeof (UserdataShared <C>))) UserdataShared <C> (t);
553       lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getClassKey ());
554       // If this goes off it means the class T is unregistered!
555       assert (lua_istable (L, -1));
556       lua_setmetatable (L, -2);
557     }
558     else
559     {
560       lua_pushnil (L);
561     }
562   }
563 };
564
565 // const objects
566 template <class C>
567 struct UserdataSharedHelper <C, true>
568 {
569   typedef typename TypeTraits::removeConst <
570     typename ContainerTraits <C>::Type>::Type T;
571
572   static void push (lua_State* L, C const& c)
573   {
574     if (ContainerTraits <C>::get (c) != 0)
575     {
576       new (lua_newuserdata (L, sizeof (UserdataShared <C>))) UserdataShared <C> (c);
577       lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getConstKey ());
578       // If this goes off it means the class T is unregistered!
579       assert (lua_istable (L, -1));
580       lua_setmetatable (L, -2);
581     }
582     else
583     {
584       lua_pushnil (L);
585     }
586   }
587
588   static void push (lua_State* L, T* const t)
589   {
590     if (t)
591     {
592       new (lua_newuserdata (L, sizeof (UserdataShared <C>))) UserdataShared <C> (t);
593       lua_rawgetp (L, LUA_REGISTRYINDEX, ClassInfo <T>::getConstKey ());
594       // If this goes off it means the class T is unregistered!
595       assert (lua_istable (L, -1));
596       lua_setmetatable (L, -2);
597     }
598     else
599     {
600       lua_pushnil (L);
601     }
602   }
603 };
604
605 /**
606   Pass by container.
607
608   The container controls the object lifetime. Typically this will be a
609   lifetime shared by C++ and Lua using a reference count. Because of type
610   erasure, containers like std::shared_ptr will not work. Containers must
611   either be of the intrusive variety, or in the style of the RefCountedPtr
612   type provided by LuaBridge (that uses a global hash table).
613 */
614 template <class C, bool byContainer, bool isEnum>
615 struct StackHelper
616 {
617   static inline void push (lua_State* L, C const& c)
618   {
619     UserdataSharedHelper <C,
620       TypeTraits::isConst <typename ContainerTraits <C>::Type>::value>::push (L, c);
621   }
622
623   typedef typename TypeTraits::removeConst <
624     typename ContainerTraits <C>::Type>::Type T;
625
626   static inline C get (lua_State* L, int index)
627   {
628     return Userdata::get <T> (L, index, true);
629   }
630 };
631
632 /**
633   Pass by value.
634
635   Lifetime is managed by Lua. A C++ function which accesses a pointer or
636   reference to an object outside the activation record in which it was
637   retrieved may result in undefined behavior if Lua garbage collected it.
638 */
639 template <class T>
640 struct StackHelper <T, false, false>
641 {
642   static inline void push (lua_State* L, T const& t)
643   {
644     UserdataValue <T>::push (L, t);
645   }
646
647   static inline T const& get (lua_State* L, int index)
648   {
649     return *Userdata::get <T> (L, index, true);
650   }
651 };
652
653 template <class T>
654 struct StackHelper <T, false, true>
655 {
656   static inline void push (lua_State* L, T const& t)
657   {
658     int v = static_cast <int> (t);
659     lua_pushinteger (L, static_cast <lua_Integer> (v));
660   }
661
662   static inline T get (lua_State* L, int index)
663   {
664     int v = static_cast <int> (luaL_checkinteger (L, index));
665     return T (v);
666   }
667 };
668
669 //==============================================================================
670
671 /**
672   Lua stack conversions for class objects passed by value.
673 */
674 template <class T>
675 struct Stack
676 {
677 public:
678   static inline void push (lua_State* L, T const& t)
679   {
680     StackHelper <T,
681       TypeTraits::isContainer <T>::value,
682       TypeTraits::isEnum<T>::value>::push (L, t);
683   }
684
685   static inline T get (lua_State* L, int index)
686   {
687     return StackHelper <T,
688       TypeTraits::isContainer <T>::value,
689       TypeTraits::isEnum<T>::value>::get (L, index);
690   }
691 };
692
693 //------------------------------------------------------------------------------
694 /**
695   Lua stack conversions for pointers and references to class objects.
696
697   Lifetime is managed by C++. Lua code which remembers a reference to the
698   value may result in undefined behavior if C++ destroys the object. The
699   handling of the const and volatile qualifiers happens in UserdataPtr.
700 */
701
702 // pointer
703 template <class T>
704 struct Stack <T*>
705 {
706   static inline void push (lua_State* L, T* const p)
707   {
708     UserdataPtr::push (L, p);
709   }
710
711   static inline T* get (lua_State* L, int index)
712   {
713     return Userdata::get <T> (L, index, false);
714   }
715 };
716
717 // Strips the const off the right side of *
718 template <class T>
719 struct Stack <T* const>
720 {
721   static inline void push (lua_State* L, T* const p)
722   {
723     UserdataPtr::push (L, p);
724   }
725
726   static inline T* get (lua_State* L, int index)
727   {
728     return Userdata::get <T> (L, index, false);
729   }
730 };
731
732 // pointer to const
733 template <class T>
734 struct Stack <T const*>
735 {
736   static inline void push (lua_State* L, T const* const p)
737   {
738     UserdataPtr::push (L, p);
739   }
740
741   static inline T const* get (lua_State* L, int index)
742   {
743     return Userdata::get <T> (L, index, true);
744   }
745 };
746
747 // Strips the const off the right side of *
748 template <class T>
749 struct Stack <T const* const>
750 {
751   static inline void push (lua_State* L, T const* const p)
752   {
753     UserdataPtr::push (L, p);
754   }
755
756   static inline T const* get (lua_State* L, int index)
757   {
758     return Userdata::get <T> (L, index, true);
759   }
760 };
761
762 // reference
763 template <class T>
764 struct Stack <T&>
765 {
766   static inline void push (lua_State* L, T& t)
767   {
768     UserdataPtr::push (L, &t);
769   }
770
771   static T& get (lua_State* L, int index)
772   {
773     T* const t = Userdata::get <T> (L, index, false);
774     if (!t)
775       luaL_error (L, "nil passed to reference");
776     return *t;
777   }
778 };
779
780 template <class C, bool byContainer>
781 struct RefStackHelper
782 {
783   typedef C return_type;
784
785   static inline void push (lua_State* L, C const& t)
786   {
787     UserdataSharedHelper <C,
788       TypeTraits::isConst <typename ContainerTraits <C>::Type>::value>::push (L, t);
789   }
790
791   typedef typename TypeTraits::removeConst <
792     typename ContainerTraits <C>::Type>::Type T;
793
794   static return_type get (lua_State* L, int index)
795   {
796     return Userdata::get <T> (L, index, true);
797   }
798 };
799
800 template <class T>
801 struct RefStackHelper <T, false>
802 {
803   typedef T const& return_type;
804
805   static inline void push (lua_State* L, T const& t)
806   {
807     UserdataPtr::push (L, &t);
808   }
809
810   static return_type get (lua_State* L, int index)
811   {
812     T const* const t = Userdata::get <T> (L, index, true);
813
814     if (!t)
815       luaL_error (L, "nil passed to reference");
816     return *t;
817   }
818
819 };
820
821 // reference to const
822 template <class T>
823 struct Stack <T const&>
824 {
825   typedef RefStackHelper <T, TypeTraits::isContainer <T>::value> helper_t;
826
827   static inline void push (lua_State* L, T const& t)
828   {
829     helper_t::push (L, t);
830   }
831
832   static typename helper_t::return_type get (lua_State* L, int index)
833   {
834     return helper_t::get (L, index);
835   }
836 };