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)
[![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.
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:
.. 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))
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
:linenos:
@ -45,7 +45,7 @@ The following C++ code will call this function from this file and retrieve the r
}
else{
// 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
@ -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
// the additional appended error message information of
// "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
-------

View File

@ -3,7 +3,7 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Sol 2.2
Sol 2.3
=======
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>
namespace sol {
namespace detail {
struct direct_error_tag {};
const auto direct_error = direct_error_tag{};
} // detail
class error : public std::runtime_error {
public:
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

View File

@ -25,6 +25,7 @@
#include "reference.hpp"
#include "tuple.hpp"
#include "stack.hpp"
#include "stack_proxy.hpp"
#include "proxy_base.hpp"
namespace sol {
@ -67,10 +68,21 @@ public:
return stack::get<T>(L, index);
}
lua_State* lua_state() const { return L; };
int stack_index() const { return index; };
~function_result() {
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
#endif // SOL_FUNCTION_RESULT_HPP

View File

@ -104,7 +104,7 @@ private:
#endif // No Exceptions
code = static_cast<call_status>(luacall(n, LUA_MULTRET, h));
int poststacksize = lua_gettop(lua_state());
returncount = poststacksize - firstreturn;
returncount = poststacksize - (stacksize - 1);
#ifndef SOL_NO_EXCEPTIONS
}
// 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);
}
#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:

View File

@ -26,6 +26,7 @@
#include "tuple.hpp"
#include "stack.hpp"
#include "proxy_base.hpp"
#include "stack_proxy.hpp"
namespace sol {
struct protected_function_result : public proxy_base<protected_function_result> {
@ -36,6 +37,40 @@ private:
int popcount;
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:
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) {
@ -75,40 +110,29 @@ public:
}
bool valid() const {
return error() == call_status::ok;
return error() == call_status::ok || error() == call_status::yielded;
}
template<typename T>
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() {
stack::remove(L, index, popcount);
}
};
struct protected_result {
private:
protected_function_result result;
template <>
struct bond_size<protected_function_result> : std::integral_constant<std::size_t, std::numeric_limits<std::size_t>::max()> {};
public:
template <typename... Args>
protected_result( Args&&... args ) : result(std::forward<Args>(args)...) {
}
bool valid() const {
return result.valid();
}
explicit operator bool () const {
return valid();
}
protected_function_result& operator* () {
return result;
}
};
template <std::size_t I>
stack_proxy get(const protected_function_result& fr) {
return stack_proxy(fr.lua_state(), static_cast<int>(fr.stack_index() + I));
}
} // sol
#endif // SOL_FUNCTION_RESULT_HPP

View File

@ -36,12 +36,12 @@ private:
template<typename T, std::size_t... I>
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>
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:
@ -146,8 +146,7 @@ template <typename Table, typename Key>
struct pusher<proxy<Table, Key>> {
static int push (lua_State*, const proxy<Table, Key>& p) {
sol::reference r = p;
r.push();
return 1;
return r.push();
}
};
} // stack

View File

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

View File

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

View File

@ -24,9 +24,11 @@
#include "types.hpp"
#include "reference.hpp"
#include "stack_reference.hpp"
#include "userdata.hpp"
#include "tuple.hpp"
#include "traits.hpp"
#include "bond.hpp"
namespace sol {
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<>
struct getter<userdata_value> {
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<>
struct pusher<bool> {
static int push(lua_State* L, bool b) {
@ -300,7 +307,7 @@ struct pusher<optional<O>> {
if (t == nullopt) {
return stack::push(L, nullopt);
}
return stack::push(L, t.value());
return stack::push(L, t.value());
}
};

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

@ -281,8 +281,8 @@ public:
template <typename Name, typename... Args>
table create_named_table(Name&& name, Args&&... args) {
table x = global.create_with(std::forward<Args>(args)...);
global.set(std::forward<Name>(name), x);
return x;
global.set(std::forward<Name>(name), x);
return x;
}
table create_table(int narr = 0, int nrec = 0) {

View File

@ -106,19 +106,19 @@ class table_core : public reference {
template <bool global, typename T, std::size_t I, typename Key>
decltype(auto) traverse_get_deep_optional( int& popcount, Key&& key ) const {
auto p = stack::probe_get_field<global>(lua_state(), std::forward<Key>(key), -1);
popcount += p.levels;
if (!p.success)
return T(nullopt);
return stack::get<T>( lua_state( ) );
auto p = stack::probe_get_field<global>(lua_state(), std::forward<Key>(key), -1);
popcount += p.levels;
if (!p.success)
return T(nullopt);
return stack::get<T>( lua_state( ) );
}
template <bool global, typename T, std::size_t I, typename Key, typename... Keys>
decltype(auto) traverse_get_deep_optional( int& popcount, Key&& key, Keys&&... keys ) const {
auto p = I > 0 ? stack::probe_get_field<global>(lua_state(), std::forward<Key>(key), - 1) : stack::probe_get_field<global>( lua_state( ), std::forward<Key>( key ) );
popcount += p.levels;
if (!p.success)
return T(nullopt);
popcount += p.levels;
if (!p.success)
return T(nullopt);
return traverse_get_deep_optional<false, T, I + 1>(popcount, std::forward<Keys>(keys)...);
}
@ -130,9 +130,9 @@ class table_core : public reference {
template <bool global, typename T, typename... Keys>
decltype(auto) traverse_get_optional( std::true_type, Keys&&... keys ) const {
int popcount = 0;
detail::ref_clean c(lua_state(), popcount);
return traverse_get_deep_optional<top_level, T, 0>(popcount, std::forward<Keys>(keys)...);
int popcount = 0;
detail::ref_clean c(lua_state(), popcount);
return traverse_get_deep_optional<top_level, T, 0>(popcount, std::forward<Keys>(keys)...);
}
template <bool global, typename Key, typename Value>
@ -174,8 +174,8 @@ public:
template<typename... Ret, typename... Keys>
decltype(auto) get( Keys&&... keys ) const {
static_assert(sizeof...(Keys) == sizeof...(Ret), "number of keys and number of return types do not match");
auto pp = stack::push_pop<is_global<Keys...>::value>(*this);
return tuple_get( types<Ret...>( ), std::make_index_sequence<sizeof...(Ret)>( ), std::forward_as_tuple(std::forward<Keys>(keys)...));
auto pp = stack::push_pop<is_global<Keys...>::value>(*this);
return tuple_get( types<Ret...>( ), std::make_index_sequence<sizeof...(Ret)>( ), std::forward_as_tuple(std::forward<Keys>(keys)...));
}
template<typename T, typename Key>

View File

@ -58,10 +58,10 @@ public:
tableidx = lua_gettop(ref.lua_state());
stack::push(ref.lua_state(), nil);
this->operator++();
if (idx == -1) {
return;
}
--idx;
if (idx == -1) {
return;
}
--idx;
}
table_iterator& operator++() {

View File

@ -163,7 +163,10 @@ enum class type : int {
};
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
@ -197,6 +200,7 @@ inline std::string type_name(lua_State*L, type t) {
}
class reference;
class stack_reference;
template<typename T>
class usertype;
template <bool>
@ -229,6 +233,9 @@ struct lua_type_of<bool> : std::integral_constant<type, type::boolean> {};
template <>
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 <>
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 <>
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 <>
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>
struct is_lua_primitive : std::integral_constant<bool,
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>
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>
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>
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 );
static const char unhandlederrormessage[] = "true error message";
static const char handlederrormessage[] = "doodle";
static const std::string handlederrormessage_s = handlederrormessage;
// Some function; just using a lambda to be cheap
auto doomfx = []() {
@ -261,33 +262,79 @@ TEST_CASE( "functions/function_result-protected_function_result", "Function resu
auto nontrampolinefx = [](lua_State*) -> int { throw "x";};
lua_CFunction c_nontrampolinefx = nontrampolinefx;
lua.set("nontrampoline", c_nontrampolinefx);
lua.set_function("bark", []() -> int {return 100;});
sol::protected_function doom = lua[ "doom" ];
sol::protected_function luadoom = lua["luadoom"];
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 cpphandler = lua[ "cpphandler" ];
doom.error_handler = luahandler;
luadoom.error_handler = cpphandler;
nontrampoline.error_handler = cpphandler;
justfinewithhandler.error_handler = luahandler;
bool present = true;
{
sol::protected_function_result result = doom();
REQUIRE(!result.valid());
std::string errorstring = result;
REQUIRE(errorstring == handlederrormessage);
REQUIRE_FALSE(result.valid());
sol::optional<sol::error> operr = result;
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();
REQUIRE(!result.valid());
std::string errorstring = result;
REQUIRE(errorstring == handlederrormessage);
REQUIRE_FALSE(result.valid());
sol::optional<sol::error> operr = result;
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();
REQUIRE(!result.valid());
std::string errorstring = result;
REQUIRE(errorstring == handlederrormessage);
REQUIRE_FALSE(result.valid());
sol::optional<sol::error> operr = result;
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( 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++") {
@ -626,3 +703,18 @@ TEST_CASE("advanced/call-referenced_obj", "A C++ object is passed by pointer/ref
REQUIRE(x == 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);
}