1 // The MIT License (MIT) 2 3 // Copyright (c) 2013-2016 Rapptz, ThePhD and contributors 4 5 // Permission is hereby granted, free of charge, to any person obtaining a copy of 6 // this software and associated documentation files (the "Software"), to deal in 7 // the Software without restriction, including without limitation the rights to 8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 // the Software, and to permit persons to whom the Software is furnished to do so, 10 // subject to the following conditions: 11 12 // The above copyright notice and this permission notice shall be included in all 13 // copies or substantial portions of the Software. 14 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22 #ifndef SOL_PROXY_HPP 23 #define SOL_PROXY_HPP 24 25 #include "traits.hpp" 26 #include "object.hpp" 27 #include "function.hpp" 28 #include "protected_function.hpp" 29 #include "proxy_base.hpp" 30 31 namespace sol { 32 template<typename Table, typename Key> 33 struct proxy : public proxy_base<proxy<Table, Key>> { 34 private: 35 typedef meta::condition<meta::is_specialization_of<std::tuple, Key>, Key, std::tuple<meta::condition<std::is_array<meta::unqualified_t<Key>>, Key&, meta::unqualified_t<Key>>>> key_type; 36 37 template<typename T, std::size_t... I> tuple_getsol::proxy38 decltype(auto) tuple_get(std::index_sequence<I...>) const { 39 return tbl.template traverse_get<T>(std::get<I>(key)...); 40 } 41 42 template<std::size_t... I, typename T> tuple_setsol::proxy43 void tuple_set(std::index_sequence<I...>, T&& value) { 44 tbl.traverse_set(std::get<I>(key)..., std::forward<T>(value)); 45 } 46 47 public: 48 Table tbl; 49 key_type key; 50 51 template<typename T> proxysol::proxy52 proxy(Table table, T&& k) : tbl(table), key(std::forward<T>(k)) {} 53 54 template<typename T> setsol::proxy55 proxy& set(T&& item) { 56 tuple_set(std::make_index_sequence<std::tuple_size<meta::unqualified_t<key_type>>::value>(), std::forward<T>(item)); 57 return *this; 58 } 59 60 template<typename... Args> set_functionsol::proxy61 proxy& set_function(Args&&... args) { 62 tbl.set_function(key, std::forward<Args>(args)...); 63 return *this; 64 } 65 66 template<typename U, meta::enable<meta::neg<is_lua_reference<meta::unwrap_unqualified_t<U>>>, meta::is_callable<meta::unwrap_unqualified_t<U>>> = meta::enabler> operator =sol::proxy67 proxy& operator=(U&& other) { 68 return set_function(std::forward<U>(other)); 69 } 70 71 template<typename U, meta::disable<meta::neg<is_lua_reference<meta::unwrap_unqualified_t<U>>>, meta::is_callable<meta::unwrap_unqualified_t<U>>> = meta::enabler> operator =sol::proxy72 proxy& operator=(U&& other) { 73 return set(std::forward<U>(other)); 74 } 75 76 template<typename T> getsol::proxy77 decltype(auto) get() const { 78 return tuple_get<T>(std::make_index_sequence<std::tuple_size<meta::unqualified_t<key_type>>::value>()); 79 } 80 81 template<typename T> get_orsol::proxy82 decltype(auto) get_or(T&& otherwise) const { 83 typedef decltype(get<T>()) U; 84 sol::optional<U> option = get<sol::optional<U>>(); 85 if (option) { 86 return static_cast<U>(option.value()); 87 } 88 return static_cast<U>(std::forward<T>(otherwise)); 89 } 90 91 template<typename T, typename D> get_orsol::proxy92 decltype(auto) get_or(D&& otherwise) const { 93 sol::optional<T> option = get<sol::optional<T>>(); 94 if (option) { 95 return static_cast<T>(option.value()); 96 } 97 return static_cast<T>(std::forward<D>(otherwise)); 98 } 99 100 template <typename K> operator []sol::proxy101 decltype(auto) operator[](K&& k) const { 102 auto keys = meta::tuplefy(key, std::forward<K>(k)); 103 return proxy<Table, decltype(keys)>(tbl, std::move(keys)); 104 } 105 106 template<typename... Ret, typename... Args> callsol::proxy107 decltype(auto) call(Args&&... args) { 108 return get<function>().template call<Ret...>(std::forward<Args>(args)...); 109 } 110 111 template<typename... Args> operator ()sol::proxy112 decltype(auto) operator()(Args&&... args) { 113 return call<>(std::forward<Args>(args)...); 114 } 115 validsol::proxy116 bool valid() const { 117 auto pp = stack::push_pop(tbl); 118 auto p = stack::probe_get_field<std::is_same<meta::unqualified_t<Table>, global_table>::value>(tbl.lua_state(), key, lua_gettop(tbl.lua_state())); 119 lua_pop(tbl.lua_state(), p.levels); 120 return p; 121 } 122 }; 123 124 template<typename Table, typename Key, typename T> operator ==(T && left,const proxy<Table,Key> & right)125 inline bool operator==(T&& left, const proxy<Table, Key>& right) { 126 typedef decltype(stack::get<T>(nullptr, 0)) U; 127 return right.template get<optional<U>>() == left; 128 } 129 130 template<typename Table, typename Key, typename T> operator ==(const proxy<Table,Key> & right,T && left)131 inline bool operator==(const proxy<Table, Key>& right, T&& left) { 132 typedef decltype(stack::get<T>(nullptr, 0)) U; 133 return right.template get<optional<U>>() == left; 134 } 135 136 template<typename Table, typename Key, typename T> operator !=(T && left,const proxy<Table,Key> & right)137 inline bool operator!=(T&& left, const proxy<Table, Key>& right) { 138 typedef decltype(stack::get<T>(nullptr, 0)) U; 139 return right.template get<optional<U>>() == left; 140 } 141 142 template<typename Table, typename Key, typename T> operator !=(const proxy<Table,Key> & right,T && left)143 inline bool operator!=(const proxy<Table, Key>& right, T&& left) { 144 typedef decltype(stack::get<T>(nullptr, 0)) U; 145 return right.template get<optional<U>>() == left; 146 } 147 148 template<typename Table, typename Key> operator ==(lua_nil_t,const proxy<Table,Key> & right)149 inline bool operator==(lua_nil_t, const proxy<Table, Key>& right) { 150 return !right.valid(); 151 } 152 153 template<typename Table, typename Key> operator ==(const proxy<Table,Key> & right,lua_nil_t)154 inline bool operator==(const proxy<Table, Key>& right, lua_nil_t) { 155 return !right.valid(); 156 } 157 158 template<typename Table, typename Key> operator !=(lua_nil_t,const proxy<Table,Key> & right)159 inline bool operator!=(lua_nil_t, const proxy<Table, Key>& right) { 160 return right.valid(); 161 } 162 163 template<typename Table, typename Key> operator !=(const proxy<Table,Key> & right,lua_nil_t)164 inline bool operator!=(const proxy<Table, Key>& right, lua_nil_t) { 165 return right.valid(); 166 } 167 168 namespace stack { 169 template <typename Table, typename Key> 170 struct pusher<proxy<Table, Key>> { pushsol::stack::pusher171 static int push(lua_State* L, const proxy<Table, Key>& p) { 172 sol::reference r = p; 173 return r.push(L); 174 } 175 }; 176 } // stack 177 } // sol 178 179 #endif // SOL_PROXY_HPP 180