initial __type implementation, need to bikeshed over what goes in it and how to query information (sol::lib::extensions time?)

fixed `sol::string_view` not pushing a string based on return type
This commit is contained in:
ThePhD 2017-09-05 13:58:17 -04:00
parent a11e127d4d
commit 761641202f
13 changed files with 187 additions and 24 deletions

View File

@ -19,8 +19,10 @@ The examples folder also has a number of really great examples for you to see. T
- If you need dynamic callbacks or runtime overridable functions, have a ``std::function`` member variable and get/set it on the usertype object - If you need dynamic callbacks or runtime overridable functions, have a ``std::function`` member variable and get/set it on the usertype object
- ``std::function`` works as a member variable or in passing as an argument / returning as a value (you can even use it with ``sol::property``) - ``std::function`` works as a member variable or in passing as an argument / returning as a value (you can even use it with ``sol::property``)
- You can also create an entirely dynamic object: see the `dynamic_object example`_ for more details - You can also create an entirely dynamic object: see the `dynamic_object example`_ for more details
* (Advanced) You can override the iteration function for Lua 5.2 and above (LuaJIT does not have the capability) `as shown in the pairs example`_
* You can use :doc:`filters<api/filters>` to control dependencies and streamline return values, as well as apply custom behavior to a functions return * You can use :doc:`filters<api/filters>` to control dependencies and streamline return values, as well as apply custom behavior to a functions return
* You can work with special wrapper types such as ``std::unique_ptr<T>``, ``std::shared_ptr<T>``, and others by default
- Extend them using the :doc:`sol::unique_usertype\<T\> traits<api/unique_usertype_traits>`
* (Advanced) You can override the iteration function for Lua 5.2 and above (LuaJIT does not have the capability) `as shown in the pairs example`_
* Please note that the colon is necessary to "automatically" pass the ``this``/``self`` argument to Lua methods * Please note that the colon is necessary to "automatically" pass the ``this``/``self`` argument to Lua methods
- ``obj:method_name()`` is how you call "member" methods in Lua - ``obj:method_name()`` is how you call "member" methods in Lua
- It is purely syntactic sugar that passes the object name as the first argument to the ``method_name`` function - It is purely syntactic sugar that passes the object name as the first argument to the ``method_name`` function
@ -32,13 +34,13 @@ The examples folder also has a number of really great examples for you to see. T
- You can retrieve a usertype from the Lua runtime at any time - You can retrieve a usertype from the Lua runtime at any time
- Methods and properties will be added to the type only after you register the usertype with the Lua runtime - Methods and properties will be added to the type only after you register the usertype with the Lua runtime
- All methods and properties will appear on all userdata, even if that object was pushed before the usertype (all userdata will be updated) - All methods and properties will appear on all userdata, even if that object was pushed before the usertype (all userdata will be updated)
* Types either copy once or move once into the memory location, if it is a value type. If it is a pointer, we store only the reference. * Types either copy once or move once into the memory location, if it is a value type. If it is a pointer, we store only the reference
- This means retrieval of class types (not primitive types like strings or integers) by ``T&`` or ``T*`` allow you to modify the data in Lua directly. - This means retrieval of class types (not primitive types like strings or integers) by ``T&`` or ``T*`` allow you to modify the data in Lua directly
- Retrieve a plain ``T`` to get a copy - Retrieve a plain ``T`` to get a copy
- Return types and passing arguments to ``sol::function``-types use perfect forwarding and reference semantics, which means no copies happen unless you specify a value explicitly. See :ref:`this note for details<function-argument-handling>`. - Return types and passing arguments to ``sol::function``-types use perfect forwarding and reference semantics, which means no copies happen unless you specify a value explicitly. See :ref:`this note for details<function-argument-handling>`
* You can set ``index`` and ``new_index`` freely on any usertype you like to override the default "if a key is missing, find it / set it here" functionality of a specific object of a usertype. * You can set ``index`` and ``new_index`` freely on any usertype you like to override the default "if a key is missing, find it / set it here" functionality of a specific object of a usertype
- ``new_index`` and ``index`` will not be called if you try to manipulate the named usertype table directly. sol2's will be called to add that function to the usertype's function/variable lookup table. - ``new_index`` and ``index`` will not be called if you try to manipulate the named usertype table directly. sol2's will be called to add that function to the usertype's function/variable lookup table
- ``new_index`` and ``index`` will be called if you attempt to call a key that does not exist on an actual userdata object (the C++ object) itself. - ``new_index`` and ``index`` will be called if you attempt to call a key that does not exist on an actual userdata object (the C++ object) itself
- If you made a usertype named ``test``, this means ``t = test()``, with ``t.hi = 54`` will call your function, but ``test.hi = function () print ("hi"); end`` will instead set the key ``hi`` to to lookup that function for all ``test`` types - If you made a usertype named ``test``, this means ``t = test()``, with ``t.hi = 54`` will call your function, but ``test.hi = function () print ("hi"); end`` will instead set the key ``hi`` to to lookup that function for all ``test`` types
* The first ``sizeof( void* )`` bytes is always a pointer to the typed C++ memory. What comes after is based on what you've pushed into the system according to :doc:`the memory specification for usertypes<api/usertype_memory>`. This is compatible with a number of systems other than just sol2, making it easy to interop with select other Lua systems. * The first ``sizeof( void* )`` bytes is always a pointer to the typed C++ memory. What comes after is based on what you've pushed into the system according to :doc:`the memory specification for usertypes<api/usertype_memory>`. This is compatible with a number of systems other than just sol2, making it easy to interop with select other Lua systems.
* Member methods, properties, variables and functions taking ``self&`` arguments modify data directly * Member methods, properties, variables and functions taking ``self&`` arguments modify data directly

View File

@ -302,8 +302,8 @@ namespace sol {
}; };
template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C> template <bool is_index, bool is_variable, bool checked, int boost, bool clean_stack, typename C>
struct agnostic_lua_call_wrapper<lua_r_CFunction, is_index, is_variable, checked, boost, clean_stack, C> { struct agnostic_lua_call_wrapper<lua_CFunction_ref, is_index, is_variable, checked, boost, clean_stack, C> {
static int call(lua_State* L, lua_r_CFunction f) { static int call(lua_State* L, lua_CFunction_ref f) {
return f(L); return f(L);
} }
}; };

View File

@ -64,12 +64,33 @@ namespace sol {
} }
}; };
template <typename F = void>
struct argument_handler { struct argument_handler {
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) { int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
return type_panic_string(L, index, expected, actual, message + " (bad argument to variable or function call)"); return type_panic_string(L, index, expected, actual, message + " (bad argument to variable or function call)");
} }
}; };
template <typename R, typename... Args>
struct argument_handler<types<R, Args...>> {
int operator()(lua_State* L, int index, type expected, type actual, const std::string& message) const noexcept(false) {
std::string addendum = " (bad argument to type expecting '";
addendum += detail::demangle<R>();
addendum += "(";
int marker = 0;
auto action = [&addendum, &marker](const std::string& n) {
if (marker > 0) {
addendum += ", ";
}
addendum += n;
++marker;
}
(void)detail::swallow{ int(), (action(detail::demangle<Args>()), int())... };
addendum += ")')";
return type_panic_string(L, index, expected, actual, message + addendum);
}
};
// Specify this function as the handler for lua::check if you know there's nothing wrong // Specify this function as the handler for lua::check if you know there's nothing wrong
inline int no_panic(lua_State*, int, type, type, const char* = nullptr) noexcept { inline int no_panic(lua_State*, int, type, type, const char* = nullptr) noexcept {
return 0; return 0;

View File

@ -184,7 +184,7 @@ namespace sol {
void* baseclasscast; void* baseclasscast;
bool mustindex; bool mustindex;
bool secondarymeta; bool secondarymeta;
std::array<bool, 29> properties; std::array<bool, 30> properties;
template <typename N> template <typename N>
void insert(N&& n, object&& o) { void insert(N&& n, object&& o) {
@ -415,6 +415,13 @@ namespace sol {
auto& properties = umx.properties; auto& properties = umx.properties;
auto sic = hasindex ? &usertype_detail::simple_index_call<T, true> : &usertype_detail::simple_index_call<T, false>; auto sic = hasindex ? &usertype_detail::simple_index_call<T, true> : &usertype_detail::simple_index_call<T, false>;
auto snic = hasnewindex ? &usertype_detail::simple_new_index_call<T, true> : &usertype_detail::simple_new_index_call<T, false>; auto snic = hasnewindex ? &usertype_detail::simple_new_index_call<T, true> : &usertype_detail::simple_new_index_call<T, false>;
lua_createtable(L, 0, 2);
stack_reference type_table(L, -1);
stack::set_field(L, "name", detail::demangle<T>(), type_table.stack_index());
stack::set_field(L, "is", &usertype_detail::is_check<T>, type_table.stack_index());
auto register_kvp = [&](std::size_t meta_index, stack_reference& t, const std::string& first, object& second) { auto register_kvp = [&](std::size_t meta_index, stack_reference& t, const std::string& first, object& second) {
meta_function mf = meta_function::construct; meta_function mf = meta_function::construct;
for (std::size_t j = 1; j < properties.size(); ++j) { for (std::size_t j = 1; j < properties.size(); ++j) {
@ -469,6 +476,8 @@ namespace sol {
} }
luaL_newmetatable(L, metakey); luaL_newmetatable(L, metakey);
stack_reference t(L, -1); stack_reference t(L, -1);
stack::set_field(L, meta_function::type, type_table, t.stack_index());
for (auto& kvp : varmap.functions) { for (auto& kvp : varmap.functions) {
auto& first = std::get<0>(kvp); auto& first = std::get<0>(kvp);
auto& second = std::get<1>(kvp); auto& second = std::get<1>(kvp);
@ -514,6 +523,7 @@ namespace sol {
// for call constructor purposes and such // for call constructor purposes and such
lua_createtable(L, 0, 2 * static_cast<int>(umx.secondarymeta) + static_cast<int>(umx.callconstructfunc.valid())); lua_createtable(L, 0, 2 * static_cast<int>(umx.secondarymeta) + static_cast<int>(umx.callconstructfunc.valid()));
stack_reference metabehind(L, -1); stack_reference metabehind(L, -1);
stack::set_field(L, meta_function::type, type_table, metabehind.stack_index());
if (umx.callconstructfunc.valid()) { if (umx.callconstructfunc.valid()) {
stack::set_field(L, sol::meta_function::call_function, umx.callconstructfunc, metabehind.stack_index()); stack::set_field(L, sol::meta_function::call_function, umx.callconstructfunc, metabehind.stack_index());
} }
@ -538,6 +548,7 @@ namespace sol {
// Now for the shim-table that actually gets pushed // Now for the shim-table that actually gets pushed
luaL_newmetatable(L, &usertype_traits<T>::user_metatable()[0]); luaL_newmetatable(L, &usertype_traits<T>::user_metatable()[0]);
stack_reference t(L, -1); stack_reference t(L, -1);
stack::set_field(L, meta_function::type, type_table, t.stack_index());
for (auto& kvp : varmap.functions) { for (auto& kvp : varmap.functions) {
auto& first = std::get<0>(kvp); auto& first = std::get<0>(kvp);
auto& second = std::get<1>(kvp); auto& second = std::get<1>(kvp);
@ -546,6 +557,7 @@ namespace sol {
{ {
lua_createtable(L, 0, 2 + static_cast<int>(umx.callconstructfunc.valid())); lua_createtable(L, 0, 2 + static_cast<int>(umx.callconstructfunc.valid()));
stack_reference metabehind(L, -1); stack_reference metabehind(L, -1);
stack::set_field(L, meta_function::type, type_table, metabehind.stack_index());
if (umx.callconstructfunc.valid()) { if (umx.callconstructfunc.valid()) {
stack::set_field(L, sol::meta_function::call_function, umx.callconstructfunc, metabehind.stack_index()); stack::set_field(L, sol::meta_function::call_function, umx.callconstructfunc, metabehind.stack_index());
} }
@ -570,6 +582,8 @@ namespace sol {
metabehind.pop(); metabehind.pop();
} }
lua_remove(L, type_table.stack_index());
// Don't pop the table when we're done; // Don't pop the table when we're done;
// return it // return it
return 1; return 1;

View File

@ -112,8 +112,8 @@ namespace sol {
inline decltype(auto) call(types<R>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) { inline decltype(auto) call(types<R>, types<Args...> ta, std::index_sequence<I...> tai, lua_State* L, int start, Fx&& fx, FxArgs&&... args) {
#ifndef _MSC_VER #ifndef _MSC_VER
static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention."); static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention.");
#endif // This compiler make me so fucking sad #endif // This compiler make me so sad
argument_handler handler{}; argument_handler<types<R, Args...>> handler{};
multi_check<checkargs, Args...>(L, start, handler); multi_check<checkargs, Args...>(L, start, handler);
record tracking{}; record tracking{};
return evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); return evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);
@ -124,7 +124,7 @@ namespace sol {
#ifndef _MSC_VER #ifndef _MSC_VER
static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention."); static_assert(meta::all<meta::is_not_move_only<Args>...>::value, "One of the arguments being bound is a move-only type, and it is not being taken by reference: this will break your code. Please take a reference and std::move it manually if this was your intention.");
#endif // This compiler make me so fucking sad #endif // This compiler make me so fucking sad
argument_handler handler{}; argument_handler<types<void, Args...>> handler{};
multi_check<checkargs, Args...>(L, start, handler); multi_check<checkargs, Args...>(L, start, handler);
record tracking{}; record tracking{};
evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...); evaluator{}.eval(ta, tai, L, start, tracking, std::forward<Fx>(fx), std::forward<FxArgs>(args)...);

View File

@ -880,7 +880,18 @@ namespace sol {
return std::visit(stack_detail::push_function(L), std::move(v)); return std::visit(stack_detail::push_function(L), std::move(v));
} }
}; };
#endif #else
template <>
struct pusher<string_view> {
static int push(lua_State* L, const std::string_view& sv) {
return stack::push(L, sv.data(), sv.length());
}
static int push(lua_State* L, const std::string_view& sv, std::size_t len) {
return stack::push(L, sv.data(), len);
}
};
#endif // C++17 Support
} // stack } // stack
} // sol } // sol

View File

@ -30,19 +30,33 @@
namespace sol { namespace sol {
enum class lib : char { enum class lib : char {
// print, assert, and other base functions
base, base,
// require and other package functions
package, package,
// coroutine functions and utilities
coroutine, coroutine,
// string library
string, string,
// functionality from the OS
os, os,
// all things math
math, math,
// the table manipulator and observer functions
table, table,
// the debug library
debug, debug,
// the bit library: different based on which you're using
bit32, bit32,
// input/output library
io, io,
// LuaJIT only
ffi, ffi,
// LuaJIT only
jit, jit,
// library for handling utf8: new to Lua
utf8, utf8,
// do not use
count count
}; };

View File

@ -186,7 +186,7 @@ namespace sol {
struct no_metatable_t {}; struct no_metatable_t {};
const no_metatable_t no_metatable = {}; const no_metatable_t no_metatable = {};
typedef std::remove_pointer_t<lua_CFunction> lua_r_CFunction; typedef std::remove_pointer_t<lua_CFunction> lua_CFunction_ref;
template <typename T> template <typename T>
struct unique_usertype_traits { struct unique_usertype_traits {
@ -617,13 +617,15 @@ namespace sol {
bitwise_or, bitwise_or,
bitwise_xor, bitwise_xor,
pairs, pairs,
next next,
type,
type_info,
}; };
typedef meta_function meta_method; typedef meta_function meta_method;
inline const std::array<std::string, 29>& meta_function_names() { inline const std::array<std::string, 31>& meta_function_names() {
static const std::array<std::string, 29> names = { { static const std::array<std::string, 31> names = { {
"new", "new",
"__index", "__index",
"__newindex", "__newindex",
@ -654,7 +656,9 @@ namespace sol {
"__bxor", "__bxor",
"__pairs", "__pairs",
"__next" "__next",
"__type",
"__typeinfo"
} }; } };
return names; return names;
} }

View File

@ -44,6 +44,11 @@ namespace sol {
} }
}; };
template <typename T>
int is_check(lua_State* L) {
return stack::push(L, stack::check<T>(L, 1, &no_panic));
}
template <typename T> template <typename T>
inline int member_default_to_string(std::true_type, lua_State* L) { inline int member_default_to_string(std::true_type, lua_State* L) {
decltype(auto) ts = stack::get<T>(L, 1).to_string(); decltype(auto) ts = stack::get<T>(L, 1).to_string();

View File

@ -379,7 +379,7 @@ namespace sol {
struct usertype_metatable<T, std::index_sequence<I...>, Tn...> : usertype_metatable_core, usertype_detail::registrar { struct usertype_metatable<T, std::index_sequence<I...>, Tn...> : usertype_metatable_core, usertype_detail::registrar {
typedef std::make_index_sequence<sizeof...(I) * 2> indices; typedef std::make_index_sequence<sizeof...(I) * 2> indices;
typedef std::index_sequence<I...> half_indices; typedef std::index_sequence<I...> half_indices;
typedef std::array<luaL_Reg, sizeof...(Tn) / 2 + 1 + 29> regs_t; typedef std::array<luaL_Reg, sizeof...(Tn) / 2 + 1 + 31> regs_t;
typedef std::tuple<Tn...> RawTuple; typedef std::tuple<Tn...> RawTuple;
typedef std::tuple<clean_type_t<Tn> ...> Tuple; typedef std::tuple<clean_type_t<Tn> ...> Tuple;
template <std::size_t Idx> template <std::size_t Idx>
@ -394,7 +394,7 @@ namespace sol {
void* baseclasscheck; void* baseclasscheck;
void* baseclasscast; void* baseclasscast;
bool secondarymeta; bool secondarymeta;
std::array<bool, 29> properties; std::array<bool, 30> properties;
template <std::size_t Idx, meta::enable<std::is_same<lua_CFunction, meta::unqualified_tuple_element<Idx + 1, RawTuple>>> = meta::enabler> template <std::size_t Idx, meta::enable<std::is_same<lua_CFunction, meta::unqualified_tuple_element<Idx + 1, RawTuple>>> = meta::enabler>
lua_CFunction make_func() const { lua_CFunction make_func() const {
@ -676,6 +676,12 @@ namespace sol {
} }
unique_table[lastreg - 1] = { value_table[lastreg - 1].name, detail::unique_destruct<T> }; unique_table[lastreg - 1] = { value_table[lastreg - 1].name, detail::unique_destruct<T> };
lua_createtable(L, 0, 2);
stack_reference type_table(L, -1);
stack::set_field(L, "name", detail::demangle<T>(), type_table.stack_index());
stack::set_field(L, "is", &usertype_detail::is_check<T>, type_table.stack_index());
// Now use um // Now use um
const bool& mustindex = umc.mustindex; const bool& mustindex = umc.mustindex;
for (std::size_t i = 0; i < 3; ++i) { for (std::size_t i = 0; i < 3; ++i) {
@ -699,6 +705,7 @@ namespace sol {
} }
luaL_newmetatable(L, metakey); luaL_newmetatable(L, metakey);
stack_reference t(L, -1); stack_reference t(L, -1);
stack::set_field(L, meta_function::type, type_table, t.stack_index());
int upvalues = 0; int upvalues = 0;
upvalues += stack::push(L, nullptr); upvalues += stack::push(L, nullptr);
upvalues += stack::push(L, make_light(um)); upvalues += stack::push(L, make_light(um));
@ -735,6 +742,9 @@ namespace sol {
stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, nullptr, make_light(um), make_light(umc)), metabehind.stack_index()); stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, nullptr, make_light(um), make_light(umc)), metabehind.stack_index());
stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, nullptr, make_light(um), make_light(umc)), metabehind.stack_index()); stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, nullptr, make_light(um), make_light(umc)), metabehind.stack_index());
} }
// type information needs to be present on the behind-tables too
stack::set_field(L, meta_function::type, type_table, metabehind.stack_index());
stack::set_field(L, metatable_key, metabehind, t.stack_index()); stack::set_field(L, metatable_key, metabehind, t.stack_index());
metabehind.pop(); metabehind.pop();
// We want to just leave the table // We want to just leave the table
@ -745,6 +755,7 @@ namespace sol {
// Now for the shim-table that actually gets assigned to the name // Now for the shim-table that actually gets assigned to the name
luaL_newmetatable(L, &usertype_traits<T>::user_metatable()[0]); luaL_newmetatable(L, &usertype_traits<T>::user_metatable()[0]);
stack_reference t(L, -1); stack_reference t(L, -1);
stack::set_field(L, meta_function::type, type_table, t.stack_index());
int upvalues = 0; int upvalues = 0;
upvalues += stack::push(L, nullptr); upvalues += stack::push(L, nullptr);
upvalues += stack::push(L, make_light(um)); upvalues += stack::push(L, make_light(um));
@ -758,11 +769,14 @@ namespace sol {
stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, nullptr, make_light(um), make_light(umc), nullptr, usertype_detail::toplevel_magic), metabehind.stack_index()); stack::set_field(L, meta_function::index, make_closure(umt_t::index_call, nullptr, make_light(um), make_light(umc), nullptr, usertype_detail::toplevel_magic), metabehind.stack_index());
stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, nullptr, make_light(um), make_light(umc), nullptr, usertype_detail::toplevel_magic), metabehind.stack_index()); stack::set_field(L, meta_function::new_index, make_closure(umt_t::new_index_call, nullptr, make_light(um), make_light(umc), nullptr, usertype_detail::toplevel_magic), metabehind.stack_index());
stack::set_field(L, metatable_key, metabehind, t.stack_index()); stack::set_field(L, metatable_key, metabehind, t.stack_index());
// type information needs to be present on the behind-tables too
stack::set_field(L, meta_function::type, type_table, metabehind.stack_index());
metabehind.pop(); metabehind.pop();
} }
lua_remove(L, type_table.stack_index());
return 1; return 1;
} }
}; };

View File

@ -888,3 +888,35 @@ TEST_CASE("simple_usertype/indexing", "make sure simple usertypes can be indexed
REQUIRE(val == 50); REQUIRE(val == 50);
} }
} }
TEST_CASE("simple_usertype/basic type information", "check that we can query some basic type information") {
struct my_thing {};
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<my_thing>("my_thing");
lua.safe_script("obj = my_thing.new()");
lua.safe_script("assert(my_thing.__type.is(obj))");
lua.safe_script("assert(not my_thing.__type.is(1))");
lua.safe_script("assert(not my_thing.__type.is(\"not a thing\"))");
lua.safe_script("print(my_thing.__type.name)");
lua.safe_script("assert(obj.__type.is(obj))");
lua.safe_script("assert(not obj.__type.is(1))");
lua.safe_script("assert(not obj.__type.is(\"not a thing\"))");
lua.safe_script("print(obj.__type.name)");
lua.safe_script("assert(getmetatable(my_thing).__type.is(obj))");
lua.safe_script("assert(not getmetatable(my_thing).__type.is(1))");
lua.safe_script("assert(not getmetatable(my_thing).__type.is(\"not a thing\"))");
lua.safe_script("print(getmetatable(my_thing).__type.name)");
lua.safe_script("assert(getmetatable(obj).__type.is(obj))");
lua.safe_script("assert(not getmetatable(obj).__type.is(1))");
lua.safe_script("assert(not getmetatable(obj).__type.is(\"not a thing\"))");
lua.safe_script("print(getmetatable(obj).__type.name)");
}

View File

@ -115,8 +115,23 @@ TEST_CASE("object/string-pushers", "test some basic string pushers with in_place
sol::object ocs(lua, sol::in_place, "bark\0bark", 9); sol::object ocs(lua, sol::in_place, "bark\0bark", 9);
sol::object os(lua, sol::in_place_type<std::string>, std::string("bark\0bark", 9), 8); sol::object os(lua, sol::in_place_type<std::string>, std::string("bark\0bark", 9), 8);
bool test1 = os.as<std::string>() == std::string("bark\0bar", 8); sol::object osv(lua, sol::in_place_type<sol::string_view>, std::string_view("woofwoof", 8), 8);
bool test2 = ocs.as<std::string>() == std::string("bark\0bark", 9); bool test1 = ocs.as<std::string>() == std::string("bark\0bark", 9);
bool test2 = os.as<std::string>() == std::string("bark\0bar", 8);
bool test3 = osv.as<std::string>() == std::string("woofwoof", 8);
REQUIRE(ocs.get_type() == sol::type::string);
REQUIRE(ocs.is<std::string>());
REQUIRE(ocs.is<sol::string_view>());
REQUIRE(os.get_type() == sol::type::string);
REQUIRE(os.is<std::string>());
REQUIRE(os.is<sol::string_view>());
REQUIRE(osv.get_type() == sol::type::string);
REQUIRE(osv.is<std::string>());
REQUIRE(osv.is<sol::string_view>());
REQUIRE(test1); REQUIRE(test1);
REQUIRE(test2); REQUIRE(test2);
REQUIRE(test3);
} }

View File

@ -1764,3 +1764,34 @@ TEST_CASE("usertype/noexcept-methods", "make sure noexcept functinos and methods
REQUIRE(v1 == 0x61); REQUIRE(v1 == 0x61);
REQUIRE(v2 == 0x62); REQUIRE(v2 == 0x62);
} }
TEST_CASE("usertype/basic type information", "check that we can query some basic type information") {
struct my_thing {};
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_simple_usertype<my_thing>("my_thing");
lua.safe_script("obj = my_thing.new()");
lua.safe_script("assert(my_thing.__type.is(obj))");
lua.safe_script("assert(not my_thing.__type.is(1))");
lua.safe_script("assert(not my_thing.__type.is(\"not a thing\"))");
lua.safe_script("print(my_thing.__type.name)");
lua.safe_script("assert(obj.__type.is(obj))");
lua.safe_script("assert(not obj.__type.is(1))");
lua.safe_script("assert(not obj.__type.is(\"not a thing\"))");
lua.safe_script("print(obj.__type.name)");
lua.safe_script("assert(getmetatable(my_thing).__type.is(obj))");
lua.safe_script("assert(not getmetatable(my_thing).__type.is(1))");
lua.safe_script("assert(not getmetatable(my_thing).__type.is(\"not a thing\"))");
lua.safe_script("print(getmetatable(my_thing).__type.name)");
lua.safe_script("assert(getmetatable(obj).__type.is(obj))");
lua.safe_script("assert(not getmetatable(obj).__type.is(1))");
lua.safe_script("assert(not getmetatable(obj).__type.is(\"not a thing\"))");
lua.safe_script("print(getmetatable(obj).__type.name)");
}