mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
NOW we're truly feature complete. Sheesh, the work that this requires....
This commit is contained in:
parent
2d14cedc17
commit
8862c65f0a
|
@ -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)
|
||||
|
|
|
@ -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::
|
||||
|
|
|
@ -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
|
||||
-------
|
||||
|
|
|
@ -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
84
sol/bond.hpp
Normal 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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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&>( );
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
47
sol/stack_proxy.hpp
Normal 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
|
|
@ -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
59
sol/stack_reference.hpp
Normal 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
|
|
@ -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) {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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++() {
|
||||
|
|
|
@ -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 {};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user