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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
use core::ffi::CStr;
use crate::{LuaState, ffi};
/// Table related functions.
impl LuaState {
/// Returns `true` if the value at the given acceptable `index` is a table, `false` otherwise.
#[inline]
#[must_use]
pub fn is_table(&self, index: i32) -> bool {
// SAFETY: self.0 is always valid.
unsafe { ffi::lua_istable(self.0, index) != 0 }
}
/// Creates a new empty table and pushes it onto the stack.
///
/// To pre-allocate elements when creating a new table, see [`LuaState::create_table`].
#[inline]
pub fn new_table(&mut self) {
// SAFETY: self.0 is always valid.
unsafe { ffi::lua_newtable(self.0); }
}
/// Creates a new empty table and pushes it onto the stack.
///
/// The table will have `n_arr` array elements and `n_rec` non-array elements pre-allocated.
///
/// To create a new table without pre-allocating, see [`LuaState::new_table`].
///
/// # Lua Errors
///
/// Calling this function way too many times may trigger a stack overflow.
///
/// Incredibly high values for `n_arr` or `n_rec` may instantly trigger a table overflow.
#[inline]
pub fn create_table(&mut self, n_arr: i32, n_rec: i32) {
// SAFETY: self.0 is always valid.
unsafe { ffi::lua_createtable(self.0, n_arr, n_rec); }
}
/// Does the equivalent of the Lua code `t[key]`, where `t` is the value located at the given valid `index`.
///
/// The result is pushed onto the stack (even if `nil`).
///
/// For a function that does the same but allows any value instead of `key`, see [`LuaState::get_table`].
///
/// # Lua Errors
///
/// Not every value `t` can be indexed: for example, if `t` is `nil` this function will error.
///
/// Indexing `t` may also trigger the `__index` metamethod which could error.
#[inline]
pub fn get_field(&mut self, index: i32, key: &CStr) {
// SAFETY: self.0 is always valid and key's pointer is valid for the duration of this function.
unsafe { ffi::lua_getfield(self.0, index, key.as_ptr()); }
}
/// Does the equivalent of the Lua code `t[key] = v`, where `t` is the value located at the given valid `index`
/// and `v` is the value at the top of the stack (which is popped).
///
/// For a function that does the same but allows any value instead of `key`, see [`LuaState::set_table`].
///
/// # Panics
///
/// Panics if the stack is empty.
///
/// # Lua Errors
///
/// Not every value `t` can be indexed: for example, if `t` is `nil` this function will error.
///
/// Indexing `t` may also trigger the `__newindex` metamethod which could error.
#[inline]
pub fn set_field(&mut self, index: i32, key: &CStr) {
assert!(self.get_top() > 0, "tried to set field {key:?} for the table at index {index} despite having an empty stack");
// SAFETY: self.0 is always valid, key's pointer is valid for the duration of this function, and the stack is not empty.
unsafe { ffi::lua_setfield(self.0, index, key.as_ptr()); }
}
/// Gets the global named `name` and pushes it onto the stack (even if `nil`).
///
/// # Lua Errors
///
/// Indexing the global environment may trigger the `__index` metamethod which could error.
#[inline]
pub fn get_global(&mut self, name: &CStr) {
// SAFETY: self.0 is always valid and name's pointer is valid for the duration of this function.
unsafe { ffi::lua_getglobal(self.0, name.as_ptr()); }
}
/// Pops the top element and sets it as the value of the global named `name`.
///
/// # Panics
///
/// Panics if the stack is empty.
///
/// # Lua Errors
///
/// Indexing the global environment may trigger the `__newindex` metamethod which could error.
#[inline]
pub fn set_global(&mut self, name: &CStr) {
assert!(self.get_top() > 0, "tried to set global {name:?} despite having an empty stack");
// SAFETY: self.0 and name's pointer are always valid and the stack is not empty.
unsafe { ffi::lua_setglobal(self.0, name.as_ptr()); }
}
/// Does the equivalent of the Lua code `t[k]`, where `t` is the value located at the given valid `index`
/// and `k` is the value at the top of the stack (which is popped).
///
/// The result is pushed onto the stack, replacing `k` (even if `nil`).
///
/// # Panics
///
/// Panics if the stack is empty.
///
/// # Lua Errors
///
/// Not every value `t` can be indexed: for example, if `t` is `nil` this function will error.
///
/// Indexing `t` may also trigger the `__index` metamethod which could error.
#[inline]
pub fn get_table(&mut self, index: i32) {
assert!(self.get_top() > 0, "tried to get a value from the table at index {index} despite having an empty stack");
// SAFETY: self.0 is always valid and the stack is not empty.
unsafe { ffi::lua_gettable(self.0, index); }
}
/// Does the equivalent of the Lua code `t[k] = v`, where `t` is the value located at the given valid `index`
/// and `v` and `k` are the values at the top of the stack (which are popped from the stack in said order).
///
/// # Panics
///
/// Panics if the stack does not contain both `v` and `k` (thus contains less than 2 elements).
///
/// # Lua Errors
///
/// Not every value `t` or `k` can be used: if `t` or `k` are `nil` this function will error.
///
/// Indexing `t` may also trigger the `__newindex` metamethod which could error.
#[inline]
pub fn set_table(&mut self, index: i32) {
assert!(2 <= self.get_top(), "tried to set a value for the table at index {index} despite not having `v` and `k` in the stack");
// SAFETY: self.0 is always valid and v and k are in the stack.
unsafe { ffi::lua_settable(self.0, index); }
}
/// Accesses a table similarly to [`LuaState::get_table`], but without triggering any metamethod (see [`LuaState::get_table`]).
///
/// # Panics
///
/// Panics if the element at the given valid `index` is not a table or if the stack is empty.
#[inline]
pub fn raw_get(&mut self, index: i32) {
assert!(self.is_table(index), "cannot raw get a value from the element at index {index} as it is not a table");
assert!(self.get_top() > 0, "tried to raw get a value from the table at index {index} despite having an empty stack");
// SAFETY: self.0 is always valid, the element specified is a table and the stack is not empty.
unsafe { ffi::lua_rawget(self.0, index); }
}
/// Accesses a table similarly to [`LuaState::set_table`], but without triggering any metamethod (see [`LuaState::set_table`]).
///
/// # Panics
///
/// Panics if the element at the given valid `index` is not a table or if the stack is empty.
///
/// # Lua errors
///
/// Not every value `k` can be used: if `k` is `nil` this function will error.
#[inline]
pub fn raw_set(&mut self, index: i32) {
assert!(self.is_table(index), "cannot raw set a value for the element at index {index} as it is not a table");
assert!(2 <= self.get_top(), "tried to raw set a value for the table at index {index} despite not having `v` and `k` in the stack");
// SAFETY: self.0 is always valid, the element specified is a table and v and k are in the stack.
unsafe { ffi::lua_rawset(self.0, index); }
}
/// Does the equivalent of the Lua code `t[i]`, where `t` is the value located at the given valid `index`.
///
/// The result is pushed onto the stack.
///
/// # Panics
///
/// Panics if the element at the given valid `index` is not a table.
#[inline]
pub fn raw_geti(&mut self, index: i32, i: i32) {
assert!(self.is_table(index), "cannot raw get an element from the element at index {index} as it is not a table");
// SAFETY: self.0 is always valid and the element specified is a table.
unsafe { ffi::lua_rawgeti(self.0, index, i); }
}
/// Does the equivalent of the Lua code `t[i] = v`, where `t` is the value located at the given valid `index`
/// and `v` is the value at the top of the stack (which is popped).
///
/// # Panics
///
/// Panics if the element at the given valid `index` is not a table or if the stack is empty.
#[inline]
pub fn raw_seti(&mut self, index: i32, i: i32) {
assert!(self.is_table(index), "cannot raw set a value for the element at index {index} as it is not a table");
assert!(self.get_top() > 0, "tried to raw set a value for the table at index {index} despite having an empty stack");
// SAFETY: self.0 is always valid, the element specified is a table and the stack is not empty.
unsafe { ffi::lua_rawseti(self.0, index, i); }
}
/// Pops the last element of the stack, treating it as the key,
/// and pushes onto the stack the *next* key-value pair from the table at the given `index`, returning `true`.
///
/// If there is no next key-value pair, then nothing is pushed and `false` is returned instead.
///
/// This function can be used to traverse all elements of a table, see the example below.
///
/// # Examples
///
/// ```
/// # use low_luajit::{LuaState, AmountReturned};
/// # extern "C-unwind" fn example(mut lua: LuaState) -> AmountReturned {
/// # let t = 1;
/// // Assume the table is located in the stack at index t.
/// lua.push_nil(); // Push the first (dummy) key.
/// while lua.next(t) { // Get the next key-value pair.
/// // (The key is located at index -2, while the value is located at index -1.)
/// // Use the key-value pair in some way...
/// lua.pop(1); // Pop the value, so that the key can be used to get the next key-value pair.
/// }
/// # AmountReturned::NONE }
/// ```
pub fn next(&mut self, index: i32) -> bool { // TODO: check for any error/panic
unsafe { ffi::lua_next(self.0, index) != 0 }
}
/// Gets the metatable of the value at the given acceptable `index` and pushes it onto the stack, returning `true`.
///
/// If `index` is invalid or the value has no metatable, nothing is pushed and the function returns `false`.
#[inline]
pub fn get_metatable(&mut self, index: i32) -> bool {
unsafe { ffi::lua_getmetatable(self.0, index) != 0 }
}
/// Pops the top elemenet and sets it as the metatable of the value at the given acceptable `index`.
///
/// This function always returns `true`.
///
/// # Panics
///
/// Panics if the top element is not a table or if the stack is empty.
#[inline]
pub fn set_metatable(&mut self, index: i32) -> bool {
assert!(self.get_top() > 0, "tried to set the metatable for the element at index {index} despite having an empty stack");
assert!(self.is_table(-1), "cannot set the metatable for the element at index {index} as the given metatable is not a table");
// SAFETY: self.0 is always valid, the stack is not empty and the top element is a table.
unsafe { ffi::lua_setmetatable(self.0, index) != 0 }
}
/// Gets the environment table of the value at the given `index` and pushes it onto the stack.
///
/// If `index` is invalid or the value has no environment table, `nil` is pushed onto the stack.
#[inline]
pub fn get_fenv(&mut self, index: i32) {
unsafe { ffi::lua_getfenv(self.0, index); }
}
/// Pops a table from the stack and sets it as the environment table of the value at the given `index`, returning `true`.
///
/// Only functions, userdata and threads may have an environment table.
///
/// If `index` is invalid or the value's type is not one listed above, the stack is still popped but the function returns `false`.
///
/// # Panics
///
/// Panics if the top element is not a table or if the stack is empty.
#[inline]
pub fn set_fenv(&mut self, index: i32) -> bool {
assert!(self.get_top() > 0, "tried to set the environment table for the element at index {index} despite having an empty stack");
assert!(self.is_table(-1), "cannot set the environment table for the element at index {index} as the given environment table is not a table");
unsafe { ffi::lua_setfenv(self.0, index) != 0 }
}
/// Calls the metamethod `method` from the metatable of the element at the given `index`.
///
/// The metamethod will receive the element itself as its only argument and its result will be pushed onto the stack, returning `true`.
///
/// If there is no metatable or no metamethod, nothing is pushed and this function returns `false` instead.
///
/// # Lua Errors
///
/// The called metamethod may error.
#[inline]
pub fn call_meta(&mut self, index: i32, method: &CStr) -> bool {
// SAFETY: method's pointer is valid for the duration of this function.
unsafe { ffi::luaL_callmeta(self.0, index, method.as_ptr()) != 0 }
}
}