?login_element?

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. // https://github.com/vinniefalco/LuaBridge
  2. // Copyright 2019, Dmitry Tarakanov
  3. // Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
  4. // SPDX-License-Identifier: MIT
  5.  
  6. #pragma once
  7.  
  8. #include <LuaBridge/detail/ClassInfo.h>
  9. #include <LuaBridge/detail/TypeTraits.h>
  10.  
  11. #include <cassert>
  12. #include <stdexcept>
  13.  
  14. namespace luabridge {
  15.  
  16. namespace detail {
  17.  
  18. //==============================================================================
  19. /**
  20.   Return the identity pointer for our lightuserdata tokens.
  21.  
  22.   Because of Lua's dynamic typing and our improvised system of imposing C++
  23.   class structure, there is the possibility that executing scripts may
  24.   knowingly or unknowingly cause invalid data to get passed to the C functions
  25.   created by LuaBridge. In particular, our security model addresses the
  26.   following:
  27.     1. Scripts cannot create a userdata (ignoring the debug lib).
  28.     2. Scripts cannot create a lightuserdata (ignoring the debug lib).
  29.     3. Scripts cannot set the metatable on a userdata.
  30. */
  31.  
  32. /**
  33.   Interface to a class pointer retrievable from a userdata.
  34. */
  35. class Userdata
  36. {
  37. protected:
  38.     void* m_p; // subclasses must set this
  39.  
  40.     Userdata() : m_p(0) {}
  41.  
  42.     //--------------------------------------------------------------------------
  43.     /**
  44.       Get an untyped pointer to the contained class.
  45.     */
  46.     void* getPointer() { return m_p; }
  47.  
  48. private:
  49.     //--------------------------------------------------------------------------
  50.     /**
  51.       Validate and retrieve a Userdata on the stack.
  52.  
  53.       The Userdata must exactly match the corresponding class table or
  54.       const table, or else a Lua error is raised. This is used for the
  55.       __gc metamethod.
  56.     */
  57.     static Userdata* getExactClass(lua_State* L, int index, void const* /*classKey*/)
  58.     {
  59.         return static_cast<Userdata*>(lua_touserdata(L, lua_absindex(L, index)));
  60.     }
  61.  
  62.     //--------------------------------------------------------------------------
  63.     /**
  64.       Validate and retrieve a Userdata on the stack.
  65.  
  66.       The Userdata must be derived from or the same as the given base class,
  67.       identified by the key. If canBeConst is false, generates an error if
  68.       the resulting Userdata represents to a const object. We do the type check
  69.       first so that the error message is informative.
  70.     */
  71.     static Userdata* getClass(lua_State* L,
  72.                               int index,
  73.                               void const* registryConstKey,
  74.                               void const* registryClassKey,
  75.                               bool canBeConst)
  76.     {
  77.         index = lua_absindex(L, index);
  78.  
  79.         lua_getmetatable(L, index); // Stack: object metatable (ot) | nil
  80.         if (!lua_istable(L, -1))
  81.         {
  82.             lua_rawgetp(
  83.                 L, LUA_REGISTRYINDEX, registryClassKey); // Stack: registry metatable (rt) | nil
  84.             return throwBadArg(L, index);
  85.         }
  86.  
  87.         lua_rawgetp(L, -1, getConstKey()); // Stack: ot | nil, const table (co) | nil
  88.         assert(lua_istable(L, -1) || lua_isnil(L, -1));
  89.  
  90.         // If const table is NOT present, object is const. Use non-const registry table
  91.         // if object cannot be const, so constness validation is done automatically.
  92.         // E.g. nonConstFn (constObj)
  93.         // -> canBeConst = false, isConst = true
  94.         // -> 'Class' registry table, 'const Class' object table
  95.         // -> 'expected Class, got const Class'
  96.         bool isConst = lua_isnil(L, -1); // Stack: ot | nil, nil, rt
  97.         if (isConst && canBeConst)
  98.         {
  99.             lua_rawgetp(L, LUA_REGISTRYINDEX, registryConstKey); // Stack: ot, nil, rt
  100.         }
  101.         else
  102.         {
  103.             lua_rawgetp(L, LUA_REGISTRYINDEX, registryClassKey); // Stack: ot, co, rt
  104.         }
  105.  
  106.         lua_insert(L, -3); // Stack: rt, ot, co | nil
  107.         lua_pop(L, 1); // Stack: rt, ot
  108.  
  109.         for (;;)
  110.         {
  111.             if (lua_rawequal(L, -1, -2)) // Stack: rt, ot
  112.             {
  113.                 lua_pop(L, 2); // Stack: -
  114.                 return static_cast<Userdata*>(lua_touserdata(L, index));
  115.             }
  116.  
  117.             // Replace current metatable with it's base class.
  118.             lua_rawgetp(L, -1, getParentKey()); // Stack: rt, ot, parent ot (pot) | nil
  119.  
  120.             if (lua_isnil(L, -1)) // Stack: rt, ot, nil
  121.             {
  122.                 // Drop the object metatable because it may be some parent metatable
  123.                 lua_pop(L, 2); // Stack: rt
  124.                 return throwBadArg(L, index);
  125.             }
  126.  
  127.             lua_remove(L, -2); // Stack: rt, pot
  128.         }
  129.  
  130.         // no return
  131.     }
  132.  
  133.     static bool isInstance(lua_State* L, int index, void const* registryClassKey)
  134.     {
  135.         index = lua_absindex(L, index);
  136.  
  137.         int result = lua_getmetatable(L, index); // Stack: object metatable (ot) | nothing
  138.         if (result == 0)
  139.         {
  140.             return false; // Nothing was pushed on the stack
  141.         }
  142.         if (!lua_istable(L, -1))
  143.         {
  144.             lua_pop(L, 1); // Stack: -
  145.             return false;
  146.         }
  147.  
  148.         lua_rawgetp(L, LUA_REGISTRYINDEX, registryClassKey); // Stack: ot, rt
  149.         lua_insert(L, -2); // Stack: rt, ot
  150.  
  151.         for (;;)
  152.         {
  153.             if (lua_rawequal(L, -1, -2)) // Stack: rt, ot
  154.             {
  155.                 lua_pop(L, 2); // Stack: -
  156.                 return true;
  157.             }
  158.  
  159.             // Replace current metatable with it's base class.
  160.             lua_rawgetp(L, -1, getParentKey()); // Stack: rt, ot, parent ot (pot) | nil
  161.  
  162.             if (lua_isnil(L, -1)) // Stack: rt, ot, nil
  163.             {
  164.                 lua_pop(L, 3); // Stack: -
  165.                 return false;
  166.             }
  167.  
  168.             lua_remove(L, -2); // Stack: rt, pot
  169.         }
  170.     }
  171.  
  172.     static Userdata* throwBadArg(lua_State* L, int index)
  173.     {
  174.         assert(lua_istable(L, -1) || lua_isnil(L, -1)); // Stack: rt | nil
  175.  
  176.         const char* expected = 0;
  177.         if (lua_isnil(L, -1)) // Stack: nil
  178.         {
  179.             expected = "unregistered class";
  180.         }
  181.         else
  182.         {
  183.             lua_rawgetp(L, -1, getTypeKey()); // Stack: rt, registry type
  184.             expected = lua_tostring(L, -1);
  185.         }
  186.  
  187.         const char* got = 0;
  188.         if (lua_isuserdata(L, index))
  189.         {
  190.             lua_getmetatable(L, index); // Stack: ..., ot | nil
  191.             if (lua_istable(L, -1)) // Stack: ..., ot
  192.             {
  193.                 lua_rawgetp(L, -1, getTypeKey()); // Stack: ..., ot, object type | nil
  194.                 if (lua_isstring(L, -1))
  195.                 {
  196.                     got = lua_tostring(L, -1);
  197.                 }
  198.             }
  199.         }
  200.         if (!got)
  201.         {
  202.             got = lua_typename(L, lua_type(L, index));
  203.         }
  204.  
  205.         luaL_argerror(L, index, lua_pushfstring(L, "%s expected, got %s", expected, got));
  206.         return 0;
  207.     }
  208.  
  209. public:
  210.     virtual ~Userdata() {}
  211.  
  212.     //--------------------------------------------------------------------------
  213.     /**
  214.       Returns the Userdata* if the class on the Lua stack matches.
  215.       If the class does not match, a Lua error is raised.
  216.  
  217.       @tparam T     A registered user class.
  218.       @param  L     A Lua state.
  219.       @param  index The index of an item on the Lua stack.
  220.       @returns A userdata pointer if the class matches.
  221.     */
  222.     template<class T>
  223.     static Userdata* getExact(lua_State* L, int index)
  224.     {
  225.         return getExactClass(L, index, detail::getClassRegistryKey<T>());
  226.     }
  227.  
  228.     //--------------------------------------------------------------------------
  229.     /**
  230.       Get a pointer to the class from the Lua stack.
  231.       If the object is not the class or a subclass, or it violates the
  232.       const-ness, a Lua error is raised.
  233.  
  234.       @tparam T          A registered user class.
  235.       @param  L          A Lua state.
  236.       @param  index      The index of an item on the Lua stack.
  237.       @param  canBeConst TBD
  238.       @returns A pointer if the class and constness match.
  239.     */
  240.     template<class T>
  241.     static T* get(lua_State* L, int index, bool canBeConst)
  242.     {
  243.         if (lua_isnil(L, index))
  244.             return 0;
  245.  
  246.         return static_cast<T*>(getClass(L,
  247.                                         index,
  248.                                         detail::getConstRegistryKey<T>(),
  249.                                         detail::getClassRegistryKey<T>(),
  250.                                         canBeConst)
  251.                                    ->getPointer());
  252.     }
  253.  
  254.     template<class T>
  255.     static bool isInstance(lua_State* L, int index)
  256.     {
  257.         return isInstance(L, index, detail::getClassRegistryKey<T>());
  258.     }
  259. };
  260.  
  261. //----------------------------------------------------------------------------
  262. /**
  263.   Wraps a class object stored in a Lua userdata.
  264.  
  265.   The lifetime of the object is managed by Lua. The object is constructed
  266.   inside the userdata using placement new.
  267. */
  268. template<class T>
  269. class UserdataValue : public Userdata
  270. {
  271. private:
  272.     UserdataValue(UserdataValue<T> const&);
  273.     UserdataValue<T> operator=(UserdataValue<T> const&);
  274.  
  275.     char m_storage[sizeof(T)];
  276.  
  277. private:
  278.     /**
  279.       Used for placement construction.
  280.     */
  281.     UserdataValue() { m_p = 0; }
  282.  
  283.     ~UserdataValue()
  284.     {
  285.         if (getPointer() != 0)
  286.         {
  287.             getObject()->~T();
  288.         }
  289.     }
  290.  
  291. public:
  292.     /**
  293.       Push a T via placement new.
  294.  
  295.       The caller is responsible for calling placement new using the
  296.       returned uninitialized storage.
  297.  
  298.       @param L A Lua state.
  299.       @returns An object referring to the newly created userdata value.
  300.     */
  301.     static UserdataValue<T>* place(lua_State* const L)
  302.     {
  303.         UserdataValue<T>* const ud =
  304.             new (lua_newuserdata(L, sizeof(UserdataValue<T>))) UserdataValue<T>();
  305.         lua_rawgetp(L, LUA_REGISTRYINDEX, detail::getClassRegistryKey<T>());
  306.         if (!lua_istable(L, -1))
  307.         {
  308.             throw std::logic_error("The class is not registered in LuaBridge");
  309.         }
  310.         lua_setmetatable(L, -2);
  311.         return ud;
  312.     }
  313.  
  314.     /**
  315.       Push T via copy construction from U.
  316.  
  317.       @tparam U A container type.
  318.       @param  L A Lua state.
  319.       @param  u A container object reference.
  320.     */
  321.     template<class U>
  322.     static inline void push(lua_State* const L, U const& u)
  323.     {
  324.         UserdataValue<T>* ud = place(L);
  325.         new (ud->getObject()) U(u);
  326.         ud->commit();
  327.     }
  328.  
  329.     /**
  330.       Confirm object construction.
  331.     */
  332.     void commit() { m_p = getObject(); }
  333.  
  334.     T* getObject()
  335.     {
  336.         // If this fails to compile it means you forgot to provide
  337.         // a Container specialization for your container!
  338.         //
  339.         return reinterpret_cast<T*>(&m_storage[0]);
  340.     }
  341. };
  342.  
  343. //----------------------------------------------------------------------------
  344. /**
  345.   Wraps a pointer to a class object inside a Lua userdata.
  346.  
  347.   The lifetime of the object is managed by C++.
  348. */
  349. class UserdataPtr : public Userdata
  350. {
  351. private:
  352.     UserdataPtr(UserdataPtr const&);
  353.     UserdataPtr operator=(UserdataPtr const&);
  354.  
  355. private:
  356.     /** Push a pointer to object using metatable key.
  357.      */
  358.     static void push(lua_State* L, const void* p, void const* const key)
  359.     {
  360.         new (lua_newuserdata(L, sizeof(UserdataPtr))) UserdataPtr(const_cast<void*>(p));
  361.         lua_rawgetp(L, LUA_REGISTRYINDEX, key);
  362.         if (!lua_istable(L, -1))
  363.         {
  364.             lua_pop(L, 1); // possibly: a nil
  365.             throw std::logic_error("The class is not registered in LuaBridge");
  366.         }
  367.         lua_setmetatable(L, -2);
  368.     }
  369.  
  370.     explicit UserdataPtr(void* const p)
  371.     {
  372.         m_p = p;
  373.  
  374.         // Can't construct with a null pointer!
  375.         //
  376.         assert(m_p != 0);
  377.     }
  378.  
  379. public:
  380.     /** Push non-const pointer to object.
  381.  
  382.       @tparam T A user registered class.
  383.       @param  L A Lua state.
  384.       @param  p A pointer to the user class instance.
  385.     */
  386.     template<class T>
  387.     static void push(lua_State* const L, T* const p)
  388.     {
  389.         if (p)
  390.             push(L, p, getClassRegistryKey<T>());
  391.         else
  392.             lua_pushnil(L);
  393.     }
  394.  
  395.     /** Push const pointer to object.
  396.  
  397.       @tparam T A user registered class.
  398.       @param  L A Lua state.
  399.       @param  p A pointer to the user class instance.
  400.     */
  401.     template<class T>
  402.     static void push(lua_State* const L, T const* const p)
  403.     {
  404.         if (p)
  405.             push(L, p, getConstRegistryKey<T>());
  406.         else
  407.             lua_pushnil(L);
  408.     }
  409. };
  410.  
  411. //============================================================================
  412. /**
  413.   Wraps a container that references a class object.
  414.  
  415.   The template argument C is the container type, ContainerTraits must be
  416.   specialized on C or else a compile error will result.
  417. */
  418. template<class C>
  419. class UserdataShared : public Userdata
  420. {
  421. private:
  422.     UserdataShared(UserdataShared<C> const&);
  423.     UserdataShared<C>& operator=(UserdataShared<C> const&);
  424.  
  425.     typedef typename TypeTraits::removeConst<typename ContainerTraits<C>::Type>::Type T;
  426.  
  427.     C m_c;
  428.  
  429. private:
  430.     ~UserdataShared() {}
  431.  
  432. public:
  433.     /**
  434.       Construct from a container to the class or a derived class.
  435.  
  436.       @tparam U A container type.
  437.       @param  u A container object reference.
  438.     */
  439.     template<class U>
  440.     explicit UserdataShared(U const& u) : m_c(u)
  441.     {
  442.         m_p = const_cast<void*>(reinterpret_cast<void const*>((ContainerTraits<C>::get(m_c))));
  443.     }
  444.  
  445.     /**
  446.       Construct from a pointer to the class or a derived class.
  447.  
  448.       @tparam U A container type.
  449.       @param  u A container object pointer.
  450.     */
  451.     template<class U>
  452.     explicit UserdataShared(U* u) : m_c(u)
  453.     {
  454.         m_p = const_cast<void*>(reinterpret_cast<void const*>((ContainerTraits<C>::get(m_c))));
  455.     }
  456. };
  457.  
  458. //----------------------------------------------------------------------------
  459. //
  460. // SFINAE helpers.
  461. //
  462.  
  463. // non-const objects
  464. template<class C, bool makeObjectConst>
  465. struct UserdataSharedHelper
  466. {
  467.     typedef typename TypeTraits::removeConst<typename ContainerTraits<C>::Type>::Type T;
  468.  
  469.     static void push(lua_State* L, C const& c)
  470.     {
  471.         if (ContainerTraits<C>::get(c) != 0)
  472.         {
  473.             new (lua_newuserdata(L, sizeof(UserdataShared<C>))) UserdataShared<C>(c);
  474.             lua_rawgetp(L, LUA_REGISTRYINDEX, getClassRegistryKey<T>());
  475.             // If this goes off it means the class T is unregistered!
  476.             assert(lua_istable(L, -1));
  477.             lua_setmetatable(L, -2);
  478.         }
  479.         else
  480.         {
  481.             lua_pushnil(L);
  482.         }
  483.     }
  484.  
  485.     static void push(lua_State* L, T* const t)
  486.     {
  487.         if (t)
  488.         {
  489.             new (lua_newuserdata(L, sizeof(UserdataShared<C>))) UserdataShared<C>(t);
  490.             lua_rawgetp(L, LUA_REGISTRYINDEX, getClassRegistryKey<T>());
  491.             // If this goes off it means the class T is unregistered!
  492.             assert(lua_istable(L, -1));
  493.             lua_setmetatable(L, -2);
  494.         }
  495.         else
  496.         {
  497.             lua_pushnil(L);
  498.         }
  499.     }
  500. };
  501.  
  502. // const objects
  503. template<class C>
  504. struct UserdataSharedHelper<C, true>
  505. {
  506.     typedef typename TypeTraits::removeConst<typename ContainerTraits<C>::Type>::Type T;
  507.  
  508.     static void push(lua_State* L, C const& c)
  509.     {
  510.         if (ContainerTraits<C>::get(c) != 0)
  511.         {
  512.             new (lua_newuserdata(L, sizeof(UserdataShared<C>))) UserdataShared<C>(c);
  513.             lua_rawgetp(L, LUA_REGISTRYINDEX, getConstRegistryKey<T>());
  514.             // If this goes off it means the class T is unregistered!
  515.             assert(lua_istable(L, -1));
  516.             lua_setmetatable(L, -2);
  517.         }
  518.         else
  519.         {
  520.             lua_pushnil(L);
  521.         }
  522.     }
  523.  
  524.     static void push(lua_State* L, T* const t)
  525.     {
  526.         if (t)
  527.         {
  528.             new (lua_newuserdata(L, sizeof(UserdataShared<C>))) UserdataShared<C>(t);
  529.             lua_rawgetp(L, LUA_REGISTRYINDEX, getConstRegistryKey<T>());
  530.             // If this goes off it means the class T is unregistered!
  531.             assert(lua_istable(L, -1));
  532.             lua_setmetatable(L, -2);
  533.         }
  534.         else
  535.         {
  536.             lua_pushnil(L);
  537.         }
  538.     }
  539. };
  540.  
  541. /**
  542.   Pass by container.
  543.  
  544.   The container controls the object lifetime. Typically this will be a
  545.   lifetime shared by C++ and Lua using a reference count. Because of type
  546.   erasure, containers like std::shared_ptr will not work. Containers must
  547.   either be of the intrusive variety, or in the style of the RefCountedPtr
  548.   type provided by LuaBridge (that uses a global hash table).
  549. */
  550. template<class C, bool byContainer>
  551. struct StackHelper
  552. {
  553.     static void push(lua_State* L, C const& c)
  554.     {
  555.         UserdataSharedHelper<C, TypeTraits::isConst<typename ContainerTraits<C>::Type>::value>::
  556.             push(L, c);
  557.     }
  558.  
  559.     typedef typename TypeTraits::removeConst<typename ContainerTraits<C>::Type>::Type T;
  560.  
  561.     static C get(lua_State* L, int index) { return Userdata::get<T>(L, index, true); }
  562. };
  563.  
  564. /**
  565.   Pass by value.
  566.  
  567.   Lifetime is managed by Lua. A C++ function which accesses a pointer or
  568.   reference to an object outside the activation record in which it was
  569.   retrieved may result in undefined behavior if Lua garbage collected it.
  570. */
  571. template<class T>
  572. struct StackHelper<T, false>
  573. {
  574.     static inline void push(lua_State* L, T const& t) { UserdataValue<T>::push(L, t); }
  575.  
  576.     static inline T const& get(lua_State* L, int index)
  577.     {
  578.         return *Userdata::get<T>(L, index, true);
  579.     }
  580. };
  581.  
  582. //------------------------------------------------------------------------------
  583. /**
  584.   Lua stack conversions for pointers and references to class objects.
  585.  
  586.   Lifetime is managed by C++. Lua code which remembers a reference to the
  587.   value may result in undefined behavior if C++ destroys the object. The
  588.   handling of the const and volatile qualifiers happens in UserdataPtr.
  589. */
  590.  
  591. template<class C, bool byContainer>
  592. struct RefStackHelper
  593. {
  594.     typedef C return_type;
  595.  
  596.     static inline void push(lua_State* L, C const& t)
  597.     {
  598.         UserdataSharedHelper<C, TypeTraits::isConst<typename ContainerTraits<C>::Type>::value>::
  599.             push(L, t);
  600.     }
  601.  
  602.     typedef typename TypeTraits::removeConst<typename ContainerTraits<C>::Type>::Type T;
  603.  
  604.     static return_type get(lua_State* L, int index) { return Userdata::get<T>(L, index, true); }
  605. };
  606.  
  607. template<class T>
  608. struct RefStackHelper<T, false>
  609. {
  610.     typedef T& return_type;
  611.  
  612.     static void push(lua_State* L, T const& t) { UserdataPtr::push(L, &t); }
  613.  
  614.     static return_type get(lua_State* L, int index)
  615.     {
  616.         T* t = Userdata::get<T>(L, index, true);
  617.  
  618.         if (!t)
  619.             luaL_error(L, "nil passed to reference");
  620.         return *t;
  621.     }
  622. };
  623.  
  624. /**
  625.  * Voider class template. Used to force a comiler to instantiate
  626.  * an otherwise probably unused template parameter type T.
  627.  * See the C++20 std::void_t <> for details.
  628.  */
  629. template<class T>
  630. struct Void
  631. {
  632.     typedef void Type;
  633. };
  634.  
  635. /**
  636.  * Trait class that selects whether to return a user registered
  637.  * class object by value or by reference.
  638.  */
  639.  
  640. template<class T, class Enabler = void>
  641. struct UserdataGetter
  642. {
  643.     typedef T* ReturnType;
  644.  
  645.     static ReturnType get(lua_State* L, int index) { return Userdata::get<T>(L, index, false); }
  646. };
  647.  
  648. template<class T>
  649. struct UserdataGetter<T, typename Void<T (*)()>::Type>
  650. {
  651.     typedef T ReturnType;
  652.  
  653.     static ReturnType get(lua_State* L, int index)
  654.     {
  655.         return StackHelper<T, TypeTraits::isContainer<T>::value>::get(L, index);
  656.     }
  657. };
  658.  
  659. } // namespace detail
  660.  
  661. //==============================================================================
  662.  
  663. /**
  664.   Lua stack conversions for class objects passed by value.
  665. */
  666. template<class T>
  667. struct Stack
  668. {
  669.     typedef void IsUserdata;
  670.  
  671.     typedef detail::UserdataGetter<T> Getter;
  672.     typedef typename Getter::ReturnType ReturnType;
  673.  
  674.     static void push(lua_State* L, T const& value)
  675.     {
  676.         using namespace detail;
  677.         StackHelper<T, TypeTraits::isContainer<T>::value>::push(L, value);
  678.     }
  679.  
  680.     static ReturnType get(lua_State* L, int index) { return Getter::get(L, index); }
  681.  
  682.     static bool isInstance(lua_State* L, int index)
  683.     {
  684.         return detail::Userdata::isInstance<T>(L, index);
  685.     }
  686. };
  687.  
  688. namespace detail {
  689.  
  690. /**
  691.  * Trait class indicating whether the parameter type must be
  692.  * a user registered class. The trait checks the existence of
  693.  * member type Stack::IsUserdata specialization for detection.
  694.  */
  695. template<class T, class Enable = void>
  696. struct IsUserdata
  697. {
  698.     static const bool value = false;
  699. };
  700.  
  701. template<class T>
  702. struct IsUserdata<T, typename Void<typename Stack<T>::IsUserdata>::Type>
  703. {
  704.     static const bool value = true;
  705. };
  706.  
  707. /**
  708.  * Trait class that selects a specific push/get implemenation.
  709.  */
  710. template<class T, bool isUserdata>
  711. struct StackOpSelector;
  712.  
  713. // pointer
  714. template<class T>
  715. struct StackOpSelector<T*, true>
  716. {
  717.     typedef T* ReturnType;
  718.  
  719.     static void push(lua_State* L, T* value) { UserdataPtr::push(L, value); }
  720.  
  721.     static T* get(lua_State* L, int index) { return Userdata::get<T>(L, index, false); }
  722.  
  723.     static bool isInstance(lua_State* L, int index) { return Userdata::isInstance<T>(L, index); }
  724. };
  725.  
  726. // pointer to const
  727. template<class T>
  728. struct StackOpSelector<const T*, true>
  729. {
  730.     typedef const T* ReturnType;
  731.  
  732.     static void push(lua_State* L, const T* value) { UserdataPtr::push(L, value); }
  733.  
  734.     static const T* get(lua_State* L, int index) { return Userdata::get<T>(L, index, true); }
  735.  
  736.     static bool isInstance(lua_State* L, int index) { return Userdata::isInstance<T>(L, index); }
  737. };
  738.  
  739. // reference
  740. template<class T>
  741. struct StackOpSelector<T&, true>
  742. {
  743.     typedef RefStackHelper<T, TypeTraits::isContainer<T>::value> Helper;
  744.     typedef typename Helper::return_type ReturnType;
  745.  
  746.     static void push(lua_State* L, T& value) { UserdataPtr::push(L, &value); }
  747.  
  748.     static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); }
  749.  
  750.     static bool isInstance(lua_State* L, int index) { return Userdata::isInstance<T>(L, index); }
  751. };
  752.  
  753. // reference to const
  754. template<class T>
  755. struct StackOpSelector<const T&, true>
  756. {
  757.     typedef RefStackHelper<T, TypeTraits::isContainer<T>::value> Helper;
  758.     typedef typename Helper::return_type ReturnType;
  759.  
  760.     static void push(lua_State* L, const T& value) { Helper::push(L, value); }
  761.  
  762.     static ReturnType get(lua_State* L, int index) { return Helper::get(L, index); }
  763.  
  764.     static bool isInstance(lua_State* L, int index) { return Userdata::isInstance<T>(L, index); }
  765. };
  766.  
  767. } // namespace detail
  768.  
  769. } // namespace luabridge
  770.