1#![allow(dead_code)]
9
10use std::convert::Infallible;
11#[allow(unused_imports)] use crate::prelude::*;
12
13use crate::state::{LuaState, LuaCFunction, LuaCallable, StackIdx,
14 LuaValueExt, LuaTypeExt, StackIdxExt,
15 LuaTableRefExt, LuaUserDataRefExt};
16use lua_types::{
17 LuaValue, LuaType, LuaError, LuaString, LuaUserData, LuaClosure,
18 GcRef, LuaStatus,
19};
20use lua_types::value::LuaTable;
21
22pub const LUA_IDENT: &[u8] =
23 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 upval_n >= 1 && upval_n <= ccl.upvalues.len()
66 } else {
67 false
68 }
69 }
70}
71
72fn index_to_value(state: &LuaState, idx: i32) -> LuaValue {
77 let ci = state.current_call_info();
78 if idx > 0 {
79 let func_idx = ci.func;
80 let slot = func_idx + idx;
81 debug_assert!(
82 idx as u32 <= ci.top.saturating_sub(func_idx + 1),
83 "unacceptable index"
84 );
85 if slot.0 >= state.top_idx().0 {
86 LuaValue::Nil
87 } else {
88 state.get_at(slot)
89 }
90 } else if !is_pseudo(idx) {
91 debug_assert!(
93 idx != 0,
94 "invalid index"
95 );
96 let top = state.top_idx();
97 let slot = (top.0 as i32 + idx) as u32;
98 state.get_at(slot)
99 } else if idx == LUA_REGISTRYINDEX {
100 state.registry_value()
101 } else {
102 let upval_n = (LUA_REGISTRYINDEX - idx) as usize;
104 debug_assert!(upval_n <= MAX_UPVAL as usize + 1, "upvalue index too large");
105 let func_val = state.get_at(ci.func);
106 if let LuaValue::Function(LuaClosure::C(ref ccl)) = func_val {
107 if upval_n >= 1 && upval_n <= ccl.upvalues.len() {
109 ccl.upvalues[upval_n - 1].clone()
110 } else {
111 LuaValue::Nil
112 }
113 } else {
114 LuaValue::Nil
115 }
116 }
117}
118
119#[inline]
121fn index_to_stack_idx(state: &LuaState, idx: i32) -> StackIdx {
122 let ci = state.current_call_info();
123 if idx > 0 {
124 let slot = ci.func + idx;
125 debug_assert!(slot.0 < state.top_idx().0, "invalid index");
126 slot
127 } else {
128 debug_assert!(idx != 0 && !is_pseudo(idx), "invalid index");
129 StackIdx((state.top_idx().0 as i32 + idx) as u32)
130 }
131}
132
133pub fn check_stack(state: &mut LuaState, n: i32) -> bool {
136 debug_assert!(n >= 0, "negative 'n'");
137 let available = state.stack_available();
138 let res = if available > n as usize {
139 true
140 } else {
141 crate::do_::grow_stack(state, n, false).unwrap_or(false)
142 };
143 if res {
144 let needed_top = state.top_idx() + n as i32;
145 let ci_idx = state.current_ci_idx();
146 if state.get_ci(ci_idx).top.0 < needed_top.0 {
147 let live_top = state.top_idx();
148 state.get_ci_mut(ci_idx).top = needed_top;
149 state.clear_stack_range(live_top, needed_top);
150 }
151 }
152 res
153}
154
155pub fn xmove(from: &mut LuaState, to: &mut LuaState, n: i32) {
172 if n <= 0 {
173 return;
174 }
175 if std::ptr::eq(from as *const LuaState, to as *const LuaState) {
176 return;
177 }
178 let abs_top = from.top_idx().0 as i32;
179 debug_assert!(abs_top >= n, "lua_xmove: from stack underflow");
180 let first_abs = abs_top - n;
181 let mut buf: Vec<lua_types::LuaValue> = Vec::with_capacity(n as usize);
182 for i in 0..n {
183 let idx = StackIdx((first_abs + i) as u32);
184 buf.push(from.get_at(idx));
185 }
186 from.set_top(StackIdx(first_abs as u32));
187 for v in buf {
188 to.push(v);
189 }
190}
191
192pub fn at_panic(
193 state: &mut LuaState,
194 panicf: Option<fn(&mut LuaState) -> Result<usize, LuaError>>,
195) -> Option<fn(&mut LuaState) -> Result<usize, LuaError>> {
196 let old = state.global_mut().panic;
197 state.global_mut().panic = panicf;
198 old
199}
200
201pub fn version(_state: &LuaState) -> f64 {
202 504.0
203}
204
205pub fn abs_index(state: &LuaState, idx: i32) -> i32 {
206 if idx > 0 || is_pseudo(idx) {
208 idx
209 } else {
210 let ci = state.current_call_info();
211 (state.top_idx().0 as i32 - ci.func.0 as i32) + idx
212 }
213}
214
215pub fn get_top(state: &LuaState) -> i32 {
216 let ci = state.current_call_info();
217 (state.top_idx().0 as i32) - (ci.func.0 as i32 + 1)
218}
219
220pub fn set_top(state: &mut LuaState, idx: i32) -> Result<(), LuaError> {
221 let func = state.current_call_info().func;
222 let ci_top = state.current_call_info().top;
223 if idx >= 0 {
224 debug_assert!(
225 idx as u32 <= ci_top.saturating_sub(func + 1),
226 "new top too large"
227 );
228 let new_top = func + 1 + idx as i32;
229 let old_top = state.top_idx();
230 if new_top.0 > old_top.0 {
231 for i in old_top.0..new_top.0 {
232 state.set_at(i, LuaValue::Nil);
233 }
234 }
235 state.set_top_idx(new_top);
238 } else {
239 debug_assert!(
240 -(idx + 1) <= (state.top_idx().0 as i32 - (func.0 as i32 + 1)),
241 "invalid new top"
242 );
243 let new_top = (state.top_idx().0 as i32 + idx + 1) as u32;
244 state.set_top_idx(new_top);
246 }
247 Ok(())
248}
249
250pub fn close_slot(state: &mut LuaState, idx: i32) -> Result<(), LuaError> {
251 let level = index_to_stack_idx(state, idx);
252 state.set_at(level, LuaValue::Nil);
254 Ok(())
255}
256
257#[inline]
258fn reverse_segment(state: &mut LuaState, from: StackIdx, to: StackIdx) {
259 let mut lo = from.0;
260 let mut hi = to.0;
261 while lo < hi {
262 let temp = state.get_at(StackIdx(lo));
263 let hi_val = state.get_at(StackIdx(hi));
264 state.set_at(StackIdx(lo), hi_val);
265 state.set_at(StackIdx(hi), temp);
266 lo += 1;
267 hi -= 1;
268 }
269}
270
271pub fn rotate(state: &mut LuaState, idx: i32, n: i32) {
272 let t = state.top_idx() - 1;
273 let p = index_to_stack_idx(state, idx);
274 debug_assert!((n.unsigned_abs() as i32) <= ((t.0 as i32) - (p.0 as i32) + 1), "invalid 'n'");
275 let m = if n >= 0 {
276 t - n
277 } else {
278 StackIdx((p.0 as i32 - n - 1) as u32)
279 };
280 reverse_segment(state, p, m);
281 reverse_segment(state, m + 1, t);
282 reverse_segment(state, p, t);
283}
284
285pub fn copy(state: &mut LuaState, fromidx: i32, toidx: i32) {
286 let fr = index_to_value(state, fromidx);
287 if is_upvalue(toidx) {
288 let upval_n = (LUA_REGISTRYINDEX - toidx) as usize;
290 let func_val = state.get_at(state.current_call_info().func);
291 if let LuaValue::Function(LuaClosure::C(ref ccl)) = func_val {
292 let _ = (upval_n, ccl);
295 }
296 } else if toidx == LUA_REGISTRYINDEX {
298 } else {
300 let to_slot = index_to_stack_idx(state, toidx);
301 state.set_at(to_slot, fr);
302 }
303}
304
305pub fn push_value(state: &mut LuaState, idx: i32) {
306 let v = index_to_value(state, idx);
307 state.push(v);
308}
309
310impl LuaState {
315 pub fn push_copy(&mut self, idx: i32) -> Result<(), LuaError> {
316 push_value(self, idx);
317 Ok(())
318 }
319
320 pub fn push_value_at(&mut self, idx: i32) -> Result<(), LuaError> {
321 push_value(self, idx);
322 Ok(())
323 }
324
325 pub fn insert(&mut self, idx: i32) -> Result<(), LuaError> {
326 rotate(self, idx, 1);
327 Ok(())
328 }
329
330 pub fn length_at(&mut self, idx: i32) -> Result<i64, LuaError> {
336 len(self, idx)?;
337 let l = match to_integer_x(self, -1) {
338 Some(n) => n,
339 None => {
340 return Err(LuaError::runtime(format_args!(
341 "object length is not an integer"
342 )));
343 }
344 };
345 self.pop_n(1);
346 Ok(l)
347 }
348
349 pub fn write_output(&mut self, msg: &[u8]) -> Result<(), LuaError> {
356 if let Some(write_fn) = self.global().stdout_hook {
357 write_fn(msg).map_err(|e| LuaError::runtime(format_args!("{}", e)))?;
358 return Ok(());
359 }
360
361 #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
362 {
363 let _ = msg;
364 Err(LuaError::runtime(format_args!(
365 "stdout not available in this host"
366 )))
367 }
368
369 #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
370 {
371 use std::io::Write;
372 let stdout = std::io::stdout();
373 let mut handle = stdout.lock();
374 handle
375 .write_all(msg)
376 .map_err(|e| LuaError::runtime(format_args!("{}", e)))?;
377 handle
378 .flush()
379 .map_err(|e| LuaError::runtime(format_args!("{}", e)))?;
380 Ok(())
381 }
382 }
383
384 pub fn to_display_string(&mut self, idx: i32) -> Result<Vec<u8>, LuaError> {
393 let abs = abs_index(self, idx);
394 let v = index_to_value(self, abs);
395 let mt: Option<GcRef<LuaTable>> = match &v {
396 LuaValue::Table(t) => t.metatable(),
397 LuaValue::UserData(u) => u.metatable(),
398 _ => self.global().mt[v.base_type() as usize].clone(),
399 };
400 if let Some(mt_ref) = mt {
401 let key = self.intern_str(b"__tostring")?;
402 let f = mt_ref.get_short_str(&key);
403 if !matches!(f, LuaValue::Nil) {
404 let func_idx = self.top_idx();
405 self.push(f);
406 self.push(v.clone());
407 if self.current_ci().is_lua_code() {
408 self.do_call(func_idx, 1)?;
409 } else {
410 self.do_call_no_yield(func_idx, 1)?;
411 }
412 let top = self.top_idx();
413 let result = self.get_at(StackIdx(top.0 - 1));
414 if let LuaValue::Str(s) = result {
415 return Ok(s.as_bytes().to_vec());
416 }
417 return Err(LuaError::runtime(format_args!(
418 "'__tostring' must return a string"
419 )));
420 }
421 }
422 let bytes: Vec<u8> = match &v {
423 LuaValue::Str(s) => {
424 let out = s.as_bytes().to_vec();
425 self.push(LuaValue::Str(s.clone()));
426 out
427 }
428 LuaValue::Int(_) | LuaValue::Float(_) => {
429 let s = crate::object::num_to_string(self, &v)?;
430 let out = s.as_bytes().to_vec();
431 self.push(LuaValue::Str(s));
432 out
433 }
434 LuaValue::Bool(b) => {
435 let lit: &[u8] = if *b { b"true" } else { b"false" };
436 let s = self.intern_str(lit)?;
437 self.push(LuaValue::Str(s));
438 lit.to_vec()
439 }
440 LuaValue::Nil => {
441 let s = self.intern_str(b"nil")?;
442 self.push(LuaValue::Str(s));
443 b"nil".to_vec()
444 }
445 _ => {
446 let kind = crate::tagmethods::obj_type_name(self, &v)?;
447 let ptr = to_pointer(self, abs).unwrap_or(0);
448 let mut buf = kind;
449 buf.extend_from_slice(b": 0x");
450 buf.extend_from_slice(format!("{:x}", ptr).as_bytes());
451 let s = self.intern_str(&buf)?;
452 self.push(LuaValue::Str(s));
453 buf
454 }
455 };
456 Ok(bytes)
457 }
458
459 pub fn top(&mut self) -> i32 {
466 get_top(self)
467 }
468
469 pub fn get_top(&mut self) -> i32 {
473 get_top(self)
474 }
475
476 pub fn type_at(&mut self, idx: i32) -> LuaType {
481 lua_type_at(self, idx)
482 }
483
484 pub fn check_arg_any(&mut self, arg: i32) -> Result<(), LuaError> {
490 if lua_type_at(self, arg) == LuaType::None {
491 return Err(LuaError::arg_error(arg, "value expected"));
492 }
493 Ok(())
494 }
495
496 pub fn check_arg_string(&mut self, arg: i32) -> Result<Vec<u8>, LuaError> {
506 match to_lua_string(self, arg)? {
507 Some(s) => Ok(s.as_bytes().to_vec()),
508 None => {
509 let got = index_to_value(self, arg);
510 let got_name = crate::tagmethods::obj_type_name(self, &got)?;
511 let extramsg = format!(
512 "string expected, got {}",
513 String::from_utf8_lossy(&got_name)
514 );
515 Err(crate::debug::arg_error_impl(self, arg, extramsg.as_bytes()))
516 }
517 }
518 }
519
520 pub fn check_arg_integer(&mut self, arg: i32) -> Result<i64, LuaError> {
532 match to_integer_x(self, arg) {
533 Some(d) => Ok(d),
534 None => {
535 if is_number(self, arg) {
536 Err(LuaError::arg_error(
537 arg,
538 "number has no integer representation",
539 ))
540 } else {
541 let got = index_to_value(self, arg);
542 let got_name = crate::tagmethods::obj_type_name(self, &got)?;
543 let extramsg = format!(
544 "number expected, got {}",
545 String::from_utf8_lossy(&got_name)
546 );
547 Err(crate::debug::arg_error_impl(self, arg, extramsg.as_bytes()))
548 }
549 }
550 }
551 }
552
553 pub fn check_number(&mut self, arg: i32) -> Result<f64, LuaError> {
563 match to_number_x(self, arg) {
564 Some(d) => Ok(d),
565 None => {
566 let got = index_to_value(self, arg);
567 let got_name = crate::tagmethods::obj_type_name(self, &got)?;
568 let extramsg = format!(
569 "number expected, got {}",
570 String::from_utf8_lossy(&got_name)
571 );
572 Err(crate::debug::arg_error_impl(self, arg, extramsg.as_bytes()))
573 }
574 }
575 }
576
577 pub fn opt_arg_integer(&mut self, arg: i32, def: i64) -> Result<i64, LuaError> {
587 match lua_type_at(self, arg) {
588 LuaType::None | LuaType::Nil => Ok(def),
589 _ => match to_integer_x(self, arg) {
590 Some(d) => Ok(d),
591 None => {
592 if is_number(self, arg) {
593 Err(LuaError::arg_error(
594 arg,
595 "number has no integer representation",
596 ))
597 } else {
598 let got = index_to_value(self, arg);
599 Err(LuaError::type_arg_error(arg, "number", &got))
600 }
601 }
602 },
603 }
604 }
605
606 pub fn protected_call(&mut self, nargs: i32, nresults: i32, msgh: i32) -> Result<(), LuaError> {
613 pcall_k(self, nargs, nresults, msgh, 0, None).map(|_| ())
614 }
615
616 pub fn protected_call_k(
620 &mut self,
621 nargs: i32,
622 nresults: i32,
623 msgh: i32,
624 ctx: isize,
625 k: Option<crate::state::LuaKFunction>,
626 ) -> Result<(), LuaError> {
627 pcall_k(self, nargs, nresults, msgh, ctx, k).map(|_| ())
628 }
629
630 pub fn push_string(&mut self, s: &[u8]) -> Result<(), LuaError> {
631 push_lstring(self, s)?;
632 Ok(())
633 }
634
635 pub fn push_c_closure(
636 &mut self,
637 f: fn(&mut LuaState) -> Result<usize, LuaError>,
638 n: i32,
639 ) -> Result<(), LuaError> {
640 push_cclosure(self, f, n)
641 }
642
643 pub fn raw_seti(&mut self, idx: i32, n: i64) -> Result<(), LuaError> {
644 raw_set_i(self, idx, n)
645 }
646
647 pub fn table_set_i(&mut self, idx: i32, n: i64) -> Result<(), LuaError> {
648 set_i(self, idx, n)
649 }
650
651 pub fn table_get_i_value(&mut self, t: &LuaValue, n: i64) -> Result<LuaType, LuaError> {
655 get_i_value(self, t, n)
656 }
657
658 pub fn table_set_i_value(&mut self, t: &LuaValue, n: i64) -> Result<(), LuaError> {
662 set_i_value(self, t, n)
663 }
664
665 pub fn create_table(&mut self, narr: i32, nrec: i32) -> Result<(), LuaError> {
666 create_table(self, narr, nrec)
667 }
668
669 pub fn registry_set(&mut self, key: &[u8]) -> Result<(), LuaError> {
673 set_field(self, LUA_REGISTRYINDEX, key)
674 }
675
676 pub fn new_metatable(&mut self, tname: &[u8]) -> Result<bool, LuaError> {
682 if get_field(self, LUA_REGISTRYINDEX, tname)? != LuaType::Nil {
683 return Ok(false);
684 }
685 self.pop_n(1);
686 create_table(self, 0, 2)?;
687 push_lstring(self, tname)?;
688 set_field(self, -2, b"__name")?;
689 push_value(self, -1);
690 set_field(self, LUA_REGISTRYINDEX, tname)?;
691 Ok(true)
692 }
693
694 pub fn new_lib(
701 &mut self,
702 funcs: &[(&[u8], LuaCFunction)],
703 ) -> Result<(), LuaError> {
704 create_table(self, 0, funcs.len() as i32)?;
705 for (name, f) in funcs {
706 push_cclosure(self, *f, 0)?;
707 set_field(self, -2, name)?;
708 }
709 Ok(())
710 }
711
712 pub fn register_lib(
718 &mut self,
719 _name: &[u8],
720 funcs: &[(&[u8], LuaCFunction)],
721 ) -> Result<(), LuaError> {
722 self.new_lib(funcs)
723 }
724
725 pub fn new_lib_table(
734 &mut self,
735 funcs: &[(&[u8], LuaCFunction)],
736 ) -> Result<(), LuaError> {
737 create_table(self, 0, funcs.len() as i32)
738 }
739
740 pub fn set_funcs_with_upvalues(
745 &mut self,
746 funcs: &[(&[u8], LuaCFunction)],
747 nup: i32,
748 ) -> Result<(), LuaError> {
749 check_stack(self, nup);
750 for (name, f) in funcs {
751 for _ in 0..nup {
752 push_value(self, -nup);
753 }
754 push_cclosure(self, *f, nup)?;
755 set_field(self, -(nup + 2), name)?;
756 }
757 self.pop_n(nup as usize);
758 Ok(())
759 }
760
761 pub fn set_metatable(&mut self, objindex: i32) -> Result<(), LuaError> {
762 set_metatable(self, objindex)?;
763 Ok(())
764 }
765
766 pub fn set_metatable_by_name(&mut self, name: &[u8]) -> Result<(), LuaError> {
772 get_field(self, LUA_REGISTRYINDEX, name)?;
773 set_metatable(self, -2)?;
774 Ok(())
775 }
776
777 pub fn get_subtable_registry(&mut self, name: &[u8]) -> Result<bool, LuaError> {
781 if get_field(self, LUA_REGISTRYINDEX, name)? == LuaType::Table {
782 return Ok(true);
783 }
784 self.pop_n(1);
785 let idx = abs_index(self, LUA_REGISTRYINDEX);
786 let new_tbl = self.new_table();
787 self.push(LuaValue::Table(new_tbl));
788 push_value(self, -1);
789 set_field(self, idx, name)?;
790 Ok(false)
791 }
792
793 pub fn new_userdata_typed(
803 &mut self,
804 _name: &[u8],
805 size: usize,
806 nuvalue: i32,
807 ) -> Result<GcRef<LuaUserData>, LuaError> {
808 debug_assert!(nuvalue >= 0 && nuvalue < u16::MAX as i32, "invalid value");
809 let u = GcRef::new(LuaUserData {
811 data: vec![0u8; size].into_boxed_slice(),
812 uv: vec![LuaValue::Nil; nuvalue as usize],
813 metatable: std::cell::RefCell::new(None),
814 host_value: std::cell::RefCell::new(None),
815 });
816 self.push(LuaValue::UserData(u.clone()));
817 self.gc().check_step();
818 Ok(u)
819 }
820}
821
822pub fn lua_type_at(state: &LuaState, idx: i32) -> LuaType {
825 if !is_valid_index(state, idx) {
826 return LuaType::None;
827 }
828 index_to_value(state, idx).base_type()
829}
830
831pub fn type_name(_state: &LuaState, t: LuaType) -> &'static [u8] {
832 t.type_name()
833}
834
835pub fn is_cfunction(state: &LuaState, idx: i32) -> bool {
836 let o = index_to_value(state, idx);
837 matches!(o, LuaValue::Function(LuaClosure::LightC(_)) | LuaValue::Function(LuaClosure::C(_)))
838}
839
840pub fn is_integer(state: &LuaState, idx: i32) -> bool {
841 let o = index_to_value(state, idx);
842 matches!(o, LuaValue::Int(_))
843}
844
845pub fn is_number(state: &LuaState, idx: i32) -> bool {
846 let o = index_to_value(state, idx);
847 o.to_number_with_strconv().is_some()
848}
849
850pub fn is_string(state: &LuaState, idx: i32) -> bool {
851 let o = index_to_value(state, idx);
852 matches!(o, LuaValue::Str(_) | LuaValue::Int(_) | LuaValue::Float(_))
853}
854
855pub fn is_userdata(state: &LuaState, idx: i32) -> bool {
856 let o = index_to_value(state, idx);
857 matches!(o, LuaValue::UserData(_) | LuaValue::LightUserData(_))
858}
859
860pub fn raw_equal(state: &LuaState, index1: i32, index2: i32) -> bool {
861 if !is_valid_index(state, index1) || !is_valid_index(state, index2) {
862 return false;
863 }
864 let o1 = index_to_value(state, index1);
865 let o2 = index_to_value(state, index2);
866 state.equal_obj(None, &o1, &o2)
867}
868
869pub fn arith(state: &mut LuaState, op: i32) -> Result<(), LuaError> {
871 const LUA_OPUNM: i32 = 12;
874 const LUA_OPBNOT: i32 = 14;
875 if op == LUA_OPUNM || op == LUA_OPBNOT {
876 let top_val = state.get_at(state.top_idx() - 1);
878 state.push(top_val);
879 }
880 let top = state.top_idx();
881 let a = state.get_at(top - 2);
882 let b = state.get_at(top - 1);
883 let result = state.arith_op(op, &a, &b)?;
884 state.set_at(top - 2, result);
885 state.pop();
886 Ok(())
887}
888
889pub fn compare(state: &mut LuaState, index1: i32, index2: i32, op: i32) -> Result<bool, LuaError> {
890 let valid = is_valid_index(state, index1) && is_valid_index(state, index2);
891 let o1 = index_to_value(state, index1);
892 let o2 = index_to_value(state, index2);
893 if valid {
894 match op {
895 0 => Ok(state.equal_obj_with_tm(&o1, &o2)?),
896 1 => state.less_than(&o1, &o2),
897 2 => state.less_equal(&o1, &o2),
898 _ => {
899 debug_assert!(false, "invalid option");
900 Ok(false)
901 }
902 }
903 } else {
904 Ok(false)
905 }
906}
907
908pub fn string_to_number(state: &mut LuaState, s: &[u8]) -> usize {
909 match state.str_to_num(s) {
911 Some((val, consumed)) => {
912 state.push(val);
913 consumed
914 }
915 None => 0,
916 }
917}
918
919pub fn to_number_x(state: &LuaState, idx: i32) -> Option<f64> {
920 let o = index_to_value(state, idx);
921 o.to_number_with_strconv()
922}
923
924pub fn to_integer_x(state: &LuaState, idx: i32) -> Option<i64> {
925 let o = index_to_value(state, idx);
926 o.to_integer_with_strconv()
927}
928
929pub fn to_boolean(state: &LuaState, idx: i32) -> bool {
930 let o = index_to_value(state, idx);
931 !matches!(o, LuaValue::Nil | LuaValue::Bool(false))
932}
933
934pub fn to_lua_string(
936 state: &mut LuaState,
937 idx: i32,
938) -> Result<Option<GcRef<LuaString>>, LuaError> {
939 let o = index_to_value(state, idx);
940 if let LuaValue::Str(s) = &o {
941 return Ok(Some(s.clone()));
942 }
943 if !matches!(o, LuaValue::Int(_) | LuaValue::Float(_)) {
944 return Ok(None);
945 }
946 state.obj_to_string(idx)?;
947 state.gc().check_step();
948 let updated = index_to_value(state, idx);
949 if let LuaValue::Str(s) = updated {
950 Ok(Some(s))
951 } else {
952 Ok(None)
953 }
954}
955
956pub fn raw_len(state: &LuaState, idx: i32) -> u64 {
957 let o = index_to_value(state, idx);
958 match &o {
959 LuaValue::Str(s) => s.len() as u64,
960 LuaValue::UserData(u) => u.len() as u64,
961 LuaValue::Table(t) => state.table_getn(t) as u64,
962 _ => 0,
963 }
964}
965
966pub fn to_cfunction(
967 state: &LuaState,
968 idx: i32,
969) -> Option<fn(&mut LuaState) -> Result<usize, LuaError>> {
970 let o = index_to_value(state, idx);
971 match o {
972 LuaValue::Function(LuaClosure::LightC(_f)) => None,
976 LuaValue::Function(LuaClosure::C(_ccl)) => None,
977 _ => None,
978 }
979}
980
981#[inline]
982fn to_userdata_ptr(o: &LuaValue) -> Option<*mut core::ffi::c_void> {
983 match o {
984 LuaValue::UserData(u) => {
985 let _ = u;
989 None
990 }
991 LuaValue::LightUserData(p) => Some(*p),
992 _ => None,
993 }
994}
995
996pub fn to_userdata(state: &LuaState, idx: i32) -> Option<*mut core::ffi::c_void> {
997 let o = index_to_value(state, idx);
998 to_userdata_ptr(&o)
999}
1000
1001pub fn to_thread(state: &LuaState, idx: i32) -> Option<GcRef<lua_types::value::LuaThread>> {
1002 let o = index_to_value(state, idx);
1006 if let LuaValue::Thread(t) = o {
1007 Some(t)
1008 } else {
1009 None
1010 }
1011}
1012
1013pub fn to_pointer(state: &LuaState, idx: i32) -> Option<usize> {
1016 let o = index_to_value(state, idx);
1017 match &o {
1020 LuaValue::Function(LuaClosure::LightC(f)) => Some(*f as usize),
1021 LuaValue::LightUserData(p) => Some(*p as usize),
1022 LuaValue::Str(s) => Some(GcRef::identity(s)),
1023 LuaValue::Table(t) => Some(GcRef::identity(t)),
1024 LuaValue::Function(LuaClosure::Lua(f)) => Some(GcRef::identity(f)),
1025 LuaValue::Function(LuaClosure::C(f)) => Some(GcRef::identity(f)),
1026 LuaValue::UserData(u) => Some(GcRef::identity(u)),
1027 LuaValue::Thread(t) => Some(GcRef::identity(t)),
1028 _ => None,
1029 }
1030}
1031
1032pub fn push_nil(state: &mut LuaState) {
1035 state.push(LuaValue::Nil);
1036}
1037
1038pub fn push_number(state: &mut LuaState, n: f64) {
1039 state.push(LuaValue::Float(n));
1040}
1041
1042pub fn push_integer(state: &mut LuaState, n: i64) {
1043 state.push(LuaValue::Int(n));
1044}
1045
1046pub fn push_lstring(state: &mut LuaState, s: &[u8]) -> Result<GcRef<LuaString>, LuaError> {
1048 let ts = state.intern_str(s)?;
1049 state.push(LuaValue::Str(ts.clone()));
1050 state.gc().check_step();
1051 Ok(ts)
1052}
1053
1054pub fn push_string(state: &mut LuaState, s: Option<&[u8]>) -> Result<Option<GcRef<LuaString>>, LuaError> {
1055 match s {
1056 None => {
1057 state.push(LuaValue::Nil);
1058 state.gc().check_step();
1059 Ok(None)
1060 }
1061 Some(bytes) => {
1062 let ts = state.intern_str(bytes)?;
1063 state.push(LuaValue::Str(ts.clone()));
1064 state.gc().check_step();
1065 Ok(Some(ts))
1066 }
1067 }
1068}
1069
1070pub fn push_vfstring(state: &mut LuaState, formatted: &[u8]) -> Result<GcRef<LuaString>, LuaError> {
1074 let ts = state.intern_str(formatted)?;
1075 state.push(LuaValue::Str(ts.clone()));
1076 state.gc().check_step();
1077 Ok(ts)
1078}
1079
1080pub fn push_fstring(state: &mut LuaState, formatted: &[u8]) -> Result<GcRef<LuaString>, LuaError> {
1082 push_vfstring(state, formatted)
1083}
1084
1085pub fn push_cclosure(
1086 state: &mut LuaState,
1087 f: fn(&mut LuaState) -> Result<usize, LuaError>,
1088 n: i32,
1089) -> Result<(), LuaError> {
1090 let idx: lua_types::closure::LuaCFnPtr = {
1104 let mut g = state.global_mut();
1105 if n == 0 {
1106 match g.c_functions.iter().position(|existing| {
1107 existing
1108 .as_bare()
1109 .is_some_and(|existing| std::ptr::fn_addr_eq(existing, f))
1110 }) {
1111 Some(i) => i,
1112 None => {
1113 let i = g.c_functions.len();
1114 g.c_functions.push(LuaCallable::bare(f));
1115 i
1116 }
1117 }
1118 } else {
1119 let i = g.c_functions.len();
1120 g.c_functions.push(LuaCallable::bare(f));
1121 i
1122 }
1123 };
1124 if n == 0 {
1125 state.push(LuaValue::Function(LuaClosure::LightC(idx)));
1126 } else {
1127 debug_assert!(n > 0 && (n as u32) <= MAX_UPVAL as u32, "upvalue index too large");
1128 let n_usize = n as usize;
1129 let top = state.top_idx();
1130 debug_assert!((top.0 as usize) >= n_usize, "not enough elements on stack");
1131 let base = top.0 as usize - n_usize;
1132 let mut upvalues: Vec<LuaValue> = Vec::with_capacity(n_usize);
1133 for i in 0..n_usize {
1134 upvalues.push(state.get_at(crate::state::StackIdx((base + i) as u32)));
1135 }
1136 state.pop_n(n_usize);
1137 let cl = LuaClosure::C(GcRef::new(lua_types::closure::LuaCClosure {
1139 func: idx,
1140 upvalues,
1141 }));
1142 state.push(LuaValue::Function(cl));
1143 state.gc().check_step();
1144 }
1145 Ok(())
1146}
1147
1148pub fn push_boolean(state: &mut LuaState, b: bool) {
1149 state.push(LuaValue::Bool(b));
1150}
1151
1152pub fn push_light_userdata(state: &mut LuaState, p: *mut core::ffi::c_void) {
1153 state.push(LuaValue::LightUserData(p));
1154}
1155
1156pub fn push_thread(state: &mut LuaState) -> bool {
1158 let (value, is_main) = {
1159 let g = state.global();
1160 let id = g.current_thread_id;
1161 let v = g
1162 .thread_value_for(id)
1163 .expect("current_thread_id must always resolve to a registered thread");
1164 (v, id == g.main_thread_id)
1165 };
1166 state.push(LuaValue::Thread(value));
1167 is_main
1168}
1169
1170fn aux_get_str(state: &mut LuaState, t: LuaValue, k: &[u8]) -> Result<LuaType, LuaError> {
1173 let str_val = {
1174 let ts = state.intern_str(k)?;
1175 LuaValue::Str(ts)
1176 };
1177 let result = state.table_get_with_tm(&t, &str_val)?;
1180 state.push(result);
1181 let top = state.top_idx();
1182 Ok(state.get_at(top - 1).base_type())
1183}
1184
1185fn get_global_table(state: &LuaState) -> LuaValue {
1186 state.global().globals.clone()
1192}
1193
1194pub fn get_global(state: &mut LuaState, name: &[u8]) -> Result<LuaType, LuaError> {
1195 let g = get_global_table(state);
1196 aux_get_str(state, g, name)
1197}
1198
1199pub fn get_table(state: &mut LuaState, idx: i32) -> Result<LuaType, LuaError> {
1200 let t = index_to_value(state, idx);
1201 let top = state.top_idx();
1202 let key = state.get_at(top - 1);
1203 let result = state.table_get_with_tm(&t, &key)?;
1204 state.set_at(top - 1, result);
1205 let val = state.get_at(top - 1);
1206 Ok(val.base_type())
1207}
1208
1209pub fn get_field(state: &mut LuaState, idx: i32, k: &[u8]) -> Result<LuaType, LuaError> {
1210 let t = index_to_value(state, idx);
1211 aux_get_str(state, t, k)
1212}
1213
1214pub fn get_i(state: &mut LuaState, idx: i32, n: i64) -> Result<LuaType, LuaError> {
1215 let t = index_to_value(state, idx);
1216 let key = LuaValue::Int(n);
1217 let result = state.table_get_with_tm(&t, &key)?;
1218 state.push(result);
1219 let top = state.top_idx();
1220 Ok(state.get_at(top - 1).base_type())
1221}
1222
1223pub fn get_i_value(state: &mut LuaState, t: &LuaValue, n: i64) -> Result<LuaType, LuaError> {
1229 let key = LuaValue::Int(n);
1230 let result = state.table_get_with_tm(t, &key)?;
1231 state.push(result);
1232 let top = state.top_idx();
1233 Ok(state.get_at(top - 1).base_type())
1234}
1235
1236fn finish_raw_get(state: &mut LuaState, val: Option<LuaValue>) -> LuaType {
1237 let v = val.unwrap_or(LuaValue::Nil);
1238 state.push(v);
1239 let top = state.top_idx();
1240 state.get_at(top - 1).base_type()
1241}
1242
1243fn get_table_value(state: &LuaState, idx: i32) -> Option<GcRef<LuaTable>> {
1244 let t = index_to_value(state, idx);
1245 debug_assert!(matches!(t, LuaValue::Table(_)), "table expected");
1246 if let LuaValue::Table(tbl) = t {
1247 Some(tbl)
1248 } else {
1249 None
1250 }
1251}
1252
1253pub fn raw_get(state: &mut LuaState, idx: i32) -> LuaType {
1254 let t = get_table_value(state, idx);
1255 let top = state.top_idx();
1256 let key = state.get_at(top - 1);
1257 let val = t.as_ref().map(|tbl| tbl.get(&key));
1258 state.set_top_idx(top - 1);
1259 finish_raw_get(state, val)
1260}
1261
1262pub fn raw_get_i(state: &mut LuaState, idx: i32, n: i64) -> LuaType {
1263 let t = get_table_value(state, idx);
1264 let val = t.as_ref().map(|tbl| tbl.get_int(n));
1265 finish_raw_get(state, val)
1266}
1267
1268pub fn raw_get_p(state: &mut LuaState, idx: i32, p: *const core::ffi::c_void) -> LuaType {
1269 let t = get_table_value(state, idx);
1270 let key = LuaValue::LightUserData(p as *mut core::ffi::c_void);
1271 let val = t.as_ref().map(|tbl| tbl.get(&key));
1272 finish_raw_get(state, val)
1273}
1274
1275pub fn create_table(state: &mut LuaState, narray: i32, nrec: i32) -> Result<(), LuaError> {
1276 let t = state.new_table();
1277 if narray > 0 || nrec > 0 {
1278 t.resize(state, narray as usize, nrec as usize)?;
1279 }
1280 state.push(LuaValue::Table(t));
1281 state.gc().check_step();
1282 Ok(())
1283}
1284
1285pub fn get_metatable(state: &mut LuaState, objindex: i32) -> bool {
1286 let obj = index_to_value(state, objindex);
1287 let mt: Option<GcRef<LuaTable>> = match &obj {
1288 LuaValue::Table(t) => t.metatable(),
1289 LuaValue::UserData(u) => u.metatable(),
1290 other => {
1291 let idx = other.base_type() as usize;
1292 state.global().mt[idx].clone()
1293 }
1294 };
1295 if let Some(mt_table) = mt {
1296 state.push(LuaValue::Table(mt_table));
1297 true
1298 } else {
1299 false
1300 }
1301}
1302
1303pub fn get_i_uservalue(state: &mut LuaState, idx: i32, n: i32) -> LuaType {
1304 let o = index_to_value(state, idx);
1305 debug_assert!(matches!(o, LuaValue::UserData(_)), "full userdata expected");
1306 if let LuaValue::UserData(ref u) = o {
1307 let uv_count = u.uv.len() as i32;
1308 if n <= 0 || n > uv_count {
1309 state.push(LuaValue::Nil);
1310 LuaType::None
1311 } else {
1312 let val = u.uv[(n - 1) as usize].clone();
1313 let t = val.base_type();
1314 state.push(val);
1315 t
1316 }
1317 } else {
1318 state.push(LuaValue::Nil);
1319 LuaType::None
1320 }
1321}
1322
1323fn aux_set_str(state: &mut LuaState, t: LuaValue, k: &[u8]) -> Result<(), LuaError> {
1326 let str_val = {
1327 let ts = state.intern_str(k)?;
1328 LuaValue::Str(ts)
1329 };
1330 let top = state.top_idx();
1335 let val = state.get_at(top - 1);
1336 state.table_set_with_tm(&t, str_val, val)?;
1337 state.pop();
1338 Ok(())
1339}
1340
1341pub fn set_global(state: &mut LuaState, name: &[u8]) -> Result<(), LuaError> {
1342 let g = get_global_table(state);
1343 aux_set_str(state, g, name)
1344}
1345
1346pub fn set_table(state: &mut LuaState, idx: i32) -> Result<(), LuaError> {
1347 let t = index_to_value(state, idx);
1348 let top = state.top_idx();
1349 let key = state.get_at(top - 2);
1350 let val = state.get_at(top - 1);
1351 state.table_set_with_tm(&t, key, val)?;
1352 state.set_top_idx(top - 2);
1353 Ok(())
1354}
1355
1356pub fn set_field(state: &mut LuaState, idx: i32, k: &[u8]) -> Result<(), LuaError> {
1357 let t = index_to_value(state, idx);
1358 aux_set_str(state, t, k)
1359}
1360
1361pub fn set_i(state: &mut LuaState, idx: i32, n: i64) -> Result<(), LuaError> {
1362 let t = index_to_value(state, idx);
1363 let top = state.top_idx();
1364 let val = state.get_at(top - 1);
1365 let key = LuaValue::Int(n);
1366 state.table_set_with_tm(&t, key, val)?;
1367 state.pop();
1368 Ok(())
1369}
1370
1371pub fn set_i_value(state: &mut LuaState, t: &LuaValue, n: i64) -> Result<(), LuaError> {
1377 let top = state.top_idx();
1378 let val = state.get_at(top - 1);
1379 let key = LuaValue::Int(n);
1380 state.table_set_with_tm(t, key, val)?;
1381 state.pop();
1382 Ok(())
1383}
1384
1385fn aux_raw_set(state: &mut LuaState, idx: i32, key: LuaValue, n: u32) -> Result<(), LuaError> {
1386 let t = get_table_value(state, idx)
1387 .ok_or_else(|| LuaError::runtime(format_args!("table expected")))?;
1388 let top = state.top_idx();
1389 let val = state.get_at(top - 1);
1390 t.raw_set(state, key, val)?;
1391 t.invalidate_tm_cache();
1392 let top_val = state.get_at(top - 1);
1393 state.gc().barrier_back(&t, &top_val);
1394 state.set_top_idx(top - n as i32);
1395 Ok(())
1396}
1397
1398pub fn raw_set(state: &mut LuaState, idx: i32) -> Result<(), LuaError> {
1399 let top = state.top_idx();
1400 let key = state.get_at(top - 2);
1401 aux_raw_set(state, idx, key, 2)
1402}
1403
1404pub fn raw_set_p(state: &mut LuaState, idx: i32, p: *const core::ffi::c_void) -> Result<(), LuaError> {
1405 let key = LuaValue::LightUserData(p as *mut core::ffi::c_void);
1406 aux_raw_set(state, idx, key, 1)
1407}
1408
1409pub fn raw_set_i(state: &mut LuaState, idx: i32, n: i64) -> Result<(), LuaError> {
1410 let t = get_table_value(state, idx)
1411 .ok_or_else(|| LuaError::runtime(format_args!("table expected")))?;
1412 let top = state.top_idx();
1413 let val = state.get_at(top - 1);
1414 t.raw_set_int(state, n, val)?;
1415 let top_val = state.get_at(top - 1);
1416 state.gc().barrier_back(&t, &top_val);
1417 state.pop();
1418 Ok(())
1419}
1420
1421fn metatable_has_gc(state: &LuaState, mt: &GcRef<LuaTable>) -> bool {
1426 let name = state.global().tmname[crate::tagmethods::TagMethod::Gc as usize].clone();
1427 !matches!(mt.get_short_str(&name), LuaValue::Nil)
1428}
1429
1430fn register_finalizable_table(state: &mut LuaState, tbl: &GcRef<LuaTable>) {
1432 let already = state
1433 .global()
1434 .pending_finalizers
1435 .iter()
1436 .any(|t| GcRef::ptr_eq(t, tbl));
1437 if !already {
1438 state.global_mut().pending_finalizers.push(tbl.clone());
1439 }
1440}
1441
1442pub fn run_pending_finalizers(state: &mut LuaState) {
1456 let mut did_run = false;
1457 loop {
1458 let target_idx = {
1463 let to_fin = &state.global().to_be_finalized;
1464 if to_fin.is_empty() { None } else { Some(to_fin.len() - 1) }
1465 };
1466 let Some(i) = target_idx else { break; };
1467 let tbl = state.global_mut().to_be_finalized.swap_remove(i);
1477 let mt = tbl.metatable();
1478 let gc_fn = match mt {
1479 Some(ref m) => {
1480 let name = state.global().tmname[crate::tagmethods::TagMethod::Gc as usize].clone();
1481 m.get_short_str(&name)
1482 }
1483 None => LuaValue::Nil,
1484 };
1485 if !matches!(gc_fn, LuaValue::Function(_)) {
1486 continue;
1487 }
1488 did_run = true;
1489 let saved_top = state.top_idx();
1490 let ci_top = state.current_call_info().top;
1491 if saved_top.0 < ci_top.0 {
1492 state.clear_stack_range(saved_top, ci_top);
1493 state.set_top(ci_top);
1494 }
1495 state.push(gc_fn);
1496 state.push(LuaValue::Table(tbl));
1497 let func_idx = state.top_idx() - 2;
1498 let _heap_guard = {
1499 let g = state.global.borrow();
1500 lua_gc::HeapGuard::push(&g.heap)
1501 };
1502 let old_allowhook = state.allowhook;
1503 let old_gcstp = state.global_mut().stop_gc_internal();
1504 state.allowhook = false;
1505 let caller_ci = state.ci;
1506 let caller_status = state.get_ci(caller_ci).callstatus;
1507 state.get_ci_mut(caller_ci).callstatus = caller_status | crate::state::CIST_FIN;
1508 let _ = crate::do_::pcall(
1509 state,
1510 |s| s.call_no_yield(func_idx, 0),
1511 func_idx,
1512 0,
1513 );
1514 state.get_ci_mut(caller_ci).callstatus = caller_status;
1515 state.allowhook = old_allowhook;
1516 state.global_mut().set_gc_stop_flags(old_gcstp);
1517 state.set_top(saved_top);
1518 }
1519 let _ = did_run;
1523}
1524
1525fn collect_live_weak_tables(state: &mut LuaState) -> Vec<GcRef<lua_types::value::LuaTable>> {
1531 let mut g = state.global_mut();
1532 g.weak_tables_registry.retain(|w| w.strong_count() > 0);
1533 let mut seen = std::collections::HashSet::<usize>::new();
1534 g.weak_tables_registry
1535 .iter()
1536 .filter_map(|w| w.upgrade())
1537 .filter_map(|rc| {
1538 let id = rc.identity();
1539 if seen.insert(id) {
1540 Some(rc)
1541 } else {
1542 None
1543 }
1544 })
1545 .collect()
1546}
1547
1548pub fn set_metatable(state: &mut LuaState, objindex: i32) -> Result<bool, LuaError> {
1549 let top = state.top_idx();
1550 let mt_val = state.get_at(top - 1);
1551 let mt: Option<GcRef<LuaTable>> = if matches!(mt_val, LuaValue::Nil) {
1552 None
1553 } else {
1554 debug_assert!(matches!(mt_val, LuaValue::Table(_)), "table expected");
1555 if let LuaValue::Table(t) = mt_val {
1556 Some(t)
1557 } else {
1558 None
1559 }
1560 };
1561
1562 let obj = index_to_value(state, objindex);
1563 match obj {
1564 LuaValue::Table(ref tbl) => {
1565 if mt.is_some() {
1566 state.gc().obj_barrier(tbl, mt.as_ref().unwrap());
1567 }
1568 tbl.set_metatable(mt.clone());
1569 if tbl.weak_mode() != 0 {
1570 state
1571 .global_mut()
1572 .weak_tables_registry
1573 .push(tbl.downgrade());
1574 }
1575 if let Some(ref mt_table) = mt {
1580 if metatable_has_gc(state, mt_table) {
1581 register_finalizable_table(state, tbl);
1582 }
1583 }
1584 }
1585 LuaValue::UserData(ref ud) => {
1586 if let Some(ref mt_table) = mt {
1587 state.gc().obj_barrier(ud, mt_table);
1588 }
1590 ud.set_metatable(mt);
1591 }
1592 ref other => {
1593 let idx = other.base_type() as usize;
1594 state.global_mut().mt[idx] = mt;
1595 }
1596 }
1597 state.pop();
1598 Ok(true)
1599}
1600
1601pub fn set_i_uservalue(state: &mut LuaState, idx: i32, n: i32) -> Result<bool, LuaError> {
1602 let o = index_to_value(state, idx);
1603 debug_assert!(matches!(o, LuaValue::UserData(_)), "full userdata expected");
1604 let top = state.top_idx();
1605 let val = state.get_at(top - 1);
1606 let res = if let LuaValue::UserData(ref ud) = o {
1607 let nuvalue = ud.uv.len() as i32;
1608 if n < 1 || n > nuvalue {
1609 false
1610 } else {
1611 state.gc().barrier_back(ud, &val);
1614 let _ = (n, ud);
1615 true
1616 }
1617 } else {
1618 false
1619 };
1620 state.pop();
1621 Ok(res)
1622}
1623
1624pub fn call_k(
1628 state: &mut LuaState,
1629 nargs: i32,
1630 nresults: i32,
1631 ctx: isize,
1632 k: Option<fn(&mut LuaState, i32, isize) -> Result<usize, LuaError>>,
1633) -> Result<(), LuaError> {
1634 let top = state.top_idx();
1635 let func_idx = top - (nargs + 1);
1636 if k.is_some() && state.is_yieldable() {
1642 let ci_idx = state.ci;
1643 {
1644 let ci = state.get_ci_mut(ci_idx);
1645 ci.set_u_c_k(k);
1646 ci.set_u_c_ctx(ctx);
1647 }
1648 state.call_at(func_idx, nresults)?;
1649 } else {
1650 state.call_no_yield(func_idx, nresults)?;
1651 }
1652 state.adjust_results(nresults);
1653 Ok(())
1654}
1655
1656pub fn pcall_k(
1658 state: &mut LuaState,
1659 nargs: i32,
1660 nresults: i32,
1661 errfunc: i32,
1662 ctx: isize,
1663 k: Option<fn(&mut LuaState, i32, isize) -> Result<usize, LuaError>>,
1664) -> Result<LuaStatus, LuaError> {
1665 let _heap_guard = {
1670 let g = state.global.borrow();
1671 lua_gc::HeapGuard::push(&g.heap)
1676 };
1677 let err_handler_idx: isize = if errfunc == 0 {
1678 0
1679 } else {
1680 let o = index_to_stack_idx(state, errfunc);
1681 debug_assert!(
1682 matches!(state.get_at(o), LuaValue::Function(_)),
1683 "error handler must be a function"
1684 );
1685 o.0 as isize
1686 };
1687 let top = state.top_idx();
1688 let func_idx = top - (nargs + 1);
1689 if k.is_none() || !state.is_yieldable() {
1690 state.protected_call_raw(func_idx, nresults, StackIdx(err_handler_idx as u32))?;
1691 state.adjust_results(nresults);
1692 return Ok(LuaStatus::Ok);
1693 }
1694 let ci_idx = state.ci;
1700 let allow = state.allowhook;
1701 let saved_errfunc = state.errfunc;
1702 {
1703 let ci = state.get_ci_mut(ci_idx);
1704 ci.set_u_c_k(k);
1705 ci.set_u_c_ctx(ctx);
1706 ci.set_u2_funcidx(func_idx.0 as i32);
1707 ci.set_u_c_old_errfunc(saved_errfunc);
1708 ci.set_oah(allow);
1709 ci.callstatus |= crate::state::CIST_YPCALL;
1710 }
1711 state.errfunc = err_handler_idx;
1712 let call_result = crate::do_::call(state, func_idx, nresults);
1713 match call_result {
1714 Ok(()) => {
1715 state.get_ci_mut(ci_idx).callstatus &= !crate::state::CIST_YPCALL;
1718 state.errfunc = saved_errfunc;
1719 state.adjust_results(nresults);
1720 Ok(LuaStatus::Ok)
1721 }
1722 Err(crate::state::LuaError::Yield) => {
1723 Err(crate::state::LuaError::Yield)
1727 }
1728 Err(e) => {
1729 Err(e)
1733 }
1734 }
1735}
1736
1737pub fn load(
1741 state: &mut LuaState,
1742 reader: Box<dyn FnMut() -> Option<Vec<u8>>>,
1743 chunkname: Option<&[u8]>,
1744 mode: Option<&[u8]>,
1745) -> Result<LuaStatus, LuaError> {
1746 let name = chunkname.unwrap_or(b"?");
1747 let z = crate::zio::ZIO::new(reader);
1748 let status = state.protected_parser(z, name, mode);
1749 if status == LuaStatus::Ok {
1750 let top = state.top_idx();
1751 let func_val = state.get_at(top - 1);
1752 if let LuaValue::Function(LuaClosure::Lua(lcl)) = func_val {
1753 if !lcl.upvals.is_empty() {
1754 let gt = get_global_table(state);
1755 let uv = state.new_upval_closed(gt);
1756 lcl.set_upval(0, uv);
1757 }
1758 }
1759 }
1760 Ok(status)
1761}
1762
1763pub fn dump(
1764 state: &LuaState,
1765 writer: &mut dyn FnMut(&[u8]) -> Result<(), LuaError>,
1766 strip: bool,
1767) -> Result<bool, LuaError> {
1768 let top = state.top_idx();
1769 let o = state.get_at(top - 1);
1770 if let LuaValue::Function(LuaClosure::Lua(ref lcl)) = o {
1771 crate::dump::dump(state, &lcl.proto, writer, strip)?;
1772 Ok(true)
1773 } else {
1774 Ok(false)
1775 }
1776}
1777
1778pub fn status(state: &LuaState) -> LuaStatus {
1779 LuaStatus::from_raw(state.status as i32)
1780}
1781
1782#[repr(i32)]
1786#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1787pub enum GcWhat {
1788 Stop = 0,
1789 Restart = 1,
1790 Collect = 2,
1791 Count = 3,
1792 CountB = 4,
1793 Step = 5,
1794 SetPause = 6,
1795 SetStepMul = 7,
1796 IsRunning = 9,
1797 Gen = 10,
1798 Inc = 11,
1799}
1800
1801pub enum GcArgs {
1803 Stop,
1804 Restart,
1805 Collect,
1806 Count,
1807 CountB,
1808 Step { data: i32 },
1809 SetPause { value: i32 },
1810 SetStepMul { value: i32 },
1811 IsRunning,
1812 Gen { minormul: i32, majormul: i32 },
1813 Inc { pause: i32, stepmul: i32, stepsize: i32 },
1814}
1815
1816pub fn gc(state: &mut LuaState, args: GcArgs) -> i32 {
1817 if state.global().is_gc_stopped_internally() {
1818 return -1;
1819 }
1820 match args {
1821 GcArgs::Stop => {
1822 state.global_mut().set_gc_stop_user();
1823 }
1824 GcArgs::Restart => {
1825 {
1826 let mut g = state.global_mut();
1827 crate::state::set_debt(&mut *g, 0);
1828 }
1829 state.global_mut().clear_gc_stop();
1830 }
1831 GcArgs::Collect => {
1832 if !state.allowhook {
1833 return 0;
1834 }
1835 state.gc().full_collect();
1841 run_pending_finalizers(state);
1845 {
1854 let mut g = state.global_mut();
1855 crate::state::reclaim_dead_long_strings(&mut *g);
1856 }
1857 {
1865 let mut g = state.global_mut();
1866 let target_tb = 32_768_isize;
1867 let cur_tb = g.totalbytes + g.gc_debt;
1868 if cur_tb < target_tb {
1869 g.totalbytes += target_tb - cur_tb;
1870 }
1871 }
1872 }
1873 GcArgs::Count => {
1874 {
1875 let mut g = state.global_mut();
1876 crate::state::reclaim_dead_long_strings(&mut *g);
1877 }
1878 let g = state.global();
1879 let long_string_bytes: usize = g.gc_tracked_long_strings.iter().map(|(_, sz)| sz).sum();
1880 let total = g.heap.bytes_used() + long_string_bytes;
1881 return (total >> 10) as i32;
1882 }
1883 GcArgs::CountB => {
1884 {
1885 let mut g = state.global_mut();
1886 crate::state::reclaim_dead_long_strings(&mut *g);
1887 }
1888 let g = state.global();
1889 let long_string_bytes: usize = g.gc_tracked_long_strings.iter().map(|(_, sz)| sz).sum();
1890 let total = g.heap.bytes_used() + long_string_bytes;
1891 return (total & 0x3ff) as i32;
1892 }
1893 GcArgs::Step { data } => {
1894 let old_stp = {
1895 let mut g = state.global_mut();
1896 let old = g.gc_stop_flags();
1897 g.clear_gc_stop();
1898 old
1899 };
1900 let stepmul = (state.global().gc_stepmul_param() as isize | 1).max(1);
1907 let work_units = if data == 0 {
1908 stepmul
1909 } else {
1910 let raw = (data as isize).saturating_mul(stepmul);
1911 raw.max(1)
1912 };
1913 if data == 0 {
1914 let mut g = state.global_mut();
1915 crate::state::set_debt(&mut *g, 0);
1916 } else {
1917 let debt = data as isize * 1024 + state.global().gc_debt();
1918 let mut g = state.global_mut();
1919 crate::state::set_debt(&mut *g, debt);
1920 }
1921 let cycle_complete = state.gc().incremental_step(work_units);
1922 if state.global().is_gen_mode() {
1923 state.gc().prune_weak_tables_mark_only();
1924 }
1925 state.global_mut().set_gc_stop_flags(old_stp);
1926 if cycle_complete {
1933 let mut g = state.global_mut();
1934 let floor: isize = 1024;
1935 let cur_tb = g.totalbytes + g.gc_debt;
1936 let new_tb = (cur_tb / 2).max(floor);
1937 if new_tb < cur_tb {
1938 g.totalbytes -= cur_tb - new_tb;
1939 }
1940 }
1941 {
1943 let heap_state = state.global().heap.gc_state();
1944 let mut g = state.global_mut();
1945 g.gcstate = if heap_state.is_pause() { 0 } else { 1 };
1946 }
1947 return if cycle_complete { 1 } else { 0 };
1948 }
1949 GcArgs::SetPause { value } => {
1950 let old = state.global().gc_pause_param() as i32;
1951 state.global_mut().set_gc_pause_param(value as u8);
1952 return old;
1953 }
1954 GcArgs::SetStepMul { value } => {
1955 let old = state.global().gc_stepmul_param() as i32;
1956 state.global_mut().set_gc_stepmul_param(value as u8);
1957 return old;
1958 }
1959 GcArgs::IsRunning => {
1960 return state.global().gc_running() as i32;
1961 }
1962 GcArgs::Gen { minormul, majormul } => {
1963 let old_mode = if state.global().is_gen_mode() { 10i32 } else { 11i32 };
1964 if minormul != 0 {
1965 state.global_mut().genminormul = minormul as u8;
1966 }
1967 if majormul != 0 {
1968 state.global_mut().set_gc_genmajormul(majormul as u8);
1969 }
1970 state.gc().change_mode(crate::state::GcKind::Generational);
1971 return old_mode;
1972 }
1973 GcArgs::Inc { pause, stepmul, stepsize } => {
1974 let old_mode = if state.global().is_gen_mode() { 10i32 } else { 11i32 };
1975 if pause != 0 {
1976 state.global_mut().set_gc_pause_param(pause as u8);
1977 }
1978 if stepmul != 0 {
1979 state.global_mut().set_gc_stepmul_param(stepmul as u8);
1980 }
1981 if stepsize != 0 {
1982 state.global_mut().gcstepsize = stepsize as u8;
1983 }
1984 state.gc().change_mode(crate::state::GcKind::Incremental);
1985 return old_mode;
1986 }
1987 }
1988 0
1989}
1990
1991pub fn lua_error(state: &mut LuaState) -> Result<Infallible, LuaError> {
1998 let top = state.top_idx();
2002 let errobj = state.get_at(top - 1);
2003 let is_mem_err = if let LuaValue::Str(ref s) = errobj {
2004 let memerr = state.global().memerrmsg.clone();
2005 GcRef::ptr_eq(s, &memerr)
2006 } else {
2007 false
2008 };
2009 if is_mem_err {
2010 Err(LuaError::Memory)
2011 } else {
2012 Err(LuaError::from_value(errobj))
2013 }
2014}
2015
2016pub fn next(state: &mut LuaState, idx: i32) -> Result<bool, LuaError> {
2017 let t = get_table_value(state, idx)
2018 .ok_or_else(|| LuaError::runtime(format_args!("table expected")))?;
2019 let top = state.top_idx();
2020 let key = state.get_at(top - 1);
2021 match t.next(key)? {
2022 Some((next_key, next_val)) => {
2023 state.set_at(top - 1, next_key);
2024 state.push(next_val);
2025 Ok(true)
2026 }
2027 None => {
2028 state.set_top_idx(top - 1);
2029 Ok(false)
2030 }
2031 }
2032}
2033
2034pub fn to_close(state: &mut LuaState, idx: i32) -> Result<(), LuaError> {
2035 let _level = index_to_stack_idx(state, idx);
2036 Ok(())
2039}
2040
2041pub fn concat(state: &mut LuaState, n: i32) -> Result<(), LuaError> {
2042 if n > 0 {
2043 state.concat(n)?;
2044 } else {
2045 let empty = state.intern_str(b"")?;
2046 state.push(LuaValue::Str(empty));
2047 }
2048 state.gc().check_step();
2049 Ok(())
2050}
2051
2052pub fn len(state: &mut LuaState, idx: i32) -> Result<(), LuaError> {
2053 let t = index_to_value(state, idx);
2054 let result = state.obj_len(&t)?;
2055 state.push(result);
2056 Ok(())
2057}
2058
2059pub fn set_warn_f(
2064 state: &mut LuaState,
2065 f: Option<Box<dyn FnMut(&[u8], bool)>>,
2066) {
2067 state.global_mut().warnf = f;
2069}
2070
2071pub fn warning(state: &mut LuaState, msg: &[u8], tocont: bool) {
2072 state.emit_warning(msg, tocont);
2073}
2074
2075pub fn new_userdata_uv(
2076 state: &mut LuaState,
2077 size: usize,
2078 nuvalue: i32,
2079) -> Result<GcRef<LuaUserData>, LuaError> {
2080 debug_assert!(nuvalue >= 0 && nuvalue < u16::MAX as i32, "invalid value");
2081 let u = state.new_userdata(size, nuvalue as usize)?;
2082 state.push(LuaValue::UserData(u.clone()));
2083 state.gc().check_step();
2084 Ok(u)
2085}
2086
2087fn aux_upvalue(
2093 state: &LuaState,
2094 fi: &LuaValue,
2095 n: i32,
2096) -> Option<(Vec<u8>, LuaValue)> {
2097 match fi {
2098 LuaValue::Function(LuaClosure::C(ccl)) => {
2099 let nupvalues = ccl.upvalues.len() as i32;
2100 if n < 1 || n > nupvalues {
2101 return None;
2102 }
2103 Some((Vec::new(), ccl.upvalues[(n - 1) as usize].clone()))
2104 }
2105 LuaValue::Function(LuaClosure::Lua(lcl)) => {
2106 let nupvalues = lcl.upvals.len() as i32;
2107 if n < 1 || n > nupvalues {
2108 return None;
2109 }
2110 let val = state.upvalue_get(lcl, (n - 1) as usize);
2111 let name: Vec<u8> = lcl
2115 .proto
2116 .upvalues
2117 .get((n - 1) as usize)
2118 .and_then(|ud| ud.name.as_ref())
2119 .map(|s| s.as_bytes().to_vec())
2120 .unwrap_or_else(|| b"(no name)".to_vec());
2121 Some((name, val))
2122 }
2123 _ => None,
2124 }
2125}
2126
2127pub fn get_upvalue(state: &mut LuaState, funcindex: i32, n: i32) -> Option<Vec<u8>> {
2128 let fi = index_to_value(state, funcindex);
2129 if let Some((name, val)) = aux_upvalue(state, &fi, n) {
2130 state.push(val);
2131 Some(name)
2132 } else {
2133 None
2134 }
2135}
2136
2137pub fn setup_value(state: &mut LuaState, funcindex: i32, n: i32) -> Option<Vec<u8>> {
2138 let fi = index_to_value(state, funcindex);
2139 let (name, _) = aux_upvalue(state, &fi, n)?;
2140 let new_val = state.pop();
2141 match &fi {
2142 LuaValue::Function(LuaClosure::Lua(lcl)) => {
2143 state.upvalue_set(lcl, (n - 1) as usize, new_val).ok()?;
2144 }
2145 LuaValue::Function(LuaClosure::C(_ccl)) => {
2146 let _ = new_val;
2149 }
2150 _ => return None,
2151 }
2152 Some(name)
2153}
2154
2155fn get_upval_ref_idx(state: &LuaState, fidx: i32, n: i32) -> Option<usize> {
2158 let fi = index_to_value(state, fidx);
2159 debug_assert!(matches!(fi, LuaValue::Function(LuaClosure::Lua(_))), "Lua function expected");
2160 if let LuaValue::Function(LuaClosure::Lua(ref lcl)) = fi {
2161 let sizeupvalues = lcl.upvals.len() as i32;
2162 if n >= 1 && n <= sizeupvalues {
2163 Some((n - 1) as usize)
2164 } else {
2165 None
2166 }
2167 } else {
2168 None
2169 }
2170}
2171
2172pub fn upvalue_id(state: &LuaState, fidx: i32, n: i32) -> Option<usize> {
2174 let fi = index_to_value(state, fidx);
2175 match &fi {
2176 LuaValue::Function(LuaClosure::Lua(lcl)) => {
2177 let idx = get_upval_ref_idx(state, fidx, n)?;
2178 Some(GcRef::identity(&lcl.upval(idx)))
2180 }
2181 LuaValue::Function(LuaClosure::C(ccl)) => {
2182 if n >= 1 && n <= ccl.upvalues.len() as i32 {
2183 Some(GcRef::identity(ccl) ^ (n as usize))
2186 } else {
2187 None
2188 }
2189 }
2190 LuaValue::Function(LuaClosure::LightC(_)) => None,
2191 _ => {
2192 debug_assert!(false, "function expected");
2193 None
2194 }
2195 }
2196}
2197
2198pub fn upvalue_join(state: &mut LuaState, fidx1: i32, n1: i32, fidx2: i32, n2: i32) {
2200 let idx1 = match get_upval_ref_idx(state, fidx1, n1) {
2201 Some(i) => i,
2202 None => return,
2203 };
2204 let idx2 = match get_upval_ref_idx(state, fidx2, n2) {
2205 Some(i) => i,
2206 None => return,
2207 };
2208 let f1 = index_to_value(state, fidx1);
2209 let f2 = index_to_value(state, fidx2);
2210 if let (
2211 LuaValue::Function(LuaClosure::Lua(lcl1)),
2212 LuaValue::Function(LuaClosure::Lua(lcl2)),
2213 ) = (&f1, &f2)
2214 {
2215 let shared = lcl2.upval(idx2);
2216 lcl1.set_upval(idx1, shared);
2217 }
2218}
2219
2220