1#![allow(dead_code)]
9
10use std::convert::Infallible;
11#[allow(unused_imports)] use crate::prelude::*;
12
13use crate::state::{LuaState, LuaCFunction, GlobalState, CallInfo, CallInfoIdx, StackIdx,
14 LuaValueExt, LuaTypeExt, StackIdxExt,
15 LuaTableRefExt, LuaUserDataRefExt, LuaStringRefExt,
16 LuaLClosureRefExt, LuaClosureExt, LuaProtoExt};
17use lua_types::{
18 LuaValue, LuaType, LuaError, LuaString, LuaUserData, LuaClosure, UpVal,
19 GcRef, LuaStatus,
20};
21use lua_types::value::LuaTable;
22
23pub const LUA_IDENT: &[u8] =
24 b"$LuaVersion: Lua 5.4.7 Copyright (C) 1994-2024 Lua.org, PUC-Rio $\
25 $LuaAuthors: R. Ierusalimschy, L. H. Figueiredo, W. Celes $";
26
27const LUA_REGISTRYINDEX: i32 = -(1_000_000) - 1000;
28
29const LUA_MULTRET: i32 = -1;
30
31const LUA_RIDX_GLOBALS: i64 = 2;
32
33const MAX_UPVAL: u8 = 255;
34
35#[inline]
36fn is_pseudo(idx: i32) -> bool {
37 idx <= LUA_REGISTRYINDEX
38}
39
40#[inline]
41fn is_upvalue(idx: i32) -> bool {
42 idx < LUA_REGISTRYINDEX
43}
44
45#[inline]
50fn is_valid_index(state: &LuaState, idx: i32) -> bool {
51 if idx == 0 {
52 return false;
53 }
54 let ci = state.current_call_info();
55 if idx > 0 {
56 let slot = ci.func + idx;
57 slot.0 < state.top_idx().0
58 } else if !is_pseudo(idx) {
59 (-idx) as u32 <= state.top_idx().0.saturating_sub(ci.func.0 + 1)
60 } else if idx == LUA_REGISTRYINDEX {
61 true
62 } else {
63 let upval_n = (LUA_REGISTRYINDEX - idx) as usize;
64 let func_val = state.get_at(ci.func);
65 if let LuaValue::Function(LuaClosure::C(ref ccl)) = func_val {
66 upval_n >= 1 && upval_n <= ccl.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!(
94 idx != 0,
95 "invalid index"
96 );
97 let top = state.top_idx();
98 let slot = (top.0 as i32 + idx) as u32;
99 state.get_at(slot)
100 } else if idx == LUA_REGISTRYINDEX {
101 state.registry_value()
102 } else {
103 let upval_n = (LUA_REGISTRYINDEX - idx) as usize;
105 debug_assert!(upval_n <= MAX_UPVAL as usize + 1, "upvalue index too large");
106 let func_val = state.get_at(ci.func);
107 if let LuaValue::Function(LuaClosure::C(ref ccl)) = func_val {
108 if upval_n >= 1 && upval_n <= ccl.upvalues.len() {
110 ccl.upvalues[upval_n - 1].clone()
111 } else {
112 LuaValue::Nil
113 }
114 } else {
115 LuaValue::Nil
116 }
117 }
118}
119
120#[inline]
122fn index_to_stack_idx(state: &LuaState, idx: i32) -> StackIdx {
123 let ci = state.current_call_info();
124 if idx > 0 {
125 let slot = ci.func + idx;
126 debug_assert!(slot.0 < state.top_idx().0, "invalid index");
127 slot
128 } else {
129 debug_assert!(idx != 0 && !is_pseudo(idx), "invalid index");
130 StackIdx((state.top_idx().0 as i32 + idx) as u32)
131 }
132}
133
134pub fn check_stack(state: &mut LuaState, n: i32) -> bool {
137 debug_assert!(n >= 0, "negative 'n'");
138 let available = state.stack_available();
139 let res = if available > n as usize {
140 true
141 } else {
142 crate::do_::grow_stack(state, n, false).unwrap_or(false)
143 };
144 if res {
145 let needed_top = state.top_idx() + n as i32;
146 let ci_idx = state.current_ci_idx();
147 if state.get_ci(ci_idx).top.0 < needed_top.0 {
148 let live_top = state.top_idx();
149 state.get_ci_mut(ci_idx).top = needed_top;
150 state.clear_stack_range(live_top, needed_top);
151 }
152 }
153 res
154}
155
156pub fn xmove(from: &mut LuaState, to: &mut LuaState, n: i32) {
173 if n <= 0 {
174 return;
175 }
176 if std::ptr::eq(from as *const LuaState, to as *const LuaState) {
177 return;
178 }
179 let abs_top = from.top_idx().0 as i32;
180 debug_assert!(abs_top >= n, "lua_xmove: from stack underflow");
181 let first_abs = abs_top - n;
182 let mut buf: Vec<lua_types::LuaValue> = Vec::with_capacity(n as usize);
183 for i in 0..n {
184 let idx = StackIdx((first_abs + i) as u32);
185 buf.push(from.get_at(idx));
186 }
187 from.set_top(StackIdx(first_abs as u32));
188 for v in buf {
189 to.push(v);
190 }
191}
192
193pub fn at_panic(
194 state: &mut LuaState,
195 panicf: Option<fn(&mut LuaState) -> Result<usize, LuaError>>,
196) -> Option<fn(&mut LuaState) -> Result<usize, LuaError>> {
197 let old = state.global_mut().panic;
198 state.global_mut().panic = panicf;
199 old
200}
201
202pub fn version(_state: &LuaState) -> f64 {
203 504.0
204}
205
206pub fn abs_index(state: &LuaState, idx: i32) -> i32 {
207 if idx > 0 || is_pseudo(idx) {
209 idx
210 } else {
211 let ci = state.current_call_info();
212 (state.top_idx().0 as i32 - ci.func.0 as i32) + idx
213 }
214}
215
216pub fn get_top(state: &LuaState) -> i32 {
217 let ci = state.current_call_info();
218 (state.top_idx().0 as i32) - (ci.func.0 as i32 + 1)
219}
220
221pub fn set_top(state: &mut LuaState, idx: i32) -> Result<(), LuaError> {
222 let func = state.current_call_info().func;
223 let ci_top = state.current_call_info().top;
224 if idx >= 0 {
225 debug_assert!(
226 idx as u32 <= ci_top.saturating_sub(func + 1),
227 "new top too large"
228 );
229 let new_top = func + 1 + idx as i32;
230 let old_top = state.top_idx();
231 if new_top.0 > old_top.0 {
232 for i in old_top.0..new_top.0 {
233 state.set_at(i, LuaValue::Nil);
234 }
235 }
236 state.set_top_idx(new_top);
239 } else {
240 debug_assert!(
241 -(idx + 1) <= (state.top_idx().0 as i32 - (func.0 as i32 + 1)),
242 "invalid new top"
243 );
244 let new_top = (state.top_idx().0 as i32 + idx + 1) as u32;
245 state.set_top_idx(new_top);
247 }
248 Ok(())
249}
250
251pub fn close_slot(state: &mut LuaState, idx: i32) -> Result<(), LuaError> {
252 let level = index_to_stack_idx(state, idx);
253 state.set_at(level, LuaValue::Nil);
255 Ok(())
256}
257
258#[inline]
259fn reverse_segment(state: &mut LuaState, from: StackIdx, to: StackIdx) {
260 let mut lo = from.0;
261 let mut hi = to.0;
262 while lo < hi {
263 let temp = state.get_at(StackIdx(lo));
264 let hi_val = state.get_at(StackIdx(hi));
265 state.set_at(StackIdx(lo), hi_val);
266 state.set_at(StackIdx(hi), temp);
267 lo += 1;
268 hi -= 1;
269 }
270}
271
272pub fn rotate(state: &mut LuaState, idx: i32, n: i32) {
273 let t = state.top_idx() - 1;
274 let p = index_to_stack_idx(state, idx);
275 debug_assert!((n.unsigned_abs() as i32) <= ((t.0 as i32) - (p.0 as i32) + 1), "invalid 'n'");
276 let m = if n >= 0 {
277 t - n
278 } else {
279 StackIdx((p.0 as i32 - n - 1) as u32)
280 };
281 reverse_segment(state, p, m);
282 reverse_segment(state, m + 1, t);
283 reverse_segment(state, p, t);
284}
285
286pub fn copy(state: &mut LuaState, fromidx: i32, toidx: i32) {
287 let fr = index_to_value(state, fromidx);
288 if is_upvalue(toidx) {
289 let upval_n = (LUA_REGISTRYINDEX - toidx) as usize;
291 let func_val = state.get_at(state.current_call_info().func);
292 if let LuaValue::Function(LuaClosure::C(ref ccl)) = func_val {
293 let _ = (upval_n, ccl);
296 }
297 } else if toidx == LUA_REGISTRYINDEX {
299 } else {
301 let to_slot = index_to_stack_idx(state, toidx);
302 state.set_at(to_slot, fr);
303 }
304}
305
306pub fn push_value(state: &mut LuaState, idx: i32) {
307 let v = index_to_value(state, idx);
308 state.push(v);
309}
310
311impl LuaState {
316 pub fn push_copy(&mut self, idx: i32) -> Result<(), LuaError> {
317 push_value(self, idx);
318 Ok(())
319 }
320
321 pub fn push_value_at(&mut self, idx: i32) -> Result<(), LuaError> {
322 push_value(self, idx);
323 Ok(())
324 }
325
326 pub fn insert(&mut self, idx: i32) -> Result<(), LuaError> {
327 rotate(self, idx, 1);
328 Ok(())
329 }
330
331 pub fn length_at(&mut self, idx: i32) -> Result<i64, LuaError> {
337 len(self, idx)?;
338 let l = match to_integer_x(self, -1) {
339 Some(n) => n,
340 None => {
341 return Err(LuaError::runtime(format_args!(
342 "object length is not an integer"
343 )));
344 }
345 };
346 self.pop_n(1);
347 Ok(l)
348 }
349
350 pub fn write_output(&mut self, msg: &[u8]) -> Result<(), LuaError> {
357 use std::io::Write;
358 let stdout = std::io::stdout();
359 let mut handle = stdout.lock();
360 handle
361 .write_all(msg)
362 .map_err(|e| LuaError::runtime(format_args!("{}", e)))?;
363 handle
364 .flush()
365 .map_err(|e| LuaError::runtime(format_args!("{}", e)))?;
366 Ok(())
367 }
368
369 pub fn to_display_string(&mut self, idx: i32) -> Result<Vec<u8>, LuaError> {
378 let abs = abs_index(self, idx);
379 let v = index_to_value(self, abs);
380 let mt: Option<GcRef<LuaTable>> = match &v {
381 LuaValue::Table(t) => t.metatable(),
382 LuaValue::UserData(u) => u.metatable(),
383 _ => self.global().mt[v.base_type() as usize].clone(),
384 };
385 if let Some(mt_ref) = mt {
386 let key = self.intern_str(b"__tostring")?;
387 let f = mt_ref.get_short_str(&key);
388 if !matches!(f, LuaValue::Nil) {
389 let func_idx = self.top_idx();
390 self.push(f);
391 self.push(v.clone());
392 if self.current_ci().is_lua_code() {
393 self.do_call(func_idx, 1)?;
394 } else {
395 self.do_call_no_yield(func_idx, 1)?;
396 }
397 let top = self.top_idx();
398 let result = self.get_at(StackIdx(top.0 - 1));
399 if let LuaValue::Str(s) = result {
400 return Ok(s.as_bytes().to_vec());
401 }
402 return Err(LuaError::runtime(format_args!(
403 "'__tostring' must return a string"
404 )));
405 }
406 }
407 let bytes: Vec<u8> = match &v {
408 LuaValue::Str(s) => {
409 let out = s.as_bytes().to_vec();
410 self.push(LuaValue::Str(s.clone()));
411 out
412 }
413 LuaValue::Int(_) | LuaValue::Float(_) => {
414 let s = crate::object::num_to_string(self, &v)?;
415 let out = s.as_bytes().to_vec();
416 self.push(LuaValue::Str(s));
417 out
418 }
419 LuaValue::Bool(b) => {
420 let lit: &[u8] = if *b { b"true" } else { b"false" };
421 let s = self.intern_str(lit)?;
422 self.push(LuaValue::Str(s));
423 lit.to_vec()
424 }
425 LuaValue::Nil => {
426 let s = self.intern_str(b"nil")?;
427 self.push(LuaValue::Str(s));
428 b"nil".to_vec()
429 }
430 _ => {
431 let kind = crate::tagmethods::obj_type_name(self, &v)?;
432 let ptr = to_pointer(self, abs).unwrap_or(0);
433 let mut buf = kind;
434 buf.extend_from_slice(b": 0x");
435 buf.extend_from_slice(format!("{:x}", ptr).as_bytes());
436 let s = self.intern_str(&buf)?;
437 self.push(LuaValue::Str(s));
438 buf
439 }
440 };
441 Ok(bytes)
442 }
443
444 pub fn top(&mut self) -> i32 {
451 get_top(self)
452 }
453
454 pub fn get_top(&mut self) -> i32 {
458 get_top(self)
459 }
460
461 pub fn type_at(&mut self, idx: i32) -> LuaType {
466 lua_type_at(self, idx)
467 }
468
469 pub fn check_arg_any(&mut self, arg: i32) -> Result<(), LuaError> {
475 if lua_type_at(self, arg) == LuaType::None {
476 return Err(LuaError::arg_error(arg, "value expected"));
477 }
478 Ok(())
479 }
480
481 pub fn check_arg_string(&mut self, arg: i32) -> Result<Vec<u8>, LuaError> {
491 match to_lua_string(self, arg)? {
492 Some(s) => Ok(s.as_bytes().to_vec()),
493 None => {
494 let got = index_to_value(self, arg);
495 let got_name = crate::tagmethods::obj_type_name(self, &got)?;
496 let extramsg = format!(
497 "string expected, got {}",
498 String::from_utf8_lossy(&got_name)
499 );
500 Err(crate::debug::arg_error_impl(self, arg, extramsg.as_bytes()))
501 }
502 }
503 }
504
505 pub fn check_arg_integer(&mut self, arg: i32) -> Result<i64, LuaError> {
517 match to_integer_x(self, arg) {
518 Some(d) => Ok(d),
519 None => {
520 if is_number(self, arg) {
521 Err(LuaError::arg_error(
522 arg,
523 "number has no integer representation",
524 ))
525 } else {
526 let got = index_to_value(self, arg);
527 let got_name = crate::tagmethods::obj_type_name(self, &got)?;
528 let extramsg = format!(
529 "number expected, got {}",
530 String::from_utf8_lossy(&got_name)
531 );
532 Err(crate::debug::arg_error_impl(self, arg, extramsg.as_bytes()))
533 }
534 }
535 }
536 }
537
538 pub fn check_number(&mut self, arg: i32) -> Result<f64, LuaError> {
548 match to_number_x(self, arg) {
549 Some(d) => Ok(d),
550 None => {
551 let got = index_to_value(self, arg);
552 let got_name = crate::tagmethods::obj_type_name(self, &got)?;
553 let extramsg = format!(
554 "number expected, got {}",
555 String::from_utf8_lossy(&got_name)
556 );
557 Err(crate::debug::arg_error_impl(self, arg, extramsg.as_bytes()))
558 }
559 }
560 }
561
562 pub fn opt_arg_integer(&mut self, arg: i32, def: i64) -> Result<i64, LuaError> {
572 match lua_type_at(self, arg) {
573 LuaType::None | LuaType::Nil => Ok(def),
574 _ => match to_integer_x(self, arg) {
575 Some(d) => Ok(d),
576 None => {
577 if is_number(self, arg) {
578 Err(LuaError::arg_error(
579 arg,
580 "number has no integer representation",
581 ))
582 } else {
583 let got = index_to_value(self, arg);
584 Err(LuaError::type_arg_error(arg, "number", &got))
585 }
586 }
587 },
588 }
589 }
590
591 pub fn protected_call(&mut self, nargs: i32, nresults: i32, msgh: i32) -> Result<(), LuaError> {
598 pcall_k(self, nargs, nresults, msgh, 0, None).map(|_| ())
599 }
600
601 pub fn protected_call_k(
605 &mut self,
606 nargs: i32,
607 nresults: i32,
608 msgh: i32,
609 ctx: isize,
610 k: Option<crate::state::LuaKFunction>,
611 ) -> Result<(), LuaError> {
612 pcall_k(self, nargs, nresults, msgh, ctx, k).map(|_| ())
613 }
614
615 pub fn push_string(&mut self, s: &[u8]) -> Result<(), LuaError> {
616 push_lstring(self, s)?;
617 Ok(())
618 }
619
620 pub fn push_c_closure(
621 &mut self,
622 f: fn(&mut LuaState) -> Result<usize, LuaError>,
623 n: i32,
624 ) -> Result<(), LuaError> {
625 push_cclosure(self, f, n)
626 }
627
628 pub fn raw_seti(&mut self, idx: i32, n: i64) -> Result<(), LuaError> {
629 raw_set_i(self, idx, n)
630 }
631
632 pub fn table_set_i(&mut self, idx: i32, n: i64) -> Result<(), LuaError> {
633 set_i(self, idx, n)
634 }
635
636 pub fn table_get_i_value(&mut self, t: &LuaValue, n: i64) -> Result<LuaType, LuaError> {
640 get_i_value(self, t, n)
641 }
642
643 pub fn table_set_i_value(&mut self, t: &LuaValue, n: i64) -> Result<(), LuaError> {
647 set_i_value(self, t, n)
648 }
649
650 pub fn create_table(&mut self, narr: i32, nrec: i32) -> Result<(), LuaError> {
651 create_table(self, narr, nrec)
652 }
653
654 pub fn registry_set(&mut self, key: &[u8]) -> Result<(), LuaError> {
658 set_field(self, LUA_REGISTRYINDEX, key)
659 }
660
661 pub fn new_metatable(&mut self, tname: &[u8]) -> Result<bool, LuaError> {
667 if get_field(self, LUA_REGISTRYINDEX, tname)? != LuaType::Nil {
668 return Ok(false);
669 }
670 self.pop_n(1);
671 create_table(self, 0, 2)?;
672 push_lstring(self, tname)?;
673 set_field(self, -2, b"__name")?;
674 push_value(self, -1);
675 set_field(self, LUA_REGISTRYINDEX, tname)?;
676 Ok(true)
677 }
678
679 pub fn new_lib(
686 &mut self,
687 funcs: &[(&[u8], LuaCFunction)],
688 ) -> Result<(), LuaError> {
689 create_table(self, 0, funcs.len() as i32)?;
690 for (name, f) in funcs {
691 push_cclosure(self, *f, 0)?;
692 set_field(self, -2, name)?;
693 }
694 Ok(())
695 }
696
697 pub fn register_lib(
703 &mut self,
704 _name: &[u8],
705 funcs: &[(&[u8], LuaCFunction)],
706 ) -> Result<(), LuaError> {
707 self.new_lib(funcs)
708 }
709
710 pub fn new_lib_table(
719 &mut self,
720 funcs: &[(&[u8], LuaCFunction)],
721 ) -> Result<(), LuaError> {
722 create_table(self, 0, funcs.len() as i32)
723 }
724
725 pub fn set_funcs_with_upvalues(
730 &mut self,
731 funcs: &[(&[u8], LuaCFunction)],
732 nup: i32,
733 ) -> Result<(), LuaError> {
734 check_stack(self, nup);
735 for (name, f) in funcs {
736 for _ in 0..nup {
737 push_value(self, -nup);
738 }
739 push_cclosure(self, *f, nup)?;
740 set_field(self, -(nup + 2), name)?;
741 }
742 self.pop_n(nup as usize);
743 Ok(())
744 }
745
746 pub fn set_metatable(&mut self, objindex: i32) -> Result<(), LuaError> {
747 set_metatable(self, objindex)?;
748 Ok(())
749 }
750
751 pub fn set_metatable_by_name(&mut self, name: &[u8]) -> Result<(), LuaError> {
757 get_field(self, LUA_REGISTRYINDEX, name)?;
758 set_metatable(self, -2)?;
759 Ok(())
760 }
761
762 pub fn get_subtable_registry(&mut self, name: &[u8]) -> Result<bool, LuaError> {
766 if get_field(self, LUA_REGISTRYINDEX, name)? == LuaType::Table {
767 return Ok(true);
768 }
769 self.pop_n(1);
770 let idx = abs_index(self, LUA_REGISTRYINDEX);
771 let new_tbl = self.new_table();
772 self.push(LuaValue::Table(new_tbl));
773 push_value(self, -1);
774 set_field(self, idx, name)?;
775 Ok(false)
776 }
777
778 pub fn new_userdata_typed(
788 &mut self,
789 _name: &[u8],
790 size: usize,
791 nuvalue: i32,
792 ) -> Result<GcRef<LuaUserData>, LuaError> {
793 debug_assert!(nuvalue >= 0 && nuvalue < u16::MAX as i32, "invalid value");
794 let u = GcRef::new(LuaUserData {
796 data: vec![0u8; size].into_boxed_slice(),
797 uv: vec![LuaValue::Nil; nuvalue as usize],
798 metatable: std::cell::RefCell::new(None),
799 });
800 self.push(LuaValue::UserData(u.clone()));
801 self.gc().check_step();
802 Ok(u)
803 }
804}
805
806pub fn lua_type_at(state: &LuaState, idx: i32) -> LuaType {
809 if !is_valid_index(state, idx) {
810 return LuaType::None;
811 }
812 index_to_value(state, idx).base_type()
813}
814
815pub fn type_name(_state: &LuaState, t: LuaType) -> &'static [u8] {
816 t.type_name()
817}
818
819pub fn is_cfunction(state: &LuaState, idx: i32) -> bool {
820 let o = index_to_value(state, idx);
821 matches!(o, LuaValue::Function(LuaClosure::LightC(_)) | LuaValue::Function(LuaClosure::C(_)))
822}
823
824pub fn is_integer(state: &LuaState, idx: i32) -> bool {
825 let o = index_to_value(state, idx);
826 matches!(o, LuaValue::Int(_))
827}
828
829pub fn is_number(state: &LuaState, idx: i32) -> bool {
830 let o = index_to_value(state, idx);
831 o.to_number_with_strconv().is_some()
832}
833
834pub fn is_string(state: &LuaState, idx: i32) -> bool {
835 let o = index_to_value(state, idx);
836 matches!(o, LuaValue::Str(_) | LuaValue::Int(_) | LuaValue::Float(_))
837}
838
839pub fn is_userdata(state: &LuaState, idx: i32) -> bool {
840 let o = index_to_value(state, idx);
841 matches!(o, LuaValue::UserData(_) | LuaValue::LightUserData(_))
842}
843
844pub fn raw_equal(state: &LuaState, index1: i32, index2: i32) -> bool {
845 if !is_valid_index(state, index1) || !is_valid_index(state, index2) {
846 return false;
847 }
848 let o1 = index_to_value(state, index1);
849 let o2 = index_to_value(state, index2);
850 state.equal_obj(None, &o1, &o2)
851}
852
853pub fn arith(state: &mut LuaState, op: i32) -> Result<(), LuaError> {
855 const LUA_OPUNM: i32 = 12;
858 const LUA_OPBNOT: i32 = 14;
859 if op == LUA_OPUNM || op == LUA_OPBNOT {
860 let top_val = state.get_at(state.top_idx() - 1);
862 state.push(top_val);
863 }
864 let top = state.top_idx();
865 let a = state.get_at(top - 2);
866 let b = state.get_at(top - 1);
867 let result = state.arith_op(op, &a, &b)?;
868 state.set_at(top - 2, result);
869 state.pop();
870 Ok(())
871}
872
873pub fn compare(state: &mut LuaState, index1: i32, index2: i32, op: i32) -> Result<bool, LuaError> {
874 let valid = is_valid_index(state, index1) && is_valid_index(state, index2);
875 let o1 = index_to_value(state, index1);
876 let o2 = index_to_value(state, index2);
877 if valid {
878 match op {
879 0 => Ok(state.equal_obj_with_tm(&o1, &o2)?),
880 1 => state.less_than(&o1, &o2),
881 2 => state.less_equal(&o1, &o2),
882 _ => {
883 debug_assert!(false, "invalid option");
884 Ok(false)
885 }
886 }
887 } else {
888 Ok(false)
889 }
890}
891
892pub fn string_to_number(state: &mut LuaState, s: &[u8]) -> usize {
893 match state.str_to_num(s) {
895 Some((val, consumed)) => {
896 state.push(val);
897 consumed
898 }
899 None => 0,
900 }
901}
902
903pub fn to_number_x(state: &LuaState, idx: i32) -> Option<f64> {
904 let o = index_to_value(state, idx);
905 o.to_number_with_strconv()
906}
907
908pub fn to_integer_x(state: &LuaState, idx: i32) -> Option<i64> {
909 let o = index_to_value(state, idx);
910 o.to_integer_with_strconv()
911}
912
913pub fn to_boolean(state: &LuaState, idx: i32) -> bool {
914 let o = index_to_value(state, idx);
915 !matches!(o, LuaValue::Nil | LuaValue::Bool(false))
916}
917
918pub fn to_lua_string(
920 state: &mut LuaState,
921 idx: i32,
922) -> Result<Option<GcRef<LuaString>>, LuaError> {
923 let o = index_to_value(state, idx);
924 if let LuaValue::Str(s) = &o {
925 return Ok(Some(s.clone()));
926 }
927 if !matches!(o, LuaValue::Int(_) | LuaValue::Float(_)) {
928 return Ok(None);
929 }
930 state.obj_to_string(idx)?;
931 state.gc().check_step();
932 let updated = index_to_value(state, idx);
933 if let LuaValue::Str(s) = updated {
934 Ok(Some(s))
935 } else {
936 Ok(None)
937 }
938}
939
940pub fn raw_len(state: &LuaState, idx: i32) -> u64 {
941 let o = index_to_value(state, idx);
942 match &o {
943 LuaValue::Str(s) => s.len() as u64,
944 LuaValue::UserData(u) => u.len() as u64,
945 LuaValue::Table(t) => state.table_getn(t) as u64,
946 _ => 0,
947 }
948}
949
950pub fn to_cfunction(
951 state: &LuaState,
952 idx: i32,
953) -> Option<fn(&mut LuaState) -> Result<usize, LuaError>> {
954 let o = index_to_value(state, idx);
955 match o {
956 LuaValue::Function(LuaClosure::LightC(_f)) => None,
960 LuaValue::Function(LuaClosure::C(_ccl)) => None,
961 _ => None,
962 }
963}
964
965#[inline]
966fn to_userdata_ptr(o: &LuaValue) -> Option<*mut core::ffi::c_void> {
967 match o {
968 LuaValue::UserData(u) => {
969 let _ = u;
973 None
974 }
975 LuaValue::LightUserData(p) => Some(*p),
976 _ => None,
977 }
978}
979
980pub fn to_userdata(state: &LuaState, idx: i32) -> Option<*mut core::ffi::c_void> {
981 let o = index_to_value(state, idx);
982 to_userdata_ptr(&o)
983}
984
985pub fn to_thread(state: &LuaState, idx: i32) -> Option<GcRef<lua_types::value::LuaThread>> {
986 let o = index_to_value(state, idx);
990 if let LuaValue::Thread(t) = o {
991 Some(t)
992 } else {
993 None
994 }
995}
996
997pub fn to_pointer(state: &LuaState, idx: i32) -> Option<usize> {
1000 let o = index_to_value(state, idx);
1001 match &o {
1004 LuaValue::Function(LuaClosure::LightC(f)) => Some(*f as usize),
1005 LuaValue::LightUserData(p) => Some(*p as usize),
1006 LuaValue::Str(s) => Some(GcRef::identity(s)),
1007 LuaValue::Table(t) => Some(GcRef::identity(t)),
1008 LuaValue::Function(LuaClosure::Lua(f)) => Some(GcRef::identity(f)),
1009 LuaValue::Function(LuaClosure::C(f)) => Some(GcRef::identity(f)),
1010 LuaValue::UserData(u) => Some(GcRef::identity(u)),
1011 LuaValue::Thread(t) => Some(GcRef::identity(t)),
1012 _ => None,
1013 }
1014}
1015
1016pub fn push_nil(state: &mut LuaState) {
1019 state.push(LuaValue::Nil);
1020}
1021
1022pub fn push_number(state: &mut LuaState, n: f64) {
1023 state.push(LuaValue::Float(n));
1024}
1025
1026pub fn push_integer(state: &mut LuaState, n: i64) {
1027 state.push(LuaValue::Int(n));
1028}
1029
1030pub fn push_lstring(state: &mut LuaState, s: &[u8]) -> Result<GcRef<LuaString>, LuaError> {
1032 let ts = state.intern_str(s)?;
1033 state.push(LuaValue::Str(ts.clone()));
1034 state.gc().check_step();
1035 Ok(ts)
1036}
1037
1038pub fn push_string(state: &mut LuaState, s: Option<&[u8]>) -> Result<Option<GcRef<LuaString>>, LuaError> {
1039 match s {
1040 None => {
1041 state.push(LuaValue::Nil);
1042 state.gc().check_step();
1043 Ok(None)
1044 }
1045 Some(bytes) => {
1046 let ts = state.intern_str(bytes)?;
1047 state.push(LuaValue::Str(ts.clone()));
1048 state.gc().check_step();
1049 Ok(Some(ts))
1050 }
1051 }
1052}
1053
1054pub fn push_vfstring(state: &mut LuaState, formatted: &[u8]) -> Result<GcRef<LuaString>, LuaError> {
1058 let ts = state.intern_str(formatted)?;
1059 state.push(LuaValue::Str(ts.clone()));
1060 state.gc().check_step();
1061 Ok(ts)
1062}
1063
1064pub fn push_fstring(state: &mut LuaState, formatted: &[u8]) -> Result<GcRef<LuaString>, LuaError> {
1066 push_vfstring(state, formatted)
1067}
1068
1069pub fn push_cclosure(
1070 state: &mut LuaState,
1071 f: fn(&mut LuaState) -> Result<usize, LuaError>,
1072 n: i32,
1073) -> Result<(), LuaError> {
1074 let idx: lua_types::closure::LuaCFnPtr = {
1088 let mut g = state.global_mut();
1089 if n == 0 {
1090 match g.c_functions.iter().position(|&existing| existing == f) {
1091 Some(i) => i,
1092 None => {
1093 let i = g.c_functions.len();
1094 g.c_functions.push(f);
1095 i
1096 }
1097 }
1098 } else {
1099 let i = g.c_functions.len();
1100 g.c_functions.push(f);
1101 i
1102 }
1103 };
1104 if n == 0 {
1105 state.push(LuaValue::Function(LuaClosure::LightC(idx)));
1106 } else {
1107 debug_assert!(n > 0 && (n as u32) <= MAX_UPVAL as u32, "upvalue index too large");
1108 let n_usize = n as usize;
1109 let top = state.top_idx();
1110 debug_assert!((top.0 as usize) >= n_usize, "not enough elements on stack");
1111 let base = top.0 as usize - n_usize;
1112 let mut upvalues: Vec<LuaValue> = Vec::with_capacity(n_usize);
1113 for i in 0..n_usize {
1114 upvalues.push(state.get_at(crate::state::StackIdx((base + i) as u32)));
1115 }
1116 state.pop_n(n_usize);
1117 let cl = LuaClosure::C(GcRef::new(lua_types::closure::LuaCClosure {
1119 func: idx,
1120 upvalues,
1121 }));
1122 state.push(LuaValue::Function(cl));
1123 state.gc().check_step();
1124 }
1125 Ok(())
1126}
1127
1128pub fn push_boolean(state: &mut LuaState, b: bool) {
1129 state.push(LuaValue::Bool(b));
1130}
1131
1132pub fn push_light_userdata(state: &mut LuaState, p: *mut core::ffi::c_void) {
1133 state.push(LuaValue::LightUserData(p));
1134}
1135
1136pub fn push_thread(state: &mut LuaState) -> bool {
1138 let (value, is_main) = {
1139 let g = state.global();
1140 let id = g.current_thread_id;
1141 let v = g
1142 .thread_value_for(id)
1143 .expect("current_thread_id must always resolve to a registered thread");
1144 (v, id == g.main_thread_id)
1145 };
1146 state.push(LuaValue::Thread(value));
1147 is_main
1148}
1149
1150fn aux_get_str(state: &mut LuaState, t: LuaValue, k: &[u8]) -> Result<LuaType, LuaError> {
1153 let str_val = {
1154 let ts = state.intern_str(k)?;
1155 LuaValue::Str(ts)
1156 };
1157 let result = state.table_get_with_tm(&t, &str_val)?;
1160 state.push(result);
1161 let top = state.top_idx();
1162 Ok(state.get_at(top - 1).base_type())
1163}
1164
1165fn get_global_table(state: &LuaState) -> LuaValue {
1166 state.global().globals.clone()
1172}
1173
1174pub fn get_global(state: &mut LuaState, name: &[u8]) -> Result<LuaType, LuaError> {
1175 let g = get_global_table(state);
1176 aux_get_str(state, g, name)
1177}
1178
1179pub fn get_table(state: &mut LuaState, idx: i32) -> Result<LuaType, LuaError> {
1180 let t = index_to_value(state, idx);
1181 let top = state.top_idx();
1182 let key = state.get_at(top - 1);
1183 let result = state.table_get_with_tm(&t, &key)?;
1184 state.set_at(top - 1, result);
1185 let val = state.get_at(top - 1);
1186 Ok(val.base_type())
1187}
1188
1189pub fn get_field(state: &mut LuaState, idx: i32, k: &[u8]) -> Result<LuaType, LuaError> {
1190 let t = index_to_value(state, idx);
1191 aux_get_str(state, t, k)
1192}
1193
1194pub fn get_i(state: &mut LuaState, idx: i32, n: i64) -> Result<LuaType, LuaError> {
1195 let t = index_to_value(state, idx);
1196 let key = LuaValue::Int(n);
1197 let result = state.table_get_with_tm(&t, &key)?;
1198 state.push(result);
1199 let top = state.top_idx();
1200 Ok(state.get_at(top - 1).base_type())
1201}
1202
1203pub fn get_i_value(state: &mut LuaState, t: &LuaValue, n: i64) -> Result<LuaType, LuaError> {
1209 let key = LuaValue::Int(n);
1210 let result = state.table_get_with_tm(t, &key)?;
1211 state.push(result);
1212 let top = state.top_idx();
1213 Ok(state.get_at(top - 1).base_type())
1214}
1215
1216fn finish_raw_get(state: &mut LuaState, val: Option<LuaValue>) -> LuaType {
1217 let v = val.unwrap_or(LuaValue::Nil);
1218 state.push(v);
1219 let top = state.top_idx();
1220 state.get_at(top - 1).base_type()
1221}
1222
1223fn get_table_value(state: &LuaState, idx: i32) -> Option<GcRef<LuaTable>> {
1224 let t = index_to_value(state, idx);
1225 debug_assert!(matches!(t, LuaValue::Table(_)), "table expected");
1226 if let LuaValue::Table(tbl) = t {
1227 Some(tbl)
1228 } else {
1229 None
1230 }
1231}
1232
1233pub fn raw_get(state: &mut LuaState, idx: i32) -> LuaType {
1234 let t = get_table_value(state, idx);
1235 let top = state.top_idx();
1236 let key = state.get_at(top - 1);
1237 let val = t.as_ref().map(|tbl| tbl.get(&key));
1238 state.set_top_idx(top - 1);
1239 finish_raw_get(state, val)
1240}
1241
1242pub fn raw_get_i(state: &mut LuaState, idx: i32, n: i64) -> LuaType {
1243 let t = get_table_value(state, idx);
1244 let val = t.as_ref().map(|tbl| tbl.get_int(n));
1245 finish_raw_get(state, val)
1246}
1247
1248pub fn raw_get_p(state: &mut LuaState, idx: i32, p: *const core::ffi::c_void) -> LuaType {
1249 let t = get_table_value(state, idx);
1250 let key = LuaValue::LightUserData(p as *mut core::ffi::c_void);
1251 let val = t.as_ref().map(|tbl| tbl.get(&key));
1252 finish_raw_get(state, val)
1253}
1254
1255pub fn create_table(state: &mut LuaState, narray: i32, nrec: i32) -> Result<(), LuaError> {
1256 let t = state.new_table();
1257 if narray > 0 || nrec > 0 {
1258 t.resize(state, narray as usize, nrec as usize)?;
1259 }
1260 state.push(LuaValue::Table(t));
1261 state.gc().check_step();
1262 Ok(())
1263}
1264
1265pub fn get_metatable(state: &mut LuaState, objindex: i32) -> bool {
1266 let obj = index_to_value(state, objindex);
1267 let mt: Option<GcRef<LuaTable>> = match &obj {
1268 LuaValue::Table(t) => t.metatable(),
1269 LuaValue::UserData(u) => u.metatable(),
1270 other => {
1271 let idx = other.base_type() as usize;
1272 state.global().mt[idx].clone()
1273 }
1274 };
1275 if let Some(mt_table) = mt {
1276 state.push(LuaValue::Table(mt_table));
1277 true
1278 } else {
1279 false
1280 }
1281}
1282
1283pub fn get_i_uservalue(state: &mut LuaState, idx: i32, n: i32) -> LuaType {
1284 let o = index_to_value(state, idx);
1285 debug_assert!(matches!(o, LuaValue::UserData(_)), "full userdata expected");
1286 if let LuaValue::UserData(ref u) = o {
1287 let uv_count = u.uv.len() as i32;
1288 if n <= 0 || n > uv_count {
1289 state.push(LuaValue::Nil);
1290 LuaType::None
1291 } else {
1292 let val = u.uv[(n - 1) as usize].clone();
1293 let t = val.base_type();
1294 state.push(val);
1295 t
1296 }
1297 } else {
1298 state.push(LuaValue::Nil);
1299 LuaType::None
1300 }
1301}
1302
1303fn aux_set_str(state: &mut LuaState, t: LuaValue, k: &[u8]) -> Result<(), LuaError> {
1306 let str_val = {
1307 let ts = state.intern_str(k)?;
1308 LuaValue::Str(ts)
1309 };
1310 let top = state.top_idx();
1315 let val = state.get_at(top - 1);
1316 state.table_set_with_tm(&t, str_val, val)?;
1317 state.pop();
1318 Ok(())
1319}
1320
1321pub fn set_global(state: &mut LuaState, name: &[u8]) -> Result<(), LuaError> {
1322 let g = get_global_table(state);
1323 aux_set_str(state, g, name)
1324}
1325
1326pub fn set_table(state: &mut LuaState, idx: i32) -> Result<(), LuaError> {
1327 let t = index_to_value(state, idx);
1328 let top = state.top_idx();
1329 let key = state.get_at(top - 2);
1330 let val = state.get_at(top - 1);
1331 state.table_set_with_tm(&t, key, val)?;
1332 state.set_top_idx(top - 2);
1333 Ok(())
1334}
1335
1336pub fn set_field(state: &mut LuaState, idx: i32, k: &[u8]) -> Result<(), LuaError> {
1337 let t = index_to_value(state, idx);
1338 aux_set_str(state, t, k)
1339}
1340
1341pub fn set_i(state: &mut LuaState, idx: i32, n: i64) -> Result<(), LuaError> {
1342 let t = index_to_value(state, idx);
1343 let top = state.top_idx();
1344 let val = state.get_at(top - 1);
1345 let key = LuaValue::Int(n);
1346 state.table_set_with_tm(&t, key, val)?;
1347 state.pop();
1348 Ok(())
1349}
1350
1351pub fn set_i_value(state: &mut LuaState, t: &LuaValue, n: i64) -> Result<(), LuaError> {
1357 let top = state.top_idx();
1358 let val = state.get_at(top - 1);
1359 let key = LuaValue::Int(n);
1360 state.table_set_with_tm(t, key, val)?;
1361 state.pop();
1362 Ok(())
1363}
1364
1365fn aux_raw_set(state: &mut LuaState, idx: i32, key: LuaValue, n: u32) -> Result<(), LuaError> {
1366 let t = get_table_value(state, idx)
1367 .ok_or_else(|| LuaError::runtime(format_args!("table expected")))?;
1368 let top = state.top_idx();
1369 let val = state.get_at(top - 1);
1370 t.raw_set(state, key, val)?;
1371 t.invalidate_tm_cache();
1372 let top_val = state.get_at(top - 1);
1373 state.gc().barrier_back(&t, &top_val);
1374 state.set_top_idx(top - n as i32);
1375 Ok(())
1376}
1377
1378pub fn raw_set(state: &mut LuaState, idx: i32) -> Result<(), LuaError> {
1379 let top = state.top_idx();
1380 let key = state.get_at(top - 2);
1381 aux_raw_set(state, idx, key, 2)
1382}
1383
1384pub fn raw_set_p(state: &mut LuaState, idx: i32, p: *const core::ffi::c_void) -> Result<(), LuaError> {
1385 let key = LuaValue::LightUserData(p as *mut core::ffi::c_void);
1386 aux_raw_set(state, idx, key, 1)
1387}
1388
1389pub fn raw_set_i(state: &mut LuaState, idx: i32, n: i64) -> Result<(), LuaError> {
1390 let t = get_table_value(state, idx)
1391 .ok_or_else(|| LuaError::runtime(format_args!("table expected")))?;
1392 let top = state.top_idx();
1393 let val = state.get_at(top - 1);
1394 t.raw_set_int(state, n, val)?;
1395 let top_val = state.get_at(top - 1);
1396 state.gc().barrier_back(&t, &top_val);
1397 state.pop();
1398 Ok(())
1399}
1400
1401fn metatable_has_gc(state: &LuaState, mt: &GcRef<LuaTable>) -> bool {
1406 let name = state.global().tmname[crate::tagmethods::TagMethod::Gc as usize].clone();
1407 !matches!(mt.get_short_str(&name), LuaValue::Nil)
1408}
1409
1410fn register_finalizable_table(state: &mut LuaState, tbl: &GcRef<LuaTable>) {
1412 let already = state
1413 .global()
1414 .pending_finalizers
1415 .iter()
1416 .any(|t| GcRef::ptr_eq(t, tbl));
1417 if !already {
1418 state.global_mut().pending_finalizers.push(tbl.clone());
1419 }
1420}
1421
1422pub fn run_pending_finalizers(state: &mut LuaState) {
1436 let mut did_run = false;
1437 loop {
1438 let target_idx = {
1443 let to_fin = &state.global().to_be_finalized;
1444 if to_fin.is_empty() { None } else { Some(to_fin.len() - 1) }
1445 };
1446 let Some(i) = target_idx else { break; };
1447 let tbl = state.global_mut().to_be_finalized.swap_remove(i);
1457 let mt = tbl.metatable();
1458 let gc_fn = match mt {
1459 Some(ref m) => {
1460 let name = state.global().tmname[crate::tagmethods::TagMethod::Gc as usize].clone();
1461 m.get_short_str(&name)
1462 }
1463 None => LuaValue::Nil,
1464 };
1465 if !matches!(gc_fn, LuaValue::Function(_)) {
1466 continue;
1467 }
1468 did_run = true;
1469 let saved_top = state.top_idx();
1470 let ci_top = state.current_call_info().top;
1471 if saved_top.0 < ci_top.0 {
1472 state.clear_stack_range(saved_top, ci_top);
1473 state.set_top(ci_top);
1474 }
1475 state.push(gc_fn);
1476 state.push(LuaValue::Table(tbl));
1477 let func_idx = state.top_idx() - 2;
1478 let _heap_guard = {
1479 let g = state.global.borrow();
1480 lua_gc::HeapGuard::push(&g.heap)
1481 };
1482 let old_allowhook = state.allowhook;
1483 let old_gcstp = state.global_mut().stop_gc_internal();
1484 state.allowhook = false;
1485 let caller_ci = state.ci;
1486 let caller_status = state.get_ci(caller_ci).callstatus;
1487 state.get_ci_mut(caller_ci).callstatus = caller_status | crate::state::CIST_FIN;
1488 let _ = crate::do_::pcall(
1489 state,
1490 |s| s.call_no_yield(func_idx, 0),
1491 func_idx,
1492 0,
1493 );
1494 state.get_ci_mut(caller_ci).callstatus = caller_status;
1495 state.allowhook = old_allowhook;
1496 state.global_mut().set_gc_stop_flags(old_gcstp);
1497 state.set_top(saved_top);
1498 }
1499 let _ = did_run;
1503}
1504
1505fn collect_live_weak_tables(state: &mut LuaState) -> Vec<GcRef<lua_types::value::LuaTable>> {
1511 let mut g = state.global_mut();
1512 g.weak_tables_registry.retain(|w| w.strong_count() > 0);
1513 let mut seen = std::collections::HashSet::<usize>::new();
1514 g.weak_tables_registry
1515 .iter()
1516 .filter_map(|w| w.upgrade())
1517 .filter_map(|rc| {
1518 let id = rc.identity();
1519 if seen.insert(id) {
1520 Some(rc)
1521 } else {
1522 None
1523 }
1524 })
1525 .collect()
1526}
1527
1528pub fn set_metatable(state: &mut LuaState, objindex: i32) -> Result<bool, LuaError> {
1529 let top = state.top_idx();
1530 let mt_val = state.get_at(top - 1);
1531 let mt: Option<GcRef<LuaTable>> = if matches!(mt_val, LuaValue::Nil) {
1532 None
1533 } else {
1534 debug_assert!(matches!(mt_val, LuaValue::Table(_)), "table expected");
1535 if let LuaValue::Table(t) = mt_val {
1536 Some(t)
1537 } else {
1538 None
1539 }
1540 };
1541
1542 let obj = index_to_value(state, objindex);
1543 match obj {
1544 LuaValue::Table(ref tbl) => {
1545 if mt.is_some() {
1546 state.gc().obj_barrier(tbl, mt.as_ref().unwrap());
1547 }
1548 tbl.set_metatable(mt.clone());
1549 if tbl.weak_mode() != 0 {
1550 state
1551 .global_mut()
1552 .weak_tables_registry
1553 .push(tbl.downgrade());
1554 }
1555 if let Some(ref mt_table) = mt {
1560 if metatable_has_gc(state, mt_table) {
1561 register_finalizable_table(state, tbl);
1562 }
1563 }
1564 }
1565 LuaValue::UserData(ref ud) => {
1566 if let Some(ref mt_table) = mt {
1567 state.gc().obj_barrier(ud, mt_table);
1568 }
1570 ud.set_metatable(mt);
1571 }
1572 ref other => {
1573 let idx = other.base_type() as usize;
1574 state.global_mut().mt[idx] = mt;
1575 }
1576 }
1577 state.pop();
1578 Ok(true)
1579}
1580
1581pub fn set_i_uservalue(state: &mut LuaState, idx: i32, n: i32) -> Result<bool, LuaError> {
1582 let o = index_to_value(state, idx);
1583 debug_assert!(matches!(o, LuaValue::UserData(_)), "full userdata expected");
1584 let top = state.top_idx();
1585 let val = state.get_at(top - 1);
1586 let res = if let LuaValue::UserData(ref ud) = o {
1587 let nuvalue = ud.uv.len() as i32;
1588 if n < 1 || n > nuvalue {
1589 false
1590 } else {
1591 state.gc().barrier_back(ud, &val);
1594 let _ = (n, ud);
1595 true
1596 }
1597 } else {
1598 false
1599 };
1600 state.pop();
1601 Ok(res)
1602}
1603
1604pub fn call_k(
1608 state: &mut LuaState,
1609 nargs: i32,
1610 nresults: i32,
1611 ctx: isize,
1612 k: Option<fn(&mut LuaState, i32, isize) -> Result<usize, LuaError>>,
1613) -> Result<(), LuaError> {
1614 let top = state.top_idx();
1615 let func_idx = top - (nargs + 1);
1616 if k.is_some() && state.is_yieldable() {
1622 let ci_idx = state.ci;
1623 {
1624 let ci = state.get_ci_mut(ci_idx);
1625 ci.set_u_c_k(k);
1626 ci.set_u_c_ctx(ctx);
1627 }
1628 state.call_at(func_idx, nresults)?;
1629 } else {
1630 state.call_no_yield(func_idx, nresults)?;
1631 }
1632 state.adjust_results(nresults);
1633 Ok(())
1634}
1635
1636pub fn pcall_k(
1638 state: &mut LuaState,
1639 nargs: i32,
1640 nresults: i32,
1641 errfunc: i32,
1642 ctx: isize,
1643 k: Option<fn(&mut LuaState, i32, isize) -> Result<usize, LuaError>>,
1644) -> Result<LuaStatus, LuaError> {
1645 let _heap_guard = {
1650 let g = state.global.borrow();
1651 lua_gc::HeapGuard::push(&g.heap)
1656 };
1657 let err_handler_idx: isize = if errfunc == 0 {
1658 0
1659 } else {
1660 let o = index_to_stack_idx(state, errfunc);
1661 debug_assert!(
1662 matches!(state.get_at(o), LuaValue::Function(_)),
1663 "error handler must be a function"
1664 );
1665 o.0 as isize
1666 };
1667 let top = state.top_idx();
1668 let func_idx = top - (nargs + 1);
1669 if k.is_none() || !state.is_yieldable() {
1670 state.protected_call_raw(func_idx, nresults, StackIdx(err_handler_idx as u32))?;
1671 state.adjust_results(nresults);
1672 return Ok(LuaStatus::Ok);
1673 }
1674 let ci_idx = state.ci;
1680 let allow = state.allowhook;
1681 let saved_errfunc = state.errfunc;
1682 {
1683 let ci = state.get_ci_mut(ci_idx);
1684 ci.set_u_c_k(k);
1685 ci.set_u_c_ctx(ctx);
1686 ci.set_u2_funcidx(func_idx.0 as i32);
1687 ci.set_u_c_old_errfunc(saved_errfunc);
1688 ci.set_oah(allow);
1689 ci.callstatus |= crate::state::CIST_YPCALL;
1690 }
1691 state.errfunc = err_handler_idx;
1692 let call_result = crate::do_::call(state, func_idx, nresults);
1693 match call_result {
1694 Ok(()) => {
1695 state.get_ci_mut(ci_idx).callstatus &= !crate::state::CIST_YPCALL;
1698 state.errfunc = saved_errfunc;
1699 state.adjust_results(nresults);
1700 Ok(LuaStatus::Ok)
1701 }
1702 Err(crate::state::LuaError::Yield) => {
1703 Err(crate::state::LuaError::Yield)
1707 }
1708 Err(e) => {
1709 Err(e)
1713 }
1714 }
1715}
1716
1717pub fn load(
1721 state: &mut LuaState,
1722 reader: Box<dyn FnMut() -> Option<Vec<u8>>>,
1723 chunkname: Option<&[u8]>,
1724 mode: Option<&[u8]>,
1725) -> Result<LuaStatus, LuaError> {
1726 let name = chunkname.unwrap_or(b"?");
1727 let z = crate::zio::ZIO::new(reader);
1728 let status = state.protected_parser(z, name, mode);
1729 if status == LuaStatus::Ok {
1730 let top = state.top_idx();
1731 let func_val = state.get_at(top - 1);
1732 if let LuaValue::Function(LuaClosure::Lua(lcl)) = func_val {
1733 if !lcl.upvals.is_empty() {
1734 let gt = get_global_table(state);
1735 let uv = state.new_upval_closed(gt);
1736 lcl.set_upval(0, uv);
1737 }
1738 }
1739 }
1740 Ok(status)
1741}
1742
1743pub fn dump(
1744 state: &LuaState,
1745 writer: &mut dyn FnMut(&[u8]) -> Result<(), LuaError>,
1746 strip: bool,
1747) -> Result<bool, LuaError> {
1748 let top = state.top_idx();
1749 let o = state.get_at(top - 1);
1750 if let LuaValue::Function(LuaClosure::Lua(ref lcl)) = o {
1751 crate::dump::dump(state, &lcl.proto, writer, strip)?;
1752 Ok(true)
1753 } else {
1754 Ok(false)
1755 }
1756}
1757
1758pub fn status(state: &LuaState) -> LuaStatus {
1759 LuaStatus::from_raw(state.status as i32)
1760}
1761
1762#[repr(i32)]
1766#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1767pub enum GcWhat {
1768 Stop = 0,
1769 Restart = 1,
1770 Collect = 2,
1771 Count = 3,
1772 CountB = 4,
1773 Step = 5,
1774 SetPause = 6,
1775 SetStepMul = 7,
1776 IsRunning = 9,
1777 Gen = 10,
1778 Inc = 11,
1779}
1780
1781pub enum GcArgs {
1783 Stop,
1784 Restart,
1785 Collect,
1786 Count,
1787 CountB,
1788 Step { data: i32 },
1789 SetPause { value: i32 },
1790 SetStepMul { value: i32 },
1791 IsRunning,
1792 Gen { minormul: i32, majormul: i32 },
1793 Inc { pause: i32, stepmul: i32, stepsize: i32 },
1794}
1795
1796pub fn gc(state: &mut LuaState, args: GcArgs) -> i32 {
1797 if state.global().is_gc_stopped_internally() {
1798 return -1;
1799 }
1800 match args {
1801 GcArgs::Stop => {
1802 state.global_mut().set_gc_stop_user();
1803 }
1804 GcArgs::Restart => {
1805 {
1806 let mut g = state.global_mut();
1807 crate::state::set_debt(&mut *g, 0);
1808 }
1809 state.global_mut().clear_gc_stop();
1810 }
1811 GcArgs::Collect => {
1812 if !state.allowhook {
1813 return 0;
1814 }
1815 state.gc().full_collect();
1821 run_pending_finalizers(state);
1825 {
1834 let mut g = state.global_mut();
1835 crate::state::reclaim_dead_long_strings(&mut *g);
1836 }
1837 {
1845 let mut g = state.global_mut();
1846 let target_tb = 32_768_isize;
1847 let cur_tb = g.totalbytes + g.gc_debt;
1848 if cur_tb < target_tb {
1849 g.totalbytes += target_tb - cur_tb;
1850 }
1851 }
1852 }
1853 GcArgs::Count => {
1854 {
1855 let mut g = state.global_mut();
1856 crate::state::reclaim_dead_long_strings(&mut *g);
1857 }
1858 let g = state.global();
1859 let long_string_bytes: usize = g.gc_tracked_long_strings.iter().map(|(_, sz)| sz).sum();
1860 let total = g.heap.bytes_used() + long_string_bytes;
1861 return (total >> 10) as i32;
1862 }
1863 GcArgs::CountB => {
1864 {
1865 let mut g = state.global_mut();
1866 crate::state::reclaim_dead_long_strings(&mut *g);
1867 }
1868 let g = state.global();
1869 let long_string_bytes: usize = g.gc_tracked_long_strings.iter().map(|(_, sz)| sz).sum();
1870 let total = g.heap.bytes_used() + long_string_bytes;
1871 return (total & 0x3ff) as i32;
1872 }
1873 GcArgs::Step { data } => {
1874 let old_stp = {
1875 let mut g = state.global_mut();
1876 let old = g.gc_stop_flags();
1877 g.clear_gc_stop();
1878 old
1879 };
1880 let stepmul = (state.global().gc_stepmul_param() as isize | 1).max(1);
1887 let work_units = if data == 0 {
1888 stepmul
1889 } else {
1890 let raw = (data as isize).saturating_mul(stepmul);
1891 raw.max(1)
1892 };
1893 if data == 0 {
1894 let mut g = state.global_mut();
1895 crate::state::set_debt(&mut *g, 0);
1896 } else {
1897 let debt = data as isize * 1024 + state.global().gc_debt();
1898 let mut g = state.global_mut();
1899 crate::state::set_debt(&mut *g, debt);
1900 }
1901 let cycle_complete = state.gc().incremental_step(work_units);
1902 if state.global().is_gen_mode() {
1903 state.gc().prune_weak_tables_mark_only();
1904 }
1905 state.global_mut().set_gc_stop_flags(old_stp);
1906 if cycle_complete {
1913 let mut g = state.global_mut();
1914 let floor: isize = 1024;
1915 let cur_tb = g.totalbytes + g.gc_debt;
1916 let new_tb = (cur_tb / 2).max(floor);
1917 if new_tb < cur_tb {
1918 g.totalbytes -= cur_tb - new_tb;
1919 }
1920 }
1921 {
1923 let heap_state = state.global().heap.gc_state();
1924 let mut g = state.global_mut();
1925 g.gcstate = if heap_state.is_pause() { 0 } else { 1 };
1926 }
1927 return if cycle_complete { 1 } else { 0 };
1928 }
1929 GcArgs::SetPause { value } => {
1930 let old = state.global().gc_pause_param() as i32;
1931 state.global_mut().set_gc_pause_param(value as u8);
1932 return old;
1933 }
1934 GcArgs::SetStepMul { value } => {
1935 let old = state.global().gc_stepmul_param() as i32;
1936 state.global_mut().set_gc_stepmul_param(value as u8);
1937 return old;
1938 }
1939 GcArgs::IsRunning => {
1940 return state.global().gc_running() as i32;
1941 }
1942 GcArgs::Gen { minormul, majormul } => {
1943 let old_mode = if state.global().is_gen_mode() { 10i32 } else { 11i32 };
1944 if minormul != 0 {
1945 state.global_mut().genminormul = minormul as u8;
1946 }
1947 if majormul != 0 {
1948 state.global_mut().set_gc_genmajormul(majormul as u8);
1949 }
1950 state.gc().change_mode(crate::state::GcKind::Generational);
1951 return old_mode;
1952 }
1953 GcArgs::Inc { pause, stepmul, stepsize } => {
1954 let old_mode = if state.global().is_gen_mode() { 10i32 } else { 11i32 };
1955 if pause != 0 {
1956 state.global_mut().set_gc_pause_param(pause as u8);
1957 }
1958 if stepmul != 0 {
1959 state.global_mut().set_gc_stepmul_param(stepmul as u8);
1960 }
1961 if stepsize != 0 {
1962 state.global_mut().gcstepsize = stepsize as u8;
1963 }
1964 state.gc().change_mode(crate::state::GcKind::Incremental);
1965 return old_mode;
1966 }
1967 }
1968 0
1969}
1970
1971pub fn lua_error(state: &mut LuaState) -> Result<Infallible, LuaError> {
1978 let top = state.top_idx();
1982 let errobj = state.get_at(top - 1);
1983 let is_mem_err = if let LuaValue::Str(ref s) = errobj {
1984 let memerr = state.global().memerrmsg.clone();
1985 GcRef::ptr_eq(s, &memerr)
1986 } else {
1987 false
1988 };
1989 if is_mem_err {
1990 Err(LuaError::Memory)
1991 } else {
1992 Err(LuaError::from_value(errobj))
1993 }
1994}
1995
1996pub fn next(state: &mut LuaState, idx: i32) -> Result<bool, LuaError> {
1997 let t = get_table_value(state, idx)
1998 .ok_or_else(|| LuaError::runtime(format_args!("table expected")))?;
1999 let top = state.top_idx();
2000 let key = state.get_at(top - 1);
2001 match t.next(key)? {
2002 Some((next_key, next_val)) => {
2003 state.set_at(top - 1, next_key);
2004 state.push(next_val);
2005 Ok(true)
2006 }
2007 None => {
2008 state.set_top_idx(top - 1);
2009 Ok(false)
2010 }
2011 }
2012}
2013
2014pub fn to_close(state: &mut LuaState, idx: i32) -> Result<(), LuaError> {
2015 let _level = index_to_stack_idx(state, idx);
2016 Ok(())
2019}
2020
2021pub fn concat(state: &mut LuaState, n: i32) -> Result<(), LuaError> {
2022 if n > 0 {
2023 state.concat(n)?;
2024 } else {
2025 let empty = state.intern_str(b"")?;
2026 state.push(LuaValue::Str(empty));
2027 }
2028 state.gc().check_step();
2029 Ok(())
2030}
2031
2032pub fn len(state: &mut LuaState, idx: i32) -> Result<(), LuaError> {
2033 let t = index_to_value(state, idx);
2034 let result = state.obj_len(&t)?;
2035 state.push(result);
2036 Ok(())
2037}
2038
2039pub fn set_warn_f(
2044 state: &mut LuaState,
2045 f: Option<Box<dyn FnMut(&[u8], bool)>>,
2046) {
2047 state.global_mut().warnf = f;
2049}
2050
2051pub fn warning(state: &mut LuaState, msg: &[u8], tocont: bool) {
2052 state.emit_warning(msg, tocont);
2053}
2054
2055pub fn new_userdata_uv(
2056 state: &mut LuaState,
2057 size: usize,
2058 nuvalue: i32,
2059) -> Result<GcRef<LuaUserData>, LuaError> {
2060 debug_assert!(nuvalue >= 0 && nuvalue < u16::MAX as i32, "invalid value");
2061 let u = state.new_userdata(size, nuvalue as usize)?;
2062 state.push(LuaValue::UserData(u.clone()));
2063 state.gc().check_step();
2064 Ok(u)
2065}
2066
2067fn aux_upvalue(
2073 state: &LuaState,
2074 fi: &LuaValue,
2075 n: i32,
2076) -> Option<(Vec<u8>, LuaValue)> {
2077 match fi {
2078 LuaValue::Function(LuaClosure::C(ccl)) => {
2079 let nupvalues = ccl.upvalues.len() as i32;
2080 if n < 1 || n > nupvalues {
2081 return None;
2082 }
2083 Some((Vec::new(), ccl.upvalues[(n - 1) as usize].clone()))
2084 }
2085 LuaValue::Function(LuaClosure::Lua(lcl)) => {
2086 let nupvalues = lcl.upvals.len() as i32;
2087 if n < 1 || n > nupvalues {
2088 return None;
2089 }
2090 let val = state.upvalue_get(lcl, (n - 1) as usize);
2091 let name: Vec<u8> = lcl
2095 .proto
2096 .upvalues
2097 .get((n - 1) as usize)
2098 .and_then(|ud| ud.name.as_ref())
2099 .map(|s| s.as_bytes().to_vec())
2100 .unwrap_or_else(|| b"(no name)".to_vec());
2101 Some((name, val))
2102 }
2103 _ => None,
2104 }
2105}
2106
2107pub fn get_upvalue(state: &mut LuaState, funcindex: i32, n: i32) -> Option<Vec<u8>> {
2108 let fi = index_to_value(state, funcindex);
2109 if let Some((name, val)) = aux_upvalue(state, &fi, n) {
2110 state.push(val);
2111 Some(name)
2112 } else {
2113 None
2114 }
2115}
2116
2117pub fn setup_value(state: &mut LuaState, funcindex: i32, n: i32) -> Option<Vec<u8>> {
2118 let fi = index_to_value(state, funcindex);
2119 let (name, _) = aux_upvalue(state, &fi, n)?;
2120 let new_val = state.pop();
2121 match &fi {
2122 LuaValue::Function(LuaClosure::Lua(lcl)) => {
2123 state.upvalue_set(lcl, (n - 1) as usize, new_val).ok()?;
2124 }
2125 LuaValue::Function(LuaClosure::C(_ccl)) => {
2126 let _ = new_val;
2129 }
2130 _ => return None,
2131 }
2132 Some(name)
2133}
2134
2135fn get_upval_ref_idx(state: &LuaState, fidx: i32, n: i32) -> Option<usize> {
2138 let fi = index_to_value(state, fidx);
2139 debug_assert!(matches!(fi, LuaValue::Function(LuaClosure::Lua(_))), "Lua function expected");
2140 if let LuaValue::Function(LuaClosure::Lua(ref lcl)) = fi {
2141 let sizeupvalues = lcl.upvals.len() as i32;
2142 if n >= 1 && n <= sizeupvalues {
2143 Some((n - 1) as usize)
2144 } else {
2145 None
2146 }
2147 } else {
2148 None
2149 }
2150}
2151
2152pub fn upvalue_id(state: &LuaState, fidx: i32, n: i32) -> Option<usize> {
2154 let fi = index_to_value(state, fidx);
2155 match &fi {
2156 LuaValue::Function(LuaClosure::Lua(lcl)) => {
2157 let idx = get_upval_ref_idx(state, fidx, n)?;
2158 Some(GcRef::identity(&lcl.upval(idx)))
2160 }
2161 LuaValue::Function(LuaClosure::C(ccl)) => {
2162 if n >= 1 && n <= ccl.upvalues.len() as i32 {
2163 Some(GcRef::identity(ccl) ^ (n as usize))
2166 } else {
2167 None
2168 }
2169 }
2170 LuaValue::Function(LuaClosure::LightC(_)) => None,
2171 _ => {
2172 debug_assert!(false, "function expected");
2173 None
2174 }
2175 }
2176}
2177
2178pub fn upvalue_join(state: &mut LuaState, fidx1: i32, n1: i32, fidx2: i32, n2: i32) {
2180 let idx1 = match get_upval_ref_idx(state, fidx1, n1) {
2181 Some(i) => i,
2182 None => return,
2183 };
2184 let idx2 = match get_upval_ref_idx(state, fidx2, n2) {
2185 Some(i) => i,
2186 None => return,
2187 };
2188 let f1 = index_to_value(state, fidx1);
2189 let f2 = index_to_value(state, fidx2);
2190 if let (
2191 LuaValue::Function(LuaClosure::Lua(lcl1)),
2192 LuaValue::Function(LuaClosure::Lua(lcl2)),
2193 ) = (&f1, &f2)
2194 {
2195 let shared = lcl2.upval(idx2);
2196 lcl1.set_upval(idx1, shared);
2197 }
2198}
2199
2200