NOW we're truly feature complete. Sheesh, the work that this requires....

This commit is contained in:
ThePhD 2016-03-31 16:16:07 -04:00
parent 2d14cedc17
commit 8862c65f0a
22 changed files with 462 additions and 80 deletions

View File

@ -1,4 +1,4 @@
## Sol 2.2 ## Sol 2.3
[![Build Status](https://travis-ci.org/ThePhD/sol2.svg?branch=develop)](https://travis-ci.org/ThePhD/sol2) [![Build Status](https://travis-ci.org/ThePhD/sol2.svg?branch=develop)](https://travis-ci.org/ThePhD/sol2)
[![Documentation Status](https://readthedocs.org/projects/sol2/badge/?version=latest)](http://sol2.readthedocs.org/en/latest/?badge=latest) [![Documentation Status](https://readthedocs.org/projects/sol2/badge/?version=latest)](http://sol2.readthedocs.org/en/latest/?badge=latest)

View File

@ -33,6 +33,23 @@ The following C++ code will call this function from this file and retrieve the r
The call ``woof(20)`` generates a :ref:`function_result<function-result>`, which is then implicitly converted to an ``double`` after being called. The intermediate temporary ``function_result`` is then destructed, popping the Lua function call results off the Lua stack. The call ``woof(20)`` generates a :ref:`function_result<function-result>`, which is then implicitly converted to an ``double`` after being called. The intermediate temporary ``function_result`` is then destructed, popping the Lua function call results off the Lua stack.
You can also return multiple values by using std::tuple, or if you need to bind them to pre-existing variables use ``sol::bond``:
.. code-block:: cpp
:linenos:
sol::state lua;
lua.script( "function f () return 10, 11, 12 end" );
sol::function f = lua["f"];
std::tuple<int, int, int> abc = f(); // 10, 11, 12 from Lua
// or
int a, b, c;
sol::bond(a, b, c) = f(); // a = 10, b = 11, c = 12 from Lua
This makes it much easier to work with multiple return values. Using ``std::tie`` from the C++ standard will result in dangling references or bad behavior because of the very poor way in which C++ tuples were implemented: please use ``sol::bond( ... )`` instead to satisfy any multi-return needs.
.. _function-result-warning: .. _function-result-warning:
.. warning:: .. warning::

View File

@ -26,7 +26,7 @@ Inspired by a request from `starwing<https://github.com/starwing>` in the old re
return (bark_energy * (bark_power / 4)) return (bark_energy * (bark_power / 4))
end end
The following C++ code will call this function from this file and retrieve the return value: The following C++ code will call this function from this file and retrieve the return value, unless an error occurs, in which case you can bind an error handling function like so:
.. code-block:: cpp .. code-block:: cpp
:linenos: :linenos:
@ -45,7 +45,7 @@ The following C++ code will call this function from this file and retrieve the r
} }
else{ else{
// An error has occured // An error has occured
std::string error = first_woof; sol::error err = first_woof;
} }
// errors, calls handler and then returns a string error from Lua at the top of the stack // errors, calls handler and then returns a string error from Lua at the top of the stack
@ -59,10 +59,34 @@ The following C++ code will call this function from this file and retrieve the r
// Note that if the handler was successfully called, this will include // Note that if the handler was successfully called, this will include
// the additional appended error message information of // the additional appended error message information of
// "got_problems handler: " ... // "got_problems handler: " ...
std::string error = secondwoof; sol::error err = secondwoof;
std::string what = err.what();
} }
This code is much more long-winded than its :doc:`function<function>` counterpart but allows a person to check for errors. The types here for ``auto`` are ``protected_function_result``. They are implicitly convertible to result types, like all :doc:`proxy-style<proxy>` types are. This code is much more long-winded than its :doc:`function<function>` counterpart but allows a person to check for errors. The type here for ``auto`` are ``sol::protected_function_result``. They are implicitly convertible to result types, like all :doc:`proxy-style<proxy>` types are.
Alternatively, with a bad or good function call, you can use ``sol::optional`` to check if the call succeeded or failed:
.. code-block:: cpp
:linenos:
sol::state lua;
lua.open_file( "pfunc_barks.lua" );
sol::protected_function problematicwoof = lua["woof"];
problematicwoof.error_handler = lua["got_problems"];
sol::optional<double> maybevalue = problematicwoof(19);
if (value) {
// Have a value, use it
double numwoof = maybevalue.value();
}
else {
// No value!
}
That makes the code a bit more concise and easy to reason about if you don't want to bother with reading the error. Thankfully, unlike ``sol::function_result``, you can save ``sol::protected_function_result`` in a variable and push/pop things above it on the stack where its returned values are. This makes it a bit more flexible than the rigid, performant ``sol::function_result`` type that comes from calling :doc:`sol::function<function>`. If you're confident the result succeeded, you can also just put the type you want (like ``double`` or ``std::string`` right there and it will get it. But, if it doesn't work out, sol can throw and/or panic if you have the :doc:`safety<../safety>` features turned on.
members members
------- -------

View File

@ -3,7 +3,7 @@
You can adapt this file completely to your liking, but it should at least You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive. contain the root `toctree` directive.
Sol 2.2 Sol 2.3
======= =======
a fast, simple C++ and Lua Binding a fast, simple C++ and Lua Binding
---------------------------------- ----------------------------------

84
sol/bond.hpp Normal file
View File

@ -0,0 +1,84 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_BOND_HPP
#define SOL_BOND_HPP
#include "traits.hpp"
namespace sol {
template <typename T>
struct bond_size : std::tuple_size<T> {};
template <typename T>
struct is_bondable : std::integral_constant<bool, (::sol::bond_size<T>::value > 0)> {};
template <typename... Tn>
struct bond_t : public std::tuple<std::add_lvalue_reference_t<Tn>...> {
private:
typedef std::tuple<std::add_lvalue_reference_t<Tn>...> base_t;
template <typename T>
void set( std::false_type, T&& target ) {
std::get<0>( *this ) = std::forward<T>( target );
}
template <typename T>
void set( std::true_type, T&& target ) {
typedef bond_size<meta::Unqualified<T>> value_size;
typedef bond_size<std::tuple<Tn...>> tie_size;
typedef std::conditional_t<(value_size::value < tie_size::value), value_size, tie_size> indices_size;
typedef std::make_index_sequence<indices_size::value> indices;
set( indices(), std::forward<T>( target ) );
}
template <std::size_t... I, typename T>
void set( std::index_sequence<I...>, T&& target ) {
using std::get;
(void)detail::swallow{ 0,
( get<I>(*this) = get<I>(target), 0 )...
, 0 };
}
public:
using base_t::base_t;
template <typename T>
bond_t& operator= ( T&& value ) {
typedef is_bondable<meta::Unqualified<T>> bondable;
set( bondable(), std::forward<T>( value ) );
return *this;
}
};
template <typename... Tn>
struct bond_size<::sol::bond_t<Tn...>> : ::std::tuple_size<::std::tuple<Tn...>> { };
template <typename... Tn>
inline bond_t<std::remove_reference_t<Tn>...> bond( Tn&&... argn ) {
return bond_t<std::remove_reference_t<Tn>...>( std::forward<Tn>( argn )... );
}
} // sol
#endif // SOL_BOND_HPP

View File

@ -26,9 +26,14 @@
#include <string> #include <string>
namespace sol { namespace sol {
namespace detail {
struct direct_error_tag {};
const auto direct_error = direct_error_tag{};
} // detail
class error : public std::runtime_error { class error : public std::runtime_error {
public: public:
error(const std::string& str): std::runtime_error("lua: error: " + str) {} error(const std::string& str): std::runtime_error("lua: error: " + str) {}
error(detail::direct_error_tag, const std::string& str) : std::runtime_error(str) {}
}; };
} // sol } // sol

View File

@ -25,6 +25,7 @@
#include "reference.hpp" #include "reference.hpp"
#include "tuple.hpp" #include "tuple.hpp"
#include "stack.hpp" #include "stack.hpp"
#include "stack_proxy.hpp"
#include "proxy_base.hpp" #include "proxy_base.hpp"
namespace sol { namespace sol {
@ -67,10 +68,21 @@ public:
return stack::get<T>(L, index); return stack::get<T>(L, index);
} }
lua_State* lua_state() const { return L; };
int stack_index() const { return index; };
~function_result() { ~function_result() {
lua_pop(L, returncount); lua_pop(L, returncount);
} }
}; };
template <>
struct bond_size<function_result> : std::integral_constant<std::size_t, std::numeric_limits<std::size_t>::max()> {};
template <std::size_t I>
stack_proxy get(const function_result& fr) {
return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
}
} // sol } // sol
#endif // SOL_FUNCTION_RESULT_HPP #endif // SOL_FUNCTION_RESULT_HPP

View File

@ -104,7 +104,7 @@ private:
#endif // No Exceptions #endif // No Exceptions
code = static_cast<call_status>(luacall(n, LUA_MULTRET, h)); code = static_cast<call_status>(luacall(n, LUA_MULTRET, h));
int poststacksize = lua_gettop(lua_state()); int poststacksize = lua_gettop(lua_state());
returncount = poststacksize - firstreturn; returncount = poststacksize - (stacksize - 1);
#ifndef SOL_NO_EXCEPTIONS #ifndef SOL_NO_EXCEPTIONS
} }
// Handle C++ errors thrown from C++ functions bound inside of lua // Handle C++ errors thrown from C++ functions bound inside of lua
@ -124,7 +124,7 @@ private:
return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime); return protected_function_result(lua_state(), firstreturn, 0, 1, call_status::runtime);
} }
#endif // No Exceptions #endif // No Exceptions
return protected_function_result(lua_state(), firstreturn + ( handlerpushed ? 0 : 1 ), returncount, returncount, code); return protected_function_result(lua_state(), firstreturn, returncount, returncount, code);
} }
public: public:

View File

@ -26,6 +26,7 @@
#include "tuple.hpp" #include "tuple.hpp"
#include "stack.hpp" #include "stack.hpp"
#include "proxy_base.hpp" #include "proxy_base.hpp"
#include "stack_proxy.hpp"
namespace sol { namespace sol {
struct protected_function_result : public proxy_base<protected_function_result> { struct protected_function_result : public proxy_base<protected_function_result> {
@ -36,6 +37,40 @@ private:
int popcount; int popcount;
call_status err; call_status err;
template <typename T>
decltype(auto) tagged_get( types<sol::optional<T>> ) const {
if (!valid()) {
return sol::optional<T>(nullopt);
}
return stack::get<sol::optional<T>>(L, index);
}
template <typename T>
decltype(auto) tagged_get( types<T> ) const {
#ifdef SOL_CHECK_ARGUMENTS
if (!valid()) {
type_panic(L, index, type_of(L, index), type::none);
}
#endif // Check Argument Safety
return stack::get<T>(L, index);
}
sol::optional<sol::error> tagged_get( types<sol::optional<sol::error>> ) const {
if (valid()) {
return nullopt;
}
return sol::error(detail::direct_error, stack::get<std::string>(L, index));
}
sol::error tagged_get( types<sol::error> ) const {
#ifdef SOL_CHECK_ARGUMENTS
if (valid()) {
type_panic(L, index, type_of(L, index), type::none);
}
#endif // Check Argument Safety
return sol::error(detail::direct_error, stack::get<std::string>(L, index));
}
public: public:
protected_function_result() = default; protected_function_result() = default;
protected_function_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, call_status error = call_status::ok): L(L), index(index), returncount(returncount), popcount(popcount), err(error) { protected_function_result(lua_State* L, int index = -1, int returncount = 0, int popcount = 0, call_status error = call_status::ok): L(L), index(index), returncount(returncount), popcount(popcount), err(error) {
@ -75,40 +110,29 @@ public:
} }
bool valid() const { bool valid() const {
return error() == call_status::ok; return error() == call_status::ok || error() == call_status::yielded;
} }
template<typename T> template<typename T>
T get() const { T get() const {
return stack::get<T>(L, index); return tagged_get(types<meta::Unqualified<T>>());
} }
lua_State* lua_state() const { return L; };
int stack_index() const { return index; };
~protected_function_result() { ~protected_function_result() {
stack::remove(L, index, popcount); stack::remove(L, index, popcount);
} }
}; };
struct protected_result { template <>
private: struct bond_size<protected_function_result> : std::integral_constant<std::size_t, std::numeric_limits<std::size_t>::max()> {};
protected_function_result result;
public: template <std::size_t I>
template <typename... Args> stack_proxy get(const protected_function_result& fr) {
protected_result( Args&&... args ) : result(std::forward<Args>(args)...) { return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
} }
bool valid() const {
return result.valid();
}
explicit operator bool () const {
return valid();
}
protected_function_result& operator* () {
return result;
}
};
} // sol } // sol
#endif // SOL_FUNCTION_RESULT_HPP #endif // SOL_FUNCTION_RESULT_HPP

View File

@ -36,12 +36,12 @@ private:
template<typename T, std::size_t... I> template<typename T, std::size_t... I>
decltype(auto) tuple_get(std::index_sequence<I...>) const { decltype(auto) tuple_get(std::index_sequence<I...>) const {
return tbl.template traverse_get<T>( std::get<I>(key)... ); return tbl.template traverse_get<T>(std::get<I>(key)...);
} }
template<std::size_t... I, typename T> template<std::size_t... I, typename T>
void tuple_set(std::index_sequence<I...>, T&& value) const { void tuple_set(std::index_sequence<I...>, T&& value) const {
tbl.traverse_set( std::get<I>(key)..., std::forward<T>(value) ); tbl.traverse_set(std::get<I>(key)..., std::forward<T>(value));
} }
public: public:
@ -146,8 +146,7 @@ template <typename Table, typename Key>
struct pusher<proxy<Table, Key>> { struct pusher<proxy<Table, Key>> {
static int push (lua_State*, const proxy<Table, Key>& p) { static int push (lua_State*, const proxy<Table, Key>& p) {
sol::reference r = p; sol::reference r = p;
r.push(); return r.push();
return 1;
} }
}; };
} // stack } // stack

View File

@ -34,19 +34,13 @@ struct proxy_base {
return super.template get<std::string>(); return super.template get<std::string>();
} }
template <typename... Args> template<typename T, meta::EnableIf<meta::Not<meta::is_string_constructible<T>>, is_proxy_primitive<meta::Unqualified<T>>> = 0>
operator std::tuple<Args...>() const {
const Super& super = *static_cast<const Super*>(static_cast<const void*>(this));
return detail::forward_tuple(super.template get<std::tuple<Args...>>());
}
template<typename T, meta::EnableIf<meta::Not<meta::is_specialization_of<meta::Unqualified<T>, std::tuple>>, meta::Not<meta::is_string_constructible<T>>, is_proxy_primitive<meta::Unqualified<T>>> = 0>
operator T ( ) const { operator T ( ) const {
const Super& super = *static_cast<const Super*>(static_cast<const void*>(this)); const Super& super = *static_cast<const Super*>(static_cast<const void*>(this));
return super.template get<T>( ); return super.template get<T>( );
} }
template<typename T, meta::EnableIf<meta::Not<meta::is_specialization_of<meta::Unqualified<T>, std::tuple>>, meta::Not<meta::is_string_constructible<T>>, meta::Not<is_proxy_primitive<meta::Unqualified<T>>>> = 0> template<typename T, meta::EnableIf<meta::Not<meta::is_string_constructible<T>>, meta::Not<is_proxy_primitive<meta::Unqualified<T>>>> = 0>
operator T& ( ) const { operator T& ( ) const {
const Super& super = *static_cast<const Super*>(static_cast<const void*>(this)); const Super& super = *static_cast<const Super*>(static_cast<const void*>(this));
return super.template get<T&>( ); return super.template get<T&>( );

View File

@ -23,6 +23,8 @@
#define SOL_STACK_HPP #define SOL_STACK_HPP
#include "stack_core.hpp" #include "stack_core.hpp"
#include "stack_reference.hpp"
#include "stack_proxy.hpp"
#include "stack_check.hpp" #include "stack_check.hpp"
#include "stack_get.hpp" #include "stack_get.hpp"
#include "stack_check_get.hpp" #include "stack_check_get.hpp"

View File

@ -24,9 +24,11 @@
#include "types.hpp" #include "types.hpp"
#include "reference.hpp" #include "reference.hpp"
#include "stack_reference.hpp"
#include "userdata.hpp" #include "userdata.hpp"
#include "tuple.hpp" #include "tuple.hpp"
#include "traits.hpp" #include "traits.hpp"
#include "bond.hpp"
namespace sol { namespace sol {
namespace detail { namespace detail {

View File

@ -69,6 +69,13 @@ struct getter<T, std::enable_if_t<std::is_base_of<reference, T>::value>> {
} }
}; };
template<>
struct getter<stack_reference> {
static stack_reference get(lua_State* L, int index = -1) {
return stack_reference(L, index);
}
};
template<> template<>
struct getter<userdata_value> { struct getter<userdata_value> {
static userdata_value get(lua_State* L, int index = -1) { static userdata_value get(lua_State* L, int index = -1) {

47
sol/stack_proxy.hpp Normal file
View File

@ -0,0 +1,47 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_STACK_PROXY_HPP
#define SOL_STACK_PROXY_HPP
#include "stack.hpp"
#include "proxy_base.hpp"
namespace sol {
struct stack_proxy : public proxy_base<stack_proxy> {
private:
lua_State* L;
int index;
public:
stack_proxy(lua_State* L, int index) : L(L), index(index) {}
template<typename T>
decltype(auto) get() const {
return stack::get<T>(L, stack_index());
}
lua_State* lua_state() const { return L; }
int stack_index() const { return index; }
};
} // sol
#endif // SOL_STACK_PROXY_HPP

View File

@ -177,6 +177,13 @@ struct pusher<T, std::enable_if_t<std::is_base_of<reference, T>::value>> {
} }
}; };
template<>
struct pusher<stack_reference> {
static int push(lua_State*, const stack_reference& ref) {
return ref.push();
}
};
template<> template<>
struct pusher<bool> { struct pusher<bool> {
static int push(lua_State* L, bool b) { static int push(lua_State* L, bool b) {

59
sol/stack_reference.hpp Normal file
View File

@ -0,0 +1,59 @@
// The MIT License (MIT)
// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#ifndef SOL_STACK_REFERENCE_HPP
#define SOL_STACK_REFERENCE_HPP
#include "reference.hpp"
namespace sol {
class stack_reference {
private:
lua_State* L = nullptr;
int index = 0;
protected:
public:
stack_reference() noexcept = default;
stack_reference(lua_State* L, int i) noexcept : L(L), index(lua_absindex(L, i)) {}
stack_reference(stack_reference&& o) noexcept = default;
stack_reference& operator=(stack_reference&&) noexcept = default;
stack_reference(const stack_reference&) noexcept = default;
stack_reference& operator=(const stack_reference&) noexcept = default;
int push() const noexcept {
lua_pushvalue(L, index);
return 1;
}
type get_type() const noexcept {
int result = lua_type(L, index);
return static_cast<type>(result);
}
lua_State* lua_state() const noexcept {
return L;
}
};
} // sol
#endif // SOL_STACK_REFERENCE_HPP

View File

@ -163,7 +163,10 @@ enum class type : int {
}; };
inline int type_panic(lua_State* L, int index, type expected, type actual) { inline int type_panic(lua_State* L, int index, type expected, type actual) {
return luaL_error(L, "stack index %d, expected %s, received %s", index, lua_typename(L, static_cast<int>(expected)), lua_typename(L, static_cast<int>(actual))); return luaL_error(L, "stack index %d, expected %s, received %s", index,
expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(expected)),
expected == type::poly ? "anything" : lua_typename(L, static_cast<int>(actual))
);
} }
// 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
@ -197,6 +200,7 @@ inline std::string type_name(lua_State*L, type t) {
} }
class reference; class reference;
class stack_reference;
template<typename T> template<typename T>
class usertype; class usertype;
template <bool> template <bool>
@ -229,6 +233,9 @@ struct lua_type_of<bool> : std::integral_constant<type, type::boolean> {};
template <> template <>
struct lua_type_of<nil_t> : std::integral_constant<type, type::nil> { }; struct lua_type_of<nil_t> : std::integral_constant<type, type::nil> { };
template <>
struct lua_type_of<sol::error> : std::integral_constant<type, type::string> { };
template <> template <>
struct lua_type_of<table> : std::integral_constant<type, type::table> { }; struct lua_type_of<table> : std::integral_constant<type, type::table> { };
@ -238,6 +245,9 @@ struct lua_type_of<global_table> : std::integral_constant<type, type::table> { }
template <> template <>
struct lua_type_of<reference> : std::integral_constant<type, type::poly> {}; struct lua_type_of<reference> : std::integral_constant<type, type::poly> {};
template <>
struct lua_type_of<stack_reference> : std::integral_constant<type, type::poly> {};
template <> template <>
struct lua_type_of<object> : std::integral_constant<type, type::poly> {}; struct lua_type_of<object> : std::integral_constant<type, type::poly> {};
@ -292,7 +302,10 @@ struct lua_type_of<T, std::enable_if_t<std::is_enum<T>::value>> : std::integral_
template <typename T> template <typename T>
struct is_lua_primitive : std::integral_constant<bool, struct is_lua_primitive : std::integral_constant<bool,
type::userdata != lua_type_of<meta::Unqualified<T>>::value type::userdata != lua_type_of<meta::Unqualified<T>>::value
|| std::is_base_of<reference, meta::Unqualified<T>>::value> { }; || std::is_base_of<reference, meta::Unqualified<T>>::value
|| meta::is_specialization_of<meta::Unqualified<T>, std::tuple>::value
|| meta::is_specialization_of<meta::Unqualified<T>, std::pair>::value
> { };
template <typename T> template <typename T>
struct is_lua_primitive<T*> : std::true_type {}; struct is_lua_primitive<T*> : std::true_type {};
@ -312,12 +325,6 @@ struct is_proxy_primitive<std::reference_wrapper<T>> : std::true_type { };
template <typename T> template <typename T>
struct is_proxy_primitive<optional<T>> : std::true_type {}; struct is_proxy_primitive<optional<T>> : std::true_type {};
template <typename... Args>
struct is_proxy_primitive<std::tuple<Args...>> : std::true_type { };
template <typename A, typename B>
struct is_proxy_primitive<std::pair<A, B>> : std::true_type { };
template <typename T> template <typename T>
struct is_unique_usertype : std::false_type {}; struct is_unique_usertype : std::false_type {};

View File

@ -233,6 +233,7 @@ TEST_CASE( "functions/function_result-protected_function_result", "Function resu
lua.open_libraries( sol::lib::base, sol::lib::debug ); lua.open_libraries( sol::lib::base, sol::lib::debug );
static const char unhandlederrormessage[] = "true error message"; static const char unhandlederrormessage[] = "true error message";
static const char handlederrormessage[] = "doodle"; static const char handlederrormessage[] = "doodle";
static const std::string handlederrormessage_s = handlederrormessage;
// Some function; just using a lambda to be cheap // Some function; just using a lambda to be cheap
auto doomfx = []() { auto doomfx = []() {
@ -261,33 +262,79 @@ TEST_CASE( "functions/function_result-protected_function_result", "Function resu
auto nontrampolinefx = [](lua_State*) -> int { throw "x";}; auto nontrampolinefx = [](lua_State*) -> int { throw "x";};
lua_CFunction c_nontrampolinefx = nontrampolinefx; lua_CFunction c_nontrampolinefx = nontrampolinefx;
lua.set("nontrampoline", c_nontrampolinefx); lua.set("nontrampoline", c_nontrampolinefx);
lua.set_function("bark", []() -> int {return 100;});
sol::protected_function doom = lua[ "doom" ]; sol::protected_function doom = lua[ "doom" ];
sol::protected_function luadoom = lua["luadoom"]; sol::protected_function luadoom = lua["luadoom"];
sol::protected_function nontrampoline = lua["nontrampoline"]; sol::protected_function nontrampoline = lua["nontrampoline"];
sol::protected_function justfine = lua["bark"];
sol::protected_function justfinewithhandler = lua["bark"];
sol::function luahandler = lua["luahandler"]; sol::function luahandler = lua["luahandler"];
sol::function cpphandler = lua[ "cpphandler" ]; sol::function cpphandler = lua[ "cpphandler" ];
doom.error_handler = luahandler; doom.error_handler = luahandler;
luadoom.error_handler = cpphandler; luadoom.error_handler = cpphandler;
nontrampoline.error_handler = cpphandler; nontrampoline.error_handler = cpphandler;
justfinewithhandler.error_handler = luahandler;
bool present = true;
{ {
sol::protected_function_result result = doom(); sol::protected_function_result result = doom();
REQUIRE(!result.valid()); REQUIRE_FALSE(result.valid());
std::string errorstring = result; sol::optional<sol::error> operr = result;
REQUIRE(errorstring == handlederrormessage); sol::optional<int> opvalue = result;
present = (bool)operr;
REQUIRE(present);
present = (bool)opvalue;
REQUIRE_FALSE(present);
sol::error err = result;
REQUIRE(err.what() == handlederrormessage_s);
} }
{ {
sol::protected_function_result result = luadoom(); sol::protected_function_result result = luadoom();
REQUIRE(!result.valid()); REQUIRE_FALSE(result.valid());
std::string errorstring = result; sol::optional<sol::error> operr = result;
REQUIRE(errorstring == handlederrormessage); sol::optional<int> opvalue = result;
present = (bool)operr;
REQUIRE(present);
present = (bool)opvalue;
REQUIRE_FALSE(present);
sol::error err = result;
REQUIRE(err.what() == handlederrormessage_s);
} }
{ {
sol::protected_function_result result = nontrampoline(); sol::protected_function_result result = nontrampoline();
REQUIRE(!result.valid()); REQUIRE_FALSE(result.valid());
std::string errorstring = result; sol::optional<sol::error> operr = result;
REQUIRE(errorstring == handlederrormessage); sol::optional<int> opvalue = result;
present = (bool)operr;
REQUIRE(present);
present = (bool)opvalue;
REQUIRE_FALSE(present);
sol::error err = result;
REQUIRE(err.what() == handlederrormessage_s);
}
{
sol::protected_function_result result = justfine();
REQUIRE(result.valid());
sol::optional<sol::error> operr = result;
sol::optional<int> opvalue = result;
present = (bool)operr;
REQUIRE_FALSE(present);
present = (bool)opvalue;
REQUIRE(present);
int value = result;
REQUIRE(value == 100);
}
{
sol::protected_function_result result = justfinewithhandler();
REQUIRE(result.valid());
sol::optional<sol::error> operr = result;
sol::optional<int> opvalue = result;
present = (bool)operr;
REQUIRE_FALSE(present);
present = (bool)opvalue;
REQUIRE(present);
int value = result;
REQUIRE(value == 100);
} }
} }
@ -484,6 +531,36 @@ M1 = m()
REQUIRE( M0 == 0xC ); REQUIRE( M0 == 0xC );
REQUIRE( M1 == 256 ); REQUIRE( M1 == 256 );
sol::bond( ob, A, B, C, D, F, G0, G1, H, I, J0, J1, K0, K1, L0, L1, M0, M1 )
= lua.get<int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int>(
"ob", "A", "B", "C", "D", "F", "G0", "G1", "H", "I", "J0", "J1", "K0", "K1", "L0", "L1", "M0", "M1"
);
REQUIRE(ob == 0xA);
REQUIRE( A == 500 );
REQUIRE( B == 501 );
REQUIRE( C == 502 );
REQUIRE( D == 503 );
REQUIRE( F == 0xA );
REQUIRE( G0 == 4 );
REQUIRE( G1 == 0xA );
REQUIRE( H == 0xA );
REQUIRE( I == 20 );
REQUIRE( J0 == 0xC );
REQUIRE( J1 == 24 );
REQUIRE( K0 == 0xC );
REQUIRE( K1 == 1024 );
REQUIRE( L0 == 0xA );
REQUIRE( L1 == 678 );
REQUIRE( M0 == 0xC );
REQUIRE( M1 == 256 );
} }
TEST_CASE("simple/call-with-parameters", "Lua function is called with a few parameters from C++") { TEST_CASE("simple/call-with-parameters", "Lua function is called with a few parameters from C++") {
@ -626,3 +703,18 @@ TEST_CASE("advanced/call-referenced_obj", "A C++ object is passed by pointer/ref
REQUIRE(x == 9); REQUIRE(x == 9);
REQUIRE(y == 9); REQUIRE(y == 9);
} }
TEST_CASE("functions/bond", "make sure advanced syntax with 'bond' works") {
sol::state lua;
lua.script(R"(function f ()
return 1, 2, 3
end)");
sol::function f = lua["f"];
int a, b, c;
sol::bond(a, b, c) = f();
REQUIRE(a == 1);
REQUIRE(b == 2);
REQUIRE(c == 3);
}