forked from ThePhD/sol2
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathusertype_dynamic_get_set.cpp
More file actions
178 lines (158 loc) · 4.38 KB
/
usertype_dynamic_get_set.cpp
File metadata and controls
178 lines (158 loc) · 4.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>
#include <iostream>
#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 get(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 set(sol::stack_object key, sol::stack_object value,
sol::this_state) {
// 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 get/set ==="
<< 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::get,
sol::meta_function::new_index,
&vec::set);
lua.script(R"(
v1 = vec.new(1, 0)
v2 = vec.new(0, 1)
-- observe usage of get/set
print("v1:", v1.x, v1.y)
print("v2:", v2.x, v2.y)
-- gets 0, 1 by doing lookup into get 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 get
-- 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 get/set methods:
sol::userdata v1 = lua["v1"];
double v1x = v1["x"];
double v1y = v1["y"];
sol_c_assert(v1x == 1.000);
sol_c_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;
}