lunka/
managed.rs

1//! See [`Managed`].
2
3use crate::{
4	cdef::*,
5	thread::*
6};
7
8#[cfg(feature = "auxlib")]
9use crate::cdef::auxlib::*;
10
11use core::{
12	ffi::{
13		c_char, c_int, c_uint, CStr
14	},
15	marker::PhantomData,
16	ops::{
17		Deref, DerefMut
18	},
19	ptr::null_mut,
20	slice::from_raw_parts,
21};
22
23/// Context for invalidating pointers that may be freed during garbage
24/// collection.
25/// 
26/// This structure is available in callbacks provided by [`Thread::run_managed`]
27/// and [`Thread::run_managed_no_gc`].
28#[derive(Debug)]
29#[repr(transparent)]
30pub struct Managed<'l> {
31    pub(crate) l: *mut State,
32    pub(crate) _life: PhantomData<&'l mut Thread>
33}
34
35impl AsRef<Thread> for Managed<'_> {
36	fn as_ref(&self) -> &Thread {
37		unsafe { Thread::from_ptr(self.l) }
38	}
39}
40
41impl AsMut<Thread> for Managed<'_> {
42	fn as_mut(&mut self) -> &mut Thread {
43		unsafe { Thread::from_ptr_mut(self.l) }
44	}
45}
46
47impl Deref for Managed<'_> {
48	type Target = Thread;
49	fn deref(&self) -> &Self::Target {
50		unsafe { Thread::from_ptr(self.l) }
51	}
52}
53
54impl DerefMut for Managed<'_> {
55	fn deref_mut(&mut self) -> &mut Self::Target {
56		unsafe { Thread::from_ptr_mut(self.l) }
57	}
58}
59
60impl Managed<'_> {
61	/// Perform an arithmetic or bitwise operation over two (or one) values at
62	/// the top of the stack, popping them, and push the result of the operation.
63	/// 
64	/// The value on the top is the second operand, and the value just below it
65	/// is the first operand.
66	/// 
67	/// This function follows the semantics of the corresponding Lua operator
68	/// (that is, it may call metamethods).
69	/// 
70	/// # Errors
71	/// The underlying Lua state may raise an arbitrary [error](crate::errors)
72	/// from a metamethod.
73	/// 
74	/// # Safety
75	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
76	pub unsafe fn arith(&mut self, operation: Arith) {
77		unsafe { lua_arith(self.l, operation as _) }
78	}
79
80	/// Call a function (or a callable object).
81	/// 
82	/// Like regular Lua calls, this function respects the `__call` metamethod.
83	/// 
84	/// To do a call, you must use the following protocol:
85	/// - First, the function to be called is pushed onto the stack.
86	/// - Then, the arguments to the call are pushed in direct order; that is, the first argument is pushed first.
87	/// - Finally, call [`Managed::call`]; `n_args` is the number of arguments that were pushed onto the stack.
88	/// 
89	/// When the function returns, all arguments and the function value are
90	/// popped and the call results are pushed onto the stack.
91	/// The number of results is adjusted to `n_results`, unless it is
92	/// [`MULT_RET`]. In this case, all results from the function are pushed;
93	/// Lua takes care that the returned values fit into the stack space, but it
94	/// does not ensure any extra space in the stack.
95	/// The function results are pushed onto the stack in direct order (the
96	/// first result is pushed first), so that after the call the last result is
97	/// on the top of the stack.
98	/// 
99	/// # Errors
100	/// Any [error](crate::errors) while calling and running the function is
101	/// propagated upwards (usually with a `longjmp`).
102	/// 
103	/// # Safety
104	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
105	pub unsafe fn call(&mut self, n_args: c_uint, n_results: c_int) {
106		unsafe { lua_call(self.l, n_args as _, n_results) }
107	}
108
109	/// Behaves exactly like [`Managed::call`], but allows the called function
110	/// to yield.
111	/// 
112	/// If the callee yields, then, once the thread is resumed, the continuation
113	/// function `continuation` will be called with the given context with
114	/// exactly the same Lua stack as it was observed before the yield.
115	/// 
116	/// # Errors
117	/// Any [error](crate::errors) while calling and running the function is
118	/// propagated upwards (usually with a `longjmp`).
119	/// 
120	/// # Safety
121	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
122	pub unsafe fn call_k(
123		&mut self,
124		n_args: c_uint, n_results: c_int,
125		continuation: KFunction, context: KContext,
126	) {
127		unsafe { lua_callk(
128			self.l,
129			n_args as _, n_results,
130			context, Some(continuation)
131		) }
132	}
133
134	/// Close the to-be-closed slot at the given index and set its value to `nil`.
135	/// 
136	/// A `__close` metamethod cannot yield when called through this function.
137	/// 
138	/// # Errors
139	/// The underlying Lua state may raise an arbitrary [error](crate::errors)
140	/// from the `__close` metamethod.
141	/// 
142	/// # Safety
143	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
144	/// 
145	/// The index must be the last index previously marked to be closed that is
146	/// still active (that is, not closed yet).
147	pub unsafe fn close_slot(&mut self, index: c_int) {
148		unsafe { lua_closeslot(self.l, index) }
149	}
150
151	/// Compare two Lua values.
152	/// 
153	/// Returns `true` if the value at `idx_a` satisfies `operation` when
154	/// compared with the value at index `idx_b`, following the semantics of the
155	/// corresponding Lua operator (that is, it may call metamethods).
156	/// Otherwise returns `false`.
157	/// Also returns `false` if any of the indices are not valid.
158	/// 
159	/// # Errors
160	/// The underlying Lua state may raise an arbitrary [error](crate::errors)
161	/// from a metamethod.
162	/// 
163	/// # Safety
164	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
165	pub unsafe fn compare(
166		&mut self,
167		operation: Compare,
168		idx_a: c_int, idx_b: c_int
169	) -> bool {
170		(unsafe { lua_compare(self.l, idx_a, idx_b, operation as _) }) != 0
171	}
172
173	/// Concatenate `n` values at the top of the stack, popping them, and leave
174	/// the result on the top.
175	/// 
176	/// If `n` is `1`, the result is the single value on the stack (that is, the
177	/// function does nothing).
178	/// 
179	/// If `n` is `0`, the result is an empty string.
180	/// 
181	/// Concatenation is performed following the usual semantics of Lua.
182	/// 
183	/// # Errors
184	/// The underlying Lua state may raise an arbitrary [error](crate::errors)
185	/// from a metamethod.
186	/// 
187	/// # Safety
188	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
189	pub unsafe fn concat(&mut self, n: c_uint) {
190		unsafe { lua_concat(self.l, n as _) }
191	}
192
193	/// Perform a full garbage collection cycle.
194	pub fn run_gc(&mut self) {
195		unsafe { lua_gc(self.l, GcTask::Collect as _) };
196	}
197
198	/// Perform an incremental step of garbage collection, corresponding to the
199	/// allocation of `stepsize` kilobytes. 
200	pub fn step_gc(&mut self, step_size: c_uint) {
201		unsafe { lua_gc(self.l, GcTask::Step as _, step_size) };
202	}
203
204	/// Push onto the stack the value `t[key]`, where `t` is the value at the
205	/// given index, and return the type of the pushed value.
206	/// 
207	/// As in Lua, this function may trigger a metamethod for the `index` event.
208	/// 
209	/// # Errors
210	/// The underlying Lua state may raise an arbitrary [error](crate::errors).
211	/// 
212	/// # Safety
213	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
214	pub unsafe fn get_field(&mut self, obj_index: c_int, key: &CStr) -> Type {
215		unsafe { Type::from_c_int_unchecked(
216			lua_getfield(self.l, obj_index, key.as_ptr())
217		) }
218	}
219
220	/// Push onto the stack the value `t[i]`, where `t` is the value at the
221	/// given index, and return the type of the pushed value.
222	/// 
223	/// As in Lua, this function may trigger a metamethod for the `index` event.
224	/// 
225	/// # Errors
226	/// The underlying Lua state may raise an arbitrary [error](crate::errors).
227	/// 
228	/// # Safety
229	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
230	pub unsafe fn get_i(&mut self, obj_index: c_int, i: Integer) -> Type {
231		unsafe { Type::from_c_int_unchecked(lua_geti(self.l, obj_index, i)) }
232	}
233
234	/// Push onto the stack the value `t[k]`, where `t` is the value at the
235	/// given index and `k` is the value on the top of the stack, and return the
236	/// type of the pushed value.
237	/// 
238	/// This function pops the key from the stack, pushing the resulting value
239	/// in its place.
240	/// 
241	/// As in Lua, this function may trigger a metamethod for the `index` event. 
242	/// 
243	/// # Errors
244	/// The underlying Lua state may raise an arbitrary [error](crate::errors).
245	/// 
246	/// # Safety
247	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
248	pub unsafe fn get_table(&mut self, obj_index: c_int) -> Type {
249		unsafe { Type::from_c_int_unchecked(lua_gettable(self.l, obj_index)) }
250	}
251
252	/// Push onto the stack the length of the value at the given index.
253	/// 
254	/// This function is equivalent to the `#` operator in Lua and may trigger a
255	/// metamethod for the `length` event.
256	/// 
257	/// # Errors
258	/// The underlying Lua state may raise an arbitrary [error](crate::errors).
259	/// 
260	/// # Safety
261	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
262	pub unsafe fn length_of(&mut self, index: c_int) {
263		unsafe { lua_len(self.l, index) }
264	}
265
266	/// Start or resume this thread (like a coroutine).
267	/// 
268	/// See also [`Managed::resume_from`].
269	/// 
270	/// This function returns [`Status::Yielded`] if the coroutine yields,
271	/// [`Status::Ok`] if the coroutine finishes its execution without errors,
272	/// or an error code in case of errors.
273	/// In case of errors, the error object is on the top of the stack.
274	/// 
275	/// # Starting a coroutine
276	/// To start a coroutine:
277	/// - Push the main function plus any arguments onto the empty stack of the thread.
278	/// - Then, call this function, with `n_args` being the number of arguments.
279	///   This call returns when the coroutine suspends or finishes its execution.
280	/// 
281	/// When it returns, the number of results is saved and the top of the stack
282	/// contains the values passed to [`Thread::yield_with`] or returned by the
283	/// body function.
284	/// 
285	/// # Resuming a coroutine
286	/// To resume a coroutine:
287	/// - Remove the yielded values from its stack.
288	/// - Push the values to be passed as results from the yield.
289	/// - Call this function.
290	pub fn resume(&mut self, n_args: c_uint) -> (Status, c_int) {
291		let mut n_res = 0;
292		let status = unsafe { lua_resume(
293			self.as_ptr(), null_mut(),
294			n_args as _,
295			&mut n_res as *mut _
296		) };
297		(unsafe { Status::from_c_int_unchecked(status) }, n_res)
298	}
299
300	/// Resume this thread, also specifying the thread that is resuming this one.
301	/// 
302	/// See [`Managed::resume`] for more information.
303	pub fn resume_from(&mut self, from: &Self, n_args: c_uint) -> (Status, c_int) {
304		let mut n_res = 0;
305		let status = unsafe { lua_resume(
306			self.as_ptr(), from.as_ptr(),
307			n_args as _,
308			&mut n_res as *mut _
309		) };
310		(unsafe { Status::from_c_int_unchecked(status) }, n_res)
311	}
312
313	/// Call a function (or a callable object) in protected mode.
314	/// 
315	/// Both `n_args` and `n_results` have the same meaning as in
316	/// [`Managed::call`].
317	/// 
318	/// If there are no errors during the call, this function behaves exactly
319	/// like [`Managed::call`].
320	/// However, if there is any error, the function catches it, pushes a single
321	/// value on the stack (the error object), and returns an error code.
322	/// Like [`Managed::call`], this function always removes the function and
323	/// its arguments from the stack.
324	/// 
325	/// If `err_func` is `0`, then the error object returned on the stack is
326	/// exactly the original error object.
327	/// Otherwise, `err_func` is the stack index of a message handler.
328	/// (This index cannot be a pseudo-index.)
329	/// In case of runtime errors, this handler will be called with the error
330	/// object and its return value will be the object returned on the stack.
331	/// 
332	/// Typically, the message handler is used to add more debug information to
333	/// the error object, such as a stack traceback.
334	/// Such information cannot be gathered after the return of this function,
335	/// since by then the stack has unwound. 
336	/// 
337	/// # Safety
338	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
339	pub unsafe fn pcall(
340		&mut self,
341		n_args: c_uint, n_results: c_int,
342		err_func: c_int
343	) -> Status {
344		unsafe { Status::from_c_int_unchecked(
345			lua_pcall(self.l, n_args as _, n_results, err_func)
346		) }
347	}
348
349	/// Behaves exactly like [`Managed::pcall`], but allows the called function
350	/// to yield.
351	/// 
352	/// If the callee yields, then, once the thread is resumed, the continuation
353	/// function `continuation` will be called with the given context with
354	/// exactly the same Lua stack as it was observed before the yield.
355	/// 
356	/// # Errors
357	/// Yielding will cause a jump similar to an error (usually, with a `longjmp`).
358	/// 
359	/// # Safety
360	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
361	pub unsafe fn pcall_k(
362		&mut self,
363		n_args: c_uint, n_results: c_int,
364		err_func: c_int,
365		continuation: KFunction, context: KContext
366	) -> Status {
367		unsafe { Status::from_c_int_unchecked(lua_pcallk(
368			self.l,
369			n_args as _, n_results,
370			err_func,
371			context, Some(continuation)
372		)) }
373	}
374
375	/// Pop `n` elements from the stack.
376	/// 
377	/// Because this is implemented with [`Managed::set_top`], this function can
378	/// also run arbitrary code when removing an index marked as to-be-closed
379	/// from the stack.
380	/// 
381	/// # Errors
382	/// The underlying Lua state may raise an arbitrary [error](crate::errors).
383	/// 
384	/// # Safety
385	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
386	pub unsafe fn pop(&mut self, n: c_uint) {
387		unsafe { lua_pop(self.l, n as _) }
388	}
389
390	/// If `package.loaded[modname]` is not true, calls the function `open_fn`
391	/// with the string `module_name` as an argument and sets the call result to
392	/// `package.loaded[modname]`, as if that function has been called through
393	/// `require`.
394	/// 
395	/// This function leaves a copy of the module on the stack. 
396	/// 
397	/// If `into_global` is true, also stores the module into the global
398	/// `module_name`.
399	/// 
400	/// # Errors
401	/// The underlying Lua state may raise an arbitrary [error](crate::errors).
402	/// 
403	/// # Safety
404	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
405	pub unsafe fn require(
406		&mut self,
407		module_name: &CStr,
408		open_fn: CFunction,
409		into_global: bool
410	) {
411		unsafe { luaL_requiref(
412			self.l,
413			module_name.as_ptr(),
414			open_fn,
415			if into_global { 1 } else { 0 }
416		) }
417	}
418
419	/// Do the equivalent to `t[key] = v`, where `t` is the value at the given
420	/// index and `v` is the value on the top of the stack.
421	/// 
422	/// This function pops the value from the stack.
423	/// 
424	/// As in Lua, this function may trigger a metamethod for the `newindex`
425	/// event.
426	/// 
427	/// # Errors
428	/// The underlying Lua state may raise an arbitrary [error](crate::errors).
429	/// 
430	/// # Safety
431	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
432	pub unsafe fn set_field(&mut self, obj_index: c_int, key: &CStr) {
433		unsafe { lua_setfield(self.l, obj_index, key.as_ptr()) }
434	}
435
436	/// Do the equivalent to `t[k] = v`, where `t` is the value at the given
437	/// index, `v` is the value on the top of the stack, and `k` is the value
438	/// just below the top.
439	/// 
440	/// This function pops the value from the stack.
441	/// 
442	/// As in Lua, this function may trigger a metamethod for the `newindex`
443	/// event.
444	/// 
445	/// # Errors
446	/// The underlying Lua state may raise an arbitrary [error](crate::errors).
447	/// 
448	/// # Safety
449	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
450	pub unsafe fn set_table(&mut self, obj_index: c_int) {
451		unsafe { lua_settable(self.l, obj_index) }
452	}
453
454	/// Accept any index, or `0`, and set the stack top to this index.
455	/// 
456	/// If the new top is greater than the old one, then the new elements are
457	/// filled with `nil`. If index is 0, then all stack elements are removed.
458	/// 
459	/// This function can run arbitrary code when removing an index marked as
460	/// to-be-closed from the stack.
461	/// 
462	/// # Errors
463	/// The underlying Lua state may raise an arbitrary [error](crate::errors).
464	/// 
465	/// # Safety
466	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
467	pub unsafe fn set_top(&mut self, top: c_int) {
468		unsafe { lua_settop(self.l, top) }
469	}
470
471	/// Do the equivalent to `t[i] = v`, where `t` is the value at the given
472	/// index and `v` is the value on the top of the stack.
473	/// 
474	/// This function pops the value from the stack.
475	/// 
476	/// As in Lua, this function may trigger a metamethod for the `newindex`
477	/// event.
478	/// 
479	/// # Errors
480	/// The underlying Lua state may raise an arbitrary [error](crate::errors).
481	/// 
482	/// # Safety
483	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
484	pub unsafe fn set_i(&mut self, obj_index: c_int, i: Integer) {
485		unsafe { lua_seti(self.l, obj_index, i) }
486	}
487}
488
489#[cfg(feature = "stdlibs")]
490impl Managed<'_> {
491	/// Open all standard Lua libraries into the associated Lua thread.
492	/// 
493	/// # Errors
494	/// The underlying Lua state may raise an arbitrary [error](crate::errors).
495	pub fn open_libs(&mut self) {
496		unsafe { stdlibs::luaL_openlibs(self.l) }
497	}
498}
499
500#[cfg(feature = "auxlib")]
501impl Managed<'_> {
502	/// Call a metamethod `event` on the object at index `obj_index`.
503	/// 
504	/// If the object at index `obj_index` has a metatable and this metatable
505	/// has a field `event`, this function calls this field passing the object
506	/// as its only argument. 
507	/// In this case, this function returns `true` and pushes onto the stack the
508	/// value returned by the call.
509	/// 
510	/// If there is no metatable or no metamethod, this function returns `false`
511	/// without pushing any value on the stack. 
512	/// 
513	/// # Errors
514	/// The underlying Lua state may raise an arbitrary [error](crate::errors).
515	/// 
516	/// # Safety
517	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
518	pub unsafe fn call_metamethod(&mut self, obj_index: c_int, event: &CStr) -> bool {
519		(unsafe { luaL_callmeta(
520			self.l,
521			obj_index, event.as_ptr()
522		) }) != 0
523	}
524
525	/// Load and run the given file.
526	/// 
527	/// # Errors
528	/// The underlying Lua state may raise a memory [error](crate::errors).
529	pub fn do_file(&mut self, file_name: &CStr) -> bool {
530		unsafe { luaL_dofile(self.l, file_name.as_ptr()) }
531	}
532
533	/// Load and run the given string.
534	pub fn do_string(&mut self, code: &CStr) -> bool {
535		unsafe { luaL_dostring(self.l, code.as_ptr()) }
536	}
537
538	/// Ensure that the value `t[table_name]`, where `t` is the value at index
539	/// `parent_index`, is a table, and push that table onto the stack.
540	/// 
541	/// This function returns `true` if it finds a previous table there and
542	/// `false` if it creates a new table.
543	/// 
544	/// # Errors
545	/// The underlying Lua state may raise an arbitrary [error](crate::errors).
546	/// 
547	/// # Safety
548	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
549	pub unsafe fn get_sub_table(&mut self, parent_index: c_int, table_name: &CStr) -> bool {
550		(unsafe { luaL_getsubtable(
551			self.l,
552			parent_index, table_name.as_ptr()
553		) }) != 0
554	}
555
556	/// Return the "length" of the value at the given index as a number.
557	/// 
558	/// This function is equivalent to the `#` operator in Lua.
559	/// 
560	/// # Errors
561	/// The underlying Lua state may raise an [error](crate::errors) if the
562	/// result of the operation is not an integer.
563	/// (This case can only happen through metamethods.)
564	/// 
565	/// It can also raise an error from a metamethod.
566	pub fn meta_length_of(&mut self, obj_index: c_int) -> Integer {
567		unsafe { luaL_len(self.l, obj_index) }
568	}
569
570	/// Convert any Lua value at the given index to a string in a reasonable
571	/// format, and push that string onto the stack.
572	/// 
573	/// This function works the same way as [`Managed::to_string_meta`].
574	/// 
575	/// # Errors
576	/// The underlying Lua state may raise an arbitrary [error](crate::errors).
577	/// 
578	/// # Safety
579	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
580	pub unsafe fn to_c_chars_meta(&mut self, index: c_int) -> Option<&[c_char]> {
581		let mut len = 0;
582		let str_ptr = unsafe { luaL_tolstring(self.l, index, &mut len as *mut _) };
583		if !str_ptr.is_null() {
584			Some(unsafe { from_raw_parts(str_ptr, len) })
585		} else {
586			None
587		}
588	}
589
590	/// Convert any Lua value at the given index to a string in a reasonable
591	/// format, and push that string onto the stack.
592	/// 
593	/// This function works the same way as [`Managed::to_string_meta`].
594	/// 
595	/// # Errors
596	/// The underlying Lua state may raise a memory [error](crate::errors).
597	pub fn to_c_str_meta(&mut self, index: c_int) -> Option<&CStr> {
598		let str_ptr = unsafe { luaL_tolstring(self.l, index, null_mut()) };
599		if !str_ptr.is_null() {
600			Some(unsafe { CStr::from_ptr(str_ptr) })
601		} else {
602			None
603		}
604	}
605
606	/// Convert any Lua value at the given index to a string in a reasonable
607	/// format, and push that string onto the stack.
608	/// 
609	/// The string created by the function is represented as the return value.
610	/// 
611	/// If the value has a metatable with a `__tostring` field, then this
612	/// function calls the corresponding metamethod with the value as argument,
613	/// and uses the result of the call as its result.
614	/// 
615	/// # Errors
616	/// The underlying Lua state may raise an arbitrary [error](crate::errors).
617	/// 
618	/// # Safety
619	/// Calling untrusted code in a possibly-unsound environment can cause Undefined Behavior.
620	pub unsafe fn to_string_meta(&mut self, index: c_int) -> Option<&[u8]> {
621		let mut len = 0;
622		let str_ptr = unsafe { luaL_tolstring(self.l, index, &mut len as *mut _) };
623		if !str_ptr.is_null() {
624			Some(unsafe { from_raw_parts(str_ptr as *const _, len) })
625		} else {
626			None
627		}
628	}
629}