mirror of
https://github.com/ThePhD/sol2.git
synced 2024-03-22 13:10:44 +08:00
Add custom metatable and c_array example
This commit is contained in:
parent
2bd1cdccf0
commit
b447c3d69c
55
examples/c_array.cpp
Normal file
55
examples/c_array.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include "assert.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
struct something {
|
||||
int arr[4];
|
||||
|
||||
something() : arr{ 5, 6, 7, 8 } {}
|
||||
};
|
||||
|
||||
int main() {
|
||||
|
||||
std::cout << "=== c arrays (works with Visual C++ too) ===" << std::endl;
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
lua.new_usertype<something>("something",
|
||||
"arr", sol::property([](something& s) {
|
||||
return std::ref(s.arr);
|
||||
})
|
||||
);
|
||||
lua.script(R"(s = something.new()
|
||||
print(s.arr[3])
|
||||
s.arr[3] = 40
|
||||
print(s.arr[3])
|
||||
)");
|
||||
|
||||
something& s = lua["s"];
|
||||
c_assert(s.arr[0] == 5);
|
||||
c_assert(s.arr[1] == 6);
|
||||
c_assert(s.arr[2] == 40);
|
||||
c_assert(s.arr[3] == 8);
|
||||
|
||||
std::string string_array[] = {
|
||||
"first string",
|
||||
"second string",
|
||||
"third string",
|
||||
};
|
||||
lua["str_arr"] = std::ref(string_array);
|
||||
// or:
|
||||
// lua["str_array"] = &string_array;
|
||||
lua.script(R"(
|
||||
print(str_arr[3])
|
||||
str_arr[3] = str_arr[3] .. ': modified'
|
||||
print(str_arr[3])
|
||||
)");
|
||||
|
||||
c_assert(string_array[2] == "third string: modified");
|
||||
|
||||
return 0;
|
||||
}
|
151
examples/metatable_customization.cpp
Normal file
151
examples/metatable_customization.cpp
Normal file
@ -0,0 +1,151 @@
|
||||
#define SOL_CHECK_ARGUMENTS 1
|
||||
#include <sol.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
struct thing {
|
||||
int member_variable = 5;
|
||||
|
||||
double member_function() const {
|
||||
return member_variable / 2.0;
|
||||
}
|
||||
};
|
||||
|
||||
#define TEMPLATE_AUTO(x) decltype(x), x
|
||||
|
||||
// cheap storage: in reality, you'd need to find a
|
||||
// better way of handling this.
|
||||
// or not! It's up to you.
|
||||
static std::unordered_map<sol::string_view, sol::object> thing_function_associations;
|
||||
static std::unordered_map<sol::string_view, sol::object> thing_variable_associations;
|
||||
|
||||
void register_thing_type(sol::state& lua) {
|
||||
thing_variable_associations.emplace_hint(thing_variable_associations.cend(),
|
||||
"member_variable", sol::object(lua.lua_state(), sol::in_place, &sol::c_call<TEMPLATE_AUTO(&thing::member_variable)>)
|
||||
);
|
||||
thing_function_associations.emplace_hint(thing_function_associations.cend(),
|
||||
"member_function", sol::object(lua.lua_state(), sol::in_place, &sol::c_call<TEMPLATE_AUTO(&thing::member_function)>)
|
||||
);
|
||||
|
||||
struct call_handler {
|
||||
static int lookup_function(lua_State* L) {
|
||||
sol::stack_object source(L, 1);
|
||||
sol::stack_object key(L, 2);
|
||||
if (!source.is<thing>()) {
|
||||
return luaL_error(L, "given an incorrect object for this call");
|
||||
}
|
||||
sol::optional<sol::string_view> maybe_svkey = key.as<sol::string_view>();
|
||||
if (maybe_svkey) {
|
||||
{
|
||||
// functions are different from variables
|
||||
// functions, when obtain with the syntax
|
||||
// obj.f, obj.f(), and obj:f()
|
||||
// must return the function itself
|
||||
// so we just push it realy into our target
|
||||
auto it = thing_function_associations.find(*maybe_svkey);
|
||||
if (it != thing_function_associations.cend()) {
|
||||
return it->second.push(L);
|
||||
}
|
||||
}
|
||||
{
|
||||
// variables are different than funtions
|
||||
// when someone does `obj.a`, they expect
|
||||
// this __index call (this lookup function) to
|
||||
// return to them the value itself they're seeing
|
||||
// so we call out lua_CFunction that we serialized earlier
|
||||
auto it = thing_variable_associations.find(*maybe_svkey);
|
||||
if (it != thing_variable_associations.cend()) {
|
||||
// note that calls generated by sol2
|
||||
// for member variables expect the stack ordering to be
|
||||
// 2(, 3, ..., n) -- value(s)
|
||||
// 1 -- source
|
||||
// so we destroy the key on the stack
|
||||
sol::stack::remove(L, 2, 1);
|
||||
lua_CFunction cf = it->second.as<lua_CFunction>();
|
||||
return cf(L);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sol::stack::push(L, sol::lua_nil);
|
||||
}
|
||||
|
||||
static int insertion_function(lua_State* L) {
|
||||
sol::stack_object source(L, 1);
|
||||
sol::stack_object key(L, 2);
|
||||
sol::stack_object value(L, 3);
|
||||
if (!source.is<thing>()) {
|
||||
return luaL_error(L, "given an incorrect object for this call");
|
||||
}
|
||||
// write to member variables, etc. etc...
|
||||
sol::optional<sol::string_view> maybe_svkey = key.as<sol::string_view>();
|
||||
if (maybe_svkey) {
|
||||
{
|
||||
// variables are different than funtions
|
||||
// when someone does `obj.a`, they expect
|
||||
// this __index call (this lookup function) to
|
||||
// return to them the value itself they're seeing
|
||||
// so we call out lua_CFunction that we serialized earlier
|
||||
auto it = thing_variable_associations.find(*maybe_svkey);
|
||||
if (it != thing_variable_associations.cend()) {
|
||||
// note that calls generated by sol2
|
||||
// for member variables expect the stack ordering to be
|
||||
// 2(, 3, ..., n) -- value(s)
|
||||
// 1 -- source
|
||||
// so we remove the key value
|
||||
sol::stack::remove(L, 2, 1);
|
||||
lua_CFunction cf = it->second.as<lua_CFunction>();
|
||||
return cf(L);
|
||||
}
|
||||
else {
|
||||
// write to member variable, maybe override function
|
||||
// if your class allows for it?
|
||||
(void)value;
|
||||
}
|
||||
}
|
||||
// exercise for reader:
|
||||
// how do you override functions on the metatable with
|
||||
// proper syntax, but error when the type is
|
||||
// an "instance" object?
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
lua.new_usertype<thing>("thing");
|
||||
sol::table metatable = lua["thing"];
|
||||
|
||||
metatable[sol::meta_method::index] = &call_handler::lookup_function;
|
||||
metatable[sol::meta_method::new_index] = &call_handler::insertion_function;
|
||||
}
|
||||
|
||||
void unregister_thing_type(sol::state&) {
|
||||
thing_function_associations.clear();
|
||||
thing_variable_associations.clear();
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
std::cout << "=== metatable with custom-built (static) handling ===" << std::endl;
|
||||
|
||||
|
||||
sol::state lua;
|
||||
lua.open_libraries(sol::lib::base);
|
||||
|
||||
// register custom type + storage
|
||||
register_thing_type(lua);
|
||||
|
||||
lua.script(R"(t = thing.new()
|
||||
print(t.member_variable)
|
||||
print(t:member_function())
|
||||
t.member_variable = 24
|
||||
print(t.member_variable)
|
||||
print(t:member_function())
|
||||
)");
|
||||
|
||||
// clear storage
|
||||
unregister_thing_type(lua);
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user