add new examples

This commit is contained in:
ThePhD 2017-04-20 22:31:59 -04:00
parent c124d51353
commit 0db6d99d4b
3 changed files with 217 additions and 2 deletions

View File

@ -0,0 +1,51 @@
#define SOL_CHECK_ARGUMENTS
#include <sol.hpp>
#include <cassert>
int main() {
struct thing {
thing(sol::this_state ts) {
lua_State* L = ts;
// references the object that called this function
// in constructors:
sol::stack_object selfobj(L, -1);
// the -1 (NEGATIVE one) above
// means "off the top fo the stack"
// (-1 is the top, -2 is one below, etc...)
// definitely the same
thing& self = selfobj.as<thing>();
assert(&self == this);
}
void func(sol::this_state ts) const {
lua_State* L = ts;
// references the object that called this function
// in regular member functions:
sol::stack_object selfobj(L, 1);
// "1" is the bottom of the Lua stack
// 2 is one up, so on and so forth...
thing& self = selfobj.as<thing>();
// definitely the same
assert(&self == this);
}
};
sol::state lua;
lua.open_libraries(sol::lib::base);
lua.new_usertype<thing>("thing",
sol::constructors<thing(sol::this_state)>(),
"func", &thing::func
);
lua.script(R"(
obj = thing.new()
obj:func()
)");
return 0;
}

View File

@ -0,0 +1,165 @@
#define SOL_CHECK_ARGUMENTS
#include <sol.hpp>
#include <iostream>
#include <cassert>
#include <cmath>
// Note that this is a bunch of if/switch statements
// for the sake of brevity and clarity
// A much more robust implementation could use a std::unordered_map
// to link between keys and desired actions for those keys on
// setting/getting
// The sky becomes the limit when you have this much control,
// so apply it wisely!
struct vec {
double x;
double y;
vec() : x(0), y(0) {}
vec(double x) : vec(x, x) {}
vec(double x, double y) : x(x), y(y) {}
sol::object getter(sol::stack_object key, sol::this_state L) {
// we use stack_object for the arguments because we know
// the values from Lua will remain on Lua's stack,
// so long we we don't mess with it
auto maybe_string_key = key.as<sol::optional<std::string>>();
if (maybe_string_key) {
const std::string& k = *maybe_string_key;
if (k == "x") {
// Return x
return sol::object(L, sol::in_place, this->x);
}
else if (k == "y") {
// Return y
return sol::object(L, sol::in_place, this->y);
}
}
// String keys failed, check for numbers
auto maybe_numeric_key = key.as<sol::optional<int>>();
if (maybe_numeric_key) {
int n = *maybe_numeric_key;
switch (n) {
case 0:
return sol::object(L, sol::in_place, this->x);
case 1:
return sol::object(L, sol::in_place, this->y);
default:
break;
}
}
// No valid key: push nil
// Note that the example above is a bit unnecessary:
// binding the variables x and y to the usertype
// would work just as well and we would not
// need to look it up here,
// but this is to show it works regardless
return sol::object(L, sol::in_place, sol::lua_nil);
}
void setter(sol::stack_object key, sol::stack_object value, sol::this_state L) {
// we use stack_object for the arguments because we know
// the values from Lua will remain on Lua's stack,
// so long we we don't mess with it
auto maybe_string_key = key.as<sol::optional<std::string>>();
if (maybe_string_key) {
const std::string& k = *maybe_string_key;
if (k == "x") {
// set x
this->x = value.as<double>();
}
else if (k == "y") {
// set y
this->y = value.as<double>();
}
}
// String keys failed, check for numbers
auto maybe_numeric_key = key.as<sol::optional<int>>();
if (maybe_numeric_key) {
int n = *maybe_numeric_key;
switch (n) {
case 0:
this->x = value.as<double>();
break;
case 1:
this->y = value.as<double>();
break;
default:
break;
}
}
}
};
int main() {
std::cout << "=== usertype dynamic getter/setter example ===" << std::endl;
sol::state lua;
lua.open_libraries();
lua.new_usertype<vec>("vec",
sol::constructors<vec(), vec(double), vec(double, double)>(),
// index and newindex control what happens when a "key"
// is looked up that is not baked into the class itself
// it is called with the object and the key for index (get)s
// or it is called with the object, the key, and the index (set)
// we can use a member function to assume the "object" is of the `vec`
// type, and then just have a function that takes
// the key (get) or the key + the value (set)
sol::meta_function::index, &vec::getter,
sol::meta_function::new_index, &vec::setter
);
lua.script(R"(
v1 = vec.new(1, 0)
v2 = vec.new(0, 1)
-- observe usage of getter/setter
print("v1:", v1.x, v1.y)
print("v2:", v2.x, v2.y)
-- gets 0, 1 by doing lookup into getter function
print("changing v2...")
v2.x = 3
v2[1] = 5
-- can use [0] [1] like popular
-- C++-style math vector classes
print("v1:", v1.x, v1.y)
print("v2:", v2.x, v2.y)
-- both obj.name and obj["name"]
-- are equivalent lookup methods
-- and both will trigger the getter
-- if it can't find 'name' on the object
assert(v1["x"] == v1.x)
assert(v1[0] == v1.x)
assert(v1["x"] == v1[0])
assert(v1["y"] == v1.y)
assert(v1[1] == v1.y)
assert(v1["y"] == v1[1])
)");
// Can also be manipulated from C++,
// and will call getter/setter methods:
sol::userdata v1 = lua["v1"];
double v1x = v1["x"];
double v1y = v1["y"];
assert(v1x == 1.000);
assert(v1y == 0.000);
v1[0] = 2.000;
lua.script(R"(
assert(v1.x == 2.000)
assert(v1["x"] == 2.000)
assert(v1[0] == 2.000)
)");
std::cout << std::endl;
return 0;
}

View File

@ -1,7 +1,6 @@
#define SOL_CHECK_ARGUMENTS #define SOL_CHECK_ARGUMENTS
#include <sol.hpp> #include <sol.hpp>
#include <iostream>
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
@ -67,5 +66,5 @@ int main() {
assert(a1 == a2) assert(a1 == a2)
)"); )");
std::cout << std::endl; return 0;
} }