mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
New feature: nested
getter for complex nested tables, plus docs and example
This commit is contained in:
parent
92d31b39b7
commit
4094ba3e7a
16
docs/source/api/nested.rst
Normal file
16
docs/source/api/nested.rst
Normal file
|
@ -0,0 +1,16 @@
|
|||
nested
|
||||
======
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
template <typename T>
|
||||
struct nested {
|
||||
T source;
|
||||
};
|
||||
|
||||
|
||||
``sol::nested<...>`` is a template class similar to :doc:`sol::as_table<as_table>`, but with the caveat that every :doc:`container type<containers>` within the ``sol::nested`` type will be retrieved as a table from lua. This is helpful when you need to receive C++-style vectors, lists, and maps nested within each other: all of them will be deserialized from lua using table properties rather than anything else.
|
||||
|
||||
The `example`_ provides a very in-depth look at both ``sol::as_table<T>`` and ``sol::nested<T>``, and how the two are equivalent.
|
||||
|
||||
.. _example: https://github.com/ThePhD/sol2/blob/develop/examples/containers_as_table.cpp
|
|
@ -6,21 +6,51 @@
|
|||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
// Nota bene the signature here
|
||||
// Every container-type that's a table must be wrapped in `sol::as_table_t`
|
||||
// it's verbose, so feel free to use typedefs ot make it easy on you
|
||||
void demo (sol::as_table_t<std::map<std::string, sol::as_table_t<std::vector<std::string>>>> src) {
|
||||
|
||||
// nested allows serialization of maps with vectors inside, and vice-versa
|
||||
// all from a nested structure of Lua tables
|
||||
// it has less control over which pieces are considered tables in Lua,
|
||||
// and which ones are considered userdata, but it covers a good 90% of cases
|
||||
// where someone wants to handle a nested table
|
||||
void demo(sol::nested<std::map<std::string, std::vector<std::string>>> src) {
|
||||
std::cout << "demo, sol::nested<...>" << std::endl;
|
||||
const auto& listmap = src.source;
|
||||
assert(listmap.size() == 2);
|
||||
for (const auto& kvp : listmap) {
|
||||
const std::vector<std::string>& strings = kvp.second.source;
|
||||
const std::vector<std::string>& strings = kvp.second;
|
||||
assert(strings.size() == 3);
|
||||
std::cout << kvp.first << " = ";
|
||||
std::cout << "\t" << kvp.first << " = ";
|
||||
for (const auto& s : strings) {
|
||||
std::cout << "'" << s << "'" << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// This second demo is equivalent to the first
|
||||
// Nota bene the signature here
|
||||
// Every container-type that's meant to be
|
||||
// a table must be wrapped in `sol::as_table_t`
|
||||
// it's verbose, so feel free to use typedefs to make it easy on you
|
||||
// you can mix which parts are considered tables from Lua, and which parts
|
||||
// are considered other kinds of types, such as userdata and the like
|
||||
void demo_explicit (sol::as_table_t<std::map<std::string, sol::as_table_t<std::vector<std::string>>>> src) {
|
||||
std::cout << "demo, explicit sol::as_table_t<...>" << std::endl;
|
||||
// Have to access the "source" member variable for as_table_t
|
||||
const auto& listmap = src.source;
|
||||
assert(listmap.size() == 2);
|
||||
for (const auto& kvp : listmap) {
|
||||
// Have to access the internal "source" for the inner as_table_t, as well
|
||||
const std::vector<std::string>& strings = kvp.second.source;
|
||||
assert(strings.size() == 3);
|
||||
std::cout << "\t" << kvp.first << " = ";
|
||||
for (const auto& s : strings) {
|
||||
std::cout << "'" << s << "'" << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
int main(int, char**) {
|
||||
|
@ -29,12 +59,15 @@ int main(int, char**) {
|
|||
sol::state lua;
|
||||
// bind the function
|
||||
lua.set_function("f", &demo);
|
||||
lua.set_function("g", &demo_explicit);
|
||||
// Call it with a table that has string sequences set to distinct keys
|
||||
lua.script(R"(
|
||||
f({
|
||||
t = {
|
||||
key1 = {'hello', 'there', 'world'},
|
||||
key2 = {'bark', 'borf', 'woof'}
|
||||
})
|
||||
}
|
||||
f(t)
|
||||
g(t)
|
||||
)");
|
||||
|
||||
std::cout << std::endl;
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// This file was generated with a script.
|
||||
// Generated 2017-03-30 08:20:24.093445 UTC
|
||||
// This header was generated with sol v2.16.0 (revision 4f72880)
|
||||
// Generated 2017-03-30 18:11:26.562402 UTC
|
||||
// This header was generated with sol v2.16.0 (revision 92d31b3)
|
||||
// https://github.com/ThePhD/sol2
|
||||
|
||||
#ifndef SOL_SINGLE_INCLUDE_HPP
|
||||
|
@ -3286,6 +3286,18 @@ namespace sol {
|
|||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct nested {
|
||||
T source;
|
||||
|
||||
template <typename... Args>
|
||||
nested(Args&&... args) : source(std::forward<Args>(args)...) {}
|
||||
|
||||
operator std::add_lvalue_reference_t<T>() {
|
||||
return source;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
as_table_t<T> as_table(T&& container) {
|
||||
return as_table_t<T>(std::forward<T>(container));
|
||||
|
@ -3674,6 +3686,18 @@ namespace sol {
|
|||
template <typename T, typename C = void>
|
||||
struct is_container : std::false_type {};
|
||||
|
||||
template <>
|
||||
struct is_container<std::string> : std::false_type {};
|
||||
|
||||
template <>
|
||||
struct is_container<std::wstring> : std::false_type {};
|
||||
|
||||
template <>
|
||||
struct is_container<std::u16string> : std::false_type {};
|
||||
|
||||
template <>
|
||||
struct is_container<std::u32string> : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_container<T, std::enable_if_t<meta::has_begin_end<meta::unqualified_t<T>>::value>> : std::true_type {};
|
||||
|
||||
|
@ -3810,6 +3834,14 @@ namespace sol {
|
|||
inline type type_of() {
|
||||
return lua_type_of<meta::unqualified_t<T>>::value;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
struct lua_type_of<nested<T>, std::enable_if_t<::sol::is_container<T>::value>> : std::integral_constant<type, type::table> {};
|
||||
|
||||
template <typename T>
|
||||
struct lua_type_of<nested<T>, std::enable_if_t<!::sol::is_container<T>::value>> : lua_type_of<T> {};
|
||||
} // detail
|
||||
} // sol
|
||||
|
||||
// end of sol/types.hpp
|
||||
|
@ -5131,7 +5163,7 @@ namespace sol {
|
|||
return true;
|
||||
}
|
||||
if (t != type::userdata) {
|
||||
handler(L, index, type::function, t);
|
||||
handler(L, index, type::table, t);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -5330,6 +5362,11 @@ namespace sol {
|
|||
struct getter<as_table_t<T>, std::enable_if_t<!meta::has_key_value_pair<meta::unqualified_t<T>>::value>> {
|
||||
static T get(lua_State* L, int relindex, record& tracking) {
|
||||
typedef typename T::value_type V;
|
||||
return get(types<V>(), L, relindex, tracking);
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
static T get(types<V>, lua_State* L, int relindex, record& tracking) {
|
||||
tracking.use(1);
|
||||
|
||||
int index = lua_absindex(L, relindex);
|
||||
|
@ -5385,10 +5422,15 @@ namespace sol {
|
|||
typedef typename T::value_type P;
|
||||
typedef typename P::first_type K;
|
||||
typedef typename P::second_type V;
|
||||
return get(types<K, V>(), L, index, tracking);
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
static T get(types<K, V>, lua_State* L, int relindex, record& tracking) {
|
||||
tracking.use(1);
|
||||
|
||||
T associative;
|
||||
index = lua_absindex(L, index);
|
||||
int index = lua_absindex(L, relindex);
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, index) != 0) {
|
||||
decltype(auto) key = stack::check_get<K>(L, -2);
|
||||
|
@ -5403,6 +5445,40 @@ namespace sol {
|
|||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<nested<T>, std::enable_if_t<!is_container<T>::value>> {
|
||||
static T get(lua_State* L, int index, record& tracking) {
|
||||
getter<T> g;
|
||||
// VC++ has a bad warning here: shut it up
|
||||
(void)g;
|
||||
return g.get(L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<nested<T>, std::enable_if_t<meta::all<is_container<T>, meta::neg<meta::has_key_value_pair<meta::unqualified_t<T>>>>::value>> {
|
||||
static T get(lua_State* L, int index, record& tracking) {
|
||||
typedef typename T::value_type V;
|
||||
getter<as_table_t<T>> g;
|
||||
// VC++ has a bad warning here: shut it up
|
||||
(void)g;
|
||||
return g.get(types<nested<V>>(), L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<nested<T>, std::enable_if_t<meta::all<is_container<T>, meta::has_key_value_pair<meta::unqualified_t<T>>>::value>> {
|
||||
static T get(lua_State* L, int index, record& tracking) {
|
||||
typedef typename T::value_type P;
|
||||
typedef typename P::first_type K;
|
||||
typedef typename P::second_type V;
|
||||
getter<as_table_t<T>> g;
|
||||
// VC++ has a bad warning here: shut it up
|
||||
(void)g;
|
||||
return g.get(types<K, nested<V>>(), L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<T, std::enable_if_t<std::is_base_of<reference, T>::value || std::is_base_of<stack_reference, T>::value>> {
|
||||
static T get(lua_State* L, int index, record& tracking) {
|
||||
|
@ -5716,35 +5792,50 @@ namespace sol {
|
|||
tracking.use(1);
|
||||
return nullptr;
|
||||
}
|
||||
return getter<detail::as_value_tag<T>>::get_no_lua_nil(L, index, tracking);
|
||||
getter<detail::as_value_tag<T>> g;
|
||||
// Avoid VC++ warning
|
||||
(void)g;
|
||||
return g.get_no_lua_nil(L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<non_null<T*>> {
|
||||
static T* get(lua_State* L, int index, record& tracking) {
|
||||
return getter<detail::as_value_tag<T>>::get_no_lua_nil(L, index, tracking);
|
||||
getter<detail::as_value_tag<T>> g;
|
||||
// Avoid VC++ warning
|
||||
(void)g;
|
||||
return g.get_no_lua_nil(L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<T&> {
|
||||
static T& get(lua_State* L, int index, record& tracking) {
|
||||
return getter<detail::as_value_tag<T>>::get(L, index, tracking);
|
||||
getter<detail::as_value_tag<T>> g;
|
||||
// Avoid VC++ warning
|
||||
(void)g;
|
||||
return g.get(L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<std::reference_wrapper<T>> {
|
||||
static T& get(lua_State* L, int index, record& tracking) {
|
||||
return getter<T&>{}.get(L, index, tracking);
|
||||
getter<T&> g;
|
||||
// Avoid VC++ warning
|
||||
(void)g;
|
||||
return g.get(L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<T*> {
|
||||
static T* get(lua_State* L, int index, record& tracking) {
|
||||
return getter<detail::as_pointer_tag<T>>::get(L, index, tracking);
|
||||
getter<detail::as_pointer_tag<T>> g;
|
||||
// Avoid VC++ warning
|
||||
(void)g;
|
||||
return g.get(L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -259,7 +259,7 @@ namespace sol {
|
|||
return true;
|
||||
}
|
||||
if (t != type::userdata) {
|
||||
handler(L, index, type::function, t);
|
||||
handler(L, index, type::table, t);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -81,6 +81,11 @@ namespace sol {
|
|||
struct getter<as_table_t<T>, std::enable_if_t<!meta::has_key_value_pair<meta::unqualified_t<T>>::value>> {
|
||||
static T get(lua_State* L, int relindex, record& tracking) {
|
||||
typedef typename T::value_type V;
|
||||
return get(types<V>(), L, relindex, tracking);
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
static T get(types<V>, lua_State* L, int relindex, record& tracking) {
|
||||
tracking.use(1);
|
||||
|
||||
int index = lua_absindex(L, relindex);
|
||||
|
@ -136,10 +141,15 @@ namespace sol {
|
|||
typedef typename T::value_type P;
|
||||
typedef typename P::first_type K;
|
||||
typedef typename P::second_type V;
|
||||
return get(types<K, V>(), L, index, tracking);
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
static T get(types<K, V>, lua_State* L, int relindex, record& tracking) {
|
||||
tracking.use(1);
|
||||
|
||||
T associative;
|
||||
index = lua_absindex(L, index);
|
||||
int index = lua_absindex(L, relindex);
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, index) != 0) {
|
||||
decltype(auto) key = stack::check_get<K>(L, -2);
|
||||
|
@ -154,6 +164,40 @@ namespace sol {
|
|||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<nested<T>, std::enable_if_t<!is_container<T>::value>> {
|
||||
static T get(lua_State* L, int index, record& tracking) {
|
||||
getter<T> g;
|
||||
// VC++ has a bad warning here: shut it up
|
||||
(void)g;
|
||||
return g.get(L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<nested<T>, std::enable_if_t<meta::all<is_container<T>, meta::neg<meta::has_key_value_pair<meta::unqualified_t<T>>>>::value>> {
|
||||
static T get(lua_State* L, int index, record& tracking) {
|
||||
typedef typename T::value_type V;
|
||||
getter<as_table_t<T>> g;
|
||||
// VC++ has a bad warning here: shut it up
|
||||
(void)g;
|
||||
return g.get(types<nested<V>>(), L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<nested<T>, std::enable_if_t<meta::all<is_container<T>, meta::has_key_value_pair<meta::unqualified_t<T>>>::value>> {
|
||||
static T get(lua_State* L, int index, record& tracking) {
|
||||
typedef typename T::value_type P;
|
||||
typedef typename P::first_type K;
|
||||
typedef typename P::second_type V;
|
||||
getter<as_table_t<T>> g;
|
||||
// VC++ has a bad warning here: shut it up
|
||||
(void)g;
|
||||
return g.get(types<K, nested<V>>(), L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<T, std::enable_if_t<std::is_base_of<reference, T>::value || std::is_base_of<stack_reference, T>::value>> {
|
||||
static T get(lua_State* L, int index, record& tracking) {
|
||||
|
@ -467,35 +511,50 @@ namespace sol {
|
|||
tracking.use(1);
|
||||
return nullptr;
|
||||
}
|
||||
return getter<detail::as_value_tag<T>>::get_no_lua_nil(L, index, tracking);
|
||||
getter<detail::as_value_tag<T>> g;
|
||||
// Avoid VC++ warning
|
||||
(void)g;
|
||||
return g.get_no_lua_nil(L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<non_null<T*>> {
|
||||
static T* get(lua_State* L, int index, record& tracking) {
|
||||
return getter<detail::as_value_tag<T>>::get_no_lua_nil(L, index, tracking);
|
||||
getter<detail::as_value_tag<T>> g;
|
||||
// Avoid VC++ warning
|
||||
(void)g;
|
||||
return g.get_no_lua_nil(L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<T&> {
|
||||
static T& get(lua_State* L, int index, record& tracking) {
|
||||
return getter<detail::as_value_tag<T>>::get(L, index, tracking);
|
||||
getter<detail::as_value_tag<T>> g;
|
||||
// Avoid VC++ warning
|
||||
(void)g;
|
||||
return g.get(L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<std::reference_wrapper<T>> {
|
||||
static T& get(lua_State* L, int index, record& tracking) {
|
||||
return getter<T&>{}.get(L, index, tracking);
|
||||
getter<T&> g;
|
||||
// Avoid VC++ warning
|
||||
(void)g;
|
||||
return g.get(L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct getter<T*> {
|
||||
static T* get(lua_State* L, int index, record& tracking) {
|
||||
return getter<detail::as_pointer_tag<T>>::get(L, index, tracking);
|
||||
getter<detail::as_pointer_tag<T>> g;
|
||||
// Avoid VC++ warning
|
||||
(void)g;
|
||||
return g.get(L, index, tracking);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -307,6 +307,18 @@ namespace sol {
|
|||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct nested {
|
||||
T source;
|
||||
|
||||
template <typename... Args>
|
||||
nested(Args&&... args) : source(std::forward<Args>(args)...) {}
|
||||
|
||||
operator std::add_lvalue_reference_t<T>() {
|
||||
return source;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
as_table_t<T> as_table(T&& container) {
|
||||
return as_table_t<T>(std::forward<T>(container));
|
||||
|
@ -695,6 +707,18 @@ namespace sol {
|
|||
template <typename T, typename C = void>
|
||||
struct is_container : std::false_type {};
|
||||
|
||||
template <>
|
||||
struct is_container<std::string> : std::false_type {};
|
||||
|
||||
template <>
|
||||
struct is_container<std::wstring> : std::false_type {};
|
||||
|
||||
template <>
|
||||
struct is_container<std::u16string> : std::false_type {};
|
||||
|
||||
template <>
|
||||
struct is_container<std::u32string> : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_container<T, std::enable_if_t<meta::has_begin_end<meta::unqualified_t<T>>::value>> : std::true_type {};
|
||||
|
||||
|
@ -831,6 +855,14 @@ namespace sol {
|
|||
inline type type_of() {
|
||||
return lua_type_of<meta::unqualified_t<T>>::value;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
struct lua_type_of<nested<T>, std::enable_if_t<::sol::is_container<T>::value>> : std::integral_constant<type, type::table> {};
|
||||
|
||||
template <typename T>
|
||||
struct lua_type_of<nested<T>, std::enable_if_t<!::sol::is_container<T>::value>> : lua_type_of<T> {};
|
||||
} // detail
|
||||
} // sol
|
||||
|
||||
#endif // SOL_TYPES_HPP
|
||||
|
|
Loading…
Reference in New Issue
Block a user