add single, add examples

This commit is contained in:
ThePhD 2017-12-10 15:56:49 -05:00
parent c3c7f42d91
commit e06d2fb581
18 changed files with 446 additions and 118 deletions

View File

@ -61,7 +61,7 @@ if (EXAMPLES)
source_group(examples FILES ${EXAMPLES_SRC})
foreach(example_source_file ${EXAMPLES_SRC})
get_filename_component(example_name ${example_source_file} NAME_WE)
set(example_name "example-${example_name}")
set(example_name "example_${example_name}")
add_executable(${example_name} ${example_source_file} ${HEADER_SRCS})
target_link_libraries(${example_name} ${LUA_LIBRARIES})
target_compile_features(${example_name} PUBLIC ${CXX_FEATURES})
@ -74,7 +74,7 @@ if (TESTS)
source_group(tests FILES ${TEST_SRC})
add_executable(tests ${TEST_SRC} ${HEADER_SRCS})
target_include_directories(tests PRIVATE ./Catch/include/)
target_include_directories(tests PRIVATE ${CMAKE_SOURCE_DIR}/Catch/include/)
find_package(Threads)
target_link_libraries(tests Threads::Threads ${LUA_LIBRARIES})
@ -83,10 +83,10 @@ endif()
find_package(PythonInterp 3)
if (PYTHONINTERP_FOUND)
add_custom_command(OUTPUT single/sol/sol.hpp single/sol/sol_forward.hpp COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/single.py --output ${CMAKE_CURRENT_SOURCE_DIR}/single/sol/sol.hpp DEPENDS ${HEADER_SRCS})
add_custom_command(OUTPUT single/sol/sol.hpp single/sol/sol_forward.hpp COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/single.py --output ${CMAKE_CURRENT_BINARY_DIR}/single/sol/sol.hpp DEPENDS ${HEADER_SRCS})
add_custom_target(single_sol DEPENDS single/sol/sol.hpp single/sol/sol_forward.hpp)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/single/sol/sol.hpp" DESTINATION include/sol)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/single/sol/sol_forward.hpp" DESTINATION include/sol)
install(FILES "${CMAKE_SOURCE_DIR}/single/sol/sol.hpp" DESTINATION include/sol)
install(FILES "${CMAKE_SOURCE_DIR}/single/sol/sol_forward.hpp" DESTINATION include/sol)
message(STATUS "single_sol can be generated as python 3 has been found.")
else()
message(STATUS "single_sol cannot be generated as python 3 has not been found.")

View File

@ -88,6 +88,32 @@ You may also retrieve an :doc:`sol::optional\<T><optional>` from this as well, t
Checks if the object at ``index`` is of type ``T``. If it is not, it will call the ``handler`` function with ``lua_State*``, ``int index``, ``type`` expected, and ``type`` actual as arguments. If you do not pass your own handler, a ``no_panic`` handler will be passed.
.. code-block:: cpp
:caption: function: get_usertype
:name: stack-get-usertype
template <typename T>
auto get_usertype( lua_State* L, int index = -1 )
template <typename T>
auto get_usertype( lua_State* L, int index, record& tracking )
Directly attempts to rertieve the type ``T`` using sol2's usertype mechanisms. Similar to a regular ``get`` for a user-defined type. Useful when you need to access sol2's usertype getter mechanism while at the same time `providing your own customization`_.
.. code-block:: cpp
:caption: function: check_usertype
:name: stack-check
template <typename T>
bool check_usertype( lua_State* L, int index = -1 )
template <typename T, typename Handler>
bool check_usertype( lua_State* L, int index, Handler&& handler )
template <typename T, typename Handler>
bool check_usertype( lua_State* L, int index, Handler&& handler, record& tracking )
Checks if the object at ``index`` is of type ``T`` and stored as a sol2 usertype. Useful when you need to access sol2's usertype checker mechanism while at the same time `providing your own customization`_.
.. code-block:: cpp
:caption: function: check_get
:name: stack-check-get
@ -305,3 +331,4 @@ This is an SFINAE-friendly struct that is meant to expose a function ``get`` tha
.. _Lua stack works in general: https://www.lua.org/pil/24.2.html
.. _calling C functions works: https://www.lua.org/pil/26.html
.. _interop examples: https://github.com/ThePhD/sol2/blob/develop/examples/interop
.. _providing your own customization: https://github.com/ThePhD/sol2/blob/develop/examples/customization_convert_on_get.cpp

View File

@ -238,6 +238,8 @@ If you don't specify a ``sol::meta_function`` name (or equivalent string metamet
- a ``sol::meta_function::pairs`` operator is generated for you
- Allows you to iterate using ``for k, v in pairs( obj ) do ... end`` in Lua
- **Lua 5.2 and better only: LuaJIT does not allow this, Lua 5.1 does NOT allow this**
* for cases where ``.size()`` exists on the C++ type
- the length operator of Lua (``#my_obj``) operator is generated for you
* for comparison operations where ``operator <`` and ``operator <=`` exist on the C++ type
- These two ``sol::meta_function::less_than(_or_equal_to)`` are generated for you
- ``>`` and ``>=`` operators are generated in Lua based on ``<`` and ``<=`` operators
@ -264,8 +266,9 @@ Otherwise, the following is used to specify functions to bind on the specific us
- Binds a typical variable to ``"{name}"``, but gets and sets using the specified setter and getter functions. Not that if you do not pass a setter function, the variable will be read-only. Also not that if you do not pass a getter function, it will be write-only
* ``"{name}", sol::var( some_value )`` or ``"{name}", sol::var( std::ref( some_value ) )``
- Binds a typical variable to ``"{name}"``, optionally by reference (e.g., refers to the same memory in C++). This is useful for global variables / static class variables and the like
* ``"{name}", sol::overloaded( Func1, Func2, ... )``
- Creates an oveloaded member function that discriminates on number of arguments and types.
* ``"{name}", sol::overload( Func1, Func2, ... )``
- Creates an oveloaded member function that discriminates on number of arguments and types
- Dumping multiple functions out with the same name **does not make an overload**: you must use **this syntax** in order for it to work
* ``sol::base_classes, sol::bases<Bases...>``
- Tells a usertype what its base classes are. You need this to have derived-to-base conversions work properly. See :ref:`inheritance<usertype-inheritance>`

View File

@ -2,7 +2,6 @@
#include <sol.hpp>
#include <iostream>
#include <iomanip>
#include <cassert>
struct two_things {

View File

@ -0,0 +1,68 @@
#define SOL_CHECK_ARGUMENTS 1
#include <sol.hpp>
#include <iostream>
#include <iomanip>
#include <cassert>
struct number_shim {
double num = 0;
};
namespace sol {
template <>
struct lua_type_of<number_shim> : std::integral_constant<sol::type, sol::type::poly> {};
namespace stack {
template <>
struct checker<number_shim> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
// check_usertype is a backdoor for directly checking sol2 usertypes
if (!check_usertype<number_shim>(L, index) && !stack::check<double>(L, index)) {
handler(L, index, type_of(L, index), type::userdata, "expected a number_shim or a number");
return false;
}
tracking.use(1);
return true;
}
};
template <>
struct getter<number_shim> {
static number_shim get(lua_State* L, int index, record& tracking) {
if (check_usertype<number_shim>(L, index)) {
number_shim& ns = get_usertype<number_shim>(L, index, tracking);
return ns;
}
number_shim ns{};
ns.num = stack::get<double>(L, index, tracking);
return ns;
}
};
} // namespace stack
} // namespace sol
int main() {
sol::state lua;
// Create a pass-through style of function
lua.safe_script("function f ( a ) return a end");
lua.set_function("g", [](double a) {
number_shim ns;
ns.num = a;
return ns;
});
lua.script("vf = f(25) vg = g(35)");
number_shim thingsf = lua["vf"];
number_shim thingsg = lua["vg"];
assert(thingsf.num == 25);
assert(thingsg.num == 35);
return 0;
}

View File

@ -191,7 +191,11 @@ if not args.quiet:
print('finished creating single forward declaration header for sol\n')
with open(single_file, 'w', encoding='utf-8') as f:
if not args.quiet:
print('writing {}...'.format(single_file))
f.write(result)
with open(forward_single_file, 'w', encoding='utf-8') as f:
if not args.quiet:
print('writing {}...'.format(single_file))
f.write(forward_result)

View File

@ -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-12-10 06:34:23.982786 UTC
// This header was generated with sol v2.19.0 (revision 87b4dd6)
// Generated 2017-12-10 20:56:35.224200 UTC
// This header was generated with sol v2.19.0 (revision c3c7f42)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_HPP
@ -72,7 +72,6 @@
#if defined(__cpp_noexcept_function_type) || ((defined(_MSC_VER) && _MSC_VER > 1911) && ((defined(_HAS_CXX17) && _HAS_CXX17 == 1) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)))
#ifndef SOL_NOEXCEPT_FUNCTION_TYPE
#define SOL_NOEXCEPT_FUNCTION_TYPE 1
#endif // noexcept is part of a function's type
#endif
@ -4439,6 +4438,11 @@ namespace sol {
int static_trampoline_noexcept(lua_State* L) noexcept {
return f(L);
}
#else
template <lua_CFunction f>
int static_trampoline_noexcept(lua_State* L) noexcept {
return f(L);
}
#endif
template <typename Fx, typename... Args>
@ -7099,6 +7103,20 @@ namespace sol {
use_reference_tag;
return pusher<std::conditional_t<use_reference_tag::value, detail::as_reference_tag, meta::unqualified_t<T>>>{}.push(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
}
template <typename T, typename Handler>
bool check_usertype(std::false_type, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) {
typedef meta::unqualified_t<T> Tu;
typedef detail::as_value_tag<Tu> detail_t;
return checker<detail_t, type::userdata>{}.check(types<meta::unqualified_t<T>>(), L, index, indextype, std::forward<Handler>(handler), tracking);
}
template <typename T, typename Handler>
bool check_usertype(std::true_type, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) {
typedef meta::unqualified_t<std::remove_pointer_t<meta::unqualified_t<T>>> Tu;
typedef detail::as_pointer_tag<Tu> detail_t;
return checker<detail_t, type::userdata>{}.check(L, index, indextype, std::forward<Handler>(handler), tracking);
}
} // namespace stack_detail
inline bool maybe_indexable(lua_State* L, int index = -1) {
@ -7198,6 +7216,24 @@ namespace sol {
return check<T>(L, index, handler);
}
template <typename T, typename Handler>
bool check_usertype(lua_State* L, int index, Handler&& handler, record& tracking) {
type indextype = type_of(L, index);
return stack_detail::check_usertype<T>(std::is_pointer<T>(), L, index, indextype, std::forward<Handler>(handler), tracking);
}
template <typename T, typename Handler>
bool check_usertype(lua_State* L, int index, Handler&& handler) {
record tracking{};
return check_usertype<T>(L, index, std::forward<Handler>(handler), tracking);
}
template <typename T>
bool check_usertype(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
auto handler = no_panic;
return check_usertype<T>(L, index, handler);
}
template <typename T, typename Handler>
inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler, record& tracking) {
typedef meta::unqualified_t<T> Tu;
@ -7226,6 +7262,11 @@ namespace sol {
auto op = check_get<T>(L, index, type_panic_c_str, tracking);
return *std::move(op);
}
template <typename T>
inline decltype(auto) tagged_get(types<optional<T>>, lua_State* L, int index, record& tracking) {
return stack_detail::unchecked_get<optional<T>>(L, index, tracking);
}
#else
template <typename T>
inline decltype(auto) tagged_get(types<T>, lua_State* L, int index, record& tracking) {
@ -7233,11 +7274,6 @@ namespace sol {
}
#endif
template <typename T>
inline decltype(auto) tagged_get(types<optional<T>>, lua_State* L, int index, record& tracking) {
return stack_detail::unchecked_get<optional<T>>(L, index, tracking);
}
template <bool b>
struct check_types {
template <typename T, typename... Args, typename Handler>
@ -7295,6 +7331,21 @@ namespace sol {
return multi_check<true, Args...>(L, index);
}
template <typename T>
inline decltype(auto) get_usertype(lua_State* L, int index, record& tracking) {
#ifdef SOL_SAFE_GETTER
return stack_detail::tagged_get(types<std::conditional_t<std::is_pointer<T>::value, detail::as_pointer_tag<std::remove_pointer_t<T>>, detail::as_value_tag<T>>>(), L, index, tracking);
#else
return stack_detail::unchecked_get<std::conditional_t<std::is_pointer<T>::value, detail::as_pointer_tag<std::remove_pointer_t<T>>, detail::as_value_tag<T>>>(L, index, tracking);
#endif
}
template <typename T>
inline decltype(auto) get_usertype(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
record tracking{};
return get_usertype<T>(L, index, tracking);
}
template <typename T>
inline decltype(auto) get(lua_State* L, int index, record& tracking) {
return stack_detail::tagged_get(types<T>(), L, index, tracking);
@ -7578,17 +7629,21 @@ namespace stack {
int isnum = 0;
lua_tointegerx(L, index, &isnum);
const bool success = isnum != 0;
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string");
}
#else
// this check is precise, does not convert
if (lua_isinteger(L, index) == 1) {
return true;
}
const bool success = false;
#endif // If numbers are enabled, use the imprecise check
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index), "not a numeric type");
}
#endif // If numbers are enabled, use the imprecise check
return success;
#else
#ifndef SOL_STRINGS_ARE_NUMBERS
@ -7887,6 +7942,12 @@ namespace stack {
template <typename T, typename C>
struct checker<detail::as_value_tag<T>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
const type indextype = type_of(L, index);
return check(types<T>(), L, index, indextype, handler, tracking);
}
template <typename U, typename Handler>
static bool check(types<U>, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) {
#ifdef SOL_ENABLE_INTEROP
@ -7937,11 +7998,28 @@ namespace stack {
};
template <typename T, typename C>
struct checker<T, type::userdata, C> {
struct checker<detail::as_pointer_tag<T>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, type indextype, Handler&& handler, record& tracking) {
if (indextype == type::lua_nil) {
tracking.use(1);
return true;
}
return stack_detail::check_usertype<T>(std::false_type(), L, index, indextype, std::forward<Handler>(handler), tracking);
}
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
const type indextype = type_of(L, index);
return checker<detail::as_value_tag<T>, type::userdata, C>{}.check(types<T>(), L, index, indextype, std::forward<Handler>(handler), tracking);
return check(L, index, handler, indextype, tracking);
}
};
template <typename T, typename C>
struct checker<T, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return check_usertype<T>(L, index, std::forward<Handler>(handler), tracking);
}
};
@ -7949,13 +8027,7 @@ namespace stack {
struct checker<T*, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
const type indextype = type_of(L, index);
// Allow lua_nil to be transformed to nullptr
if (indextype == type::lua_nil) {
tracking.use(1);
return true;
}
return checker<meta::unqualified_t<T>, type::userdata, C>{}.check(L, index, std::forward<Handler>(handler), tracking);
return check_usertype<T*>(L, index, std::forward<Handler>(handler), tracking);
}
};
@ -15148,9 +15220,8 @@ namespace sol {
};
static auto& get_src(lua_State* L) {
typedef std::remove_pointer_t<meta::unwrap_unqualified_t<X>> Tu;
#ifdef SOL_SAFE_USERTYPE
auto p = stack::check_get<Tu*>(L, 1);
auto p = stack::check_get<T*>(L, 1);
if (!p) {
luaL_error(L, "sol: 'self' is not of type '%s' (pass 'self' as first argument with ':' or call on proper type)", detail::demangle<T>().c_str());
}
@ -17050,14 +17121,21 @@ namespace sol {
if (toplevel && stack::get<type>(L, keyidx) != type::string) {
return is_index ? f.indexfunc(L) : f.newindexfunc(L);
}
std::string name = stack::get<std::string>(L, keyidx);
auto memberit = f.mapping.find(name);
if (memberit != f.mapping.cend()) {
const usertype_detail::call_information& ci = memberit->second;
const usertype_detail::member_search& member = is_index ? ci.index : ci.new_index;
return (member)(L, static_cast<void*>(&f), ci.runtime_target);
int runtime_target = 0;
usertype_detail::member_search member = nullptr;
{
std::string name = stack::get<std::string>(L, keyidx);
auto memberit = f.mapping.find(name);
if (memberit != f.mapping.cend()) {
const usertype_detail::call_information& ci = memberit->second;
member = is_index ? ci.index : ci.new_index;
runtime_target = ci.runtime_target;
}
}
string_view accessor = name;
if (member != nullptr) {
return (member)(L, static_cast<void*>(&f), runtime_target);
}
string_view accessor = stack::get<string_view>(L, keyidx);
int ret = 0;
bool found = false;
// Otherwise, we need to do propagating calls through the bases
@ -17311,7 +17389,7 @@ namespace sol {
function_map& functions = sm.functions;
static const int keyidx = -2 + static_cast<int>(is_index);
if (toplevel) {
if (stack::get<type>(L, keyidx) != type::string) {
if (type_of(L, keyidx) != type::string) {
if (has_indexing) {
object& indexingfunc = is_index
? sm.index
@ -17326,35 +17404,44 @@ namespace sol {
}
}
string_view accessor = stack::get<string_view>(L, keyidx);
std::string accessorkey = accessor.data();
auto vit = variables.find(accessorkey);
if (vit != variables.cend()) {
auto& varwrap = *(vit->second);
if (is_index) {
return varwrap.index(L);
variable_wrapper* varwrap = nullptr;
{
std::string accessorkey(accessor.data(), accessor.size());
auto vit = variables.find(accessorkey);
if (vit != variables.cend()) {
varwrap = vit->second.get();
}
return varwrap.new_index(L);
}
auto fit = functions.find(accessorkey);
if (fit != functions.cend()) {
object& func = fit->second;
if (is_index) {
return stack::push(L, func);
}
else {
if (has_indexing && !is_toplevel(L)) {
object& indexingfunc = is_index
? sm.index
: sm.newindex;
return call_indexing_object(L, indexingfunc);
if (varwrap != nullptr) {
return is_index ? varwrap->index(L) : varwrap->new_index(L);
}
bool function_failed = false;
{
std::string accessorkey(accessor.data(), accessor.size());
auto fit = functions.find(accessorkey);
if (fit != functions.cend()) {
object& func = fit->second;
if (is_index) {
return stack::push(L, func);
}
else {
return is_index
? indexing_fail<T, is_index>(L)
: metatable_newindex<T, true>(L);
function_failed = true;
}
}
}
if (function_failed) {
if (has_indexing && !is_toplevel(L)) {
object& indexingfunc = is_index
? sm.index
: sm.newindex;
return call_indexing_object(L, indexingfunc);
}
else {
return is_index
? indexing_fail<T, is_index>(L)
: metatable_newindex<T, true>(L);
}
}
/* Check table storage first for a method that works
luaL_getmetatable(L, sm.metakey);
if (type_of(L, -1) != type::lua_nil) {

View File

@ -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-12-10 06:34:24.172779 UTC
// This header was generated with sol v2.19.0 (revision 87b4dd6)
// Generated 2017-12-10 20:56:35.410742 UTC
// This header was generated with sol v2.19.0 (revision c3c7f42)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP
@ -39,7 +39,6 @@
#if defined(__cpp_noexcept_function_type) || ((defined(_MSC_VER) && _MSC_VER > 1911) && ((defined(_HAS_CXX17) && _HAS_CXX17 == 1) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)))
#ifndef SOL_NOEXCEPT_FUNCTION_TYPE
#define SOL_NOEXCEPT_FUNCTION_TYPE 1
#endif // noexcept is part of a function's type
#endif

View File

@ -538,9 +538,8 @@ namespace sol {
};
static auto& get_src(lua_State* L) {
typedef std::remove_pointer_t<meta::unwrap_unqualified_t<X>> Tu;
#ifdef SOL_SAFE_USERTYPE
auto p = stack::check_get<Tu*>(L, 1);
auto p = stack::check_get<T*>(L, 1);
if (!p) {
luaL_error(L, "sol: 'self' is not of type '%s' (pass 'self' as first argument with ':' or call on proper type)", detail::demangle<T>().c_str());
}

View File

@ -30,7 +30,7 @@
#if defined(__cpp_noexcept_function_type) || ((defined(_MSC_VER) && _MSC_VER > 1911) && ((defined(_HAS_CXX17) && _HAS_CXX17 == 1) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)))
#ifndef SOL_NOEXCEPT_FUNCTION_TYPE
#define SOL_NOEXCEPT_FUNCTION_TYPE 1
//#define SOL_NOEXCEPT_FUNCTION_TYPE 1
#endif // noexcept is part of a function's type
#endif

View File

@ -51,7 +51,7 @@ namespace sol {
function_map& functions = sm.functions;
static const int keyidx = -2 + static_cast<int>(is_index);
if (toplevel) {
if (stack::get<type>(L, keyidx) != type::string) {
if (type_of(L, keyidx) != type::string) {
if (has_indexing) {
object& indexingfunc = is_index
? sm.index
@ -66,35 +66,44 @@ namespace sol {
}
}
string_view accessor = stack::get<string_view>(L, keyidx);
std::string accessorkey = accessor.data();
auto vit = variables.find(accessorkey);
if (vit != variables.cend()) {
auto& varwrap = *(vit->second);
if (is_index) {
return varwrap.index(L);
variable_wrapper* varwrap = nullptr;
{
std::string accessorkey(accessor.data(), accessor.size());
auto vit = variables.find(accessorkey);
if (vit != variables.cend()) {
varwrap = vit->second.get();
}
return varwrap.new_index(L);
}
auto fit = functions.find(accessorkey);
if (fit != functions.cend()) {
object& func = fit->second;
if (is_index) {
return stack::push(L, func);
}
else {
if (has_indexing && !is_toplevel(L)) {
object& indexingfunc = is_index
? sm.index
: sm.newindex;
return call_indexing_object(L, indexingfunc);
if (varwrap != nullptr) {
return is_index ? varwrap->index(L) : varwrap->new_index(L);
}
bool function_failed = false;
{
std::string accessorkey(accessor.data(), accessor.size());
auto fit = functions.find(accessorkey);
if (fit != functions.cend()) {
object& func = fit->second;
if (is_index) {
return stack::push(L, func);
}
else {
return is_index
? indexing_fail<T, is_index>(L)
: metatable_newindex<T, true>(L);
function_failed = true;
}
}
}
if (function_failed) {
if (has_indexing && !is_toplevel(L)) {
object& indexingfunc = is_index
? sm.index
: sm.newindex;
return call_indexing_object(L, indexingfunc);
}
else {
return is_index
? indexing_fail<T, is_index>(L)
: metatable_newindex<T, true>(L);
}
}
/* Check table storage first for a method that works
luaL_getmetatable(L, sm.metakey);
if (type_of(L, -1) != type::lua_nil) {

View File

@ -99,17 +99,21 @@ namespace stack {
int isnum = 0;
lua_tointegerx(L, index, &isnum);
const bool success = isnum != 0;
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index), "not a numeric type or numeric string");
}
#else
// this check is precise, does not convert
if (lua_isinteger(L, index) == 1) {
return true;
}
const bool success = false;
#endif // If numbers are enabled, use the imprecise check
if (!success) {
// expected type, actual type
handler(L, index, type::number, type_of(L, index), "not a numeric type");
}
#endif // If numbers are enabled, use the imprecise check
return success;
#else
#ifndef SOL_STRINGS_ARE_NUMBERS
@ -408,6 +412,12 @@ namespace stack {
template <typename T, typename C>
struct checker<detail::as_value_tag<T>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
const type indextype = type_of(L, index);
return check(types<T>(), L, index, indextype, handler, tracking);
}
template <typename U, typename Handler>
static bool check(types<U>, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) {
#ifdef SOL_ENABLE_INTEROP
@ -458,11 +468,28 @@ namespace stack {
};
template <typename T, typename C>
struct checker<T, type::userdata, C> {
struct checker<detail::as_pointer_tag<T>, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, type indextype, Handler&& handler, record& tracking) {
if (indextype == type::lua_nil) {
tracking.use(1);
return true;
}
return stack_detail::check_usertype<T>(std::false_type(), L, index, indextype, std::forward<Handler>(handler), tracking);
}
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
const type indextype = type_of(L, index);
return checker<detail::as_value_tag<T>, type::userdata, C>{}.check(types<T>(), L, index, indextype, std::forward<Handler>(handler), tracking);
return check(L, index, handler, indextype, tracking);
}
};
template <typename T, typename C>
struct checker<T, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
return check_usertype<T>(L, index, std::forward<Handler>(handler), tracking);
}
};
@ -470,13 +497,7 @@ namespace stack {
struct checker<T*, type::userdata, C> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
const type indextype = type_of(L, index);
// Allow lua_nil to be transformed to nullptr
if (indextype == type::lua_nil) {
tracking.use(1);
return true;
}
return checker<meta::unqualified_t<T>, type::userdata, C>{}.check(L, index, std::forward<Handler>(handler), tracking);
return check_usertype<T*>(L, index, std::forward<Handler>(handler), tracking);
}
};

View File

@ -550,6 +550,20 @@ namespace sol {
use_reference_tag;
return pusher<std::conditional_t<use_reference_tag::value, detail::as_reference_tag, meta::unqualified_t<T>>>{}.push(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
}
template <typename T, typename Handler>
bool check_usertype(std::false_type, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) {
typedef meta::unqualified_t<T> Tu;
typedef detail::as_value_tag<Tu> detail_t;
return checker<detail_t, type::userdata>{}.check(types<meta::unqualified_t<T>>(), L, index, indextype, std::forward<Handler>(handler), tracking);
}
template <typename T, typename Handler>
bool check_usertype(std::true_type, lua_State* L, int index, type indextype, Handler&& handler, record& tracking) {
typedef meta::unqualified_t<std::remove_pointer_t<meta::unqualified_t<T>>> Tu;
typedef detail::as_pointer_tag<Tu> detail_t;
return checker<detail_t, type::userdata>{}.check(L, index, indextype, std::forward<Handler>(handler), tracking);
}
} // namespace stack_detail
inline bool maybe_indexable(lua_State* L, int index = -1) {
@ -649,6 +663,24 @@ namespace sol {
return check<T>(L, index, handler);
}
template <typename T, typename Handler>
bool check_usertype(lua_State* L, int index, Handler&& handler, record& tracking) {
type indextype = type_of(L, index);
return stack_detail::check_usertype<T>(std::is_pointer<T>(), L, index, indextype, std::forward<Handler>(handler), tracking);
}
template <typename T, typename Handler>
bool check_usertype(lua_State* L, int index, Handler&& handler) {
record tracking{};
return check_usertype<T>(L, index, std::forward<Handler>(handler), tracking);
}
template <typename T>
bool check_usertype(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
auto handler = no_panic;
return check_usertype<T>(L, index, handler);
}
template <typename T, typename Handler>
inline decltype(auto) check_get(lua_State* L, int index, Handler&& handler, record& tracking) {
typedef meta::unqualified_t<T> Tu;
@ -677,6 +709,11 @@ namespace sol {
auto op = check_get<T>(L, index, type_panic_c_str, tracking);
return *std::move(op);
}
template <typename T>
inline decltype(auto) tagged_get(types<optional<T>>, lua_State* L, int index, record& tracking) {
return stack_detail::unchecked_get<optional<T>>(L, index, tracking);
}
#else
template <typename T>
inline decltype(auto) tagged_get(types<T>, lua_State* L, int index, record& tracking) {
@ -684,11 +721,6 @@ namespace sol {
}
#endif
template <typename T>
inline decltype(auto) tagged_get(types<optional<T>>, lua_State* L, int index, record& tracking) {
return stack_detail::unchecked_get<optional<T>>(L, index, tracking);
}
template <bool b>
struct check_types {
template <typename T, typename... Args, typename Handler>
@ -746,6 +778,21 @@ namespace sol {
return multi_check<true, Args...>(L, index);
}
template <typename T>
inline decltype(auto) get_usertype(lua_State* L, int index, record& tracking) {
#ifdef SOL_SAFE_GETTER
return stack_detail::tagged_get(types<std::conditional_t<std::is_pointer<T>::value, detail::as_pointer_tag<std::remove_pointer_t<T>>, detail::as_value_tag<T>>>(), L, index, tracking);
#else
return stack_detail::unchecked_get<std::conditional_t<std::is_pointer<T>::value, detail::as_pointer_tag<std::remove_pointer_t<T>>, detail::as_value_tag<T>>>(L, index, tracking);
#endif
}
template <typename T>
inline decltype(auto) get_usertype(lua_State* L, int index = -lua_size<meta::unqualified_t<T>>::value) {
record tracking{};
return get_usertype<T>(L, index, tracking);
}
template <typename T>
inline decltype(auto) get(lua_State* L, int index, record& tracking) {
return stack_detail::tagged_get(types<T>(), L, index, tracking);

View File

@ -57,6 +57,11 @@ namespace sol {
int static_trampoline_noexcept(lua_State* L) noexcept {
return f(L);
}
#else
template <lua_CFunction f>
int static_trampoline_noexcept(lua_State* L) noexcept {
return f(L);
}
#endif
template <typename Fx, typename... Args>

View File

@ -555,14 +555,21 @@ namespace sol {
if (toplevel && stack::get<type>(L, keyidx) != type::string) {
return is_index ? f.indexfunc(L) : f.newindexfunc(L);
}
std::string name = stack::get<std::string>(L, keyidx);
auto memberit = f.mapping.find(name);
if (memberit != f.mapping.cend()) {
const usertype_detail::call_information& ci = memberit->second;
const usertype_detail::member_search& member = is_index ? ci.index : ci.new_index;
return (member)(L, static_cast<void*>(&f), ci.runtime_target);
int runtime_target = 0;
usertype_detail::member_search member = nullptr;
{
std::string name = stack::get<std::string>(L, keyidx);
auto memberit = f.mapping.find(name);
if (memberit != f.mapping.cend()) {
const usertype_detail::call_information& ci = memberit->second;
member = is_index ? ci.index : ci.new_index;
runtime_target = ci.runtime_target;
}
}
string_view accessor = name;
if (member != nullptr) {
return (member)(L, static_cast<void*>(&f), runtime_target);
}
string_view accessor = stack::get<string_view>(L, keyidx);
int ret = 0;
bool found = false;
// Otherwise, we need to do propagating calls through the bases

View File

@ -772,9 +772,7 @@ y = a.readonly_seq
std::list<bar>& seqrefy = lua["y"];
REQUIRE(&seqrefx == &seqrefy);
REQUIRE(seqrefx.size() == 3);
auto result = lua.do_string(R"(
a.readonly_seq = value;
)");
auto result = lua.safe_script("a.readonly_seq = value", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid());
}
@ -903,7 +901,7 @@ TEST_CASE("containers/non_copyable", "make sure non-copyable types in containers
lua["v"] = std::vector<non_copyable>{};
auto pfr = lua.safe_script("t = test.new()\nt.b = v", sol::script_pass_on_error);
auto pfr = lua.safe_script("t = test.new() t.b = v", sol::script_pass_on_error);
REQUIRE_FALSE(pfr.valid());
}
SECTION("simple") {
@ -913,7 +911,7 @@ TEST_CASE("containers/non_copyable", "make sure non-copyable types in containers
lua["v"] = std::vector<non_copyable>{};
auto pfr = lua.safe_script("t = test.new()\nt.b = v", sol::script_pass_on_error);
auto pfr = lua.safe_script("t = test.new() t.b = v", sol::script_pass_on_error);
REQUIRE_FALSE(pfr.valid());
}
}

View File

@ -12,6 +12,10 @@ struct two_things {
bool b;
};
struct number_shim {
double num = 0;
};
namespace sol {
// First, the expected size
@ -23,6 +27,10 @@ namespace sol {
template <>
struct lua_type_of<two_things> : std::integral_constant<sol::type, sol::type::poly> {};
// do note specialize size for this because it is our type
template <>
struct lua_type_of<number_shim> : std::integral_constant<sol::type, sol::type::poly> {};
// Now, specialize various stack structures
namespace stack {
@ -62,6 +70,33 @@ namespace sol {
}
};
template <>
struct checker<number_shim> {
template <typename Handler>
static bool check(lua_State* L, int index, Handler&& handler, record& tracking) {
// check_usertype is a backdoor for directly checking sol2 usertypes
if (!check_usertype<number_shim>(L, index) && !stack::check<double>(L, index)) {
handler(L, index, type_of(L, index), type::userdata, "expected a number_shim or a number");
return false;
}
tracking.use(1);
return true;
}
};
template <>
struct getter<number_shim> {
static number_shim get(lua_State* L, int index, record& tracking) {
if (check_usertype<number_shim>(L, index)) {
number_shim& ns = get_usertype<number_shim>(L, index, tracking);
return ns;
}
number_shim ns{};
ns.num = stack::get<double>(L, index, tracking);
return ns;
}
};
} // namespace stack
} // namespace sol
@ -89,3 +124,24 @@ TEST_CASE("customization/split struct", "using the newly documented customizatio
REQUIRE_FALSE(thingsg.b);
REQUIRE(d == 36.5);
}
TEST_CASE("customization/get_ check_usertype", "using the newly documented customization points to handle different kinds of classes") {
sol::state lua;
// Create a pass-through style of function
lua.safe_script("function f ( a ) return a end");
lua.set_function("g", [](double a) {
number_shim ns;
ns.num = a;
return ns;
});
auto result = lua.safe_script("vf = f(25) vg = g(35)", sol::script_pass_on_error);
REQUIRE(result.valid());
number_shim thingsf = lua["vf"];
number_shim thingsg = lua["vg"];
REQUIRE(thingsf.num == 25);
REQUIRE(thingsg.num == 35);
}

View File

@ -635,15 +635,14 @@ end
REQUIRE_FALSE(result.valid());
}
REQUIRE_NOTHROW([&lua]() {
{
auto result = lua.safe_script(R"(
function t:runtime_func(a)
return a + 52
end
)",
sol::script_pass_on_error);
)", sol::script_pass_on_error);
REQUIRE_FALSE(result.valid());
}());
}
lua.safe_script("val = t:func(2)");
val = lua["val"];