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}