low_luajit/lua/type/table.rs
1use core::ffi::CStr;
2use crate::{LuaState, ffi};
3
4/// Table related functions.
5impl LuaState {
6 /// Returns `true` if the value at the given acceptable `index` is a table, `false` otherwise.
7 #[inline]
8 #[must_use]
9 pub fn is_table(&self, index: i32) -> bool {
10 // SAFETY: self.0 is always valid.
11 unsafe { ffi::lua_istable(self.0, index) != 0 }
12 }
13
14 /// Creates a new empty table and pushes it onto the stack.
15 ///
16 /// To pre-allocate elements when creating a new table, see [`LuaState::create_table`].
17 #[inline]
18 pub fn new_table(&mut self) {
19 // SAFETY: self.0 is always valid.
20 unsafe { ffi::lua_newtable(self.0); }
21 }
22
23 /// Creates a new empty table and pushes it onto the stack.
24 ///
25 /// The table will have `n_arr` array elements and `n_rec` non-array elements pre-allocated.
26 ///
27 /// To create a new table without pre-allocating, see [`LuaState::new_table`].
28 ///
29 /// # Lua Errors
30 ///
31 /// Calling this function way too many times may trigger a stack overflow.
32 ///
33 /// Incredibly high values for `n_arr` or `n_rec` may instantly trigger a table overflow.
34 #[inline]
35 pub fn create_table(&mut self, n_arr: i32, n_rec: i32) {
36 // SAFETY: self.0 is always valid.
37 unsafe { ffi::lua_createtable(self.0, n_arr, n_rec); }
38 }
39
40 /// Does the equivalent of the Lua code `t[key]`, where `t` is the value located at the given valid `index`.
41 ///
42 /// The result is pushed onto the stack (even if `nil`).
43 ///
44 /// For a function that does the same but allows any value instead of `key`, see [`LuaState::get_table`].
45 ///
46 /// # Lua Errors
47 ///
48 /// Not every value `t` can be indexed: for example, if `t` is `nil` this function will error.
49 ///
50 /// Indexing `t` may also trigger the `__index` metamethod which could error.
51 #[inline]
52 pub fn get_field(&mut self, index: i32, key: &CStr) {
53 // SAFETY: self.0 is always valid and key's pointer is valid for the duration of this function.
54 unsafe { ffi::lua_getfield(self.0, index, key.as_ptr()); }
55 }
56
57 /// Does the equivalent of the Lua code `t[key] = v`, where `t` is the value located at the given valid `index`
58 /// and `v` is the value at the top of the stack (which is popped).
59 ///
60 /// For a function that does the same but allows any value instead of `key`, see [`LuaState::set_table`].
61 ///
62 /// # Panics
63 ///
64 /// Panics if the stack is empty.
65 ///
66 /// # Lua Errors
67 ///
68 /// Not every value `t` can be indexed: for example, if `t` is `nil` this function will error.
69 ///
70 /// Indexing `t` may also trigger the `__newindex` metamethod which could error.
71 #[inline]
72 pub fn set_field(&mut self, index: i32, key: &CStr) {
73 assert!(self.get_top() > 0, "tried to set field {key:?} for the table at index {index} despite having an empty stack");
74
75 // SAFETY: self.0 is always valid, key's pointer is valid for the duration of this function, and the stack is not empty.
76 unsafe { ffi::lua_setfield(self.0, index, key.as_ptr()); }
77 }
78
79 /// Gets the global named `name` and pushes it onto the stack (even if `nil`).
80 ///
81 /// # Lua Errors
82 ///
83 /// Indexing the global environment may trigger the `__index` metamethod which could error.
84 #[inline]
85 pub fn get_global(&mut self, name: &CStr) {
86 // SAFETY: self.0 is always valid and name's pointer is valid for the duration of this function.
87 unsafe { ffi::lua_getglobal(self.0, name.as_ptr()); }
88 }
89
90 /// Pops the top element and sets it as the value of the global named `name`.
91 ///
92 /// # Panics
93 ///
94 /// Panics if the stack is empty.
95 ///
96 /// # Lua Errors
97 ///
98 /// Indexing the global environment may trigger the `__newindex` metamethod which could error.
99 #[inline]
100 pub fn set_global(&mut self, name: &CStr) {
101 assert!(self.get_top() > 0, "tried to set global {name:?} despite having an empty stack");
102
103 // SAFETY: self.0 and name's pointer are always valid and the stack is not empty.
104 unsafe { ffi::lua_setglobal(self.0, name.as_ptr()); }
105 }
106
107 /// Does the equivalent of the Lua code `t[k]`, where `t` is the value located at the given valid `index`
108 /// and `k` is the value at the top of the stack (which is popped).
109 ///
110 /// The result is pushed onto the stack, replacing `k` (even if `nil`).
111 ///
112 /// # Panics
113 ///
114 /// Panics if the stack is empty.
115 ///
116 /// # Lua Errors
117 ///
118 /// Not every value `t` can be indexed: for example, if `t` is `nil` this function will error.
119 ///
120 /// Indexing `t` may also trigger the `__index` metamethod which could error.
121 #[inline]
122 pub fn get_table(&mut self, index: i32) {
123 assert!(self.get_top() > 0, "tried to get a value from the table at index {index} despite having an empty stack");
124
125 // SAFETY: self.0 is always valid and the stack is not empty.
126 unsafe { ffi::lua_gettable(self.0, index); }
127 }
128
129 /// Does the equivalent of the Lua code `t[k] = v`, where `t` is the value located at the given valid `index`
130 /// and `v` and `k` are the values at the top of the stack (which are popped from the stack in said order).
131 ///
132 /// # Panics
133 ///
134 /// Panics if the stack does not contain both `v` and `k` (thus contains less than 2 elements).
135 ///
136 /// # Lua Errors
137 ///
138 /// Not every value `t` or `k` can be used: if `t` or `k` are `nil` this function will error.
139 ///
140 /// Indexing `t` may also trigger the `__newindex` metamethod which could error.
141 #[inline]
142 pub fn set_table(&mut self, index: i32) {
143 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");
144
145 // SAFETY: self.0 is always valid and v and k are in the stack.
146 unsafe { ffi::lua_settable(self.0, index); }
147 }
148
149 /// Accesses a table similarly to [`LuaState::get_table`], but without triggering any metamethod (see [`LuaState::get_table`]).
150 ///
151 /// # Panics
152 ///
153 /// Panics if the element at the given valid `index` is not a table or if the stack is empty.
154 #[inline]
155 pub fn raw_get(&mut self, index: i32) {
156 assert!(self.is_table(index), "cannot raw get a value from the element at index {index} as it is not a table");
157 assert!(self.get_top() > 0, "tried to raw get a value from the table at index {index} despite having an empty stack");
158
159 // SAFETY: self.0 is always valid, the element specified is a table and the stack is not empty.
160 unsafe { ffi::lua_rawget(self.0, index); }
161 }
162
163 /// Accesses a table similarly to [`LuaState::set_table`], but without triggering any metamethod (see [`LuaState::set_table`]).
164 ///
165 /// # Panics
166 ///
167 /// Panics if the element at the given valid `index` is not a table or if the stack is empty.
168 ///
169 /// # Lua errors
170 ///
171 /// Not every value `k` can be used: if `k` is `nil` this function will error.
172 #[inline]
173 pub fn raw_set(&mut self, index: i32) {
174 assert!(self.is_table(index), "cannot raw set a value for the element at index {index} as it is not a table");
175 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");
176
177 // SAFETY: self.0 is always valid, the element specified is a table and v and k are in the stack.
178 unsafe { ffi::lua_rawset(self.0, index); }
179 }
180
181 /// Does the equivalent of the Lua code `t[i]`, where `t` is the value located at the given valid `index`.
182 ///
183 /// The result is pushed onto the stack.
184 ///
185 /// # Panics
186 ///
187 /// Panics if the element at the given valid `index` is not a table.
188 #[inline]
189 pub fn raw_geti(&mut self, index: i32, i: i32) {
190 assert!(self.is_table(index), "cannot raw get an element from the element at index {index} as it is not a table");
191
192 // SAFETY: self.0 is always valid and the element specified is a table.
193 unsafe { ffi::lua_rawgeti(self.0, index, i); }
194 }
195
196 /// Does the equivalent of the Lua code `t[i] = v`, where `t` is the value located at the given valid `index`
197 /// and `v` is the value at the top of the stack (which is popped).
198 ///
199 /// # Panics
200 ///
201 /// Panics if the element at the given valid `index` is not a table or if the stack is empty.
202 #[inline]
203 pub fn raw_seti(&mut self, index: i32, i: i32) {
204 assert!(self.is_table(index), "cannot raw set a value for the element at index {index} as it is not a table");
205 assert!(self.get_top() > 0, "tried to raw set a value for the table at index {index} despite having an empty stack");
206
207 // SAFETY: self.0 is always valid, the element specified is a table and the stack is not empty.
208 unsafe { ffi::lua_rawseti(self.0, index, i); }
209 }
210
211 /// Pops the last element of the stack, treating it as the key,
212 /// and pushes onto the stack the *next* key-value pair from the table at the given `index`, returning `true`.
213 ///
214 /// If there is no next key-value pair, then nothing is pushed and `false` is returned instead.
215 ///
216 /// This function can be used to traverse all elements of a table, see the example below.
217 ///
218 /// # Examples
219 ///
220 /// ```
221 /// # use low_luajit::{LuaState, AmountReturned};
222 /// # extern "C-unwind" fn example(mut lua: LuaState) -> AmountReturned {
223 /// # let t = 1;
224 /// // Assume the table is located in the stack at index t.
225 /// lua.push_nil(); // Push the first (dummy) key.
226 /// while lua.next(t) { // Get the next key-value pair.
227 /// // (The key is located at index -2, while the value is located at index -1.)
228 /// // Use the key-value pair in some way...
229 /// lua.pop(1); // Pop the value, so that the key can be used to get the next key-value pair.
230 /// }
231 /// # AmountReturned::NONE }
232 /// ```
233 pub fn next(&mut self, index: i32) -> bool { // TODO: check for any error/panic
234 unsafe { ffi::lua_next(self.0, index) != 0 }
235 }
236
237 /// Gets the metatable of the value at the given acceptable `index` and pushes it onto the stack, returning `true`.
238 ///
239 /// If `index` is invalid or the value has no metatable, nothing is pushed and the function returns `false`.
240 #[inline]
241 pub fn get_metatable(&mut self, index: i32) -> bool {
242 unsafe { ffi::lua_getmetatable(self.0, index) != 0 }
243 }
244
245 /// Pops the top elemenet and sets it as the metatable of the value at the given acceptable `index`.
246 ///
247 /// This function always returns `true`.
248 ///
249 /// # Panics
250 ///
251 /// Panics if the top element is not a table or if the stack is empty.
252 #[inline]
253 pub fn set_metatable(&mut self, index: i32) -> bool {
254 assert!(self.get_top() > 0, "tried to set the metatable for the element at index {index} despite having an empty stack");
255 assert!(self.is_table(-1), "cannot set the metatable for the element at index {index} as the given metatable is not a table");
256
257 // SAFETY: self.0 is always valid, the stack is not empty and the top element is a table.
258 unsafe { ffi::lua_setmetatable(self.0, index) != 0 }
259 }
260
261 /// Gets the environment table of the value at the given `index` and pushes it onto the stack.
262 ///
263 /// If `index` is invalid or the value has no environment table, `nil` is pushed onto the stack.
264 #[inline]
265 pub fn get_fenv(&mut self, index: i32) {
266 unsafe { ffi::lua_getfenv(self.0, index); }
267 }
268
269 /// Pops a table from the stack and sets it as the environment table of the value at the given `index`, returning `true`.
270 ///
271 /// Only functions, userdata and threads may have an environment table.
272 ///
273 /// If `index` is invalid or the value's type is not one listed above, the stack is still popped but the function returns `false`.
274 ///
275 /// # Panics
276 ///
277 /// Panics if the top element is not a table or if the stack is empty.
278 #[inline]
279 pub fn set_fenv(&mut self, index: i32) -> bool {
280 assert!(self.get_top() > 0, "tried to set the environment table for the element at index {index} despite having an empty stack");
281 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");
282
283 unsafe { ffi::lua_setfenv(self.0, index) != 0 }
284 }
285
286 /// Calls the metamethod `method` from the metatable of the element at the given `index`.
287 ///
288 /// The metamethod will receive the element itself as its only argument and its result will be pushed onto the stack, returning `true`.
289 ///
290 /// If there is no metatable or no metamethod, nothing is pushed and this function returns `false` instead.
291 ///
292 /// # Lua Errors
293 ///
294 /// The called metamethod may error.
295 #[inline]
296 pub fn call_meta(&mut self, index: i32, method: &CStr) -> bool {
297 // SAFETY: method's pointer is valid for the duration of this function.
298 unsafe { ffi::luaL_callmeta(self.0, index, method.as_ptr()) != 0 }
299 }
300}