1 // sol2 2 3 // The MIT License (MIT) 4 5 // Copyright (c) 2013-2018 Rapptz, ThePhD and contributors 6 7 // Permission is hereby granted, free of charge, to any person obtaining a copy of 8 // this software and associated documentation files (the "Software"), to deal in 9 // the Software without restriction, including without limitation the rights to 10 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 // the Software, and to permit persons to whom the Software is furnished to do so, 12 // subject to the following conditions: 13 14 // The above copyright notice and this permission notice shall be included in all 15 // copies or substantial portions of the Software. 16 17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 24 #ifndef SOL_ENVIRONMENT_HPP 25 #define SOL_ENVIRONMENT_HPP 26 27 #include "table.hpp" 28 29 namespace sol { 30 31 template <typename base_type> 32 struct basic_environment : basic_table<base_type> { 33 private: 34 typedef basic_table<base_type> base_t; 35 36 public: 37 using base_t::lua_state; 38 39 basic_environment() noexcept = default; 40 basic_environment(const basic_environment&) = default; 41 basic_environment(basic_environment&&) = default; 42 basic_environment& operator=(const basic_environment&) = default; 43 basic_environment& operator=(basic_environment&&) = default; basic_environmentsol::basic_environment44 basic_environment(const stack_reference& r) 45 : basic_environment(r.lua_state(), r.stack_index()) { 46 } basic_environmentsol::basic_environment47 basic_environment(stack_reference&& r) 48 : basic_environment(r.lua_state(), r.stack_index()) { 49 } 50 basic_environmentsol::basic_environment51 basic_environment(lua_State* L, new_table nt) 52 : base_t(L, std::move(nt)) { 53 } 54 template <bool b> basic_environmentsol::basic_environment55 basic_environment(lua_State* L, new_table t, const basic_reference<b>& fallback) 56 : basic_environment(L, std::move(t)) { 57 stack_table mt(L, new_table(0, 1)); 58 mt.set(meta_function::index, fallback); 59 this->set(metatable_key, mt); 60 mt.pop(); 61 } 62 basic_environmentsol::basic_environment63 basic_environment(env_t, const stack_reference& extraction_target) 64 : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { 65 #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES 66 constructor_handler handler{}; 67 stack::check<env_t>(this->lua_state(), -1, handler); 68 #endif // Safety 69 lua_pop(this->lua_state(), 2); 70 } 71 template <bool b> basic_environmentsol::basic_environment72 basic_environment(env_t, const basic_reference<b>& extraction_target) 73 : base_t(detail::no_safety, extraction_target.lua_state(), (stack::push_environment_of(extraction_target), -1)) { 74 #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES 75 constructor_handler handler{}; 76 stack::check<env_t>(this->lua_state(), -1, handler); 77 #endif // Safety 78 lua_pop(this->lua_state(), 2); 79 } basic_environmentsol::basic_environment80 basic_environment(lua_State* L, int index = -1) 81 : base_t(detail::no_safety, L, index) { 82 #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES 83 constructor_handler handler{}; 84 stack::check<basic_environment>(L, index, handler); 85 #endif // Safety 86 } basic_environmentsol::basic_environment87 basic_environment(lua_State* L, ref_index index) 88 : base_t(detail::no_safety, L, index) { 89 #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES 90 auto pp = stack::push_pop(*this); 91 constructor_handler handler{}; 92 stack::check<basic_environment>(L, -1, handler); 93 #endif // Safety 94 } 95 template <typename T, meta::enable<meta::neg<meta::any_same<meta::unqualified_t<T>, basic_environment>>, meta::neg<std::is_same<base_type, stack_reference>>, meta::neg<std::is_same<lua_nil_t, meta::unqualified_t<T>>>, is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> basic_environmentsol::basic_environment96 basic_environment(T&& r) noexcept 97 : base_t(detail::no_safety, std::forward<T>(r)) { 98 #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES 99 if (!is_environment<meta::unqualified_t<T>>::value) { 100 auto pp = stack::push_pop(*this); 101 constructor_handler handler{}; 102 stack::check<basic_environment>(lua_state(), -1, handler); 103 } 104 #endif // Safety 105 } basic_environmentsol::basic_environment106 basic_environment(lua_nil_t r) noexcept 107 : base_t(detail::no_safety, r) { 108 } 109 110 template <typename T, meta::enable<is_lua_reference<meta::unqualified_t<T>>> = meta::enabler> basic_environmentsol::basic_environment111 basic_environment(lua_State* L, T&& r) noexcept 112 : base_t(detail::no_safety, L, std::forward<T>(r)) { 113 #if defined(SOL_SAFE_REFERENCES) && SOL_SAFE_REFERENCES 114 if (!is_environment<meta::unqualified_t<T>>::value) { 115 auto pp = stack::push_pop(*this); 116 constructor_handler handler{}; 117 stack::check<basic_environment>(lua_state(), -1, handler); 118 } 119 #endif // Safety 120 } 121 122 template <typename T> set_onsol::basic_environment123 void set_on(const T& target) const { 124 lua_State* L = target.lua_state(); 125 auto pp = stack::push_pop(target); 126 #if SOL_LUA_VERSION < 502 127 // Use lua_setfenv 128 this->push(); 129 lua_setfenv(L, -2); 130 #else 131 // Use upvalues as explained in Lua 5.2 and beyond's manual 132 this->push(); 133 const char* name = lua_setupvalue(L, -2, 1); 134 if (name == nullptr) { 135 this->pop(); 136 } 137 #endif 138 } 139 }; 140 141 template <typename T, typename E> set_environment(const basic_environment<E> & env,const T & target)142 void set_environment(const basic_environment<E>& env, const T& target) { 143 env.set_on(target); 144 } 145 146 template <typename E = reference, typename T> get_environment(const T & target)147 basic_environment<E> get_environment(const T& target) { 148 lua_State* L = target.lua_state(); 149 auto pp = stack::pop_n(L, stack::push_environment_of(target)); 150 return basic_environment<E>(L, -1); 151 } 152 153 struct this_environment { 154 optional<environment> env; 155 this_environmentsol::this_environment156 this_environment() 157 : env(nullopt) { 158 } this_environmentsol::this_environment159 this_environment(environment e) 160 : env(std::move(e)) { 161 } 162 this_environment(const this_environment&) = default; 163 this_environment(this_environment&&) = default; 164 this_environment& operator=(const this_environment&) = default; 165 this_environment& operator=(this_environment&&) = default; 166 operator boolsol::this_environment167 explicit operator bool() const { 168 return static_cast<bool>(env); 169 } 170 operator optional<environment>&sol::this_environment171 operator optional<environment>&() { 172 return env; 173 } 174 operator const optional<environment>&sol::this_environment175 operator const optional<environment>&() const { 176 return env; 177 } 178 operator environment&sol::this_environment179 operator environment&() { 180 return env.value(); 181 } 182 operator const environment&sol::this_environment183 operator const environment&() const { 184 return env.value(); 185 } 186 }; 187 188 namespace stack { 189 template <> 190 struct getter<env_t> { getsol::stack::getter191 static environment get(lua_State* L, int index, record& tracking) { 192 tracking.use(1); 193 return get_environment(stack_reference(L, raw_index(index))); 194 } 195 }; 196 197 template <> 198 struct getter<this_environment> { getsol::stack::getter199 static this_environment get(lua_State* L, int, record& tracking) { 200 tracking.use(0); 201 lua_Debug info; 202 // Level 0 means current function (this C function, which may or may not be useful for us?) 203 // Level 1 means next call frame up the stack. (Can be nothing if function called directly from C++ with lua_p/call) 204 int pre_stack_size = lua_gettop(L); 205 if (lua_getstack(L, 1, &info) != 1) { 206 if (lua_getstack(L, 0, &info) != 1) { 207 lua_settop(L, pre_stack_size); 208 return this_environment(); 209 } 210 } 211 if (lua_getinfo(L, "f", &info) == 0) { 212 lua_settop(L, pre_stack_size); 213 return this_environment(); 214 } 215 216 stack_reference f(L, -1); 217 environment env(env_key, f); 218 if (!env.valid()) { 219 lua_settop(L, pre_stack_size); 220 return this_environment(); 221 } 222 return this_environment(std::move(env)); 223 } 224 }; 225 } // namespace stack 226 } // namespace sol 227 228 #endif // SOL_ENVIRONMENT_HPP 229