?login_element?

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download

  1. // https://github.com/vinniefalco/LuaBridge
  2. // Copyright 2019, Dmitry Tarakanov
  3. // Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
  4. // Copyright 2007, Nathan Reed
  5. // SPDX-License-Identifier: MIT
  6.  
  7. #pragma once
  8.  
  9. #include <LuaBridge/detail/ClassInfo.h>
  10. #include <LuaBridge/detail/Config.h>
  11. #include <LuaBridge/detail/LuaException.h>
  12. #include <LuaBridge/detail/Security.h>
  13. #include <LuaBridge/detail/TypeTraits.h>
  14.  
  15. #include <stdexcept>
  16. #include <string>
  17.  
  18. namespace luabridge {
  19.  
  20. namespace detail {
  21.  
  22. /**
  23.  * Base for class and namespace registration.
  24.  * Maintains Lua stack in the proper state.
  25.  * Once beginNamespace, beginClass or deriveClass is called the parent
  26.  * object upon its destruction may no longer clear the Lua stack.
  27.  * Then endNamespace or endClass is called, a new parent is created
  28.  * and the child transfers the responsibility for clearing stack to it.
  29.  * So there can be maximum one "active" registrar object.
  30.  */
  31. class Registrar
  32. {
  33. protected:
  34.     lua_State* const L;
  35.     int mutable m_stackSize;
  36.  
  37.     Registrar(lua_State* L) : L(L), m_stackSize(0) {}
  38.  
  39.     Registrar(const Registrar& rhs) : L(rhs.L), m_stackSize(rhs.m_stackSize)
  40.     {
  41.         rhs.m_stackSize = 0;
  42.     }
  43.  
  44. #ifndef _MSC_VER
  45.     // MS compiler thinks it's the 2nd copy ctor
  46.     Registrar(Registrar& rhs) : L(rhs.L), m_stackSize(rhs.m_stackSize) { rhs.m_stackSize = 0; }
  47. #endif // ifndef _MSC_VER
  48.  
  49.     Registrar& operator=(const Registrar& rhs)
  50.     {
  51.         Registrar tmp(rhs);
  52.         std::swap(m_stackSize, tmp.m_stackSize);
  53.         return *this;
  54.     }
  55.  
  56.     ~Registrar()
  57.     {
  58.         if (m_stackSize > 0)
  59.         {
  60.             assert(m_stackSize <= lua_gettop(L));
  61.             lua_pop(L, m_stackSize);
  62.         }
  63.     }
  64.  
  65.     void assertIsActive() const
  66.     {
  67.         if (m_stackSize == 0)
  68.         {
  69.             throw std::logic_error("Unable to continue registration");
  70.         }
  71.     }
  72. };
  73.  
  74. } // namespace detail
  75.  
  76. /** Provides C++ to Lua registration capabilities.
  77.  
  78.     This class is not instantiated directly, call `getGlobalNamespace` to start
  79.     the registration process.
  80. */
  81. class Namespace : public detail::Registrar
  82. {
  83.     typedef detail::CFunc CFunc;
  84.  
  85.     //============================================================================
  86. #if 0
  87.   /**
  88.     Error reporting.
  89.  
  90.     VF: This function looks handy, why aren't we using it?
  91.   */
  92.   static int luaError (lua_State* L, std::string message)
  93.   {
  94.     assert (lua_isstring (L, lua_upvalueindex (1)));
  95.     std::string s;
  96.  
  97.     // Get information on the caller's caller to format the message,
  98.     // so the error appears to originate from the Lua source.
  99.     lua_Debug ar;
  100.     int result = lua_getstack (L, 2, &ar);
  101.     if (result != 0)
  102.     {
  103.       lua_getinfo (L, "Sl", &ar);
  104.       s = ar.short_src;
  105.       if (ar.currentline != -1)
  106.       {
  107.         // poor mans int to string to avoid <strstrream>.
  108.         lua_pushnumber (L, ar.currentline);
  109.         s = s + ":" + lua_tostring (L, -1) + ": ";
  110.         lua_pop (L, 1);
  111.       }
  112.     }
  113.  
  114.     s = s + message;
  115.  
  116.     return luaL_error (L, s.c_str ());
  117.   }
  118. #endif
  119.  
  120.     /**
  121.       Factored base to reduce template instantiations.
  122.     */
  123.     class ClassBase : public detail::Registrar
  124.     {
  125.     public:
  126.         explicit ClassBase(Namespace& parent) : Registrar(parent) {}
  127.  
  128.         using Registrar::operator=;
  129.  
  130.     protected:
  131.         //--------------------------------------------------------------------------
  132.         /**
  133.           Create the const table.
  134.         */
  135.         void createConstTable(const char* name, bool trueConst = true)
  136.         {
  137.             std::string type_name = std::string(trueConst ? "const " : "") + name;
  138.  
  139.             // Stack: namespace table (ns)
  140.             lua_newtable(L); // Stack: ns, const table (co)
  141.             lua_pushvalue(L, -1); // Stack: ns, co, co
  142.             lua_setmetatable(L, -2); // co.__metatable = co. Stack: ns, co
  143.  
  144.             lua_pushstring(L, type_name.c_str());
  145.             lua_rawsetp(L, -2, detail::getTypeKey()); // co [typeKey] = name. Stack: ns, co
  146.  
  147.             lua_pushcfunction(L, &CFunc::indexMetaMethod);
  148.             rawsetfield(L, -2, "__index");
  149.  
  150.             lua_pushcfunction(L, &CFunc::newindexObjectMetaMethod);
  151.             rawsetfield(L, -2, "__newindex");
  152.  
  153.             lua_newtable(L);
  154.             lua_rawsetp(L, -2, detail::getPropgetKey());
  155.  
  156.             if (Security::hideMetatables())
  157.             {
  158.                 lua_pushnil(L);
  159.                 rawsetfield(L, -2, "__metatable");
  160.             }
  161.         }
  162.  
  163.         //--------------------------------------------------------------------------
  164.         /**
  165.           Create the class table.
  166.  
  167.           The Lua stack should have the const table on top.
  168.         */
  169.         void createClassTable(char const* name)
  170.         {
  171.             // Stack: namespace table (ns), const table (co)
  172.  
  173.             // Class table is the same as const table except the propset table
  174.             createConstTable(name, false); // Stack: ns, co, cl
  175.  
  176.             lua_newtable(L); // Stack: ns, co, cl, propset table (ps)
  177.             lua_rawsetp(L, -2, detail::getPropsetKey()); // cl [propsetKey] = ps. Stack: ns, co, cl
  178.  
  179.             lua_pushvalue(L, -2); // Stack: ns, co, cl, co
  180.             lua_rawsetp(L, -2, detail::getConstKey()); // cl [constKey] = co. Stack: ns, co, cl
  181.  
  182.             lua_pushvalue(L, -1); // Stack: ns, co, cl, cl
  183.             lua_rawsetp(L, -3, detail::getClassKey()); // co [classKey] = cl. Stack: ns, co, cl
  184.         }
  185.  
  186.         //--------------------------------------------------------------------------
  187.         /**
  188.           Create the static table.
  189.         */
  190.         void createStaticTable(char const* name)
  191.         {
  192.             // Stack: namespace table (ns), const table (co), class table (cl)
  193.             lua_newtable(L); // Stack: ns, co, cl, visible static table (vst)
  194.             lua_newtable(L); // Stack: ns, co, cl, st, static metatable (st)
  195.             lua_pushvalue(L, -1); // Stack: ns, co, cl, vst, st, st
  196.             lua_setmetatable(L, -3); // st.__metatable = mt. Stack: ns, co, cl, vst, st
  197.             lua_insert(L, -2); // Stack: ns, co, cl, st, vst
  198.             rawsetfield(L, -5, name); // ns [name] = vst. Stack: ns, co, cl, st
  199.  
  200. #if 0
  201.       lua_pushlightuserdata (L, this);
  202.       lua_pushcclosure (L, &tostringMetaMethod, 1);
  203.       rawsetfield (L, -2, "__tostring");
  204. #endif
  205.             lua_pushcfunction(L, &CFunc::indexMetaMethod);
  206.             rawsetfield(L, -2, "__index");
  207.  
  208.             lua_pushcfunction(L, &CFunc::newindexStaticMetaMethod);
  209.             rawsetfield(L, -2, "__newindex");
  210.  
  211.             lua_newtable(L); // Stack: ns, co, cl, st, proget table (pg)
  212.             lua_rawsetp(
  213.                 L, -2, detail::getPropgetKey()); // st [propgetKey] = pg. Stack: ns, co, cl, st
  214.  
  215.             lua_newtable(L); // Stack: ns, co, cl, st, propset table (ps)
  216.             lua_rawsetp(
  217.                 L, -2, detail::getPropsetKey()); // st [propsetKey] = pg. Stack: ns, co, cl, st
  218.  
  219.             lua_pushvalue(L, -2); // Stack: ns, co, cl, st, cl
  220.             lua_rawsetp(L, -2, detail::getClassKey()); // st [classKey] = cl. Stack: ns, co, cl, st
  221.  
  222.             if (Security::hideMetatables())
  223.             {
  224.                 lua_pushnil(L);
  225.                 rawsetfield(L, -2, "__metatable");
  226.             }
  227.         }
  228.  
  229.         //==========================================================================
  230.         /**
  231.           lua_CFunction to construct a class object wrapped in a container.
  232.         */
  233.         template<class Params, class C>
  234.         static int ctorContainerProxy(lua_State* L)
  235.         {
  236.             typedef typename ContainerTraits<C>::Type T;
  237.             detail::ArgList<Params, 2> args(L);
  238.             T* const p = detail::Constructor<T, Params>::call(args);
  239.             detail::UserdataSharedHelper<C, false>::push(L, p);
  240.             return 1;
  241.         }
  242.  
  243.         //--------------------------------------------------------------------------
  244.         /**
  245.           lua_CFunction to construct a class object in-place in the userdata.
  246.         */
  247.         template<class Params, class T>
  248.         static int ctorPlacementProxy(lua_State* L)
  249.         {
  250.             detail::ArgList<Params, 2> args(L);
  251.             detail::UserdataValue<T>* value = detail::UserdataValue<T>::place(L);
  252.             detail::Constructor<T, Params>::call(value->getObject(), args);
  253.             value->commit();
  254.             return 1;
  255.         }
  256.  
  257.         void assertStackState() const
  258.         {
  259.             // Stack: const table (co), class table (cl), static table (st)
  260.             assert(lua_istable(L, -3));
  261.             assert(lua_istable(L, -2));
  262.             assert(lua_istable(L, -1));
  263.         }
  264.     };
  265.  
  266.     //============================================================================
  267.     //
  268.     // Class
  269.     //
  270.     //============================================================================
  271.     /**
  272.       Provides a class registration in a lua_State.
  273.  
  274.       After construction the Lua stack holds these objects:
  275.         -1 static table
  276.         -2 class table
  277.         -3 const table
  278.         -4 enclosing namespace table
  279.     */
  280.     template<class T>
  281.     class Class : public ClassBase
  282.     {
  283.         typedef detail::CFunc CFunc;
  284.  
  285.     public:
  286.         //==========================================================================
  287.         /**
  288.           Register a new class or add to an existing class registration.
  289.  
  290.           @param name   The new class name.
  291.           @param parent A parent namespace object.
  292.         */
  293.         Class(char const* name, Namespace& parent) : ClassBase(parent)
  294.         {
  295.             assert(lua_istable(L, -1)); // Stack: namespace table (ns)
  296.             rawgetfield(L, -1, name); // Stack: ns, static table (st) | nil
  297.  
  298.             if (lua_isnil(L, -1)) // Stack: ns, nil
  299.             {
  300.                 lua_pop(L, 1); // Stack: ns
  301.  
  302.                 createConstTable(name); // Stack: ns, const table (co)
  303.                 lua_pushcfunction(L, &CFunc::gcMetaMethod<T>); // Stack: ns, co, function
  304.                 rawsetfield(L, -2, "__gc"); // co ["__gc"] = function. Stack: ns, co
  305.                 ++m_stackSize;
  306.  
  307.                 createClassTable(name); // Stack: ns, co, class table (cl)
  308.                 lua_pushcfunction(L, &CFunc::gcMetaMethod<T>); // Stack: ns, co, cl, function
  309.                 rawsetfield(L, -2, "__gc"); // cl ["__gc"] = function. Stack: ns, co, cl
  310.                 ++m_stackSize;
  311.  
  312.                 createStaticTable(name); // Stack: ns, co, cl, st
  313.                 ++m_stackSize;
  314.  
  315.                 // Map T back to its tables.
  316.                 lua_pushvalue(L, -1); // Stack: ns, co, cl, st, st
  317.                 lua_rawsetp(L,
  318.                             LUA_REGISTRYINDEX,
  319.                             detail::getStaticRegistryKey<T>()); // Stack: ns, co, cl, st
  320.                 lua_pushvalue(L, -2); // Stack: ns, co, cl, st, cl
  321.                 lua_rawsetp(L,
  322.                             LUA_REGISTRYINDEX,
  323.                             detail::getClassRegistryKey<T>()); // Stack: ns, co, cl, st
  324.                 lua_pushvalue(L, -3); // Stack: ns, co, cl, st, co
  325.                 lua_rawsetp(L,
  326.                             LUA_REGISTRYINDEX,
  327.                             detail::getConstRegistryKey<T>()); // Stack: ns, co, cl, st
  328.             }
  329.             else
  330.             {
  331.                 assert(lua_istable(L, -1)); // Stack: ns, st
  332.                 ++m_stackSize;
  333.  
  334.                 // Map T back from its stored tables
  335.  
  336.                 lua_rawgetp(
  337.                     L, LUA_REGISTRYINDEX, detail::getConstRegistryKey<T>()); // Stack: ns, st, co
  338.                 lua_insert(L, -2); // Stack: ns, co, st
  339.                 ++m_stackSize;
  340.  
  341.                 lua_rawgetp(L,
  342.                             LUA_REGISTRYINDEX,
  343.                             detail::getClassRegistryKey<T>()); // Stack: ns, co, st, cl
  344.                 lua_insert(L, -2); // Stack: ns, co, cl, st
  345.                 ++m_stackSize;
  346.             }
  347.         }
  348.  
  349.         //==========================================================================
  350.         /**
  351.           Derive a new class.
  352.  
  353.           @param name     The class name.
  354.           @param parent A parent namespace object.
  355.           @param staticKey
  356.         */
  357.         Class(char const* name, Namespace& parent, void const* const staticKey) : ClassBase(parent)
  358.         {
  359.             assert(lua_istable(L, -1)); // Stack: namespace table (ns)
  360.  
  361.             createConstTable(name); // Stack: ns, const table (co)
  362.             lua_pushcfunction(L, &CFunc::gcMetaMethod<T>); // Stack: ns, co, function
  363.             rawsetfield(L, -2, "__gc"); // co ["__gc"] = function. Stack: ns, co
  364.             ++m_stackSize;
  365.  
  366.             createClassTable(name); // Stack: ns, co, class table (cl)
  367.             lua_pushcfunction(L, &CFunc::gcMetaMethod<T>); // Stack: ns, co, cl, function
  368.             rawsetfield(L, -2, "__gc"); // cl ["__gc"] = function. Stack: ns, co, cl
  369.             ++m_stackSize;
  370.  
  371.             createStaticTable(name); // Stack: ns, co, cl, st
  372.             ++m_stackSize;
  373.  
  374.             lua_rawgetp(
  375.                 L, LUA_REGISTRYINDEX, staticKey); // Stack: ns, co, cl, st, parent st (pst) | nil
  376.             if (lua_isnil(L, -1)) // Stack: ns, co, cl, st, nil
  377.             {
  378.                 ++m_stackSize;
  379.                 throw std::runtime_error("Base class is not registered");
  380.             }
  381.  
  382.             assert(lua_istable(L, -1)); // Stack: ns, co, cl, st, pst
  383.  
  384.             lua_rawgetp(
  385.                 L, -1, detail::getClassKey()); // Stack: ns, co, cl, st, pst, parent cl (pcl)
  386.             assert(lua_istable(L, -1));
  387.  
  388.             lua_rawgetp(
  389.                 L, -1, detail::getConstKey()); // Stack: ns, co, cl, st, pst, pcl, parent co (pco)
  390.             assert(lua_istable(L, -1));
  391.  
  392.             lua_rawsetp(
  393.                 L,
  394.                 -6,
  395.                 detail::getParentKey()); // co [parentKey] = pco. Stack: ns, co, cl, st, pst, pcl
  396.             lua_rawsetp(
  397.                 L, -4, detail::getParentKey()); // cl [parentKey] = pcl. Stack: ns, co, cl, st, pst
  398.             lua_rawsetp(
  399.                 L, -2, detail::getParentKey()); // st [parentKey] = pst. Stack: ns, co, cl, st
  400.  
  401.             lua_pushvalue(L, -1); // Stack: ns, co, cl, st, st
  402.             lua_rawsetp(
  403.                 L, LUA_REGISTRYINDEX, detail::getStaticRegistryKey<T>()); // Stack: ns, co, cl, st
  404.             lua_pushvalue(L, -2); // Stack: ns, co, cl, st, cl
  405.             lua_rawsetp(
  406.                 L, LUA_REGISTRYINDEX, detail::getClassRegistryKey<T>()); // Stack: ns, co, cl, st
  407.             lua_pushvalue(L, -3); // Stack: ns, co, cl, st, co
  408.             lua_rawsetp(
  409.                 L, LUA_REGISTRYINDEX, detail::getConstRegistryKey<T>()); // Stack: ns, co, cl, st
  410.         }
  411.  
  412.         //--------------------------------------------------------------------------
  413.         /**
  414.           Continue registration in the enclosing namespace.
  415.  
  416.           @returns A parent registration object.
  417.         */
  418.         Namespace endClass()
  419.         {
  420.             assert(m_stackSize > 3);
  421.             m_stackSize -= 3;
  422.             lua_pop(L, 3);
  423.             return Namespace(*this);
  424.         }
  425.  
  426.         //--------------------------------------------------------------------------
  427.         /**
  428.           Add or replace a static property.
  429.  
  430.           @tparam U          The type of the property.
  431.           @param  name       The property name.
  432.           @param  value      A property value pointer.
  433.           @param  isWritable True for a read-write, false for read-only property.
  434.           @returns This class registration object.
  435.         */
  436.         template<class U>
  437.         Class<T>& addStaticProperty(char const* name, U* value, bool isWritable = true)
  438.         {
  439.             return addStaticData(name, value, isWritable);
  440.         }
  441.  
  442.         //--------------------------------------------------------------------------
  443.         /**
  444.           Add or replace a static property.
  445.  
  446.           @tparam U          The type of the property.
  447.           @param  name       The property name.
  448.           @param  value      A property value pointer.
  449.           @param  isWritable True for a read-write, false for read-only property.
  450.           @returns This class registration object.
  451.         */
  452.         template<class U>
  453.         Class<T>& addStaticData(char const* name, U* value, bool isWritable = true)
  454.         {
  455.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  456.  
  457.             lua_pushlightuserdata(L, value); // Stack: co, cl, st, pointer
  458.             lua_pushcclosure(L, &CFunc::getVariable<U>, 1); // Stack: co, cl, st, getter
  459.             CFunc::addGetter(L, name, -2); // Stack: co, cl, st
  460.  
  461.             if (isWritable)
  462.             {
  463.                 lua_pushlightuserdata(L, value); // Stack: co, cl, st, ps, pointer
  464.                 lua_pushcclosure(L, &CFunc::setVariable<U>, 1); // Stack: co, cl, st, ps, setter
  465.             }
  466.             else
  467.             {
  468.                 lua_pushstring(L, name); // Stack: co, cl, st, name
  469.                 lua_pushcclosure(L, &CFunc::readOnlyError, 1); // Stack: co, cl, st, error_fn
  470.             }
  471.             CFunc::addSetter(L, name, -2); // Stack: co, cl, st
  472.  
  473.             return *this;
  474.         }
  475.  
  476.         //--------------------------------------------------------------------------
  477.         /// Add or replace a static property member.
  478.         ///
  479.         /// @tparam U          The type of the property.
  480.         /// @param  name       The property name.
  481.         /// @param  get        A property getter function pointer.
  482.         /// @param  set        A property setter function pointer, optional, nullable.
  483.         ///                    Omit or pass nullptr for a read-only property.
  484.         /// @returns This class registration object.
  485.         ///
  486.         template<class U>
  487.         Class<T>& addStaticProperty(char const* name, U (*get)(), void (*set)(U) = 0)
  488.         {
  489.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  490.  
  491.             lua_pushlightuserdata(L,
  492.                                   reinterpret_cast<void*>(get)); // Stack: co, cl, st, function ptr
  493.             lua_pushcclosure(L, &CFunc::Call<U (*)()>::f, 1); // Stack: co, cl, st, getter
  494.             CFunc::addGetter(L, name, -2); // Stack: co, cl, st
  495.  
  496.             if (set != 0)
  497.             {
  498.                 lua_pushlightuserdata(
  499.                     L, reinterpret_cast<void*>(set)); // Stack: co, cl, st, function ptr
  500.                 lua_pushcclosure(L, &CFunc::Call<void (*)(U)>::f, 1); // Stack: co, cl, st, setter
  501.             }
  502.             else
  503.             {
  504.                 lua_pushstring(L, name); // Stack: co, cl, st, ps, name
  505.                 lua_pushcclosure(L, &CFunc::readOnlyError, 1); // Stack: co, cl, st, error_fn
  506.             }
  507.             CFunc::addSetter(L, name, -2); // Stack: co, cl, st
  508.  
  509.             return *this;
  510.         }
  511.  
  512.         //--------------------------------------------------------------------------
  513.         /**
  514.           Add or replace a static member function.
  515.         */
  516.         template<class FP>
  517.         Class<T>& addStaticFunction(char const* name, FP const fp)
  518.         {
  519.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  520.  
  521.             lua_pushlightuserdata(L,
  522.                                   reinterpret_cast<void*>(fp)); // Stack: co, cl, st, function ptr
  523.             lua_pushcclosure(L, &CFunc::Call<FP>::f, 1); // co, cl, st, function
  524.             rawsetfield(L, -2, name); // co, cl, st
  525.  
  526.             return *this;
  527.         }
  528.  
  529.         //--------------------------------------------------------------------------
  530.         /**
  531.           Add or replace a static member function by std::function.
  532.         */
  533.         template<class ReturnType, class... Params>
  534.         Class<T>& addStaticFunction(char const* name, std::function<ReturnType(Params...)> function)
  535.         {
  536.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  537.  
  538.             using FnType = decltype(function);
  539.             new (lua_newuserdata(L, sizeof(function)))
  540.                 FnType(std::move(function)); // Stack: co, cl, st, function userdata (ud)
  541.             lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt)
  542.             lua_pushcfunction(
  543.                 L, &CFunc::gcMetaMethodAny<FnType>); // Stack: co, cl, st, ud, mt, gc function
  544.             rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt
  545.             lua_setmetatable(L, -2); // Stack: co, cl, st, ud
  546.             lua_pushcclosure(
  547.                 L, &CFunc::CallProxyFunctor<FnType>::f, 1); // Stack: co, cl, st, function
  548.             rawsetfield(L, -2, name); // Stack: co, cl, st
  549.  
  550.             return *this;
  551.         }
  552.  
  553.         //--------------------------------------------------------------------------
  554.         /**
  555.           Add or replace a lua_CFunction.
  556.  
  557.           @param name The name of the function.
  558.           @param fp   A C-function pointer.
  559.           @returns This class registration object.
  560.         */
  561.         Class<T>& addStaticFunction(char const* name, int (*const fp)(lua_State*))
  562.         {
  563.             return addStaticCFunction(name, fp);
  564.         }
  565.  
  566.         //--------------------------------------------------------------------------
  567.         /**
  568.           Add or replace a lua_CFunction.
  569.         */
  570.         Class<T>& addStaticCFunction(char const* name, int (*const fp)(lua_State*))
  571.         {
  572.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  573.  
  574.             lua_pushcfunction(L, fp); // co, cl, st, function
  575.             rawsetfield(L, -2, name); // co, cl, st
  576.  
  577.             return *this;
  578.         }
  579.  
  580.         //--------------------------------------------------------------------------
  581.         template<class U>
  582.         Class<T>& addProperty(char const* name, U T::*mp, bool isWritable = true)
  583.         {
  584.             return addData(name, mp, isWritable);
  585.         }
  586.  
  587.         //--------------------------------------------------------------------------
  588.         /**
  589.           Add or replace a data member.
  590.         */
  591.         template<class U>
  592.         Class<T>& addData(char const* name, U T::*mp, bool isWritable = true)
  593.         {
  594.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  595.  
  596.             typedef const U T::*mp_t;
  597.             new (lua_newuserdata(L, sizeof(mp_t))) mp_t(mp); // Stack: co, cl, st, field ptr
  598.             lua_pushcclosure(L, &CFunc::getProperty<T, U>, 1); // Stack: co, cl, st, getter
  599.             lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter
  600.             CFunc::addGetter(L, name, -5); // Stack: co, cl, st, getter
  601.             CFunc::addGetter(L, name, -3); // Stack: co, cl, st
  602.  
  603.             if (isWritable)
  604.             {
  605.                 new (lua_newuserdata(L, sizeof(mp_t))) mp_t(mp); // Stack: co, cl, st, field ptr
  606.                 lua_pushcclosure(L, &CFunc::setProperty<T, U>, 1); // Stack: co, cl, st, setter
  607.                 CFunc::addSetter(L, name, -3); // Stack: co, cl, st
  608.             }
  609.  
  610.             return *this;
  611.         }
  612.  
  613.         //--------------------------------------------------------------------------
  614.         /**
  615.           Add or replace a property member.
  616.         */
  617.         template<class TG, class TS = TG>
  618.         Class<T>& addProperty(char const* name, TG (T::*get)() const, void (T::*set)(TS) = 0)
  619.         {
  620.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  621.  
  622.             typedef TG (T::*get_t)() const;
  623.             new (lua_newuserdata(L, sizeof(get_t))) get_t(get); // Stack: co, cl, st, funcion ptr
  624.             lua_pushcclosure(L, &CFunc::CallConstMember<get_t>::f, 1); // Stack: co, cl, st, getter
  625.             lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter
  626.             CFunc::addGetter(L, name, -5); // Stack: co, cl, st, getter
  627.             CFunc::addGetter(L, name, -3); // Stack: co, cl, st
  628.  
  629.             if (set != 0)
  630.             {
  631.                 typedef void (T::*set_t)(TS);
  632.                 new (lua_newuserdata(L, sizeof(set_t)))
  633.                     set_t(set); // Stack: co, cl, st, function ptr
  634.                 lua_pushcclosure(L, &CFunc::CallMember<set_t>::f, 1); // Stack: co, cl, st, setter
  635.                 CFunc::addSetter(L, name, -3); // Stack: co, cl, st
  636.             }
  637.  
  638.             return *this;
  639.         }
  640.  
  641.         //--------------------------------------------------------------------------
  642.         /**
  643.           Add or replace a property member.
  644.         */
  645.         template<class TG, class TS = TG>
  646.         Class<T>& addProperty(char const* name,
  647.                               TG (T::*get)(lua_State*) const,
  648.                               void (T::*set)(TS, lua_State*) = 0)
  649.         {
  650.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  651.  
  652.             typedef TG (T::*get_t)(lua_State*) const;
  653.             new (lua_newuserdata(L, sizeof(get_t))) get_t(get); // Stack: co, cl, st, funcion ptr
  654.             lua_pushcclosure(L, &CFunc::CallConstMember<get_t>::f, 1); // Stack: co, cl, st, getter
  655.             lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter
  656.             CFunc::addGetter(L, name, -5); // Stack: co, cl, st, getter
  657.             CFunc::addGetter(L, name, -3); // Stack: co, cl, st
  658.  
  659.             if (set != 0)
  660.             {
  661.                 typedef void (T::*set_t)(TS, lua_State*);
  662.                 new (lua_newuserdata(L, sizeof(set_t)))
  663.                     set_t(set); // Stack: co, cl, st, function ptr
  664.                 lua_pushcclosure(L, &CFunc::CallMember<set_t>::f, 1); // Stack: co, cl, st, setter
  665.                 CFunc::addSetter(L, name, -3); // Stack: co, cl, st
  666.             }
  667.  
  668.             return *this;
  669.         }
  670.  
  671.         //--------------------------------------------------------------------------
  672.         /**
  673.           Add or replace a property member, by proxy.
  674.  
  675.           When a class is closed for modification and does not provide (or cannot
  676.           provide) the function signatures necessary to implement get or set for
  677.           a property, this will allow non-member functions act as proxies.
  678.  
  679.           Both the get and the set functions require a T const* and T* in the first
  680.           argument respectively.
  681.         */
  682.         template<class TG, class TS = TG>
  683.         Class<T>& addProperty(char const* name, TG (*get)(T const*), void (*set)(T*, TS) = 0)
  684.         {
  685.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  686.  
  687.             lua_pushlightuserdata(L,
  688.                                   reinterpret_cast<void*>(get)); // Stack: co, cl, st, function ptr
  689.             lua_pushcclosure(L, &CFunc::Call<TG (*)(const T*)>::f, 1); // Stack: co, cl, st, getter
  690.             lua_pushvalue(L, -1); // Stack: co, cl, st,, getter, getter
  691.             CFunc::addGetter(L, name, -5); // Stack: co, cl, st, getter
  692.             CFunc::addGetter(L, name, -3); // Stack: co, cl, st
  693.  
  694.             if (set != 0)
  695.             {
  696.                 lua_pushlightuserdata(
  697.                     L, reinterpret_cast<void*>(set)); // Stack: co, cl, st, function ptr
  698.                 lua_pushcclosure(
  699.                     L, &CFunc::Call<void (*)(T*, TS)>::f, 1); // Stack: co, cl, st, setter
  700.                 CFunc::addSetter(L, name, -3); // Stack: co, cl, st
  701.             }
  702.  
  703.             return *this;
  704.         }
  705.  
  706.         //--------------------------------------------------------------------------
  707.         /**
  708.           Add or replace a property member, by proxy C-function.
  709.  
  710.           When a class is closed for modification and does not provide (or cannot
  711.           provide) the function signatures necessary to implement get or set for
  712.           a property, this will allow non-member functions act as proxies.
  713.  
  714.           The object userdata ('this') value is at the index 1.
  715.           The new value for set function is at the index 2.
  716.         */
  717.         Class<T>& addProperty(char const* name, int (*get)(lua_State*), int (*set)(lua_State*) = 0)
  718.         {
  719.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  720.  
  721.             lua_pushcfunction(L, get);
  722.             lua_pushvalue(L, -1); // Stack: co, cl, st,, getter, getter
  723.             CFunc::addGetter(L, name, -5); // Stack: co, cl, st,, getter
  724.             CFunc::addGetter(L, name, -3); // Stack: co, cl, st,
  725.  
  726.             if (set != 0)
  727.             {
  728.                 lua_pushcfunction(L, set);
  729.                 CFunc::addSetter(L, name, -3); // Stack: co, cl, st,
  730.             }
  731.  
  732.             return *this;
  733.         }
  734.  
  735.         template<class TG, class TS = TG>
  736.         Class<T>& addProperty(char const* name,
  737.                               std::function<TG(const T*)> get,
  738.                               std::function<void(T*, TS)> set = nullptr)
  739.         {
  740.             using GetType = decltype(get);
  741.             new (lua_newuserdata(L, sizeof(get)))
  742.                 GetType(std::move(get)); // Stack: co, cl, st, function userdata (ud)
  743.             lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt)
  744.             lua_pushcfunction(
  745.                 L, &CFunc::gcMetaMethodAny<GetType>); // Stack: co, cl, st, ud, mt, gc function
  746.             rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt
  747.             lua_setmetatable(L, -2); // Stack: co, cl, st, ud
  748.             lua_pushcclosure(
  749.                 L, &CFunc::CallProxyFunctor<GetType>::f, 1); // Stack: co, cl, st, getter
  750.             lua_pushvalue(L, -1); // Stack: co, cl, st, getter, getter
  751.             CFunc::addGetter(L, name, -4); // Stack: co, cl, st, getter
  752.             CFunc::addGetter(L, name, -4); // Stack: co, cl, st
  753.  
  754.             if (set != nullptr)
  755.             {
  756.                 using SetType = decltype(set);
  757.                 new (lua_newuserdata(L, sizeof(set)))
  758.                     SetType(std::move(set)); // Stack: co, cl, st, function userdata (ud)
  759.                 lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt)
  760.                 lua_pushcfunction(
  761.                     L, &CFunc::gcMetaMethodAny<SetType>); // Stack: co, cl, st, ud, mt, gc function
  762.                 rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt
  763.                 lua_setmetatable(L, -2); // Stack: co, cl, st, ud
  764.                 lua_pushcclosure(
  765.                     L, &CFunc::CallProxyFunctor<SetType>::f, 1); // Stack: co, cl, st, setter
  766.                 CFunc::addSetter(L, name, -3); // Stack: co, cl, st
  767.             }
  768.  
  769.             return *this;
  770.         }
  771.  
  772.         //--------------------------------------------------------------------------
  773.         /**
  774.             Add or replace a member function by std::function.
  775.         */
  776.         template<class ReturnType, class... Params>
  777.         Class<T>& addFunction(char const* name, std::function<ReturnType(T*, Params...)> function)
  778.         {
  779.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  780.  
  781.             using FnType = decltype(function);
  782.             new (lua_newuserdata(L, sizeof(function)))
  783.                 FnType(std::move(function)); // Stack: co, cl, st, function userdata (ud)
  784.             lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt)
  785.             lua_pushcfunction(
  786.                 L, &CFunc::gcMetaMethodAny<FnType>); // Stack: co, cl, st, ud, mt, gc function
  787.             rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt
  788.             lua_setmetatable(L, -2); // Stack: co, cl, st, ud
  789.             lua_pushcclosure(
  790.                 L, &CFunc::CallProxyFunctor<FnType>::f, 1); // Stack: co, cl, st, function
  791.             rawsetfield(L, -3, name); // Stack: co, cl, st
  792.  
  793.             return *this;
  794.         }
  795.  
  796.         //--------------------------------------------------------------------------
  797.         /**
  798.             Add or replace a const member function by std::function.
  799.         */
  800.         template<class ReturnType, class... Params>
  801.         Class<T>& addFunction(char const* name,
  802.                               std::function<ReturnType(const T*, Params...)> function)
  803.         {
  804.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  805.  
  806.             using FnType = decltype(function);
  807.             new (lua_newuserdata(L, sizeof(function)))
  808.                 FnType(std::move(function)); // Stack: co, cl, st, function userdata (ud)
  809.             lua_newtable(L); // Stack: co, cl, st, ud, ud metatable (mt)
  810.             lua_pushcfunction(
  811.                 L, &CFunc::gcMetaMethodAny<FnType>); // Stack: co, cl, st, ud, mt, gc function
  812.             rawsetfield(L, -2, "__gc"); // Stack: co, cl, st, ud, mt
  813.             lua_setmetatable(L, -2); // Stack: co, cl, st, ud
  814.             lua_pushcclosure(
  815.                 L, &CFunc::CallProxyFunctor<FnType>::f, 1); // Stack: co, cl, st, function
  816.             lua_pushvalue(L, -1); // Stack: co, cl, st, function, function
  817.             rawsetfield(L, -4, name); // Stack: co, cl, st, function
  818.             rawsetfield(L, -4, name); // Stack: co, cl, st
  819.  
  820.             return *this;
  821.         }
  822.  
  823.         //--------------------------------------------------------------------------
  824.         /**
  825.             Add or replace a member function.
  826.         */
  827.         template<class ReturnType, class... Params>
  828.         Class<T>& addFunction(char const* name, ReturnType (T::*mf)(Params...))
  829.         {
  830.             using MemFn = ReturnType (T::*)(Params...);
  831.  
  832.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  833.  
  834.             static const std::string GC = "__gc";
  835.             if (name == GC)
  836.             {
  837.                 throw std::logic_error(GC + " metamethod registration is forbidden");
  838.             }
  839.             CFunc::CallMemberFunctionHelper<MemFn, false>::add(L, name, mf);
  840.             return *this;
  841.         }
  842.  
  843.         template<class ReturnType, class... Params>
  844.         Class<T>& addFunction(char const* name, ReturnType (T::*mf)(Params...) const)
  845.         {
  846.             using MemFn = ReturnType (T::*)(Params...) const;
  847.  
  848.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  849.  
  850.             static const std::string GC = "__gc";
  851.             if (name == GC)
  852.             {
  853.                 throw std::logic_error(GC + " metamethod registration is forbidden");
  854.             }
  855.             CFunc::CallMemberFunctionHelper<MemFn, true>::add(L, name, mf);
  856.             return *this;
  857.         }
  858.  
  859.         //--------------------------------------------------------------------------
  860.         /**
  861.             Add or replace a proxy function.
  862.         */
  863.         template<class ReturnType, class... Params>
  864.         Class<T>& addFunction(char const* name, ReturnType (*proxyFn)(T* object, Params...))
  865.         {
  866.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  867.  
  868.             static const std::string GC = "__gc";
  869.             if (name == GC)
  870.             {
  871.                 throw std::logic_error(GC + " metamethod registration is forbidden");
  872.             }
  873.             using FnType = decltype(proxyFn);
  874.             lua_pushlightuserdata(
  875.                 L, reinterpret_cast<void*>(proxyFn)); // Stack: co, cl, st, function ptr
  876.             lua_pushcclosure(
  877.                 L, &CFunc::CallProxyFunction<FnType>::f, 1); // Stack: co, cl, st, function
  878.             rawsetfield(L, -3, name); // Stack: co, cl, st
  879.             return *this;
  880.         }
  881.  
  882.         template<class ReturnType, class... Params>
  883.         Class<T>& addFunction(char const* name, ReturnType (*proxyFn)(const T* object, Params...))
  884.         {
  885.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  886.  
  887.             static const std::string GC = "__gc";
  888.             if (name == GC)
  889.             {
  890.                 throw std::logic_error(GC + " metamethod registration is forbidden");
  891.             }
  892.             using FnType = decltype(proxyFn);
  893.             lua_pushlightuserdata(
  894.                 L, reinterpret_cast<void*>(proxyFn)); // Stack: co, cl, st, function ptr
  895.             lua_pushcclosure(
  896.                 L, &CFunc::CallProxyFunction<FnType>::f, 1); // Stack: co, cl, st, function
  897.             lua_pushvalue(L, -1); // Stack: co, cl, st, function, function
  898.             rawsetfield(L, -4, name); // Stack: co, cl, st, function
  899.             rawsetfield(L, -4, name); // Stack: co, cl, st
  900.             return *this;
  901.         }
  902.  
  903.         //--------------------------------------------------------------------------
  904.         /**
  905.             Add or replace a member lua_CFunction.
  906.         */
  907.         Class<T>& addFunction(char const* name, int (T::*mfp)(lua_State*))
  908.         {
  909.             return addCFunction(name, mfp);
  910.         }
  911.  
  912.         //--------------------------------------------------------------------------
  913.         /**
  914.             Add or replace a member lua_CFunction.
  915.         */
  916.         Class<T>& addCFunction(char const* name, int (T::*mfp)(lua_State*))
  917.         {
  918.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  919.  
  920.             typedef int (T::*MFP)(lua_State*);
  921.             new (lua_newuserdata(L, sizeof(mfp))) MFP(mfp); // Stack: co, cl, st, function ptr
  922.             lua_pushcclosure(
  923.                 L, &CFunc::CallMemberCFunction<T>::f, 1); // Stack: co, cl, st, function
  924.             rawsetfield(L, -3, name); // Stack: co, cl, st
  925.  
  926.             return *this;
  927.         }
  928.  
  929.         //--------------------------------------------------------------------------
  930.         /**
  931.             Add or replace a const member lua_CFunction.
  932.         */
  933.         Class<T>& addFunction(char const* name, int (T::*mfp)(lua_State*) const)
  934.         {
  935.             return addCFunction(name, mfp);
  936.         }
  937.  
  938.         //--------------------------------------------------------------------------
  939.         /**
  940.             Add or replace a const member lua_CFunction.
  941.         */
  942.         Class<T>& addCFunction(char const* name, int (T::*mfp)(lua_State*) const)
  943.         {
  944.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  945.  
  946.             typedef int (T::*MFP)(lua_State*) const;
  947.             new (lua_newuserdata(L, sizeof(mfp))) MFP(mfp);
  948.             lua_pushcclosure(L, &CFunc::CallConstMemberCFunction<T>::f, 1);
  949.             lua_pushvalue(L, -1); // Stack: co, cl, st, function, function
  950.             rawsetfield(L, -4, name); // Stack: co, cl, st, function
  951.             rawsetfield(L, -4, name); // Stack: co, cl, st
  952.  
  953.             return *this;
  954.         }
  955.  
  956.         //--------------------------------------------------------------------------
  957.         /**
  958.           Add or replace a primary Constructor.
  959.  
  960.           The primary Constructor is invoked when calling the class type table
  961.           like a function.
  962.  
  963.           The template parameter should be a function pointer type that matches
  964.           the desired Constructor (since you can't take the address of a Constructor
  965.           and pass it as an argument).
  966.         */
  967.         template<class MemFn, class C>
  968.         Class<T>& addConstructor()
  969.         {
  970.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  971.  
  972.             lua_pushcclosure(
  973.                 L, &ctorContainerProxy<typename detail::FuncTraits<MemFn>::Params, C>, 0);
  974.             rawsetfield(L, -2, "__call");
  975.  
  976.             return *this;
  977.         }
  978.  
  979.         template<class MemFn>
  980.         Class<T>& addConstructor()
  981.         {
  982.             assertStackState(); // Stack: const table (co), class table (cl), static table (st)
  983.  
  984.             lua_pushcclosure(
  985.                 L, &ctorPlacementProxy<typename detail::FuncTraits<MemFn>::Params, T>, 0);
  986.             rawsetfield(L, -2, "__call");
  987.  
  988.             return *this;
  989.         }
  990.     };
  991.  
  992. private:
  993.     //----------------------------------------------------------------------------
  994.     /**
  995.         Open the global namespace for registrations.
  996.  
  997.         @param L A Lua state.
  998.     */
  999.     explicit Namespace(lua_State* L) : Registrar(L)
  1000.     {
  1001.         lua_getglobal(L, "_G");
  1002.         ++m_stackSize;
  1003.     }
  1004.  
  1005.     //----------------------------------------------------------------------------
  1006.     /**
  1007.         Open a namespace for registrations.
  1008.         The namespace is created if it doesn't already exist.
  1009.  
  1010.         @param name   The namespace name.
  1011.         @param parent The parent namespace object.
  1012.         @pre The parent namespace is at the top of the Lua stack.
  1013.     */
  1014.     Namespace(char const* name, Namespace& parent) : Registrar(parent)
  1015.     {
  1016.         assert(lua_istable(L, -1)); // Stack: parent namespace (pns)
  1017.  
  1018.         rawgetfield(L, -1, name); // Stack: pns, namespace (ns) | nil
  1019.  
  1020.         if (lua_isnil(L, -1)) // Stack: pns, nil
  1021.         {
  1022.             lua_pop(L, 1); // Stack: pns
  1023.  
  1024.             lua_newtable(L); // Stack: pns, ns
  1025.             lua_pushvalue(L, -1); // Stack: pns, ns, ns
  1026.  
  1027.             // na.__metatable = ns
  1028.             lua_setmetatable(L, -2); // Stack: pns, ns
  1029.  
  1030.             // ns.__index = indexMetaMethod
  1031.             lua_pushcfunction(L, &CFunc::indexMetaMethod);
  1032.             rawsetfield(L, -2, "__index"); // Stack: pns, ns
  1033.  
  1034.             // ns.__newindex = newindexMetaMethod
  1035.             lua_pushcfunction(L, &CFunc::newindexStaticMetaMethod);
  1036.             rawsetfield(L, -2, "__newindex"); // Stack: pns, ns
  1037.  
  1038.             lua_newtable(L); // Stack: pns, ns, propget table (pg)
  1039.             lua_rawsetp(L, -2, detail::getPropgetKey()); // ns [propgetKey] = pg. Stack: pns, ns
  1040.  
  1041.             lua_newtable(L); // Stack: pns, ns, propset table (ps)
  1042.             lua_rawsetp(L, -2, detail::getPropsetKey()); // ns [propsetKey] = ps. Stack: pns, ns
  1043.  
  1044.             // pns [name] = ns
  1045.             lua_pushvalue(L, -1); // Stack: pns, ns, ns
  1046.             rawsetfield(L, -3, name); // Stack: pns, ns
  1047. #if 0
  1048.       lua_pushcfunction (L, &tostringMetaMethod);
  1049.       rawsetfield (L, -2, "__tostring");
  1050. #endif
  1051.         }
  1052.  
  1053.         ++m_stackSize;
  1054.     }
  1055.  
  1056.     //----------------------------------------------------------------------------
  1057.     /**
  1058.         Close the class and continue the namespace registrations.
  1059.  
  1060.         @param child A child class registration object.
  1061.     */
  1062.     explicit Namespace(ClassBase& child) : Registrar(child) {}
  1063.  
  1064.     using Registrar::operator=;
  1065.  
  1066. public:
  1067.     //----------------------------------------------------------------------------
  1068.     /**
  1069.       Retrieve the global namespace.
  1070.       It is recommended to put your namespace inside the global namespace, and
  1071.       then add your classes and functions to it, rather than adding many classes
  1072.       and functions directly to the global namespace.
  1073.  
  1074.       @param L A Lua state.
  1075.       @returns A namespace registration object.
  1076.     */
  1077.     static Namespace getGlobalNamespace(lua_State* L)
  1078.     {
  1079.         enableExceptions(L);
  1080.         return Namespace(L);
  1081.     }
  1082.  
  1083.     //----------------------------------------------------------------------------
  1084.     /**
  1085.         Open a new or existing namespace for registrations.
  1086.  
  1087.         @param name The namespace name.
  1088.         @returns A namespace registration object.
  1089.     */
  1090.     Namespace beginNamespace(char const* name)
  1091.     {
  1092.         assertIsActive();
  1093.         return Namespace(name, *this);
  1094.     }
  1095.  
  1096.     //----------------------------------------------------------------------------
  1097.     /**
  1098.         Continue namespace registration in the parent.
  1099.         Do not use this on the global namespace.
  1100.  
  1101.         @returns A parent namespace registration object.
  1102.     */
  1103.     Namespace endNamespace()
  1104.     {
  1105.         if (m_stackSize == 1)
  1106.         {
  1107.             throw std::logic_error("endNamespace () called on global namespace");
  1108.         }
  1109.  
  1110.         assert(m_stackSize > 1);
  1111.         --m_stackSize;
  1112.         lua_pop(L, 1);
  1113.         return Namespace(*this);
  1114.     }
  1115.  
  1116.     //----------------------------------------------------------------------------
  1117.     /**
  1118.         Add or replace a property.
  1119.  
  1120.         @param name       The property name.
  1121.         @param value      A value pointer.
  1122.         @param isWritable True for a read-write, false for read-only property.
  1123.         @returns This namespace registration object.
  1124.     */
  1125.     template<class T>
  1126.     Namespace& addProperty(char const* name, T* value, bool isWritable = true)
  1127.     {
  1128.         return addVariable(name, value, isWritable);
  1129.     }
  1130.  
  1131.     //----------------------------------------------------------------------------
  1132.     /**
  1133.         Add or replace a property.
  1134.  
  1135.         @param name       The property name.
  1136.         @param value      A value pointer.
  1137.         @param isWritable True for a read-write, false for read-only property.
  1138.         @returns This namespace registration object.
  1139.     */
  1140.     template<class T>
  1141.     Namespace& addVariable(char const* name, T* value, bool isWritable = true)
  1142.     {
  1143.         if (m_stackSize == 1)
  1144.         {
  1145.             throw std::logic_error("addProperty () called on global namespace");
  1146.         }
  1147.  
  1148.         assert(lua_istable(L, -1)); // Stack: namespace table (ns)
  1149.  
  1150.         lua_pushlightuserdata(L, value); // Stack: ns, pointer
  1151.         lua_pushcclosure(L, &CFunc::getVariable<T>, 1); // Stack: ns, getter
  1152.         CFunc::addGetter(L, name, -2); // Stack: ns
  1153.  
  1154.         if (isWritable)
  1155.         {
  1156.             lua_pushlightuserdata(L, value); // Stack: ns, pointer
  1157.             lua_pushcclosure(L, &CFunc::setVariable<T>, 1); // Stack: ns, setter
  1158.         }
  1159.         else
  1160.         {
  1161.             lua_pushstring(L, name); // Stack: ns, ps, name
  1162.             lua_pushcclosure(L, &CFunc::readOnlyError, 1); // Stack: ns, error_fn
  1163.         }
  1164.         CFunc::addSetter(L, name, -2); // Stack: ns
  1165.  
  1166.         return *this;
  1167.     }
  1168.     template<class T>
  1169.     Namespace& addConstant(char const* name, T value)
  1170.     {
  1171.         if (m_stackSize == 1)
  1172.         {
  1173.             throw std::logic_error("addConstant () called on global namespace");
  1174.         }
  1175.  
  1176.         assert(lua_istable(L, -1)); // Stack: namespace table (ns)
  1177.  
  1178.         Stack<T>::push(L, value); // Stack: ns, value
  1179.         rawsetfield(L, -2, name); // Stack: ns
  1180.  
  1181.         return *this;
  1182.     }
  1183.  
  1184.     //----------------------------------------------------------------------------
  1185.     /**
  1186.         Add or replace a property.
  1187.         If the set function is omitted or null, the property is read-only.
  1188.  
  1189.         @param name       The property name.
  1190.         @param get  A pointer to a property getter function.
  1191.         @param set  A pointer to a property setter function, optional.
  1192.         @returns This namespace registration object.
  1193.     */
  1194.     template<class TG, class TS = TG>
  1195.     Namespace& addProperty(char const* name, TG (*get)(), void (*set)(TS) = 0)
  1196.     {
  1197.         if (m_stackSize == 1)
  1198.         {
  1199.             throw std::logic_error("addProperty () called on global namespace");
  1200.         }
  1201.  
  1202.         assert(lua_istable(L, -1)); // Stack: namespace table (ns)
  1203.  
  1204.         lua_pushlightuserdata(L, reinterpret_cast<void*>(get)); // Stack: ns, function ptr
  1205.         lua_pushcclosure(L, &CFunc::Call<TG (*)()>::f, 1); // Stack: ns, getter
  1206.         CFunc::addGetter(L, name, -2);
  1207.  
  1208.         if (set != 0)
  1209.         {
  1210.             lua_pushlightuserdata(L, reinterpret_cast<void*>(set)); // Stack: ns, function ptr
  1211.             lua_pushcclosure(L, &CFunc::Call<void (*)(TS)>::f, 1);
  1212.         }
  1213.         else
  1214.         {
  1215.             lua_pushstring(L, name);
  1216.             lua_pushcclosure(L, &CFunc::readOnlyError, 1);
  1217.         }
  1218.         CFunc::addSetter(L, name, -2);
  1219.  
  1220.         return *this;
  1221.     }
  1222.  
  1223.     //----------------------------------------------------------------------------
  1224.     /**
  1225.         Add or replace a property.
  1226.         If the set function is omitted or null, the property is read-only.
  1227.  
  1228.         @param name The property name.
  1229.         @param get  A pointer to a property getter function.
  1230.         @param set  A pointer to a property setter function, optional.
  1231.         @returns This namespace registration object.
  1232.     */
  1233.     Namespace& addProperty(char const* name, int (*get)(lua_State*), int (*set)(lua_State*) = 0)
  1234.     {
  1235.         if (m_stackSize == 1)
  1236.         {
  1237.             throw std::logic_error("addProperty () called on global namespace");
  1238.         }
  1239.  
  1240.         assert(lua_istable(L, -1)); // Stack: namespace table (ns)
  1241.         lua_pushcfunction(L, get); // Stack: ns, getter
  1242.         CFunc::addGetter(L, name, -2); // Stack: ns
  1243.         if (set != 0)
  1244.         {
  1245.             lua_pushcfunction(L, set); // Stack: ns, setter
  1246.             CFunc::addSetter(L, name, -2); // Stack: ns
  1247.         }
  1248.         else
  1249.         {
  1250.             lua_pushstring(L, name); // Stack: ns, name
  1251.             lua_pushcclosure(L, &CFunc::readOnlyError, 1); // Stack: ns, name, readOnlyError
  1252.             CFunc::addSetter(L, name, -2); // Stack: ns
  1253.         }
  1254.  
  1255.         return *this;
  1256.     }
  1257.  
  1258.     //----------------------------------------------------------------------------
  1259.     /**
  1260.         Add or replace a namespace function by std::function.
  1261.     */
  1262.     template<class ReturnType, class... Params>
  1263.     Namespace& addFunction(char const* name, std::function<ReturnType(Params...)> function)
  1264.     {
  1265.         assert(lua_istable(L, -1)); // Stack: namespace table (ns)
  1266.  
  1267.         using FnType = decltype(function);
  1268.         new (lua_newuserdata(L, sizeof(function)))
  1269.             FnType(std::move(function)); // Stack: ns, function userdata (ud)
  1270.         lua_newtable(L); // Stack: ns, ud, ud metatable (mt)
  1271.         lua_pushcfunction(L, &CFunc::gcMetaMethodAny<FnType>); // Stack: ns, ud, mt, gc function
  1272.         rawsetfield(L, -2, "__gc"); // Stack: ns, ud, mt
  1273.         lua_setmetatable(L, -2); // Stack: ns, ud
  1274.         lua_pushcclosure(L, &CFunc::CallProxyFunctor<FnType>::f, 1); // Stack: ns, function
  1275.         rawsetfield(L, -2, name); // Stack: ns
  1276.  
  1277.         return *this;
  1278.     }
  1279.  
  1280.     //----------------------------------------------------------------------------
  1281.     /**
  1282.         Add or replace a free function.
  1283.     */
  1284.     template<class ReturnType, class... Params>
  1285.     Namespace& addFunction(char const* name, ReturnType (*fp)(Params...))
  1286.     {
  1287.         assert(lua_istable(L, -1)); // Stack: namespace table (ns)
  1288.  
  1289.         using FnType = decltype(fp);
  1290.         lua_pushlightuserdata(L, reinterpret_cast<void*>(fp)); // Stack: ns, function ptr
  1291.         lua_pushcclosure(L, &CFunc::Call<FnType>::f, 1); // Stack: ns, function
  1292.         rawsetfield(L, -2, name); // Stack: ns
  1293.  
  1294.         return *this;
  1295.     }
  1296.  
  1297. #ifdef _M_IX86 // Windows 32bit only
  1298.  
  1299.     //----------------------------------------------------------------------------
  1300.     /**
  1301.         Add or replace a free __stdcall function.
  1302.     */
  1303.     template<class ReturnType, class... Params>
  1304.     Namespace& addFunction(char const* name, ReturnType(__stdcall* fp)(Params...))
  1305.     {
  1306.         assert(lua_istable(L, -1)); // Stack: namespace table (ns)
  1307.  
  1308.         using FnType = decltype(fp);
  1309.         lua_pushlightuserdata(L, reinterpret_cast<void*>(fp)); // Stack: ns, function ptr
  1310.         lua_pushcclosure(L, &CFunc::Call<FnType>::f, 1); // Stack: ns, function
  1311.         rawsetfield(L, -2, name); // Stack: ns
  1312.  
  1313.         return *this;
  1314.     }
  1315.  
  1316. #endif // _M_IX86
  1317.  
  1318.     //----------------------------------------------------------------------------
  1319.     /**
  1320.         Add or replace a lua_CFunction.
  1321.  
  1322.         @param name The function name.
  1323.         @param fp   A C-function pointer.
  1324.         @returns This namespace registration object.
  1325.     */
  1326.     Namespace& addFunction(char const* name, int (*const fp)(lua_State*))
  1327.     {
  1328.         return addCFunction(name, fp);
  1329.     }
  1330.  
  1331.     //----------------------------------------------------------------------------
  1332.     /**
  1333.         Add or replace a lua_CFunction.
  1334.  
  1335.         @param name The function name.
  1336.         @param fp   A C-function pointer.
  1337.         @returns This namespace registration object.
  1338.     */
  1339.     Namespace& addCFunction(char const* name, int (*const fp)(lua_State*))
  1340.     {
  1341.         assert(lua_istable(L, -1)); // Stack: namespace table (ns)
  1342.  
  1343.         lua_pushcfunction(L, fp); // Stack: ns, function
  1344.         rawsetfield(L, -2, name); // Stack: ns
  1345.  
  1346.         return *this;
  1347.     }
  1348.  
  1349.     //----------------------------------------------------------------------------
  1350.     /**
  1351.         Open a new or existing class for registrations.
  1352.  
  1353.         @param name The class name.
  1354.         @returns A class registration object.
  1355.     */
  1356.     template<class T>
  1357.     Class<T> beginClass(char const* name)
  1358.     {
  1359.         assertIsActive();
  1360.         return Class<T>(name, *this);
  1361.     }
  1362.  
  1363.     //----------------------------------------------------------------------------
  1364.     /**
  1365.         Derive a new class for registrations.
  1366.         Call deriveClass() only once.
  1367.         To continue registrations for the class later, use beginClass().
  1368.  
  1369.         @param name The class name.
  1370.         @returns A class registration object.
  1371.     */
  1372.     template<class Derived, class Base>
  1373.     Class<Derived> deriveClass(char const* name)
  1374.     {
  1375.         assertIsActive();
  1376.         return Class<Derived>(name, *this, detail::getStaticRegistryKey<Base>());
  1377.     }
  1378. };
  1379.  
  1380. //------------------------------------------------------------------------------
  1381. /**
  1382.     Retrieve the global namespace.
  1383.     It is recommended to put your namespace inside the global namespace, and
  1384.     then add your classes and functions to it, rather than adding many classes
  1385.     and functions directly to the global namespace.
  1386.  
  1387.     @param L A Lua state.
  1388.     @returns A namespace registration object.
  1389. */
  1390. inline Namespace getGlobalNamespace(lua_State* L)
  1391. {
  1392.     return Namespace::getGlobalNamespace(L);
  1393. }
  1394.  
  1395. } // namespace luabridge
  1396.