mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
New base object customization point management example, derived directly form @NullCascade. Thanks!
This commit is contained in:
parent
c77b5b432e
commit
5301bc1d4c
176
examples/source/customization_base_object_catch.cpp
Normal file
176
examples/source/customization_base_object_catch.cpp
Normal file
|
@ -0,0 +1,176 @@
|
|||
#define SOL_ALL_SAFETIES_ON 1
|
||||
#include <sol/sol.hpp>
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
|
||||
// We capture the base objects
|
||||
// lifetime style
|
||||
// You can add more here,
|
||||
// e.g. "Unique" for a unique pointer kind of lifestyle,
|
||||
// but you would need to think about how to handle
|
||||
// copying / moving in that case
|
||||
enum class BaseObjectLifetime { Value, Pointer, Shared };
|
||||
|
||||
// The base object
|
||||
// that we do inheritance and other work
|
||||
// on
|
||||
class BaseObject {
|
||||
public:
|
||||
BaseObject() {
|
||||
objectType = 0;
|
||||
}
|
||||
|
||||
unsigned int getObjectType() const {
|
||||
return objectType;
|
||||
}
|
||||
|
||||
bool doArmorThing() const {
|
||||
return false;
|
||||
}
|
||||
bool doWeaponThing() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
// helper function defined later after we define all the
|
||||
// base classes we care about
|
||||
sol::object getAsRetyped(lua_State* L, BaseObjectLifetime Lifetime) const;
|
||||
|
||||
// For convenience with the customization points below
|
||||
int pushAsRetyped(lua_State* L, BaseObjectLifetime Lifetime) const {
|
||||
return getAsRetyped(L, Lifetime).push(L);
|
||||
}
|
||||
|
||||
protected:
|
||||
unsigned int objectType;
|
||||
};
|
||||
|
||||
class Armor : public BaseObject {
|
||||
public:
|
||||
Armor() {
|
||||
objectType = 1;
|
||||
}
|
||||
|
||||
bool doArmorThing() const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class Weapon : public BaseObject {
|
||||
public:
|
||||
Weapon() {
|
||||
objectType = 2;
|
||||
}
|
||||
|
||||
bool doWeaponThing() const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Get the most-derived type
|
||||
// that we care about from the base object,
|
||||
// obeying the lifetime type
|
||||
sol::object BaseObject::getAsRetyped(lua_State* L, BaseObjectLifetime Lifetime) const {
|
||||
switch (objectType) {
|
||||
case 1:
|
||||
std::cout << "Retyping as armor." << std::endl;
|
||||
switch (Lifetime) {
|
||||
case BaseObjectLifetime::Value:
|
||||
return sol::make_object(L, *static_cast<const Armor*>(this));
|
||||
case BaseObjectLifetime::Pointer:
|
||||
return sol::make_object(L, static_cast<const Armor*>(this));
|
||||
case BaseObjectLifetime::Shared:
|
||||
return sol::make_object(L, std::make_shared<Armor>(*static_cast<const Armor*>(this)));
|
||||
}
|
||||
case 2:
|
||||
std::cout << "Retyping as weapon." << std::endl;
|
||||
switch (Lifetime) {
|
||||
case BaseObjectLifetime::Value:
|
||||
return sol::make_object(L, *static_cast<const Weapon*>(this));
|
||||
case BaseObjectLifetime::Pointer:
|
||||
return sol::make_object(L, static_cast<const Weapon*>(this));
|
||||
case BaseObjectLifetime::Shared:
|
||||
return sol::make_object(L, std::make_shared<Weapon>(*static_cast<const Weapon*>(this)));
|
||||
}
|
||||
default:
|
||||
// we have a normal type here, so that means we
|
||||
// must bypass customization points
|
||||
std::cout << "Unknown type: falling back to base object." << std::endl;
|
||||
switch (Lifetime) {
|
||||
case BaseObjectLifetime::Value:
|
||||
return sol::make_object_userdata(L, *this);
|
||||
case BaseObjectLifetime::Shared:
|
||||
return sol::make_object_userdata(L, std::make_shared<BaseObject>(*this));
|
||||
case BaseObjectLifetime::Pointer:
|
||||
default:
|
||||
return sol::make_object_userdata(L, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// sol customization points
|
||||
//
|
||||
|
||||
// Defining a customization point that lets us put the correct object type on the stack.
|
||||
int sol_lua_push(sol::types<BaseObject>, lua_State* L, const BaseObject& obj) {
|
||||
return obj.pushAsRetyped(L, BaseObjectLifetime::Value);
|
||||
}
|
||||
int sol_lua_push(sol::types<BaseObject*>, lua_State* L, const BaseObject* obj) {
|
||||
return obj->pushAsRetyped(L, BaseObjectLifetime::Pointer);
|
||||
}
|
||||
int sol_lua_push(sol::types<std::shared_ptr<BaseObject>>, lua_State* L, const std::shared_ptr<BaseObject>& obj) {
|
||||
return obj->pushAsRetyped(L, BaseObjectLifetime::Shared);
|
||||
}
|
||||
|
||||
int main() {
|
||||
// test our customization points out
|
||||
std::cout << "=== Base object customization points ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base, sol::lib::string, sol::lib::table);
|
||||
|
||||
lua["objectCache"] = lua.create_table();
|
||||
|
||||
// Do basic type binding.
|
||||
auto luaBaseObject = lua.new_usertype<BaseObject>("tes3baseObject");
|
||||
luaBaseObject["objectType"] = sol::readonly_property(&BaseObject::getObjectType);
|
||||
luaBaseObject["doArmorThing"] = &BaseObject::doArmorThing;
|
||||
luaBaseObject["doWeaponThing"] = &BaseObject::doWeaponThing;
|
||||
auto luaArmorObject = lua.new_usertype<Armor>("tes3armor");
|
||||
luaArmorObject[sol::base_classes] = sol::bases<BaseObject>();
|
||||
luaArmorObject["doArmorThing"] = &Armor::doArmorThing;
|
||||
auto luaWeaponObject = lua.new_usertype<Weapon>("tes3weapon");
|
||||
luaWeaponObject[sol::base_classes] = sol::bases<BaseObject>();
|
||||
luaWeaponObject["doWeaponThing"] = &Weapon::doWeaponThing;
|
||||
|
||||
// Objects we'll play with.
|
||||
BaseObject base;
|
||||
Armor armor;
|
||||
Weapon weapon;
|
||||
|
||||
// Push some objects to lua.
|
||||
std::cout << "Normal pointers..." << std::endl;
|
||||
lua["ptrBase"] = &base;
|
||||
lua["ptrArmor"] = &armor;
|
||||
lua["ptrWeapon"] = &weapon;
|
||||
std::cout << std::endl;
|
||||
|
||||
// Same objects but as base objects to test mapping.
|
||||
std::cout << "Base-cast pointers..." << std::endl;
|
||||
lua["ptrArmorAsBase"] = static_cast<BaseObject*>(&armor);
|
||||
lua["ptrWeaponAsBase"] = static_cast<BaseObject*>(&weapon);
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << "Smart direct pointers..." << std::endl;
|
||||
lua["sharedBase"] = std::make_shared<BaseObject>();
|
||||
lua["sharedArmor"] = std::make_shared<Armor>();
|
||||
lua["sharedArmor"] = std::make_shared<Weapon>();
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << "Smart pointers put as the base class..." << std::endl;
|
||||
lua["sharedArmorAsBase"] = (std::shared_ptr<BaseObject>)std::make_shared<Armor>();
|
||||
lua["sharedArmorAsBase"] = (std::shared_ptr<BaseObject>)std::make_shared<Weapon>();
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -49,6 +49,26 @@ namespace sol {
|
|||
return r;
|
||||
}
|
||||
|
||||
template <typename R = reference, bool should_pop = !is_stack_based_v<R>, typename T>
|
||||
R make_reference_userdata(lua_State* L, T&& value) {
|
||||
int backpedal = stack::push_userdata(L, std::forward<T>(value));
|
||||
R r = stack::get<R>(L, -backpedal);
|
||||
if (should_pop) {
|
||||
lua_pop(L, backpedal);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
template <typename T, typename R = reference, bool should_pop = !is_stack_based_v<R>, typename... Args>
|
||||
R make_reference_userdata(lua_State* L, Args&&... args) {
|
||||
int backpedal = stack::push_userdata<T>(L, std::forward<Args>(args)...);
|
||||
R r = stack::get<R>(L, -backpedal);
|
||||
if (should_pop) {
|
||||
lua_pop(L, backpedal);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
} // namespace sol
|
||||
|
||||
#endif // SOL_MAKE_REFERENCE_HPP
|
||||
|
|
|
@ -146,6 +146,16 @@ namespace sol {
|
|||
object make_object(lua_State* L, Args&&... args) {
|
||||
return make_reference<T, object, true>(L, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
object make_object_userdata(lua_State* L, T&& value) {
|
||||
return make_reference_userdata<object, true>(L, std::forward<T>(value));
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
object make_object_userdata(lua_State* L, Args&&... args) {
|
||||
return make_reference_userdata<T, object, true>(L, std::forward<Args>(args)...);
|
||||
}
|
||||
} // namespace sol
|
||||
|
||||
#endif // SOL_OBJECT_HPP
|
||||
|
|
|
@ -55,6 +55,8 @@ namespace sol {
|
|||
template <typename T>
|
||||
struct as_value_tag {};
|
||||
template <typename T>
|
||||
struct as_unique_tag {};
|
||||
template <typename T>
|
||||
struct as_table_tag {};
|
||||
|
||||
using lua_reg_table = luaL_Reg[64];
|
||||
|
@ -921,14 +923,26 @@ namespace sol {
|
|||
template <typename T, typename... Args>
|
||||
int push_userdata(lua_State* L, T&& t, Args&&... args) {
|
||||
using U = meta::unqualified_t<T>;
|
||||
using Tr = meta::conditional_t<std::is_pointer<U>::value, detail::as_pointer_tag<std::remove_pointer_t<U>>, detail::as_value_tag<U>>;
|
||||
using Tr = meta::conditional_t<std::is_pointer_v<U>,
|
||||
detail::as_pointer_tag<std::remove_pointer_t<U>>,
|
||||
meta::conditional_t<is_unique_usertype_v<U>,
|
||||
detail::as_unique_tag<U>,
|
||||
detail::as_value_tag<U>
|
||||
>
|
||||
>;
|
||||
return stack::push<Tr>(L, std::forward<T>(t), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T, typename Arg, typename... Args>
|
||||
int push_userdata(lua_State* L, Arg&& arg, Args&&... args) {
|
||||
using U = meta::unqualified_t<T>;
|
||||
using Tr = meta::conditional_t<std::is_pointer<U>::value, detail::as_pointer_tag<std::remove_pointer_t<U>>, detail::as_value_tag<U>>;
|
||||
using Tr = meta::conditional_t<std::is_pointer_v<U>,
|
||||
detail::as_pointer_tag<std::remove_pointer_t<U>>,
|
||||
meta::conditional_t<is_unique_usertype_v<U>,
|
||||
detail::as_unique_tag<U>,
|
||||
detail::as_value_tag<U>
|
||||
>
|
||||
>;
|
||||
return stack::push<Tr>(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
|
|
|
@ -189,6 +189,16 @@ namespace sol { namespace stack {
|
|||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct unqualified_pusher<detail::as_unique_tag<T>> {
|
||||
template <typename... Args>
|
||||
static int push (lua_State* L, Args&&... args) {
|
||||
stack_detail::uu_pusher<T> p;
|
||||
(void)p;
|
||||
return p.push(L, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
namespace stack_detail {
|
||||
template <typename T>
|
||||
struct uu_pusher {
|
||||
|
@ -293,9 +303,7 @@ namespace sol { namespace stack {
|
|||
return stack::push<detail::as_pointer_tag<std::remove_pointer_t<T>>>(L, std::forward<Args>(args)...);
|
||||
}
|
||||
else if constexpr (is_unique_usertype_v<Tu>) {
|
||||
stack_detail::uu_pusher<T> p;
|
||||
(void)p;
|
||||
return p.push(L, std::forward<Args>(args)...);
|
||||
return stack::push<detail::as_unique_tag<T>>(L, std::forward<Args>(args)...);
|
||||
}
|
||||
else {
|
||||
return stack::push<detail::as_value_tag<T>>(L, std::forward<Args>(args)...);
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// This file was generated with a script.
|
||||
// Generated 2020-01-17 10:21:31.165776 UTC
|
||||
// This header was generated with sol v3.2.0 (revision 1c89390)
|
||||
// Generated 2020-01-25 00:57:45.038692 UTC
|
||||
// This header was generated with sol v3.2.0 (revision c77b5b4)
|
||||
// https://github.com/ThePhD/sol2
|
||||
|
||||
#ifndef SOL_SINGLE_INCLUDE_FORWARD_HPP
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// This file was generated with a script.
|
||||
// Generated 2020-01-17 10:21:30.504542 UTC
|
||||
// This header was generated with sol v3.2.0 (revision 1c89390)
|
||||
// Generated 2020-01-25 00:57:44.490128 UTC
|
||||
// This header was generated with sol v3.2.0 (revision c77b5b4)
|
||||
// https://github.com/ThePhD/sol2
|
||||
|
||||
#ifndef SOL_SINGLE_INCLUDE_HPP
|
||||
|
@ -9499,6 +9499,8 @@ namespace sol {
|
|||
template <typename T>
|
||||
struct as_value_tag {};
|
||||
template <typename T>
|
||||
struct as_unique_tag {};
|
||||
template <typename T>
|
||||
struct as_table_tag {};
|
||||
|
||||
using lua_reg_table = luaL_Reg[64];
|
||||
|
@ -10364,14 +10366,26 @@ namespace sol {
|
|||
template <typename T, typename... Args>
|
||||
int push_userdata(lua_State* L, T&& t, Args&&... args) {
|
||||
using U = meta::unqualified_t<T>;
|
||||
using Tr = meta::conditional_t<std::is_pointer<U>::value, detail::as_pointer_tag<std::remove_pointer_t<U>>, detail::as_value_tag<U>>;
|
||||
using Tr = meta::conditional_t<std::is_pointer_v<U>,
|
||||
detail::as_pointer_tag<std::remove_pointer_t<U>>,
|
||||
meta::conditional_t<is_unique_usertype_v<U>,
|
||||
detail::as_unique_tag<U>,
|
||||
detail::as_value_tag<U>
|
||||
>
|
||||
>;
|
||||
return stack::push<Tr>(L, std::forward<T>(t), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T, typename Arg, typename... Args>
|
||||
int push_userdata(lua_State* L, Arg&& arg, Args&&... args) {
|
||||
using U = meta::unqualified_t<T>;
|
||||
using Tr = meta::conditional_t<std::is_pointer<U>::value, detail::as_pointer_tag<std::remove_pointer_t<U>>, detail::as_value_tag<U>>;
|
||||
using Tr = meta::conditional_t<std::is_pointer_v<U>,
|
||||
detail::as_pointer_tag<std::remove_pointer_t<U>>,
|
||||
meta::conditional_t<is_unique_usertype_v<U>,
|
||||
detail::as_unique_tag<U>,
|
||||
detail::as_value_tag<U>
|
||||
>
|
||||
>;
|
||||
return stack::push<Tr>(L, std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
|
@ -13262,6 +13276,16 @@ namespace sol { namespace stack {
|
|||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct unqualified_pusher<detail::as_unique_tag<T>> {
|
||||
template <typename... Args>
|
||||
static int push (lua_State* L, Args&&... args) {
|
||||
stack_detail::uu_pusher<T> p;
|
||||
(void)p;
|
||||
return p.push(L, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
namespace stack_detail {
|
||||
template <typename T>
|
||||
struct uu_pusher {
|
||||
|
@ -13366,9 +13390,7 @@ namespace sol { namespace stack {
|
|||
return stack::push<detail::as_pointer_tag<std::remove_pointer_t<T>>>(L, std::forward<Args>(args)...);
|
||||
}
|
||||
else if constexpr (is_unique_usertype_v<Tu>) {
|
||||
stack_detail::uu_pusher<T> p;
|
||||
(void)p;
|
||||
return p.push(L, std::forward<Args>(args)...);
|
||||
return stack::push<detail::as_unique_tag<T>>(L, std::forward<Args>(args)...);
|
||||
}
|
||||
else {
|
||||
return stack::push<detail::as_value_tag<T>>(L, std::forward<Args>(args)...);
|
||||
|
@ -14870,6 +14892,26 @@ namespace sol {
|
|||
return r;
|
||||
}
|
||||
|
||||
template <typename R = reference, bool should_pop = !is_stack_based_v<R>, typename T>
|
||||
R make_reference_userdata(lua_State* L, T&& value) {
|
||||
int backpedal = stack::push_userdata(L, std::forward<T>(value));
|
||||
R r = stack::get<R>(L, -backpedal);
|
||||
if (should_pop) {
|
||||
lua_pop(L, backpedal);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
template <typename T, typename R = reference, bool should_pop = !is_stack_based_v<R>, typename... Args>
|
||||
R make_reference_userdata(lua_State* L, Args&&... args) {
|
||||
int backpedal = stack::push_userdata<T>(L, std::forward<Args>(args)...);
|
||||
R r = stack::get<R>(L, -backpedal);
|
||||
if (should_pop) {
|
||||
lua_pop(L, backpedal);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
} // namespace sol
|
||||
|
||||
// end of sol/make_reference.hpp
|
||||
|
@ -15052,6 +15094,16 @@ namespace sol {
|
|||
object make_object(lua_State* L, Args&&... args) {
|
||||
return make_reference<T, object, true>(L, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
object make_object_userdata(lua_State* L, T&& value) {
|
||||
return make_reference_userdata<object, true>(L, std::forward<T>(value));
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
object make_object_userdata(lua_State* L, Args&&... args) {
|
||||
return make_reference_userdata<T, object, true>(L, std::forward<Args>(args)...);
|
||||
}
|
||||
} // namespace sol
|
||||
|
||||
// end of sol/object.hpp
|
||||
|
|
Loading…
Reference in New Issue
Block a user