Skip to main content

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}