1#![allow(dead_code)]
9
10#[allow(unused_imports)]
11use crate::prelude::*;
12use std::convert::Infallible;
13
14use crate::state::{
15 FinalizerObject, LuaCFunction, LuaCallable, LuaState, LuaTableRefExt, LuaTypeExt,
16 LuaUserDataRefExt, LuaValueExt, StackIdx, StackIdxExt, WeakTableEntry,
17};
18use lua_types::value::LuaTable;
19use lua_types::{
20 GcRef, LuaClosure, LuaError, LuaStatus, LuaString, LuaType, LuaUserData, LuaValue,
21};
22
23pub const LUA_IDENT: &[u8] = b"$LuaVersion: Lua 5.4.7 Copyright (C) 1994-2024 Lua.org, PUC-Rio $\
24 $LuaAuthors: R. Ierusalimschy, L. H. Figueiredo, W. Celes $";
25
26const LUA_REGISTRYINDEX: i32 = -(1_000_000) - 1000;
27
28const LUA_MULTRET: i32 = -1;
29
30const LUA_RIDX_GLOBALS: i64 = 2;
31
32const MAX_UPVAL: u8 = 255;
33
34#[inline]
35fn is_pseudo(idx: i32) -> bool {
36 idx <= LUA_REGISTRYINDEX
37}
38
39#[inline]
40fn is_upvalue(idx: i32) -> bool {
41 idx < LUA_REGISTRYINDEX
42}
43
44#[inline]
49fn is_valid_index(state: &LuaState, idx: i32) -> bool {
50 if idx == 0 {
51 return false;
52 }
53 let ci = state.current_call_info();
54 if idx > 0 {
55 let slot = ci.func + idx;
56 slot.0 < state.top_idx().0
57 } else if !is_pseudo(idx) {
58 (-idx) as u32 <= state.top_idx().0.saturating_sub(ci.func.0 + 1)
59 } else if idx == LUA_REGISTRYINDEX {
60 true
61 } else {
62 let upval_n = (LUA_REGISTRYINDEX - idx) as usize;
63 let func_val = state.get_at(ci.func);
64 if let LuaValue::Function(LuaClosure::C(ref ccl)) = func_val {
65 let upvalues = ccl.upvalues.borrow();
66 upval_n >= 1 && upval_n <= upvalues.len()
67 } else {
68 false
69 }
70 }
71}
72
73fn index_to_value(state: &LuaState, idx: i32) -> LuaValue {
78 let ci = state.current_call_info();
79 if idx > 0 {
80 let func_idx = ci.func;
81 let slot = func_idx + idx;
82 debug_assert!(
83 idx as u32 <= ci.top.saturating_sub(func_idx + 1),
84 "unacceptable index"
85 );
86 if slot.0 >= state.top_idx().0 {
87 LuaValue::Nil
88 } else {
89 state.get_at(slot)
90 }
91 } else if !is_pseudo(idx) {
92 debug_assert!(idx != 0, "invalid index");
94 let top = state.top_idx();
95 let slot = (top.0 as i32 + idx) as u32;
96 state.get_at(slot)
97 } else if idx == LUA_REGISTRYINDEX {
98 state.registry_value()
99 } else {
100 let upval_n = (LUA_REGISTRYINDEX - idx) as usize;
102 debug_assert!(upval_n <= MAX_UPVAL as usize + 1, "upvalue index too large");
103 let func_val = state.get_at(ci.func);
104 if let LuaValue::Function(LuaClosure::C(ref ccl)) = func_val {
105 let upvalues = ccl.upvalues.borrow();
107 if upval_n >= 1 && upval_n <= upvalues.len() {
108 upvalues[upval_n - 1].clone()
109 } else {
110 LuaValue::Nil
111 }
112 } else {
113 LuaValue::Nil
114 }
115 }
116}
117
118#[inline(always)]
125pub fn positive_index_value(state: &LuaState, idx: i32) -> LuaValue {
126 debug_assert!(idx > 0, "positive_index_value requires a positive index");
127 let ci = state.current_call_info();
128 let func_idx = ci.func;
129 let slot = func_idx + idx;
130 debug_assert!(
131 idx as u32 <= ci.top.saturating_sub(func_idx + 1),
132 "unacceptable index"
133 );
134 if slot.0 >= state.top_idx().0 {
135 LuaValue::Nil
136 } else {
137 state.get_at(slot)
138 }
139}
140
141#[inline]
143fn index_to_stack_idx(state: &LuaState, idx: i32) -> StackIdx {
144 let ci = state.current_call_info();
145 if idx > 0 {
146 let slot = ci.func + idx;
147 debug_assert!(slot.0 < state.top_idx().0, "invalid index");
148 slot
149 } else {
150 debug_assert!(idx != 0 && !is_pseudo(idx), "invalid index");
151 StackIdx((state.top_idx().0 as i32 + idx) as u32)
152 }
153}
154
155pub fn check_stack(state: &mut LuaState, n: i32) -> bool {
158 debug_assert!(n >= 0, "negative 'n'");
159 let available = state.stack_available();
160 let res = if available > n as usize {
161 true
162 } else {
163 crate::do_::grow_stack(state, n, false).unwrap_or(false)
164 };
165 if res {
166 let needed_top = state.top_idx() + n as i32;
167 let ci_idx = state.current_ci_idx();
168 if state.get_ci(ci_idx).top.0 < needed_top.0 {
169 let live_top = state.top_idx();
170 state.get_ci_mut(ci_idx).top = needed_top;
171 state.clear_stack_range(live_top, needed_top);
172 }
173 }
174 res
175}
176
177pub fn xmove(from: &mut LuaState, to: &mut LuaState, n: i32) {
194 if n <= 0 {
195 return;
196 }
197 if std::ptr::eq(from as *const LuaState, to as *const LuaState) {
198 return;
199 }
200 let abs_top = from.top_idx().0 as i32;
201 debug_assert!(abs_top >= n, "lua_xmove: from stack underflow");
202 let first_abs = abs_top - n;
203 let mut buf: Vec<lua_types::LuaValue> = Vec::with_capacity(n as usize);
204 for i in 0..n {
205 let idx = StackIdx((first_abs + i) as u32);
206 buf.push(from.get_at(idx));
207 }
208 from.set_top(StackIdx(first_abs as u32));
209 for v in buf {
210 to.push(v);
211 }
212}
213
214pub fn at_panic(
215 state: &mut LuaState,
216 panicf: Option<fn(&mut LuaState) -> Result<usize, LuaError>>,
217) -> Option<fn(&mut LuaState) -> Result<usize, LuaError>> {
218 let old = state.global_mut().panic;
219 state.global_mut().panic = panicf;
220 old
221}
222
223pub fn version(_state: &LuaState) -> f64 {
224 504.0
225}
226
227pub fn abs_index(state: &LuaState, idx: i32) -> i32 {
228 if idx > 0 || is_pseudo(idx) {
230 idx
231 } else {
232 let ci = state.current_call_info();
233 (state.top_idx().0 as i32 - ci.func.0 as i32) + idx
234 }
235}
236
237pub fn get_top(state: &LuaState) -> i32 {
238 let ci = state.current_call_info();
239 (state.top_idx().0 as i32) - (ci.func.0 as i32 + 1)
240}
241
242pub fn set_top(state: &mut LuaState, idx: i32) -> Result<(), LuaError> {
243 let func = state.current_call_info().func;
244 let ci_top = state.current_call_info().top;
245 if idx >= 0 {
246 debug_assert!(
247 idx as u32 <= ci_top.saturating_sub(func + 1),
248 "new top too large"
249 );
250 let new_top = func + 1 + idx as i32;
251 let old_top = state.top_idx();
252 if new_top.0 > old_top.0 {
253 for i in old_top.0..new_top.0 {
254 state.set_at(i, LuaValue::Nil);
255 }
256 }
257 state.set_top_idx(new_top);
260 } else {
261 debug_assert!(
262 -(idx + 1) <= (state.top_idx().0 as i32 - (func.0 as i32 + 1)),
263 "invalid new top"
264 );
265 let new_top = (state.top_idx().0 as i32 + idx + 1) as u32;
266 state.set_top_idx(new_top);
268 }
269 Ok(())
270}
271
272pub fn close_slot(state: &mut LuaState, idx: i32) -> Result<(), LuaError> {
273 let level = index_to_stack_idx(state, idx);
274 state.set_at(level, LuaValue::Nil);
276 Ok(())
277}
278
279#[inline]
280fn reverse_segment(state: &mut LuaState, from: StackIdx, to: StackIdx) {
281 let mut lo = from.0;
282 let mut hi = to.0;
283 while lo < hi {
284 let temp = state.get_at(StackIdx(lo));
285 let hi_val = state.get_at(StackIdx(hi));
286 state.set_at(StackIdx(lo), hi_val);
287 state.set_at(StackIdx(hi), temp);
288 lo += 1;
289 hi -= 1;
290 }
291}
292
293pub fn rotate(state: &mut LuaState, idx: i32, n: i32) {
294 let t = state.top_idx() - 1;
295 let p = index_to_stack_idx(state, idx);
296 debug_assert!(
297 (n.unsigned_abs() as i32) <= ((t.0 as i32) - (p.0 as i32) + 1),
298 "invalid 'n'"
299 );
300 let m = if n >= 0 {
301 t - n
302 } else {
303 StackIdx((p.0 as i32 - n - 1) as u32)
304 };
305 reverse_segment(state, p, m);
306 reverse_segment(state, m + 1, t);
307 reverse_segment(state, p, t);
308}
309
310pub fn copy(state: &mut LuaState, fromidx: i32, toidx: i32) {
311 let fr = index_to_value(state, fromidx);
312 if is_upvalue(toidx) {
313 let upval_n = (LUA_REGISTRYINDEX - toidx) as usize;
315 let func_val = state.get_at(state.current_call_info().func);
316 if let LuaValue::Function(LuaClosure::C(ref ccl)) = func_val {
317 let wrote = {
318 let mut upvalues = ccl.upvalues.borrow_mut();
319 if upval_n >= 1 && upval_n <= upvalues.len() {
320 upvalues[upval_n - 1] = fr.clone();
321 true
322 } else {
323 false
324 }
325 };
326 if wrote {
327 state.gc().barrier(ccl, &fr);
328 }
329 }
330 } else if toidx == LUA_REGISTRYINDEX {
331 } else {
333 let to_slot = index_to_stack_idx(state, toidx);
334 state.set_at(to_slot, fr);
335 }
336}
337
338pub fn push_value(state: &mut LuaState, idx: i32) {
339 let v = index_to_value(state, idx);
340 state.push(v);
341}
342
343impl LuaState {
348 pub fn push_copy(&mut self, idx: i32) -> Result<(), LuaError> {
349 push_value(self, idx);
350 Ok(())
351 }
352
353 pub fn push_value_at(&mut self, idx: i32) -> Result<(), LuaError> {
354 push_value(self, idx);
355 Ok(())
356 }
357
358 pub fn insert(&mut self, idx: i32) -> Result<(), LuaError> {
359 rotate(self, idx, 1);
360 Ok(())
361 }
362
363 pub fn length_at(&mut self, idx: i32) -> Result<i64, LuaError> {
369 len(self, idx)?;
370 let l = match to_integer_x(self, -1) {
371 Some(n) => n,
372 None => {
373 return Err(LuaError::runtime(format_args!(
374 "object length is not an integer"
375 )));
376 }
377 };
378 self.pop_n(1);
379 Ok(l)
380 }
381
382 pub fn write_output(&mut self, msg: &[u8]) -> Result<(), LuaError> {
389 if let Some(write_fn) = self.global().stdout_hook {
390 write_fn(msg).map_err(|e| LuaError::runtime(format_args!("{}", e)))?;
391 return Ok(());
392 }
393
394 #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
395 {
396 let _ = msg;
397 Err(LuaError::runtime(format_args!(
398 "stdout not available in this host"
399 )))
400 }
401
402 #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
403 {
404 use std::io::Write;
405 let stdout = std::io::stdout();
406 let mut handle = stdout.lock();
407 handle
408 .write_all(msg)
409 .map_err(|e| LuaError::runtime(format_args!("{}", e)))?;
410 handle
411 .flush()
412 .map_err(|e| LuaError::runtime(format_args!("{}", e)))?;
413 Ok(())
414 }
415 }
416
417 pub fn to_display_string(&mut self, idx: i32) -> Result<Vec<u8>, LuaError> {
426 let abs = abs_index(self, idx);
427 let v = index_to_value(self, abs);
428 let mt: Option<GcRef<LuaTable>> = match &v {
429 LuaValue::Table(t) => t.metatable(),
430 LuaValue::UserData(u) => u.metatable(),
431 _ => self.global().mt[v.base_type() as usize].clone(),
432 };
433 if let Some(mt_ref) = mt {
434 let key = self.intern_str(b"__tostring")?;
435 let f = mt_ref.get_short_str(&key);
436 if !matches!(f, LuaValue::Nil) {
437 let func_idx = self.top_idx();
438 self.push(f);
439 self.push(v.clone());
440 if self.current_ci().is_lua_code() {
441 self.do_call(func_idx, 1)?;
442 } else {
443 self.do_call_no_yield(func_idx, 1)?;
444 }
445 let top = self.top_idx();
446 let result = self.get_at(StackIdx(top.0 - 1));
447 if let LuaValue::Str(s) = result {
448 return Ok(s.as_bytes().to_vec());
449 }
450 return Err(LuaError::runtime(format_args!(
451 "'__tostring' must return a string"
452 )));
453 }
454 }
455 let bytes: Vec<u8> = match &v {
456 LuaValue::Str(s) => {
457 let out = s.as_bytes().to_vec();
458 self.push(LuaValue::Str(s.clone()));
459 out
460 }
461 LuaValue::Int(_) | LuaValue::Float(_) => {
462 let s = crate::object::num_to_string(self, &v)?;
463 let out = s.as_bytes().to_vec();
464 self.push(LuaValue::Str(s));
465 out
466 }
467 LuaValue::Bool(b) => {
468 let lit: &[u8] = if *b { b"true" } else { b"false" };
469 let s = self.intern_str(lit)?;
470 self.push(LuaValue::Str(s));
471 lit.to_vec()
472 }
473 LuaValue::Nil => {
474 let s = self.intern_str(b"nil")?;
475 self.push(LuaValue::Str(s));
476 b"nil".to_vec()
477 }
478 _ => {
479 let kind = crate::tagmethods::obj_type_name(self, &v)?;
480 let ptr = to_pointer(self, abs).unwrap_or(0);
481 let mut buf = kind;
482 buf.extend_from_slice(b": 0x");
483 buf.extend_from_slice(format!("{:x}", ptr).as_bytes());
484 let s = self.intern_str(&buf)?;
485 self.push(LuaValue::Str(s));
486 buf
487 }
488 };
489 Ok(bytes)
490 }
491
492 pub fn top(&mut self) -> i32 {
499 get_top(self)
500 }
501
502 pub fn get_top(&mut self) -> i32 {
506 get_top(self)
507 }
508
509 pub fn type_at(&mut self, idx: i32) -> LuaType {
514 lua_type_at(self, idx)
515 }
516
517 pub fn check_arg_any(&mut self, arg: i32) -> Result<(), LuaError> {
523 if lua_type_at(self, arg) == LuaType::None {
524 return Err(LuaError::arg_error(arg, "value expected"));
525 }
526 Ok(())
527 }
528
529 pub fn check_arg_string(&mut self, arg: i32) -> Result<Vec<u8>, LuaError> {
539 match to_lua_string(self, arg)? {
540 Some(s) => Ok(s.as_bytes().to_vec()),
541 None => {
542 let got = index_to_value(self, arg);
543 let got_name = if lua_type_at(self, arg) == LuaType::None {
544 b"no value".to_vec()
545 } else {
546 crate::tagmethods::obj_type_name(self, &got)?
547 };
548 let extramsg = format!(
549 "string expected, got {}",
550 String::from_utf8_lossy(&got_name)
551 );
552 Err(crate::debug::arg_error_impl(self, arg, extramsg.as_bytes()))
553 }
554 }
555 }
556
557 pub fn check_arg_integer(&mut self, arg: i32) -> Result<i64, LuaError> {
569 match to_integer_x(self, arg) {
570 Some(d) => Ok(d),
571 None => {
572 if is_number(self, arg) {
573 Err(crate::debug::arg_error_impl(
574 self,
575 arg,
576 b"number has no integer representation",
577 ))
578 } else {
579 let got = index_to_value(self, arg);
580 let got_name = if lua_type_at(self, arg) == LuaType::None {
581 b"no value".to_vec()
582 } else {
583 crate::tagmethods::obj_type_name(self, &got)?
584 };
585 let extramsg = format!(
586 "number expected, got {}",
587 String::from_utf8_lossy(&got_name)
588 );
589 Err(crate::debug::arg_error_impl(self, arg, extramsg.as_bytes()))
590 }
591 }
592 }
593 }
594
595 pub fn check_number(&mut self, arg: i32) -> Result<f64, LuaError> {
605 match to_number_x(self, arg) {
606 Some(d) => Ok(d),
607 None => {
608 let got = index_to_value(self, arg);
609 let got_name = if lua_type_at(self, arg) == LuaType::None {
610 b"no value".to_vec()
611 } else {
612 crate::tagmethods::obj_type_name(self, &got)?
613 };
614 let extramsg = format!(
615 "number expected, got {}",
616 String::from_utf8_lossy(&got_name)
617 );
618 Err(crate::debug::arg_error_impl(self, arg, extramsg.as_bytes()))
619 }
620 }
621 }
622
623 pub fn opt_arg_integer(&mut self, arg: i32, def: i64) -> Result<i64, LuaError> {
633 match lua_type_at(self, arg) {
634 LuaType::None | LuaType::Nil => Ok(def),
635 _ => match to_integer_x(self, arg) {
636 Some(d) => Ok(d),
637 None => {
638 if is_number(self, arg) {
639 Err(LuaError::arg_error(
640 arg,
641 "number has no integer representation",
642 ))
643 } else {
644 let got = index_to_value(self, arg);
645 Err(LuaError::type_arg_error(arg, "number", &got))
646 }
647 }
648 },
649 }
650 }
651
652 pub fn protected_call(&mut self, nargs: i32, nresults: i32, msgh: i32) -> Result<(), LuaError> {
659 pcall_k(self, nargs, nresults, msgh, 0, None).map(|_| ())
660 }
661
662 pub fn protected_call_k(
666 &mut self,
667 nargs: i32,
668 nresults: i32,
669 msgh: i32,
670 ctx: isize,
671 k: Option<crate::state::LuaKFunction>,
672 ) -> Result<(), LuaError> {
673 pcall_k(self, nargs, nresults, msgh, ctx, k).map(|_| ())
674 }
675
676 pub fn push_string(&mut self, s: &[u8]) -> Result<(), LuaError> {
677 push_lstring(self, s)?;
678 Ok(())
679 }
680
681 pub fn push_c_closure(
682 &mut self,
683 f: fn(&mut LuaState) -> Result<usize, LuaError>,
684 n: i32,
685 ) -> Result<(), LuaError> {
686 push_cclosure(self, f, n)
687 }
688
689 pub fn raw_seti(&mut self, idx: i32, n: i64) -> Result<(), LuaError> {
690 raw_set_i(self, idx, n)
691 }
692
693 pub fn table_set_i(&mut self, idx: i32, n: i64) -> Result<(), LuaError> {
694 set_i(self, idx, n)
695 }
696
697 pub fn table_get_i_value(&mut self, t: &LuaValue, n: i64) -> Result<LuaType, LuaError> {
701 get_i_value(self, t, n)
702 }
703
704 pub fn table_set_i_value(&mut self, t: &LuaValue, n: i64) -> Result<(), LuaError> {
708 set_i_value(self, t, n)
709 }
710
711 pub fn create_table(&mut self, narr: i32, nrec: i32) -> Result<(), LuaError> {
712 create_table(self, narr, nrec)
713 }
714
715 pub fn registry_set(&mut self, key: &[u8]) -> Result<(), LuaError> {
719 set_field(self, LUA_REGISTRYINDEX, key)
720 }
721
722 pub fn new_metatable(&mut self, tname: &[u8]) -> Result<bool, LuaError> {
728 if get_field(self, LUA_REGISTRYINDEX, tname)? != LuaType::Nil {
729 return Ok(false);
730 }
731 self.pop_n(1);
732 create_table(self, 0, 2)?;
733 push_lstring(self, tname)?;
734 set_field(self, -2, b"__name")?;
735 push_value(self, -1);
736 set_field(self, LUA_REGISTRYINDEX, tname)?;
737 Ok(true)
738 }
739
740 pub fn new_lib(&mut self, funcs: &[(&[u8], LuaCFunction)]) -> Result<(), LuaError> {
747 create_table(self, 0, funcs.len() as i32)?;
748 for (name, f) in funcs {
749 push_cclosure(self, *f, 0)?;
750 set_field(self, -2, name)?;
751 }
752 Ok(())
753 }
754
755 pub fn register_lib(
761 &mut self,
762 _name: &[u8],
763 funcs: &[(&[u8], LuaCFunction)],
764 ) -> Result<(), LuaError> {
765 self.new_lib(funcs)
766 }
767
768 pub fn new_lib_table(&mut self, funcs: &[(&[u8], LuaCFunction)]) -> Result<(), LuaError> {
777 create_table(self, 0, funcs.len() as i32)
778 }
779
780 pub fn set_funcs_with_upvalues(
785 &mut self,
786 funcs: &[(&[u8], LuaCFunction)],
787 nup: i32,
788 ) -> Result<(), LuaError> {
789 check_stack(self, nup);
790 for (name, f) in funcs {
791 for _ in 0..nup {
792 push_value(self, -nup);
793 }
794 push_cclosure(self, *f, nup)?;
795 set_field(self, -(nup + 2), name)?;
796 }
797 self.pop_n(nup as usize);
798 Ok(())
799 }
800
801 pub fn set_metatable(&mut self, objindex: i32) -> Result<(), LuaError> {
802 set_metatable(self, objindex)?;
803 Ok(())
804 }
805
806 pub fn set_metatable_by_name(&mut self, name: &[u8]) -> Result<(), LuaError> {
812 get_field(self, LUA_REGISTRYINDEX, name)?;
813 set_metatable(self, -2)?;
814 Ok(())
815 }
816
817 pub fn get_subtable_registry(&mut self, name: &[u8]) -> Result<bool, LuaError> {
821 if get_field(self, LUA_REGISTRYINDEX, name)? == LuaType::Table {
822 return Ok(true);
823 }
824 self.pop_n(1);
825 let idx = abs_index(self, LUA_REGISTRYINDEX);
826 let new_tbl = self.new_table();
827 self.push(LuaValue::Table(new_tbl));
828 push_value(self, -1);
829 set_field(self, idx, name)?;
830 Ok(false)
831 }
832
833 pub fn new_userdata_typed(
843 &mut self,
844 _name: &[u8],
845 size: usize,
846 nuvalue: i32,
847 ) -> Result<GcRef<LuaUserData>, LuaError> {
848 debug_assert!(nuvalue >= 0 && nuvalue < u16::MAX as i32, "invalid value");
849 let u = GcRef::new(LuaUserData {
851 data: vec![0u8; size].into_boxed_slice(),
852 uv: std::cell::RefCell::new(vec![LuaValue::Nil; nuvalue as usize]),
853 metatable: std::cell::RefCell::new(None),
854 host_value: std::cell::RefCell::new(None),
855 });
856 u.account_buffer(u.buffer_bytes() as isize);
857 self.push(LuaValue::UserData(u.clone()));
858 self.gc().check_step();
859 Ok(u)
860 }
861}
862
863pub fn lua_type_at(state: &LuaState, idx: i32) -> LuaType {
866 if !is_valid_index(state, idx) {
867 return LuaType::None;
868 }
869 index_to_value(state, idx).base_type()
870}
871
872pub fn type_name(_state: &LuaState, t: LuaType) -> &'static [u8] {
873 t.type_name()
874}
875
876pub fn is_cfunction(state: &LuaState, idx: i32) -> bool {
877 let o = index_to_value(state, idx);
878 matches!(
879 o,
880 LuaValue::Function(LuaClosure::LightC(_)) | LuaValue::Function(LuaClosure::C(_))
881 )
882}
883
884pub fn is_integer(state: &LuaState, idx: i32) -> bool {
885 let o = index_to_value(state, idx);
886 matches!(o, LuaValue::Int(_))
887}
888
889pub fn is_number(state: &LuaState, idx: i32) -> bool {
890 let o = index_to_value(state, idx);
891 o.to_number_with_strconv().is_some()
892}
893
894pub fn is_string(state: &LuaState, idx: i32) -> bool {
895 let o = index_to_value(state, idx);
896 matches!(o, LuaValue::Str(_) | LuaValue::Int(_) | LuaValue::Float(_))
897}
898
899pub fn is_userdata(state: &LuaState, idx: i32) -> bool {
900 let o = index_to_value(state, idx);
901 matches!(o, LuaValue::UserData(_) | LuaValue::LightUserData(_))
902}
903
904pub fn raw_equal(state: &LuaState, index1: i32, index2: i32) -> bool {
905 if !is_valid_index(state, index1) || !is_valid_index(state, index2) {
906 return false;
907 }
908 let o1 = index_to_value(state, index1);
909 let o2 = index_to_value(state, index2);
910 state.equal_obj(None, &o1, &o2)
911}
912
913pub fn arith(state: &mut LuaState, op: i32) -> Result<(), LuaError> {
915 const LUA_OPUNM: i32 = 12;
918 const LUA_OPBNOT: i32 = 14;
919 if op == LUA_OPUNM || op == LUA_OPBNOT {
920 let top_val = state.get_at(state.top_idx() - 1);
922 state.push(top_val);
923 }
924 let top = state.top_idx();
925 let a = state.get_at(top - 2);
926 let b = state.get_at(top - 1);
927 let result = state.arith_op(op, &a, &b)?;
928 state.set_at(top - 2, result);
929 state.pop();
930 Ok(())
931}
932
933pub fn compare(state: &mut LuaState, index1: i32, index2: i32, op: i32) -> Result<bool, LuaError> {
934 let valid = is_valid_index(state, index1) && is_valid_index(state, index2);
935 let o1 = index_to_value(state, index1);
936 let o2 = index_to_value(state, index2);
937 if valid {
938 match op {
939 0 => Ok(state.equal_obj_with_tm(&o1, &o2)?),
940 1 => state.less_than(&o1, &o2),
941 2 => state.less_equal(&o1, &o2),
942 _ => {
943 debug_assert!(false, "invalid option");
944 Ok(false)
945 }
946 }
947 } else {
948 Ok(false)
949 }
950}
951
952pub fn string_to_number(state: &mut LuaState, s: &[u8]) -> usize {
953 match state.str_to_num(s) {
955 Some((val, consumed)) => {
956 state.push(val);
957 consumed
958 }
959 None => 0,
960 }
961}
962
963pub fn to_number_x(state: &LuaState, idx: i32) -> Option<f64> {
964 let o = index_to_value(state, idx);
965 o.to_number_with_strconv()
966}
967
968pub fn to_integer_x(state: &LuaState, idx: i32) -> Option<i64> {
969 let o = index_to_value(state, idx);
970 o.to_integer_with_strconv()
971}
972
973pub fn to_boolean(state: &LuaState, idx: i32) -> bool {
974 let o = index_to_value(state, idx);
975 !matches!(o, LuaValue::Nil | LuaValue::Bool(false))
976}
977
978pub fn to_lua_string(state: &mut LuaState, idx: i32) -> Result<Option<GcRef<LuaString>>, LuaError> {
980 let o = index_to_value(state, idx);
981 if let LuaValue::Str(s) = &o {
982 return Ok(Some(s.clone()));
983 }
984 if !matches!(o, LuaValue::Int(_) | LuaValue::Float(_)) {
985 return Ok(None);
986 }
987 state.obj_to_string(idx)?;
988 state.gc().check_step();
989 let updated = index_to_value(state, idx);
990 if let LuaValue::Str(s) = updated {
991 Ok(Some(s))
992 } else {
993 Ok(None)
994 }
995}
996
997pub fn raw_len(state: &LuaState, idx: i32) -> u64 {
998 let o = index_to_value(state, idx);
999 match &o {
1000 LuaValue::Str(s) => s.len() as u64,
1001 LuaValue::UserData(u) => u.len() as u64,
1002 LuaValue::Table(t) => state.table_getn(t) as u64,
1003 _ => 0,
1004 }
1005}
1006
1007pub fn to_cfunction(
1008 state: &LuaState,
1009 idx: i32,
1010) -> Option<fn(&mut LuaState) -> Result<usize, LuaError>> {
1011 let o = index_to_value(state, idx);
1012 match o {
1013 LuaValue::Function(LuaClosure::LightC(_f)) => None,
1017 LuaValue::Function(LuaClosure::C(_ccl)) => None,
1018 _ => None,
1019 }
1020}
1021
1022#[inline]
1023fn to_userdata_ptr(o: &LuaValue) -> Option<*mut core::ffi::c_void> {
1024 match o {
1025 LuaValue::UserData(u) => {
1026 let _ = u;
1030 None
1031 }
1032 LuaValue::LightUserData(p) => Some(*p),
1033 _ => None,
1034 }
1035}
1036
1037pub fn to_userdata(state: &LuaState, idx: i32) -> Option<*mut core::ffi::c_void> {
1038 let o = index_to_value(state, idx);
1039 to_userdata_ptr(&o)
1040}
1041
1042pub fn to_thread(state: &LuaState, idx: i32) -> Option<GcRef<lua_types::value::LuaThread>> {
1043 let o = index_to_value(state, idx);
1047 if let LuaValue::Thread(t) = o {
1048 Some(t)
1049 } else {
1050 None
1051 }
1052}
1053
1054pub fn to_pointer(state: &LuaState, idx: i32) -> Option<usize> {
1057 let o = index_to_value(state, idx);
1058 match &o {
1061 LuaValue::Function(LuaClosure::LightC(f)) => Some(*f as usize),
1062 LuaValue::LightUserData(p) => Some(*p as usize),
1063 LuaValue::Str(s) => Some(GcRef::identity(s)),
1064 LuaValue::Table(t) => Some(GcRef::identity(t)),
1065 LuaValue::Function(LuaClosure::Lua(f)) => Some(GcRef::identity(f)),
1066 LuaValue::Function(LuaClosure::C(f)) => Some(GcRef::identity(f)),
1067 LuaValue::UserData(u) => Some(GcRef::identity(u)),
1068 LuaValue::Thread(t) => Some(GcRef::identity(t)),
1069 _ => None,
1070 }
1071}
1072
1073pub fn push_nil(state: &mut LuaState) {
1076 state.push(LuaValue::Nil);
1077}
1078
1079pub fn push_number(state: &mut LuaState, n: f64) {
1080 state.push(LuaValue::Float(n));
1081}
1082
1083pub fn push_integer(state: &mut LuaState, n: i64) {
1084 state.push(LuaValue::Int(n));
1085}
1086
1087pub fn push_lstring(state: &mut LuaState, s: &[u8]) -> Result<GcRef<LuaString>, LuaError> {
1089 let ts = state.intern_str(s)?;
1090 state.push(LuaValue::Str(ts.clone()));
1091 state.gc().check_step();
1092 Ok(ts)
1093}
1094
1095pub fn push_string(
1096 state: &mut LuaState,
1097 s: Option<&[u8]>,
1098) -> Result<Option<GcRef<LuaString>>, LuaError> {
1099 match s {
1100 None => {
1101 state.push(LuaValue::Nil);
1102 state.gc().check_step();
1103 Ok(None)
1104 }
1105 Some(bytes) => {
1106 let ts = state.intern_str(bytes)?;
1107 state.push(LuaValue::Str(ts.clone()));
1108 state.gc().check_step();
1109 Ok(Some(ts))
1110 }
1111 }
1112}
1113
1114pub fn push_vfstring(state: &mut LuaState, formatted: &[u8]) -> Result<GcRef<LuaString>, LuaError> {
1118 let ts = state.intern_str(formatted)?;
1119 state.push(LuaValue::Str(ts.clone()));
1120 state.gc().check_step();
1121 Ok(ts)
1122}
1123
1124pub fn push_fstring(state: &mut LuaState, formatted: &[u8]) -> Result<GcRef<LuaString>, LuaError> {
1126 push_vfstring(state, formatted)
1127}
1128
1129pub fn push_cclosure(
1130 state: &mut LuaState,
1131 f: fn(&mut LuaState) -> Result<usize, LuaError>,
1132 n: i32,
1133) -> Result<(), LuaError> {
1134 let idx: lua_types::closure::LuaCFnPtr = {
1148 let mut g = state.global_mut();
1149 if n == 0 {
1150 match g.c_functions.iter().position(|existing| {
1151 existing
1152 .as_bare()
1153 .is_some_and(|existing| std::ptr::fn_addr_eq(existing, f))
1154 }) {
1155 Some(i) => i,
1156 None => {
1157 let i = g.c_functions.len();
1158 g.c_functions.push(LuaCallable::bare(f));
1159 i
1160 }
1161 }
1162 } else {
1163 let i = g.c_functions.len();
1164 g.c_functions.push(LuaCallable::bare(f));
1165 i
1166 }
1167 };
1168 if n == 0 {
1169 state.push(LuaValue::Function(LuaClosure::LightC(idx)));
1170 } else {
1171 debug_assert!(
1172 n > 0 && (n as u32) <= MAX_UPVAL as u32,
1173 "upvalue index too large"
1174 );
1175 let n_usize = n as usize;
1176 let top = state.top_idx();
1177 debug_assert!((top.0 as usize) >= n_usize, "not enough elements on stack");
1178 let base = top.0 as usize - n_usize;
1179 let mut upvalues: Vec<LuaValue> = Vec::with_capacity(n_usize);
1180 for i in 0..n_usize {
1181 upvalues.push(state.get_at(crate::state::StackIdx((base + i) as u32)));
1182 }
1183 state.pop_n(n_usize);
1184 let cl = LuaClosure::C(GcRef::new(lua_types::closure::LuaCClosure {
1186 func: idx,
1187 upvalues: std::cell::RefCell::new(upvalues),
1188 }));
1189 if let LuaClosure::C(ccl) = &cl {
1190 ccl.account_buffer(ccl.buffer_bytes() as isize);
1191 }
1192 state.push(LuaValue::Function(cl));
1193 state.gc().check_step();
1194 }
1195 Ok(())
1196}
1197
1198pub fn push_boolean(state: &mut LuaState, b: bool) {
1199 state.push(LuaValue::Bool(b));
1200}
1201
1202pub fn push_light_userdata(state: &mut LuaState, p: *mut core::ffi::c_void) {
1203 state.push(LuaValue::LightUserData(p));
1204}
1205
1206pub fn push_thread(state: &mut LuaState) -> bool {
1208 let (value, is_main) = {
1209 let g = state.global();
1210 let id = g.current_thread_id;
1211 let v = g
1212 .thread_value_for(id)
1213 .expect("current_thread_id must always resolve to a registered thread");
1214 (v, id == g.main_thread_id)
1215 };
1216 state.push(LuaValue::Thread(value));
1217 is_main
1218}
1219
1220fn aux_get_str(state: &mut LuaState, t: LuaValue, k: &[u8]) -> Result<LuaType, LuaError> {
1223 let str_val = {
1224 let ts = state.intern_str(k)?;
1225 LuaValue::Str(ts)
1226 };
1227 let result = state.table_get_with_tm(&t, &str_val)?;
1230 state.push(result);
1231 let top = state.top_idx();
1232 Ok(state.get_at(top - 1).base_type())
1233}
1234
1235fn get_global_table(state: &LuaState) -> LuaValue {
1236 state.global().globals.clone()
1242}
1243
1244pub fn get_global(state: &mut LuaState, name: &[u8]) -> Result<LuaType, LuaError> {
1245 let g = get_global_table(state);
1246 aux_get_str(state, g, name)
1247}
1248
1249pub fn get_table(state: &mut LuaState, idx: i32) -> Result<LuaType, LuaError> {
1250 let t = index_to_value(state, idx);
1251 let top = state.top_idx();
1252 let key = state.get_at(top - 1);
1253 let result = state.table_get_with_tm(&t, &key)?;
1254 state.set_at(top - 1, result);
1255 let val = state.get_at(top - 1);
1256 Ok(val.base_type())
1257}
1258
1259pub fn get_field(state: &mut LuaState, idx: i32, k: &[u8]) -> Result<LuaType, LuaError> {
1260 let t = index_to_value(state, idx);
1261 aux_get_str(state, t, k)
1262}
1263
1264pub fn get_i(state: &mut LuaState, idx: i32, n: i64) -> Result<LuaType, LuaError> {
1265 let t = index_to_value(state, idx);
1266 let key = LuaValue::Int(n);
1267 let result = state.table_get_with_tm(&t, &key)?;
1268 state.push(result);
1269 let top = state.top_idx();
1270 Ok(state.get_at(top - 1).base_type())
1271}
1272
1273pub fn get_i_value(state: &mut LuaState, t: &LuaValue, n: i64) -> Result<LuaType, LuaError> {
1279 let key = LuaValue::Int(n);
1280 let result = state.table_get_with_tm(t, &key)?;
1281 state.push(result);
1282 let top = state.top_idx();
1283 Ok(state.get_at(top - 1).base_type())
1284}
1285
1286fn finish_raw_get(state: &mut LuaState, val: Option<LuaValue>) -> LuaType {
1287 let v = val.unwrap_or(LuaValue::Nil);
1288 state.push(v);
1289 let top = state.top_idx();
1290 state.get_at(top - 1).base_type()
1291}
1292
1293fn get_table_value(state: &LuaState, idx: i32) -> Option<GcRef<LuaTable>> {
1294 let t = index_to_value(state, idx);
1295 debug_assert!(matches!(t, LuaValue::Table(_)), "table expected");
1296 if let LuaValue::Table(tbl) = t {
1297 Some(tbl)
1298 } else {
1299 None
1300 }
1301}
1302
1303pub fn raw_get(state: &mut LuaState, idx: i32) -> LuaType {
1304 let t = get_table_value(state, idx);
1305 let top = state.top_idx();
1306 let key = state.get_at(top - 1);
1307 let val = t.as_ref().map(|tbl| tbl.get(&key));
1308 state.set_top_idx(top - 1);
1309 finish_raw_get(state, val)
1310}
1311
1312pub fn raw_get_i(state: &mut LuaState, idx: i32, n: i64) -> LuaType {
1313 let t = get_table_value(state, idx);
1314 let val = t.as_ref().map(|tbl| tbl.get_int(n));
1315 finish_raw_get(state, val)
1316}
1317
1318pub fn raw_get_p(state: &mut LuaState, idx: i32, p: *const core::ffi::c_void) -> LuaType {
1319 let t = get_table_value(state, idx);
1320 let key = LuaValue::LightUserData(p as *mut core::ffi::c_void);
1321 let val = t.as_ref().map(|tbl| tbl.get(&key));
1322 finish_raw_get(state, val)
1323}
1324
1325pub fn create_table(state: &mut LuaState, narray: i32, nrec: i32) -> Result<(), LuaError> {
1326 let t = state.new_table();
1327 if narray > 0 || nrec > 0 {
1328 t.resize(state, narray as usize, nrec as usize)?;
1329 }
1330 state.push(LuaValue::Table(t));
1331 state.gc().check_step();
1332 Ok(())
1333}
1334
1335pub fn get_metatable(state: &mut LuaState, objindex: i32) -> bool {
1336 let obj = index_to_value(state, objindex);
1337 let mt: Option<GcRef<LuaTable>> = match &obj {
1338 LuaValue::Table(t) => t.metatable(),
1339 LuaValue::UserData(u) => u.metatable(),
1340 other => {
1341 let idx = other.base_type() as usize;
1342 state.global().mt[idx].clone()
1343 }
1344 };
1345 if let Some(mt_table) = mt {
1346 state.push(LuaValue::Table(mt_table));
1347 true
1348 } else {
1349 false
1350 }
1351}
1352
1353pub fn get_i_uservalue(state: &mut LuaState, idx: i32, n: i32) -> LuaType {
1354 let o = index_to_value(state, idx);
1355 debug_assert!(matches!(o, LuaValue::UserData(_)), "full userdata expected");
1356 if let LuaValue::UserData(ref u) = o {
1357 let uv = u.uv.borrow();
1358 let uv_count = uv.len() as i32;
1359 if n <= 0 || n > uv_count {
1360 state.push(LuaValue::Nil);
1361 LuaType::None
1362 } else {
1363 let val = uv[(n - 1) as usize].clone();
1364 let t = val.base_type();
1365 state.push(val);
1366 t
1367 }
1368 } else {
1369 state.push(LuaValue::Nil);
1370 LuaType::None
1371 }
1372}
1373
1374fn aux_set_str(state: &mut LuaState, t: LuaValue, k: &[u8]) -> Result<(), LuaError> {
1377 let str_val = {
1378 let ts = state.intern_str(k)?;
1379 LuaValue::Str(ts)
1380 };
1381 let top = state.top_idx();
1386 let val = state.get_at(top - 1);
1387 state.table_set_with_tm(&t, str_val, val)?;
1388 state.pop();
1389 Ok(())
1390}
1391
1392pub fn set_global(state: &mut LuaState, name: &[u8]) -> Result<(), LuaError> {
1393 let g = get_global_table(state);
1394 aux_set_str(state, g, name)
1395}
1396
1397pub fn set_table(state: &mut LuaState, idx: i32) -> Result<(), LuaError> {
1398 let t = index_to_value(state, idx);
1399 let top = state.top_idx();
1400 let key = state.get_at(top - 2);
1401 let val = state.get_at(top - 1);
1402 state.table_set_with_tm(&t, key, val)?;
1403 state.set_top_idx(top - 2);
1404 Ok(())
1405}
1406
1407pub fn set_field(state: &mut LuaState, idx: i32, k: &[u8]) -> Result<(), LuaError> {
1408 let t = index_to_value(state, idx);
1409 aux_set_str(state, t, k)
1410}
1411
1412pub fn set_i(state: &mut LuaState, idx: i32, n: i64) -> Result<(), LuaError> {
1413 let t = index_to_value(state, idx);
1414 let top = state.top_idx();
1415 let val = state.get_at(top - 1);
1416 let key = LuaValue::Int(n);
1417 state.table_set_with_tm(&t, key, val)?;
1418 state.pop();
1419 Ok(())
1420}
1421
1422pub fn set_i_value(state: &mut LuaState, t: &LuaValue, n: i64) -> Result<(), LuaError> {
1428 let top = state.top_idx();
1429 let val = state.get_at(top - 1);
1430 let key = LuaValue::Int(n);
1431 state.table_set_with_tm(t, key, val)?;
1432 state.pop();
1433 Ok(())
1434}
1435
1436fn aux_raw_set(state: &mut LuaState, idx: i32, key: LuaValue, n: u32) -> Result<(), LuaError> {
1437 let t = get_table_value(state, idx)
1438 .ok_or_else(|| LuaError::runtime(format_args!("table expected")))?;
1439 let top = state.top_idx();
1440 let val = state.get_at(top - 1);
1441 t.raw_set(state, key, val)?;
1442 t.invalidate_tm_cache();
1443 let top_val = state.get_at(top - 1);
1444 state.gc().table_barrier_back(&t, &top_val);
1445 state.set_top_idx(top - n as i32);
1446 Ok(())
1447}
1448
1449pub fn raw_set(state: &mut LuaState, idx: i32) -> Result<(), LuaError> {
1450 let top = state.top_idx();
1451 let key = state.get_at(top - 2);
1452 aux_raw_set(state, idx, key, 2)
1453}
1454
1455pub fn raw_set_p(
1456 state: &mut LuaState,
1457 idx: i32,
1458 p: *const core::ffi::c_void,
1459) -> Result<(), LuaError> {
1460 let key = LuaValue::LightUserData(p as *mut core::ffi::c_void);
1461 aux_raw_set(state, idx, key, 1)
1462}
1463
1464pub fn raw_set_i(state: &mut LuaState, idx: i32, n: i64) -> Result<(), LuaError> {
1465 let t = get_table_value(state, idx)
1466 .ok_or_else(|| LuaError::runtime(format_args!("table expected")))?;
1467 let top = state.top_idx();
1468 let val = state.get_at(top - 1);
1469 t.raw_set_int(state, n, val)?;
1470 let top_val = state.get_at(top - 1);
1471 state.gc().table_barrier_back(&t, &top_val);
1472 state.pop();
1473 Ok(())
1474}
1475
1476fn metatable_has_gc(state: &LuaState, mt: &GcRef<LuaTable>) -> bool {
1481 let name = state.global().tmname[crate::tagmethods::TagMethod::Gc as usize].clone();
1482 !matches!(mt.get_short_str(&name), LuaValue::Nil)
1483}
1484
1485fn register_finalizable_object(state: &mut LuaState, object: FinalizerObject) {
1486 let heap_ptr = object.heap_ptr();
1487 let mut g = state.global_mut();
1488 if g.finalizers.push_pending_unique(object) {
1489 if let Some(ptr) = heap_ptr {
1490 g.heap.move_allgc_to_finobj(ptr);
1491 }
1492 }
1493}
1494
1495pub fn run_pending_finalizers(state: &mut LuaState) {
1498 let _ = run_pending_finalizers_inner(state, false);
1499}
1500
1501const GC_FIN_MAX: usize = 10;
1502
1503pub fn run_pending_finalizers_inner(state: &mut LuaState, propagate: bool) -> Result<(), LuaError> {
1523 run_pending_finalizers_limited(state, propagate, None).map(|_| ())
1524}
1525
1526pub(crate) fn run_some_pending_finalizers_inner(
1527 state: &mut LuaState,
1528 propagate: bool,
1529) -> Result<usize, LuaError> {
1530 run_pending_finalizers_limited(state, propagate, Some(GC_FIN_MAX))
1531}
1532
1533fn run_pending_finalizers_limited(
1534 state: &mut LuaState,
1535 propagate: bool,
1536 limit: Option<usize>,
1537) -> Result<usize, LuaError> {
1538 let version = state.global().lua_version;
1539 let mut processed = 0usize;
1540 loop {
1541 if limit.map_or(false, |limit| processed >= limit) {
1542 break;
1543 }
1544 if !state.global().finalizers.has_to_be_finalized() {
1548 break;
1549 }
1550 let object = {
1560 let mut g = state.global_mut();
1561 let object = g
1562 .finalizers
1563 .pop_to_be_finalized()
1564 .expect("to-be-finalized checked non-empty");
1565 if let Some(ptr) = object.heap_ptr() {
1566 g.heap.move_tobefnz_to_allgc(ptr);
1567 }
1568 object
1569 };
1570 processed += 1;
1571 let mt = object.metatable();
1572 let gc_fn = match mt {
1573 Some(ref m) => {
1574 let name = state.global().tmname[crate::tagmethods::TagMethod::Gc as usize].clone();
1575 m.get_short_str(&name)
1576 }
1577 None => LuaValue::Nil,
1578 };
1579 if !matches!(gc_fn, LuaValue::Function(_)) {
1580 continue;
1581 }
1582 let saved_top = state.top_idx();
1583 let ci_top = state.current_call_info().top;
1584 if saved_top.0 < ci_top.0 {
1585 state.clear_stack_range(saved_top, ci_top);
1586 state.set_top(ci_top);
1587 }
1588 state.push(gc_fn);
1589 state.push(object.as_lua_value());
1590 let func_idx = state.top_idx() - 2;
1591 let _heap_guard = {
1592 let g = state.global.borrow();
1593 lua_gc::HeapGuard::push(&g.heap)
1594 };
1595 let old_allowhook = state.allowhook;
1596 let old_gcstp = state.global_mut().stop_gc_internal();
1597 state.allowhook = false;
1598 let caller_ci = state.ci;
1599 let caller_status = state.get_ci(caller_ci).callstatus;
1600 state.get_ci_mut(caller_ci).callstatus = caller_status | crate::state::CIST_FIN;
1601 let status = crate::do_::pcall(state, |s| s.call_no_yield(func_idx, 0), func_idx, 0);
1602 let finalizer_error: Option<LuaValue> = if status != LuaStatus::Ok {
1606 Some(state.get_at(state.top_idx() - 1).clone())
1607 } else {
1608 None
1609 };
1610 state.get_ci_mut(caller_ci).callstatus = caller_status;
1611 state.allowhook = old_allowhook;
1612 state.global_mut().set_gc_stop_flags(old_gcstp);
1613 state.set_top(saved_top);
1614
1615 if let Some(errobj) = finalizer_error {
1616 match version {
1617 lua_types::LuaVersion::V52 | lua_types::LuaVersion::V53 if propagate => {
1618 let msg: Vec<u8> = match &errobj {
1625 LuaValue::Str(s) => s.as_bytes().to_vec(),
1626 _ => b"no message".to_vec(),
1627 };
1628 let mut wrapped = b"error in __gc metamethod (".to_vec();
1629 wrapped.extend_from_slice(&msg);
1630 wrapped.push(b')');
1631 let interned = state.intern_str(&wrapped)?;
1632 return Err(LuaError::from_value(LuaValue::Str(interned)));
1633 }
1634 lua_types::LuaVersion::V54 | lua_types::LuaVersion::V55 if propagate => {
1635 let msg: Vec<u8> = match &errobj {
1639 LuaValue::Str(s) => s.as_bytes().to_vec(),
1640 _ => b"error object is not a string".to_vec(),
1641 };
1642 state.emit_warning(b"error in ", true);
1643 state.emit_warning(b"__gc", true);
1644 state.emit_warning(b" (", true);
1645 state.emit_warning(&msg, true);
1646 state.emit_warning(b")", false);
1647 }
1648 _ => {}
1649 }
1650 }
1651 }
1652 Ok(processed)
1656}
1657
1658pub fn run_close_finalizers(state: &mut LuaState) {
1677 let pending: Vec<FinalizerObject> = state.global_mut().finalizers.take_pending();
1678 if pending.is_empty() {
1679 return;
1680 }
1681 let mut seen = std::collections::HashSet::<usize>::new();
1682 {
1683 let mut g = state.global_mut();
1684 for object in pending.into_iter().rev() {
1685 let heap_ptr = object.heap_ptr();
1686 if seen.insert(object.identity()) {
1687 g.finalizers.push_to_be_finalized(object);
1688 if let Some(ptr) = heap_ptr {
1689 g.heap.move_finobj_to_tobefnz(ptr);
1690 }
1691 }
1692 }
1693 }
1694 run_pending_finalizers(state);
1695}
1696
1697fn collect_live_weak_tables(state: &mut LuaState) -> Vec<GcRef<lua_types::value::LuaTable>> {
1703 let mut g = state.global_mut();
1704 g.weak_tables_registry.live_snapshot()
1705}
1706
1707pub fn set_metatable(state: &mut LuaState, objindex: i32) -> Result<bool, LuaError> {
1708 let top = state.top_idx();
1709 let mt_val = state.get_at(top - 1);
1710 let mt: Option<GcRef<LuaTable>> = if matches!(mt_val, LuaValue::Nil) {
1711 None
1712 } else {
1713 debug_assert!(matches!(mt_val, LuaValue::Table(_)), "table expected");
1714 if let LuaValue::Table(t) = mt_val {
1715 Some(t)
1716 } else {
1717 None
1718 }
1719 };
1720
1721 let obj = index_to_value(state, objindex);
1722 match obj {
1723 LuaValue::Table(ref tbl) => {
1724 if mt.is_some() {
1725 state.gc().obj_barrier(tbl, mt.as_ref().unwrap());
1726 }
1727 tbl.set_metatable(mt.clone());
1728 if tbl.weak_mode() == 0 {
1729 state
1730 .global_mut()
1731 .weak_tables_registry
1732 .remove_identity(tbl.identity());
1733 } else {
1734 state
1735 .global_mut()
1736 .weak_tables_registry
1737 .push_unique(WeakTableEntry::new(tbl));
1738 }
1739 let tables_finalizable =
1749 !matches!(state.global().lua_version, lua_types::LuaVersion::V51);
1750 if tables_finalizable {
1751 if let Some(ref mt_table) = mt {
1752 if metatable_has_gc(state, mt_table) {
1753 register_finalizable_object(state, FinalizerObject::Table(tbl.clone()));
1754 }
1755 }
1756 }
1757 }
1758 LuaValue::UserData(ref ud) => {
1759 if let Some(ref mt_table) = mt {
1760 state.gc().obj_barrier(ud, mt_table);
1761 if metatable_has_gc(state, mt_table) {
1762 register_finalizable_object(state, FinalizerObject::UserData(ud.clone()));
1763 }
1764 }
1765 ud.set_metatable(mt);
1766 }
1767 ref other => {
1768 let idx = other.base_type() as usize;
1769 state.global_mut().mt[idx] = mt;
1770 }
1771 }
1772 state.pop();
1773 Ok(true)
1774}
1775
1776pub fn set_i_uservalue(state: &mut LuaState, idx: i32, n: i32) -> Result<bool, LuaError> {
1777 let o = index_to_value(state, idx);
1778 debug_assert!(matches!(o, LuaValue::UserData(_)), "full userdata expected");
1779 let top = state.top_idx();
1780 let val = state.get_at(top - 1);
1781 let res = if let LuaValue::UserData(ref ud) = o {
1782 let mut uv = ud.uv.borrow_mut();
1783 let nuvalue = uv.len() as i32;
1784 if n < 1 || n > nuvalue {
1785 false
1786 } else {
1787 uv[(n - 1) as usize] = val.clone();
1788 drop(uv);
1789 state.gc().barrier_back(ud, &val);
1790 true
1791 }
1792 } else {
1793 false
1794 };
1795 state.pop();
1796 Ok(res)
1797}
1798
1799pub fn call_k(
1803 state: &mut LuaState,
1804 nargs: i32,
1805 nresults: i32,
1806 ctx: isize,
1807 k: Option<fn(&mut LuaState, i32, isize) -> Result<usize, LuaError>>,
1808) -> Result<(), LuaError> {
1809 let top = state.top_idx();
1810 let func_idx = top - (nargs + 1);
1811 if k.is_some() && state.is_yieldable() {
1817 let ci_idx = state.ci;
1818 {
1819 let ci = state.get_ci_mut(ci_idx);
1820 ci.set_u_c_k(k);
1821 ci.set_u_c_ctx(ctx);
1822 }
1823 state.call_at(func_idx, nresults)?;
1824 } else {
1825 state.call_no_yield(func_idx, nresults)?;
1826 }
1827 state.adjust_results(nresults);
1828 Ok(())
1829}
1830
1831pub fn pcall_k(
1833 state: &mut LuaState,
1834 nargs: i32,
1835 nresults: i32,
1836 errfunc: i32,
1837 ctx: isize,
1838 k: Option<fn(&mut LuaState, i32, isize) -> Result<usize, LuaError>>,
1839) -> Result<LuaStatus, LuaError> {
1840 let _heap_guard = {
1845 let g = state.global.borrow();
1846 lua_gc::HeapGuard::push(&g.heap)
1851 };
1852 let err_handler_idx: isize = if errfunc == 0 {
1853 0
1854 } else {
1855 let o = index_to_stack_idx(state, errfunc);
1856 debug_assert!(
1857 matches!(state.get_at(o), LuaValue::Function(_)),
1858 "error handler must be a function"
1859 );
1860 o.0 as isize
1861 };
1862 let top = state.top_idx();
1863 let func_idx = top - (nargs + 1);
1864 if k.is_none() || !state.is_yieldable() {
1865 state.protected_call_raw(func_idx, nresults, StackIdx(err_handler_idx as u32))?;
1866 state.adjust_results(nresults);
1867 return Ok(LuaStatus::Ok);
1868 }
1869 let ci_idx = state.ci;
1875 let allow = state.allowhook;
1876 let saved_errfunc = state.errfunc;
1877 {
1878 let ci = state.get_ci_mut(ci_idx);
1879 ci.set_u_c_k(k);
1880 ci.set_u_c_ctx(ctx);
1881 ci.set_u2_funcidx(func_idx.0 as i32);
1882 ci.set_u_c_old_errfunc(saved_errfunc);
1883 ci.set_oah(allow);
1884 ci.callstatus |= crate::state::CIST_YPCALL;
1885 }
1886 state.errfunc = err_handler_idx;
1887 let call_result = crate::do_::call(state, func_idx, nresults);
1888 match call_result {
1889 Ok(()) => {
1890 state.get_ci_mut(ci_idx).callstatus &= !crate::state::CIST_YPCALL;
1893 state.errfunc = saved_errfunc;
1894 state.adjust_results(nresults);
1895 Ok(LuaStatus::Ok)
1896 }
1897 Err(crate::state::LuaError::Yield) => {
1898 Err(crate::state::LuaError::Yield)
1902 }
1903 Err(e) => {
1904 Err(e)
1908 }
1909 }
1910}
1911
1912pub fn load(
1916 state: &mut LuaState,
1917 reader: Box<dyn FnMut() -> Option<Vec<u8>>>,
1918 chunkname: Option<&[u8]>,
1919 mode: Option<&[u8]>,
1920) -> Result<LuaStatus, LuaError> {
1921 let name = chunkname.unwrap_or(b"?");
1922 let z = crate::zio::ZIO::new(reader);
1923 let status = state.protected_parser(z, name, mode);
1924 if status == LuaStatus::Ok {
1925 let top = state.top_idx();
1926 let func_val = state.get_at(top - 1);
1927 if let LuaValue::Function(LuaClosure::Lua(lcl)) = func_val {
1928 if !lcl.upvals.is_empty() {
1929 let gt = get_global_table(state);
1930 let uv = state.new_upval_closed(gt);
1931 lcl.set_upval(0, uv);
1932 state.gc().obj_barrier(&lcl, &uv);
1933 }
1934 }
1935 }
1936 Ok(status)
1937}
1938
1939pub fn dump(
1940 state: &LuaState,
1941 writer: &mut dyn FnMut(&[u8]) -> Result<(), LuaError>,
1942 strip: bool,
1943) -> Result<bool, LuaError> {
1944 let top = state.top_idx();
1945 let o = state.get_at(top - 1);
1946 if let LuaValue::Function(LuaClosure::Lua(ref lcl)) = o {
1947 crate::dump::dump(state, &lcl.proto, writer, strip)?;
1948 Ok(true)
1949 } else {
1950 Ok(false)
1951 }
1952}
1953
1954pub fn status(state: &LuaState) -> LuaStatus {
1955 LuaStatus::from_raw(state.status as i32)
1956}
1957
1958#[repr(i32)]
1962#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1963pub enum GcWhat {
1964 Stop = 0,
1965 Restart = 1,
1966 Collect = 2,
1967 Count = 3,
1968 CountB = 4,
1969 Step = 5,
1970 SetPause = 6,
1971 SetStepMul = 7,
1972 IsRunning = 9,
1973 Gen = 10,
1974 Inc = 11,
1975}
1976
1977pub enum GcArgs {
1979 Stop,
1980 Restart,
1981 Collect,
1982 Count,
1983 CountB,
1984 Step {
1985 data: i32,
1986 },
1987 SetPause {
1988 value: i32,
1989 },
1990 SetStepMul {
1991 value: i32,
1992 },
1993 IsRunning,
1994 Gen {
1995 minormul: i32,
1996 majormul: i32,
1997 },
1998 Inc {
1999 pause: i32,
2000 stepmul: i32,
2001 stepsize: i32,
2002 },
2003 Param {
2006 param: usize,
2007 value: i64,
2008 },
2009}
2010
2011pub fn gc(state: &mut LuaState, args: GcArgs) -> i32 {
2012 if let GcArgs::Param { param, value } = &args {
2016 return state.global_mut().gc55_param(*param, *value) as i32;
2017 }
2018 if state.global().is_gc_stopped_internally() {
2019 return -1;
2020 }
2021 match args {
2022 GcArgs::Stop => {
2023 state.global_mut().set_gc_stop_user();
2024 }
2025 GcArgs::Restart => {
2026 {
2027 let mut g = state.global_mut();
2028 crate::state::set_debt(&mut *g, 0);
2029 }
2030 state.global_mut().clear_gc_stop();
2031 }
2032 GcArgs::Collect => {
2033 if !state.allowhook {
2034 return 0;
2035 }
2036 state.gc().full_collect();
2042 if let Err(e) = run_pending_finalizers_inner(state, true) {
2050 state.global_mut().gc_finalizer_error = Some(e.into_value());
2051 }
2052 }
2053 GcArgs::Count => {
2054 let g = state.global();
2055 let total = g.heap.bytes_used();
2056 return (total >> 10) as i32;
2057 }
2058 GcArgs::CountB => {
2059 let g = state.global();
2060 let total = g.heap.bytes_used();
2061 return (total & 0x3ff) as i32;
2062 }
2063 GcArgs::Step { data } => {
2064 let old_stp = {
2065 let mut g = state.global_mut();
2066 let old = g.gc_stop_flags();
2067 g.clear_gc_stop();
2068 old
2069 };
2070 let stepmul = (state.global().gc_stepmul_param() as isize | 1).max(1);
2077 let work_units = if data == 0 {
2078 stepmul
2079 } else {
2080 let raw = (data as isize).saturating_mul(stepmul);
2081 raw.max(1)
2082 };
2083 let debt_for_result = if data == 0 {
2084 let mut g = state.global_mut();
2085 crate::state::set_debt(&mut *g, 0);
2086 0
2087 } else {
2088 let debt = data as isize * 1024 + state.global().gc_debt();
2089 let mut g = state.global_mut();
2090 crate::state::set_debt(&mut *g, debt);
2091 debt
2092 };
2093 let gen_mode = state.global().is_gen_mode();
2094 let cycle_complete = if gen_mode {
2095 if data == 0 {
2096 state.gc().generational_step_minor_only();
2097 } else {
2098 state.gc().generational_step();
2099 }
2100 if state.global().finalizers.has_to_be_finalized() {
2101 if let Err(e) = run_pending_finalizers_inner(state, true) {
2102 state.global_mut().gc_finalizer_error = Some(e.into_value());
2103 }
2104 }
2105 debt_for_result > 0 && state.global().gc_at_pause()
2106 } else if state.global().heap.gc_state() == lua_gc::GcState::CallFin
2107 && state.global().finalizers.has_to_be_finalized()
2108 {
2109 if let Err(e) = run_some_pending_finalizers_inner(state, true) {
2110 state.global_mut().gc_finalizer_error = Some(e.into_value());
2111 }
2112 if state.global().finalizers.has_to_be_finalized() {
2113 false
2114 } else {
2115 state.global().heap.finish_callfin_phase()
2116 }
2117 } else {
2118 let completed = state.gc().incremental_step(work_units);
2119 if state.global().heap.gc_state() == lua_gc::GcState::CallFin
2120 && state.global().finalizers.has_to_be_finalized()
2121 {
2122 if let Err(e) = run_some_pending_finalizers_inner(state, true) {
2123 state.global_mut().gc_finalizer_error = Some(e.into_value());
2124 }
2125 if state.global().finalizers.has_to_be_finalized() {
2126 false
2127 } else {
2128 state.global().heap.finish_callfin_phase()
2129 }
2130 } else {
2131 completed
2132 }
2133 };
2134 state.global_mut().set_gc_stop_flags(old_stp);
2135 {
2137 let heap_state = state.global().heap.gc_state();
2138 let mut g = state.global_mut();
2139 g.gcstate = if heap_state.is_pause() { 0 } else { 1 };
2140 }
2141 return if cycle_complete { 1 } else { 0 };
2142 }
2143 GcArgs::SetPause { value } => {
2144 let old = state.global().gc_pause_param();
2145 state.global_mut().set_gc_pause_param(value);
2146 return old;
2147 }
2148 GcArgs::SetStepMul { value } => {
2149 let old = state.global().gc_stepmul_param();
2150 state.global_mut().set_gc_stepmul_param(value);
2151 return old;
2152 }
2153 GcArgs::IsRunning => {
2154 return state.global().gc_running() as i32;
2155 }
2156 GcArgs::Gen { minormul, majormul } => {
2157 let old_mode = if state.global().is_gen_mode() {
2158 10i32
2159 } else {
2160 11i32
2161 };
2162 if minormul != 0 {
2163 state.global_mut().genminormul = minormul as u8;
2164 }
2165 if majormul != 0 {
2166 state.global_mut().set_gc_genmajormul(majormul);
2167 }
2168 state.gc().change_mode(crate::state::GcKind::Generational);
2169 return old_mode;
2170 }
2171 GcArgs::Inc {
2172 pause,
2173 stepmul,
2174 stepsize,
2175 } => {
2176 let old_mode = if state.global().is_gen_mode() {
2177 10i32
2178 } else {
2179 11i32
2180 };
2181 if pause != 0 {
2182 state.global_mut().set_gc_pause_param(pause);
2183 }
2184 if stepmul != 0 {
2185 state.global_mut().set_gc_stepmul_param(stepmul);
2186 }
2187 if stepsize != 0 {
2188 state.global_mut().gcstepsize = stepsize as u8;
2189 }
2190 state.gc().change_mode(crate::state::GcKind::Incremental);
2191 return old_mode;
2192 }
2193 GcArgs::Param { .. } => unreachable!("Param handled before the finalizer guard"),
2194 }
2195 0
2196}
2197
2198pub fn configure_startup_gc_mode(state: &mut LuaState) {
2205 if matches!(
2206 state.global().lua_version,
2207 lua_types::LuaVersion::V54 | lua_types::LuaVersion::V55
2208 ) {
2209 let _ = gc(state, GcArgs::Restart);
2210 let _ = gc(
2211 state,
2212 GcArgs::Gen {
2213 minormul: 0,
2214 majormul: 0,
2215 },
2216 );
2217 }
2218}
2219
2220pub fn lua_error(state: &mut LuaState) -> Result<Infallible, LuaError> {
2227 let top = state.top_idx();
2231 let errobj = state.get_at(top - 1);
2232 let is_mem_err = if let LuaValue::Str(ref s) = errobj {
2233 let memerr = state.global().memerrmsg.clone();
2234 GcRef::ptr_eq(s, &memerr)
2235 } else {
2236 false
2237 };
2238 if is_mem_err {
2239 Err(LuaError::Memory)
2240 } else {
2241 Err(LuaError::from_value(errobj))
2242 }
2243}
2244
2245pub fn next(state: &mut LuaState, idx: i32) -> Result<bool, LuaError> {
2246 let t = get_table_value(state, idx)
2247 .ok_or_else(|| LuaError::runtime(format_args!("table expected")))?;
2248 let top = state.top_idx();
2249 let key = state.get_at(top - 1);
2250 match t.next(key)? {
2251 Some((next_key, next_val)) => {
2252 state.set_at(top - 1, next_key);
2253 state.push(next_val);
2254 Ok(true)
2255 }
2256 None => {
2257 state.set_top_idx(top - 1);
2258 Ok(false)
2259 }
2260 }
2261}
2262
2263pub fn to_close(state: &mut LuaState, idx: i32) -> Result<(), LuaError> {
2264 let _level = index_to_stack_idx(state, idx);
2265 Ok(())
2268}
2269
2270pub fn concat(state: &mut LuaState, n: i32) -> Result<(), LuaError> {
2271 if n > 0 {
2272 state.concat(n)?;
2273 } else {
2274 let empty = state.intern_str(b"")?;
2275 state.push(LuaValue::Str(empty));
2276 }
2277 state.gc().check_step();
2278 Ok(())
2279}
2280
2281pub fn len(state: &mut LuaState, idx: i32) -> Result<(), LuaError> {
2282 let t = index_to_value(state, idx);
2283 let result = state.obj_len(&t)?;
2284 state.push(result);
2285 Ok(())
2286}
2287
2288pub fn set_warn_f(state: &mut LuaState, f: Option<Box<dyn FnMut(&[u8], bool)>>) {
2293 state.global_mut().warnf = f;
2295}
2296
2297pub fn warning(state: &mut LuaState, msg: &[u8], tocont: bool) {
2298 state.emit_warning(msg, tocont);
2299}
2300
2301pub fn new_userdata_uv(
2302 state: &mut LuaState,
2303 size: usize,
2304 nuvalue: i32,
2305) -> Result<GcRef<LuaUserData>, LuaError> {
2306 debug_assert!(nuvalue >= 0 && nuvalue < u16::MAX as i32, "invalid value");
2307 let u = state.new_userdata(size, nuvalue as usize)?;
2308 state.push(LuaValue::UserData(u.clone()));
2309 state.gc().check_step();
2310 Ok(u)
2311}
2312
2313fn aux_upvalue(state: &LuaState, fi: &LuaValue, n: i32) -> Option<(Vec<u8>, LuaValue)> {
2319 match fi {
2320 LuaValue::Function(LuaClosure::C(ccl)) => {
2321 let upvalues = ccl.upvalues.borrow();
2322 let nupvalues = upvalues.len() as i32;
2323 if n < 1 || n > nupvalues {
2324 return None;
2325 }
2326 Some((Vec::new(), upvalues[(n - 1) as usize].clone()))
2327 }
2328 LuaValue::Function(LuaClosure::Lua(lcl)) => {
2329 let nupvalues = lcl.upvals.len() as i32;
2330 if n < 1 || n > nupvalues {
2331 return None;
2332 }
2333 let val = state.upvalue_get(lcl, (n - 1) as usize);
2334 let name: Vec<u8> = lcl
2338 .proto
2339 .upvalues
2340 .get((n - 1) as usize)
2341 .and_then(|ud| ud.name.as_ref())
2342 .map(|s| s.as_bytes().to_vec())
2343 .unwrap_or_else(|| b"(no name)".to_vec());
2344 Some((name, val))
2345 }
2346 _ => None,
2347 }
2348}
2349
2350pub fn get_upvalue(state: &mut LuaState, funcindex: i32, n: i32) -> Option<Vec<u8>> {
2351 let fi = index_to_value(state, funcindex);
2352 if let Some((name, val)) = aux_upvalue(state, &fi, n) {
2353 state.push(val);
2354 Some(name)
2355 } else {
2356 None
2357 }
2358}
2359
2360pub fn setup_value(state: &mut LuaState, funcindex: i32, n: i32) -> Option<Vec<u8>> {
2361 let fi = index_to_value(state, funcindex);
2362 let (name, _) = aux_upvalue(state, &fi, n)?;
2363 let new_val = state.pop();
2364 match &fi {
2365 LuaValue::Function(LuaClosure::Lua(lcl)) => {
2366 state.upvalue_set(lcl, (n - 1) as usize, new_val).ok()?;
2367 }
2368 LuaValue::Function(LuaClosure::C(ccl)) => {
2369 let idx = (n - 1) as usize;
2370 {
2371 let mut upvalues = ccl.upvalues.borrow_mut();
2372 if idx >= upvalues.len() {
2373 return None;
2374 }
2375 upvalues[idx] = new_val.clone();
2376 }
2377 state.gc().barrier(ccl, &new_val);
2378 }
2379 _ => return None,
2380 }
2381 Some(name)
2382}
2383
2384fn get_upval_ref_idx(state: &LuaState, fidx: i32, n: i32) -> Option<usize> {
2387 let fi = index_to_value(state, fidx);
2388 debug_assert!(
2389 matches!(fi, LuaValue::Function(LuaClosure::Lua(_))),
2390 "Lua function expected"
2391 );
2392 if let LuaValue::Function(LuaClosure::Lua(ref lcl)) = fi {
2393 let sizeupvalues = lcl.upvals.len() as i32;
2394 if n >= 1 && n <= sizeupvalues {
2395 Some((n - 1) as usize)
2396 } else {
2397 None
2398 }
2399 } else {
2400 None
2401 }
2402}
2403
2404pub fn upvalue_id(state: &LuaState, fidx: i32, n: i32) -> Option<usize> {
2406 let fi = index_to_value(state, fidx);
2407 match &fi {
2408 LuaValue::Function(LuaClosure::Lua(lcl)) => {
2409 let idx = get_upval_ref_idx(state, fidx, n)?;
2410 Some(GcRef::identity(&lcl.upval(idx)))
2412 }
2413 LuaValue::Function(LuaClosure::C(ccl)) => {
2414 let upvalues = ccl.upvalues.borrow();
2415 if n >= 1 && n <= upvalues.len() as i32 {
2416 Some(GcRef::identity(ccl) ^ (n as usize))
2419 } else {
2420 None
2421 }
2422 }
2423 LuaValue::Function(LuaClosure::LightC(_)) => None,
2424 _ => {
2425 debug_assert!(false, "function expected");
2426 None
2427 }
2428 }
2429}
2430
2431pub fn upvalue_join(state: &mut LuaState, fidx1: i32, n1: i32, fidx2: i32, n2: i32) {
2433 let idx1 = match get_upval_ref_idx(state, fidx1, n1) {
2434 Some(i) => i,
2435 None => return,
2436 };
2437 let idx2 = match get_upval_ref_idx(state, fidx2, n2) {
2438 Some(i) => i,
2439 None => return,
2440 };
2441 let f1 = index_to_value(state, fidx1);
2442 let f2 = index_to_value(state, fidx2);
2443 if let (LuaValue::Function(LuaClosure::Lua(lcl1)), LuaValue::Function(LuaClosure::Lua(lcl2))) =
2444 (&f1, &f2)
2445 {
2446 let shared = lcl2.upval(idx2);
2447 lcl1.set_upval(idx1, shared);
2448 state.gc().obj_barrier(lcl1, &shared);
2449 }
2450}
2451
2452