low_luajit/lua/type/function.rs
1use core::{error::Error, ffi::{CStr, c_int, c_void}, fmt::{self, Display, Formatter}, mem, num::NonZeroI32, slice};
2use crate::{LuaState, SafeFn, ffi::{self, lua_CFunction, lua_State}};
3
4/// A safe function using the C ABI that Lua can call.
5///
6/// This type is technically a *subset* of [`lua_CFunction`], as it only allows safe functions.
7/// Different methods will use either [`lua_CFunction`] or `CFunction` based on if they work with only safe functions or not.
8///
9/// It is always safe to convert a `CFunction` into a [`lua_CFunction`] (see [`SafeFn::to_raw`]).
10///
11/// # Protocol
12///
13/// To communicate properly, Lua expects `CFunction`s to follow a specific protocol:
14///
15/// Arguments passed to the `CFunction` are located in the stack (index 1 contains the first argument, etc.),
16/// thus [`LuaState::get_top`] can be used to know the number of arguments received.
17///
18/// Values to return to the caller should be pushed onto the stack (first value is returned first, etc.),
19/// using the returned [`AmountReturned`] to specify how many values were returned.
20///
21/// [`AmountReturned`] can be obtained manually using [`LuaState::return_any`] or automatically for simple values
22/// using the designated methods ([`LuaState::return_number`], [`LuaState::return_string`], etc...).
23///
24/// # Examples
25///
26/// ```
27/// use low_luajit::{LuaState, AmountReturned};
28///
29/// extern "C-unwind" fn sum(mut lua: LuaState) -> AmountReturned {
30/// // Retrieve the arguments, asserting that they exist and are of the correct type.
31/// let x = lua.check_number(1);
32/// let y = lua.check_number(2);
33///
34/// // Push the value to return and return 1 since we're only returning a single value.
35/// lua.push_number(x + y);
36/// lua.return_any(1)
37/// }
38///
39/// # let mut lua = unsafe { low_luajit::__test!() };
40/// lua.push_cfunction(sum);
41/// lua.push_number(123.0);
42/// lua.push_number(456.0);
43/// lua.call(2, 1);
44/// assert_eq!(lua.to_number(-1), 579.0);
45/// ```
46///
47/// Alternatively, using [`LuaState::return_number`]:
48///
49/// ```
50/// use low_luajit::{LuaState, AmountReturned};
51///
52/// extern "C-unwind" fn sum(lua: LuaState) -> AmountReturned {
53/// // Retrieve the arguments, asserting that they exist and are of the correct type.
54/// let x = lua.check_number(1);
55/// let y = lua.check_number(2);
56///
57/// // Just return the number (does the same as the other example, just more concise).
58/// lua.return_number(x + y)
59/// }
60///
61/// # let mut lua = unsafe { low_luajit::__test!() };
62/// lua.push_cfunction(sum);
63/// lua.push_number(0.5);
64/// lua.push_number(0.5);
65/// lua.call(2, 1);
66/// assert_eq!(lua.to_number(-1), 1.0);
67/// ```
68///
69/// [`lua_CFunction`]: ./ffi/type.lua_CFunction.html
70pub type CFunction = extern "C-unwind" fn(lua: LuaState) -> AmountReturned;
71
72impl SafeFn for CFunction {
73 type RawFn = lua_CFunction;
74
75 #[inline]
76 unsafe fn from_raw(raw: lua_CFunction) -> Self {
77 // SAFETY: lua_CFunction and CFunction are effectively the same.
78 unsafe { mem::transmute(raw) }
79 }
80
81 #[inline]
82 fn to_raw(self) -> lua_CFunction {
83 // SAFETY: CFunction and lua_CFunction are effectively the same.
84 unsafe { mem::transmute(self) }
85 }
86}
87
88/// Simple wrapper that tells Lua how many values a [`CFunction`] is intending to return.
89///
90/// Without this wrapper, Lua would willingly attempt to return as many values as you say,
91/// which can easily go beyond the stack and result in undefined behavior.
92///
93/// This wrapper can only be (safely) created by [`LuaState`],
94/// which will check if the amount is valid before returning the `AmountReturned` (see [`LuaState::return_any`]).
95#[repr(transparent)]
96#[derive(Debug)]
97#[must_use = "this `AmountReturned` should be returned to the caller"]
98pub struct AmountReturned(core::ffi::c_int);
99
100impl AmountReturned {
101 /// Tells Lua that no values are intended to be returned.
102 ///
103 /// Always safe to use since nothing gets popped.
104 pub const NONE: Self = Self(0);
105
106 /// Wraps `amount` around an `AmountReturned`, without doing any checks.
107 ///
108 /// # Safety
109 ///
110 /// `amount` must not be higher than the amount of values the Lua stack is holding at the time of returning.
111 pub const unsafe fn unchecked(amount: i32) -> Self {
112 Self(amount)
113 }
114}
115
116/// Trait for all closures and functions that can be used with [`LuaState::dump`].
117///
118/// See [`LuaState::dump`] for more information.
119pub trait Writer: FnMut(&LuaState, &[u8]) -> Result<(), NonZeroI32> {}
120impl<T: FnMut(&LuaState, &[u8]) -> Result<(), NonZeroI32>> Writer for T {}
121
122/*/// Trait for all closures and functions that can be used with [`LuaState::load`].
123///
124/// See [`LuaState::load`] for more information.
125pub trait Reader<T: AsRef<[u8]>>: FnMut(&mut LuaState) -> Option<T> {}
126impl<T: AsRef<[u8]>, U: FnMut(&mut LuaState) -> Option<T>> Reader<T> for U {}*/
127
128/// All error codes that a function may return when erroring while called in protected mode.
129///
130/// This enum is used by the following functions:
131/// - [`LuaState::pcall`].
132/// - [`LuaState::cpcall`].
133#[repr(i32)]
134#[derive(Debug)]
135pub enum PCallError {
136 /// Any error during runtime.
137 RuntimeError = ffi::LUA_ERRRUN,
138
139 /// Memory allocation error (rare).
140 ///
141 /// *([`LuaState::pcall`] will not call the error handler for these errors.)*
142 MemoryError = ffi::LUA_ERRMEM,
143
144 /// Error while calling the error handler.
145 ErrorHandlerError = ffi::LUA_ERRERR,
146}
147
148impl Display for PCallError {
149 #[inline]
150 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
151 f.write_str(match self {
152 Self::RuntimeError => "runtime error",
153 Self::MemoryError => "memory allocation error",
154 Self::ErrorHandlerError => "error within error handler",
155 })
156 }
157}
158
159impl Error for PCallError {}
160
161impl PCallError {
162 /// Converts the given `value` into a `Result`.
163 ///
164 /// # Safety
165 ///
166 /// `value` must either be `0` or a valid `PCallError` value.
167 ///
168 /// # Errors
169 ///
170 /// Returns `Err` if `value` is not `0`.
171 #[inline]
172 pub const unsafe fn check_raw(value: i32) -> Result<(), Self> {
173 // SAFETY: The caller must only give 0 or a valid error code.
174 if value == 0 { Ok(()) } else { Err(unsafe { mem::transmute::<i32, PCallError>(value) }) }
175 }
176}
177
178/// All error codes that may be returned when failing to load a chunk.
179///
180/// This enum is used by the following functions:
181/// - [`LuaState::load_bytes`].
182/// - [`LuaState::load_cstring`].
183/// - [`LuaState::load_file`].
184#[repr(i32)]
185#[derive(Debug)]
186pub enum LoadError {
187 /// Syntax error during pre-compilation.
188 SyntaxError = ffi::LUA_ERRSYNTAX,
189
190 /// Memory allocation error (rare).
191 MemoryError = ffi::LUA_ERRMEM,
192
193 /// *(Only returned by [`LuaState::load_file`].)*
194 FileError = ffi::LUA_ERRFILE,
195}
196
197impl Display for LoadError {
198 #[inline]
199 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
200 f.write_str(match self {
201 Self::SyntaxError => "syntax error",
202 Self::MemoryError => "memory allocation error",
203 Self::FileError => "file error",
204 })
205 }
206}
207
208impl Error for LoadError {}
209
210impl LoadError {
211 /// Converts the given `value` into a `Result`.
212 ///
213 /// # Safety
214 ///
215 /// `value` must either be `0` or a valid `LoadError` value.
216 ///
217 /// # Errors
218 ///
219 /// Returns `Err` if `value` is not `0`.
220 #[inline]
221 pub const unsafe fn check_raw(value: i32) -> Result<(), Self> {
222 // SAFETY: The caller must only give 0 or a valid error code.
223 if value == 0 { Ok(()) } else { Err(unsafe { mem::transmute::<i32, LoadError>(value) }) }
224 }
225}
226
227/// Function related functions.
228impl LuaState {
229 /// Finishes the currently called [`CFunction`], returning the last `amount` elements that were pushed to the stack to the caller.
230 ///
231 /// The `LuaState` wrapper is consumed to prevent invalidating the `AmountReturned` (the Lua state itself is left intact).
232 ///
233 /// # Panics
234 ///
235 /// Panics if `amount` is negative or higher than the amount of elements currently held in the stack (see [`LuaState::get_top`]).
236 ///
237 /// # Examples
238 ///
239 /// ```
240 /// use low_luajit::{LuaState, AmountReturned};
241 ///
242 /// extern "C-unwind" fn example(mut lua: LuaState) -> AmountReturned {
243 /// lua.push_number(12.3); // First value returned.
244 /// lua.push_string("abc"); // Second value returned.
245 /// lua.return_any(2)
246 /// }
247 ///
248 /// # let mut lua = unsafe { low_luajit::__test!() };
249 /// lua.push_cfunction(example);
250 /// lua.call(0, 2);
251 /// assert_eq!(lua.to_number(1), 12.3);
252 /// assert_eq!(lua.to_string(2), Some("abc"));
253 /// ```
254 #[inline]
255 pub fn return_any(self, amount: i32) -> AmountReturned {
256 assert!(amount >= 0, "cannot return a negative amount of values");
257 assert!(amount <= self.get_top(), "tried to return {amount} values but the stack currently holds {} values", self.get_top());
258
259 // SAFETY: amount should not be higher than the amount of values currently present in the stack.
260 unsafe { AmountReturned::unchecked(amount) }
261 }
262
263 /// Returns `true` if the value at the given acceptable `index` is a function (either [`CFunction`] or Lua function), `false` otherwise.
264 #[inline]
265 #[must_use]
266 pub fn is_function(&self, index: i32) -> bool {
267 // SAFETY: self.as_ptr() is always valid.
268 unsafe { ffi::lua_isfunction(self.as_ptr(), index) != 0 }
269 }
270
271 /// Returns `true` if the value at the given acceptable `index` is a [`CFunction`], `false` otherwise.
272 #[inline]
273 #[must_use]
274 pub fn is_cfunction(&self, index: i32) -> bool {
275 // SAFETY: self.as_ptr() is always valid.
276 unsafe { ffi::lua_iscfunction(self.as_ptr(), index) != 0 }
277 }
278
279 /// Returns `true` if the value at the given acceptable `index` is a Lua function, `false` otherwise.
280 #[inline]
281 #[must_use]
282 pub fn is_lua_function(&self, index: i32) -> bool {
283 self.is_function(index) && !self.is_cfunction(index)
284 }
285
286 /// Returns the [`lua_CFunction`] at the given `index`, or `None` if the value is anything else.
287 ///
288 /// [`lua_CFunction`] is returned instead of [`CFunction`] as this function cannot determine its safety.
289 /// Additionally, this function may sometimes return `None` for some C functions even if [`LuaState::is_cfunction`] returns `true`.
290 ///
291 /// If you just want to call a function, you probably want to use [`LuaState::call`], [`LuaState::pcall`], or [`LuaState::cpcall`] instead.
292 ///
293 /// # Examples
294 ///
295 /// ```
296 /// # use low_luajit::{LuaState, AmountReturned};
297 /// # extern "C-unwind" fn example(lua: LuaState) -> AmountReturned {
298 /// let f = lua.to_cfunction(-1).unwrap();
299 /// // SAFETY: This function is safe to call.
300 /// unsafe { f(lua.as_ptr()) };
301 /// # AmountReturned::NONE }
302 /// ```
303 #[inline]
304 #[must_use]
305 pub fn to_cfunction(&self, index: i32) -> Option<lua_CFunction> {
306 // SAFETY: self.as_ptr() is always valid.
307 unsafe { ffi::lua_tocfunction(self.as_ptr(), index) }
308 }
309
310 /// Pushes the given [`CFunction`] `func` onto the stack.
311 ///
312 /// To associate values with `func`, see [`LuaState::push_cclosure`].
313 #[inline]
314 pub fn push_cfunction(&mut self, func: CFunction) {
315 // SAFETY: self.as_ptr() and transmuting from CFunction to lua_CFunction are always valid.
316 unsafe { ffi::lua_pushcfunction(self.as_ptr(), func.to_raw()); }
317 }
318
319 /// Pushes the given [`CFunction`] `func` onto the stack, while also associating `n` values to it (called upvalues).
320 ///
321 /// To associate values with `func`, simply push said values before calling this function;
322 /// they will be popped but will be accessible from within `func` at the pseudo-indices returned by [`LuaState::upvalue_index`].
323 ///
324 /// If `n` is `0` this function will behave exactly as [`LuaState::push_cfunction`].
325 ///
326 /// # Panics
327 ///
328 /// Panics if the stack currently contains less than `n` values.
329 #[inline]
330 pub fn push_cclosure(&mut self, func: CFunction, n: u8) {
331 assert!(i32::from(n) <= self.get_top(), "tried to push a `CFunction` with {n} upvalues but the stack currently holds {} values", self.get_top());
332
333 // SAFETY: self.as_ptr() is always valid, the raw version of func is safe to call by Lua, and the stack contains enough values to pop.
334 unsafe { ffi::lua_pushcclosure(self.as_ptr(), func.to_raw(), i32::from(n)); }
335 }
336
337 /// Sets the given [`CFunction`] `func` as a global named `name`.
338 ///
339 /// # Lua Errors
340 ///
341 /// Indexing the global environment may trigger the `__newindex` metamethod which could error.
342 #[inline]
343 pub fn register_cfunction(&mut self, name: &CStr, func: CFunction) {
344 // SAFETY: self.as_ptr() and name's pointer are always valid, and the raw version of func is safe to call by Lua.
345 unsafe { ffi::lua_register(self.as_ptr(), name.as_ptr(), func.to_raw()); }
346 }
347
348 /// When passed as the number of expected results for the called functions in [`LuaState::call`] or [`LuaState::pcall`],
349 /// it will tell Lua to push to the stack exactly as many values as the called function returned.
350 pub const MULTI_RETURN: i32 = ffi::LUA_MULTRET;
351
352 /// Calls a function.
353 ///
354 /// To properly call a function, follow these steps:
355 /// 1. Push the function onto the stack.
356 /// 2. Push the arguments of the function (as many as `n_args`), pushing the first arg first and so on.
357 /// 3. Call this function, which will pop the function and arguments and push the results (as many as `n_results`) in the same order.
358 ///
359 /// If `n_results` is [`LuaState::MULTI_RETURN`] (`-1`), all the results from the function are pushed to the stack.
360 /// If `n_results` is higher than the amount of values returned by the function, additional `nil`s will be pushed to compensate.
361 ///
362 /// # Panics
363 ///
364 /// Panics if the stack does not contain the function itself and its arguments.
365 ///
366 /// # Lua Errors
367 ///
368 /// The called function itself may error, to catch any error consider using [`LuaState::pcall`] or [`LuaState::cpcall`] instead.
369 ///
370 /// Additionally, this function will error if the first element popped (the function to call) is not a function.
371 #[inline]
372 pub fn call(&mut self, n_args: i32, n_results: i32) {
373 let top = self.get_top();
374 assert!(top > 0, "tried to call a function despite having an empty stack");
375 assert!(n_args < top, "cannot pass {n_args} arguments to the called function, as there are only {top} elements");
376
377 // SAFETY: self.as_ptr() is always valid and the stack contains enough values to pop.
378 unsafe { ffi::lua_call(self.as_ptr(), n_args, n_results); }
379 }
380
381 /// Calls a function in protected mode.
382 ///
383 /// See [`LuaState::call`] for how to properly call a function.
384 ///
385 /// If the called function does not error, this function behaves exactly like [`LuaState::call`].
386 ///
387 /// `error_func` should either be `0` or the index to an error handler function,
388 /// which will be called on error and its returned value will be treated as the error object instead of the original error message.
389 /// *(Pesudo-indices cannot be used for `error_func`.)*
390 ///
391 /// # Panics
392 ///
393 /// Panics if the stack does not contain the function itself and its arguments.
394 ///
395 /// # Errors
396 ///
397 /// If the called function triggers a Lua error,
398 /// `Err` will be returned with the appropriate [`PCallError`] and the error object is pushed onto of the stack.
399 ///
400 /// Additionally, this function will error if the first element popped (the function to call)
401 /// or the element at index `error_func` are not functions.
402 #[inline]
403 pub fn pcall(&mut self, n_args: i32, n_results: i32, error_func: i32) -> Result<(), PCallError> {
404 let top = self.get_top();
405 assert!(top > 0, "tried to pcall a function despite having an empty stack");
406 assert!(n_args < top, "cannot pass {n_args} arguments to the pcalled function, as there are only {top} elements");
407
408 // SAFETY: self.as_ptr() is always valid, the stack contains enough values to pop, and the returned value is either 0 or a valid PCallError.
409 unsafe { PCallError::check_raw(ffi::lua_pcall(self.as_ptr(), n_args, n_results, error_func)) }
410 }
411
412 /// Calls the function `func` in protected mode with a single argument: a light userdata containing `ud`.
413 ///
414 /// Any value returned by `func` will be discarded (the stack is not changed).
415 ///
416 /// # Errors
417 ///
418 /// If `func` triggers a Lua error,
419 /// `Err` will be returned with the appropriate [`PCallError`] and the error object is pushed onto of the stack.
420 #[inline]
421 pub fn cpcall<T>(&mut self, func: CFunction, ud: *mut T) -> Result<(), PCallError> {
422 // SAFETY: self.as_ptr() is always valid, func is safe to call, ud is only stored and the returned value is either 0 or a valid PCallError.
423 unsafe { PCallError::check_raw(ffi::lua_cpcall(self.as_ptr(), func.to_raw(), ud.cast())) }
424 }
425
426 /// Dumps the Lua function at the top of the stack as a binary chunk ([`CFunction`]s cannot be dumped).
427 ///
428 /// Dumping is done by sending fragments of the chunk to the `writer` function, which should combine them together into the full chunk.
429 ///
430 /// If an error happens during dumping, `Err` is returned with any non-zero number.
431 ///
432 /// Reloading the chunk results in a function equivalent to the one originally dumped (see [`LuaState::load_bytes`]).
433 ///
434 /// # Errors
435 ///
436 /// If the top element is not a Lua function (or the stack is empty), this function will error returning `1`.
437 ///
438 /// `writer` may error and return any other non-zero number (`1` included), based on its implementation.
439 ///
440 /// # Examples
441 ///
442 /// ```
443 /// # use low_luajit::{LuaState, AmountReturned};
444 /// # extern "C-unwind" fn example(lua: LuaState) -> AmountReturned {
445 /// if lua.is_lua_function(-1) {
446 /// let mut chunk = Vec::new();
447 /// lua.dump(|_, fragment| {
448 /// chunk.extend_from_slice(fragment);
449 /// Ok(())
450 /// }).expect("the given writer never errors");
451 /// // Use the chunk in some way...
452 /// }
453 /// # AmountReturned::NONE }
454 /// ```
455 #[inline]
456 pub fn dump<F: Writer>(&self, mut writer: F) -> Result<(), NonZeroI32> {
457 unsafe extern "C-unwind" fn middleware<F: Writer>(lua: *mut lua_State, ptr: *const c_void, size: usize, writer: *mut c_void) -> c_int {
458 // SAFETY: writer should be a valid pointer to the writer of the upper function, the lua_State should always be valid,
459 // ptr should be non-null and valid for size amount of values, and Result<(), NonZeroI32> can be transmuted to i32.
460 unsafe { mem::transmute((&mut *writer.cast::<F>())(&LuaState::from_ptr(lua), slice::from_raw_parts(ptr.cast(), size))) }
461 }
462
463 // SAFETY: self.as_ptr() is always valid, lua_dump calls middleware properly, and i32 can be transmuted to Result<(), NonZeroI32>.
464 unsafe { mem::transmute(ffi::lua_dump(self.as_ptr(), middleware::<F>, (&raw mut writer).cast())) }
465 }
466
467 /// Loads the given `bytes` as a Lua chunk named `chunk_name`, pushing the resulting function onto the stack (if successful).
468 ///
469 /// *(The resulting function is only pushed, not called.)*
470 ///
471 /// While `chunk_name` can be any value, there are some common naming conventions:
472 /// - If the name is the path to a file, it should be prefixed with `'@'`. *([`LuaState::load_file`] does this.)*
473 /// - If the name is a custom identifier for the function, it should be prefixed with `'='`. *(All [`CFunction`]s are named `"=[C]"`.)*
474 /// - Anything else will be interpreted as if being the function's source itself. *([`LuaState::load_cstring`] does this.)*
475 ///
476 /// # Errors
477 ///
478 /// If unable to load the given `bytes`,
479 /// `Err` will be returned with the appropriate [`LoadError`] and the error message is pushed onto the stack.
480 #[inline]
481 pub fn load_bytes(&mut self, bytes: &[u8], chunk_name: &CStr) -> Result<(), LoadError> {
482 // SAFETY: self.as_ptr(), bytes and chunk_name are always valid, u8 can be casted as c_char (they're both 1 byte),
483 // the length is correct as it's returned from the array itself, and the returned value is either 0 or a valid LoadError.
484 unsafe { LoadError::check_raw(ffi::luaL_loadbuffer(self.as_ptr(), bytes.as_ptr().cast(), bytes.len(), chunk_name.as_ptr())) }
485 }
486
487 /// Loads the given `cstring` as a Lua chunk, pushing the resulting function onto the stack (if successful).
488 ///
489 /// *(The resulting function is only pushed, not called.)*
490 ///
491 /// The chunk will be named after the given `cstring` itself.
492 ///
493 /// # Errors
494 ///
495 /// If unable to load the given `cstring`,
496 /// `Err` will be returned with the appropriate [`LoadError`] and the error message is pushed onto the stack.
497 #[inline]
498 pub fn load_cstring(&mut self, cstring: &CStr) -> Result<(), LoadError> {
499 // SAFETY: self.as_ptr() and cstring's pointer are always valid and the returned value is either 0 or a valid LoadError.
500 unsafe { LoadError::check_raw(ffi::luaL_loadstring(self.as_ptr(), cstring.as_ptr())) }
501 }
502
503 /// Attempts to open the file named `filename` and load it as a Lua chunk, pushing the resulting function onto the stack (if successful).
504 ///
505 /// *(The resulting function is only pushed, not called.)*
506 ///
507 /// The chunk will be named after the given `filename` itself.
508 ///
509 /// # Errors
510 ///
511 /// If unable to open the file or load its contents,
512 /// `Err` will be returned with the appropriate [`LoadError`] and the error message is pushed onto the stack.
513 #[inline]
514 pub fn load_file(&mut self, filename: &CStr) -> Result<(), LoadError> {
515 // SAFETY: self.as_ptr() and filename's pointer are always valid and the returned value is either 0 or a valid LoadError.
516 unsafe { LoadError::check_raw(ffi::luaL_loadfile(self.as_ptr(), filename.as_ptr())) }
517 }
518
519 /*#[inline] TODO: this doesn't work, also it might be over the top? maybe it should just accept the chunk as a simple variable?
520 pub fn load<T: AsRef<[u8]>, F: Reader<T>>(&mut self, mut reader: F, chunk_name: &CStr) {
521 unsafe extern "C-unwind" fn middleware<T: AsRef<[u8]>, F: Reader<T>>(lua: *mut lua_State, reader: *mut c_void, size: *mut usize) -> *const c_char {
522 unsafe { (&mut *reader.cast::<F>())(&mut LuaState::from_ptr(lua)).map_or(ptr::null(), |fragment| {
523 *size = fragment.as_ref().len();
524 (&raw const fragment).cast()
525 }) }
526 }
527
528 unsafe { ffi::lua_load(self.as_ptr(), middleware::<T, F>, (&raw mut reader).cast(), chunk_name.as_ptr()); }
529 }*/
530
531 /// Finishes the currently called [`CFunction`], returning the given `func` to the caller.
532 ///
533 /// The `LuaState` wrapper is consumed to prevent invalidating the `AmountReturned` (the Lua state itself is left intact).
534 #[inline]
535 pub fn return_cfunction(mut self, func: CFunction) -> AmountReturned {
536 self.push_cfunction(func);
537
538 // SAFETY: There should always be at least one element in the stack.
539 unsafe { AmountReturned::unchecked(1) }
540 }
541
542 /// Finishes the currently called [`CFunction`], returning the given `func` to the caller while also associating `n` values to it
543 /// (see [`LuaState::push_cclosure`]).
544 ///
545 /// The `LuaState` wrapper is consumed to prevent invalidating the `AmountReturned` (the Lua state itself is left intact).
546 ///
547 /// # Panics
548 ///
549 /// Panics if the stack currently contains less than `n` values.
550 #[inline]
551 pub fn return_cclosure(mut self, func: CFunction, n: u8) -> AmountReturned {
552 self.push_cclosure(func, n);
553
554 // SAFETY: There should always be at least one element in the stack.
555 unsafe { AmountReturned::unchecked(1) }
556 }
557
558 /// If `condition` is `false`, [`LuaState::arg_error`] is called using `arg_n` and `extra_msg`.
559 /// Otherwise nothing happens.
560 ///
561 /// # Lua Errors
562 ///
563 /// Intentionally errors if `condition` is `false`.
564 #[inline]
565 pub fn arg_check(&self, condition: bool, arg_n: i32, extra_msg: &CStr) {
566 if !condition {
567 self.arg_error(arg_n, extra_msg)
568 }
569 }
570}