Skip to main content

lua_stdlib/
state_stub.rs

1//! Phase-B reconcile shim: re-exports the canonical `LuaState` from
2//! `lua-vm` and provides an extension trait holding every method the
3//! Phase-A stdlib translation used to call on the Phase-A stub.
4//!
5//! TODO_ARCH(phase-b-reconcile): all extension-trait method bodies are
6//! `todo!("phase-b-reconcile: <name>")`. They must move to real
7//! implementations on `lua_vm::state::LuaState` itself; that work lives in
8//! `lua-vm`, not here. The shim exists only so stdlib code keeps compiling
9//! while the canonical `LuaState` API stabilises.
10//!
11//! Where a trait method's name collides with an inherent method on the
12//! canonical `LuaState`, Rust resolves to the inherent method. Most
13//! Phase-A call sites compile through the inherent method unchanged; the
14//! handful that depend on a different return shape (e.g. `state.push(...)?`
15//! against the canonical `pub fn push(&mut self, val: LuaValue)`) are
16//! patched at the call site.
17
18#![allow(dead_code, unused_variables, clippy::too_many_arguments)]
19
20use lua_types::{
21    arith::ArithOp,
22    closure::{LuaCFnPtr, LuaClosure},
23    error::LuaError,
24    gc::GcRef,
25    string::LuaString,
26    userdata::LuaUserData,
27    value::{LuaThread, LuaValue},
28    CallInfoIdx,
29    LuaType,
30    LuaStatus,
31};
32
33pub use lua_vm::state::LuaState;
34use lua_vm::state::LuaCallable;
35
36/// Bare function callable from Lua. C: `lua_CFunction`.
37#[allow(non_camel_case_types)]
38pub type lua_CFunction = fn(&mut LuaState) -> Result<usize, LuaError>;
39
40/// Pseudo-index for the `i`-th upvalue of a C function.
41pub fn upvalue_index(i: i32) -> i32 {
42    -1_001_000 - i
43}
44
45/// Comparison operations (eq, lt, le). C: `LUA_OP*`.
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
47pub enum CompareOp {
48    Eq,
49    Lt,
50    Le,
51}
52
53/// Reader-callback type for `lua_load`. C: `lua_Reader`.
54pub type LuaReader<'a> = dyn FnMut() -> Option<Vec<u8>> + 'a;
55
56/// Writer-callback type for `lua_dump`. C: `lua_Writer`.
57pub type LuaWriter<'a> = dyn FnMut(&[u8]) -> Result<(), LuaError> + 'a;
58
59/// Debug introspection record. C: `lua_Debug`.
60#[derive(Debug, Default, Clone)]
61pub struct LuaDebug {
62    pub name: Option<Vec<u8>>,
63    pub namewhat: Vec<u8>,
64    pub what: u8,
65    pub source: Vec<u8>,
66    pub short_src: Vec<u8>,
67    pub linedefined: i32,
68    pub lastlinedefined: i32,
69    pub currentline: i32,
70    pub nups: u8,
71    pub nparams: u8,
72    pub isvararg: bool,
73    pub istailcall: bool,
74    pub ftransfer: u16,
75    pub ntransfer: u16,
76    /// Active CallInfo index, set by `get_stack`/`get_stack_level` and read by
77    /// `get_info`/`get_local_at`/`set_local_at`. Mirrors C's `lua_Debug.i_ci`
78    /// (a raw pointer in C; an index here).
79    pub(crate) i_ci_idx: Option<CallInfoIdx>,
80}
81
82impl LuaDebug {
83    pub fn name_bytes(&self) -> &[u8] { self.name.as_deref().unwrap_or(b"?") }
84    pub fn namewhat_bytes(&self) -> &[u8] { &self.namewhat }
85    pub fn what_bytes(&self) -> &[u8] { match self.what { b'L' => b"Lua", b'C' => b"C", b'm' => b"main", _ => b"?" } }
86    pub fn short_src_bytes(&self) -> &[u8] { &self.short_src }
87    pub fn source_bytes(&self) -> &[u8] { &self.source }
88}
89
90/// Extension trait wiring every Phase-A stub method onto the canonical
91/// `LuaState`. Bodies are `todo!("phase-b-reconcile: …")`. When the
92/// canonical type already defines a method with the same name, Rust's
93/// inherent-first resolution makes this trait method unreachable (the
94/// inherent one wins) — the trait is then only providing the *missing*
95/// methods. Conflicting call-sites whose shape no longer matches the
96/// inherent signature are patched in their respective stdlib modules.
97pub trait LuaStateStubExt {
98    fn push_value(&mut self, idx: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: push_value") }
99    fn push_copy(&mut self, idx: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: push_copy") }
100    fn push_string(&mut self, s: &[u8]) -> Result<(), LuaError> { todo!("phase-b-reconcile: push_string") }
101    fn push_bytes(&mut self, s: &[u8]) -> Result<(), LuaError> { todo!("phase-b-reconcile: push_bytes") }
102    fn push_fstring(&mut self, args: std::fmt::Arguments<'_>) -> Result<(), LuaError> { todo!("phase-b-reconcile: push_fstring") }
103    fn push_c_function(&mut self, f: lua_CFunction) -> Result<(), LuaError> { todo!("phase-b-reconcile: push_c_function") }
104    fn push_c_closure(&mut self, f: lua_CFunction, n: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: push_c_closure") }
105    fn push_where(&mut self, level: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: push_where") }
106    fn push_globals(&mut self) -> Result<(), LuaError> { todo!("phase-b-reconcile: push_globals") }
107
108    fn pop_bytes(&mut self) -> Vec<u8> { todo!("phase-b-reconcile: pop_bytes") }
109
110    fn top(&mut self) -> i32 { todo!("phase-b-reconcile: top") }
111    fn top_count(&mut self) -> i32 { todo!("phase-b-reconcile: top_count") }
112
113    fn insert(&mut self, idx: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: insert") }
114    fn remove(&mut self, idx: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: remove") }
115    fn replace(&mut self, idx: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: replace") }
116    fn rotate(&mut self, idx: i32, n: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: rotate") }
117    fn copy_value(&mut self, from: i32, to: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: copy_value") }
118    fn abs_index(&mut self, idx: i32) -> i32 { todo!("phase-b-reconcile: abs_index") }
119    fn ensure_stack<S: AsRef<[u8]> + ?Sized>(&mut self, n: i32, msg: &S) -> Result<(), LuaError> { let _ = msg.as_ref(); todo!("phase-b-reconcile: ensure_stack") }
120    fn check_stack_space(&mut self, n: i32) -> bool { todo!("phase-b-reconcile: check_stack_space") }
121
122    fn type_at(&mut self, idx: i32) -> LuaType { todo!("phase-b-reconcile: type_at") }
123    fn type_name(&mut self, t: LuaType) -> &'static [u8] { todo!("phase-b-reconcile: type_name") }
124    fn type_name_at(&mut self, idx: i32) -> &'static [u8] { todo!("phase-b-reconcile: type_name_at") }
125    fn value_at(&mut self, idx: i32) -> LuaValue { todo!("phase-b-reconcile: value_at") }
126    fn is_none_or_nil(&mut self, idx: i32) -> bool { todo!("phase-b-reconcile: is_none_or_nil") }
127    fn is_integer(&mut self, idx: i32) -> bool { todo!("phase-b-reconcile: is_integer") }
128    fn is_number(&mut self, idx: i32) -> bool { todo!("phase-b-reconcile: is_number") }
129
130    fn to_lua_string(&mut self, idx: i32) -> Option<GcRef<LuaString>> { todo!("phase-b-reconcile: to_lua_string") }
131    fn to_lua_string_bytes(&mut self, idx: i32) -> Option<Vec<u8>> { todo!("phase-b-reconcile: to_lua_string_bytes") }
132    fn to_lua_string_len(&mut self, idx: i32) -> Option<usize> { todo!("phase-b-reconcile: to_lua_string_len") }
133    fn to_integer_x(&mut self, idx: i32) -> Option<i64> { todo!("phase-b-reconcile: to_integer_x") }
134    fn to_number_x(&mut self, idx: i32) -> Option<f64> { todo!("phase-b-reconcile: to_number_x") }
135    fn to_boolean(&mut self, idx: i32) -> bool { todo!("phase-b-reconcile: to_boolean") }
136    fn to_userdata(&mut self, idx: i32) -> Option<GcRef<LuaUserData>> { todo!("phase-b-reconcile: to_userdata") }
137    fn to_display_string(&mut self, idx: i32) -> Result<Vec<u8>, LuaError> { todo!("phase-b-reconcile: to_display_string") }
138
139    fn check_arg_any(&mut self, arg: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: check_arg_any") }
140    fn check_arg_integer(&mut self, arg: i32) -> Result<i64, LuaError> { todo!("phase-b-reconcile: check_arg_integer") }
141    fn check_arg_string(&mut self, arg: i32) -> Result<Vec<u8>, LuaError> { todo!("phase-b-reconcile: check_arg_string") }
142    fn check_arg_type(&mut self, arg: i32, t: LuaType) -> Result<(), LuaError> { todo!("phase-b-reconcile: check_arg_type") }
143    fn check_arg_option(&mut self, arg: i32, def: Option<&[u8]>, lst: &[&[u8]]) -> Result<usize, LuaError> { todo!("phase-b-reconcile: check_arg_option") }
144
145    fn opt_arg_integer(&mut self, arg: i32, def: i64) -> Result<i64, LuaError> { todo!("phase-b-reconcile: opt_arg_integer") }
146    fn opt_arg_string_bytes(&mut self, arg: i32) -> Result<Vec<u8>, LuaError> { todo!("phase-b-reconcile: opt_arg_string_bytes") }
147    fn opt_arg_string(&mut self, arg: i32, def: &[u8]) -> Result<Vec<u8>, LuaError> { todo!("phase-b-reconcile: opt_arg_string") }
148    fn arg_to_bool(&mut self, arg: i32) -> bool { todo!("phase-b-reconcile: arg_to_bool") }
149
150    fn get_field(&mut self, idx: i32, k: &[u8]) -> Result<LuaType, LuaError> { todo!("phase-b-reconcile: get_field") }
151    fn set_field(&mut self, idx: i32, k: &[u8]) -> Result<(), LuaError> { todo!("phase-b-reconcile: set_field") }
152    fn raw_get(&mut self, idx: i32) -> Result<LuaType, LuaError> { todo!("phase-b-reconcile: raw_get") }
153    fn raw_set(&mut self, idx: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: raw_set") }
154    fn raw_get_i(&mut self, idx: i32, n: i64) -> Result<LuaType, LuaError> { todo!("phase-b-reconcile: raw_get_i") }
155    fn raw_set_i(&mut self, idx: i32, n: i64) -> Result<(), LuaError> { todo!("phase-b-reconcile: raw_set_i") }
156    fn raw_equal(&mut self, idx1: i32, idx2: i32) -> Result<bool, LuaError> { todo!("phase-b-reconcile: raw_equal") }
157    fn raw_len(&mut self, idx: i32) -> i64 { todo!("phase-b-reconcile: raw_len") }
158    fn get_i(&mut self, idx: i32, n: i64) -> Result<LuaType, LuaError> { todo!("phase-b-reconcile: get_i") }
159    fn get_metafield(&mut self, idx: i32, name: &[u8]) -> Result<LuaType, LuaError> { todo!("phase-b-reconcile: get_metafield") }
160    fn get_meta_field(&mut self, idx: i32, name: &[u8]) -> Result<bool, LuaError> { todo!("phase-b-reconcile: get_meta_field") }
161    fn get_metatable(&mut self, idx: i32) -> Result<bool, LuaError> { todo!("phase-b-reconcile: get_metatable") }
162    fn set_metatable(&mut self, idx: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: set_metatable") }
163    fn table_next(&mut self, idx: i32) -> Result<bool, LuaError> { todo!("phase-b-reconcile: table_next") }
164    fn create_table(&mut self, narr: i32, nrec: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: create_table") }
165
166    fn gc_control_simple(&mut self, op: i32) -> Result<i32, LuaError> { todo!("phase-b-reconcile: gc_control_simple") }
167    fn gc_count(&mut self) -> Result<i32, LuaError> { todo!("phase-b-reconcile: gc_count") }
168    fn gc_count_b(&mut self) -> Result<i32, LuaError> { todo!("phase-b-reconcile: gc_count_b") }
169    fn gc_step(&mut self, data: i32) -> Result<i32, LuaError> { todo!("phase-b-reconcile: gc_step") }
170    fn gc_set_param(&mut self, op: i32, value: i32) -> Result<i32, LuaError> { todo!("phase-b-reconcile: gc_set_param") }
171    fn gc_is_running(&mut self) -> Result<bool, LuaError> { todo!("phase-b-reconcile: gc_is_running") }
172    fn gc_gen(&mut self, minor_mul: i32, major_mul: i32) -> Result<i32, LuaError> { todo!("phase-b-reconcile: gc_gen") }
173    fn gc_inc(&mut self, pause: i32, step_mul: i32, step_size: i32) -> Result<i32, LuaError> { todo!("phase-b-reconcile: gc_inc") }
174    fn gc_param(&mut self, param: usize, value: i64) -> Result<i64, LuaError> { todo!("phase-b-reconcile: gc_param") }
175
176    fn call(&mut self, nargs: i32, nresults: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: call") }
177    fn call_k(
178        &mut self,
179        nargs: i32,
180        nresults: i32,
181        ctx: isize,
182        k: Option<fn(&mut LuaState, i32, isize) -> Result<usize, LuaError>>,
183    ) -> Result<(), LuaError> {
184        let _ = (nargs, nresults, ctx, k);
185        todo!("phase-b-reconcile: call_k")
186    }
187    fn protected_call(&mut self, nargs: i32, nresults: i32, msgh: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: protected_call") }
188    fn protected_call_k(
189        &mut self,
190        nargs: i32,
191        nresults: i32,
192        msgh: i32,
193        ctx: isize,
194        k: Option<fn(&mut LuaState, i32, isize) -> Result<usize, LuaError>>,
195    ) -> Result<(), LuaError> {
196        let _ = (nargs, nresults, msgh, ctx, k);
197        todo!("phase-b-reconcile: protected_call_k")
198    }
199    fn len_op(&mut self, idx: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: len_op") }
200    fn arith(&mut self, op: ArithOp) -> Result<(), LuaError> { todo!("phase-b-reconcile: arith") }
201
202    fn load(&mut self, chunk: &[u8], name: &[u8], mode: Option<&[u8]>) -> Result<bool, LuaError> { todo!("phase-b-reconcile: load") }
203    fn load_buffer_ex<M: ?Sized>(&mut self, buf: &[u8], name: &[u8], mode: &M) -> Result<bool, LuaError>
204    where
205        M: AsRef<[u8]>,
206    { let _ = (buf, name, mode); todo!("phase-b-reconcile: load_buffer_ex") }
207    fn load_file(&mut self, path: Option<&[u8]>) -> Result<bool, LuaError> { todo!("phase-b-reconcile: load_file") }
208    fn load_file_ex(&mut self, path: Option<&[u8]>, mode: Option<&[u8]>) -> Result<bool, LuaError> { todo!("phase-b-reconcile: load_file_ex") }
209    fn load_with_reader<F, M: ?Sized>(&mut self, reader: F, name: &[u8], mode: &M) -> Result<bool, LuaError>
210    where
211        F: FnMut(&mut LuaState) -> Result<Option<Vec<u8>>, LuaError>,
212        M: AsRef<[u8]>,
213    { let _ = (reader, name, mode); todo!("phase-b-reconcile: load_with_reader") }
214    fn dump_function(&mut self, strip: bool) -> Result<Vec<u8>, LuaError> { todo!("phase-b-reconcile: dump_function") }
215
216    fn warning(&mut self, msg: &[u8], to_cont: bool) -> Result<(), LuaError> { todo!("phase-b-reconcile: warning") }
217    fn write_output(&mut self, msg: &[u8]) -> Result<(), LuaError> { todo!("phase-b-reconcile: write_output") }
218    fn set_warn_fn(&mut self, f: Option<lua_CFunction>, ud: Option<LuaValue>) -> Result<(), LuaError> { todo!("phase-b-reconcile: set_warn_fn") }
219    fn set_funcs(&mut self, funcs: &[(&[u8], lua_CFunction)], nup: i32) -> Result<(), LuaError> {
220        let _ = (funcs, nup);
221        todo!("phase-b-reconcile: set_funcs")
222    }
223    fn set_global(&mut self, name: &[u8]) -> Result<(), LuaError> { todo!("phase-b-reconcile: set_global") }
224    fn set_upvalue(&mut self, fidx: i32, n: i32) -> Result<Option<Vec<u8>>, LuaError> { todo!("phase-b-reconcile: set_upvalue") }
225    fn get_info(&mut self, what: &[u8], ar: &mut LuaDebug) -> Result<(), LuaError> { todo!("phase-b-reconcile: get_info") }
226    fn get_stack(&mut self, level: i32, ar: &mut LuaDebug) -> bool { todo!("phase-b-reconcile: get_stack") }
227    fn lua_version(&mut self) -> f64 { todo!("phase-b-reconcile: lua_version") }
228    fn string_to_number(&mut self, idx: i32) -> Option<usize> { todo!("phase-b-reconcile: string_to_number") }
229    fn string_to_number_push<S: AsRef<[u8]> + ?Sized>(&mut self, s: &S) -> Result<usize, LuaError> { let _ = s.as_ref(); todo!("phase-b-reconcile: string_to_number_push") }
230    fn require_lib(&mut self, name: &[u8], openf: lua_CFunction, glb: bool) -> Result<(), LuaError> { todo!("phase-b-reconcile: require_lib") }
231    fn peek_bytes(&mut self, idx: i32) -> Option<Vec<u8>> { todo!("phase-b-reconcile: peek_bytes") }
232
233    fn check_number(&mut self, arg: i32) -> Result<f64, LuaError> { todo!("phase-b-reconcile: check_number") }
234    fn check_integer(&mut self, arg: i32) -> Result<i64, LuaError> { todo!("phase-b-reconcile: check_integer") }
235    fn check_any(&mut self, arg: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: check_any") }
236    fn check_arg_number(&mut self, arg: i32) -> Result<f64, LuaError> { todo!("phase-b-reconcile: check_arg_number") }
237    fn check_arg_userdata(&mut self, arg: i32, name: &[u8]) -> Result<GcRef<LuaUserData>, LuaError> { todo!("phase-b-reconcile: check_arg_userdata") }
238    fn check_stack_growth(&mut self, n: i32) -> bool { todo!("phase-b-reconcile: check_stack_growth") }
239    fn opt_integer(&mut self, arg: i32, def: i64) -> Result<i64, LuaError> { todo!("phase-b-reconcile: opt_integer") }
240    fn opt_number(&mut self, arg: i32, def: f64) -> Result<f64, LuaError> { todo!("phase-b-reconcile: opt_number") }
241    fn opt_arg_lstring(&mut self, arg: i32, def: Option<&[u8]>) -> Result<Option<Vec<u8>>, LuaError> { todo!("phase-b-reconcile: opt_arg_lstring") }
242
243    fn table_get_i(&mut self, idx: i32, n: i64) -> Result<LuaType, LuaError> { todo!("phase-b-reconcile: table_get_i") }
244    fn table_set_i(&mut self, idx: i32, n: i64) -> Result<(), LuaError> { todo!("phase-b-reconcile: table_set_i") }
245    fn table_get_i_value(&mut self, t: &LuaValue, n: i64) -> Result<LuaType, LuaError> { todo!("phase-b-reconcile: table_get_i_value") }
246    fn table_set_i_value(&mut self, t: &LuaValue, n: i64) -> Result<(), LuaError> { todo!("phase-b-reconcile: table_set_i_value") }
247    fn get_table(&mut self, idx: i32) -> Result<LuaType, LuaError> { todo!("phase-b-reconcile: get_table") }
248    fn raw_geti(&mut self, idx: i32, n: i64) -> Result<LuaType, LuaError> { todo!("phase-b-reconcile: raw_geti") }
249    fn raw_seti(&mut self, idx: i32, n: i64) -> Result<(), LuaError> { todo!("phase-b-reconcile: raw_seti") }
250    fn len_at(&mut self, idx: i32) -> i64 { todo!("phase-b-reconcile: len_at") }
251    fn length_at(&mut self, idx: i32) -> Result<i64, LuaError> { todo!("phase-b-reconcile: length_at") }
252    fn stack_top(&mut self) -> i32 { todo!("phase-b-reconcile: stack_top") }
253    fn get_top(&mut self) -> i32 { todo!("phase-b-reconcile: get_top") }
254
255    fn push_value_at(&mut self, idx: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: push_value_at") }
256    fn push_fail(&mut self) -> Result<(), LuaError> { todo!("phase-b-reconcile: push_fail") }
257    fn push_lstring(&mut self, s: &[u8]) -> Result<(), LuaError> { todo!("phase-b-reconcile: push_lstring") }
258    fn push_thread(&mut self) -> Result<bool, LuaError> { todo!("phase-b-reconcile: push_thread") }
259    fn push_cclosure(&mut self, f: lua_CFunction, n: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: push_cclosure") }
260    fn push_upvalue(&mut self, idx: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: push_upvalue") }
261    fn push_registry(&mut self) -> Result<(), LuaError> { todo!("phase-b-reconcile: push_registry") }
262
263    fn to_integer(&mut self, idx: i32) -> Option<i64> { todo!("phase-b-reconcile: to_integer") }
264    fn to_integer_opt(&mut self, idx: i32) -> Option<i64> { todo!("phase-b-reconcile: to_integer_opt") }
265    fn to_number(&mut self, idx: i32) -> Option<f64> { todo!("phase-b-reconcile: to_number") }
266    fn to_bytes(&mut self, idx: i32) -> Option<Vec<u8>> { todo!("phase-b-reconcile: to_bytes") }
267    fn to_bytes_at(&mut self, idx: i32) -> Option<Vec<u8>> { todo!("phase-b-reconcile: to_bytes_at") }
268    fn to_string_coerced(&mut self, idx: i32) -> Option<Vec<u8>> { todo!("phase-b-reconcile: to_string_coerced") }
269    fn to_light_userdata(&mut self, idx: i32) -> Option<*mut std::ffi::c_void> { todo!("phase-b-reconcile: to_light_userdata") }
270    fn to_thread(&mut self, idx: i32) -> Option<GcRef<LuaThread>> { todo!("phase-b-reconcile: to_thread") }
271    fn to_thread_at(&mut self, idx: i32) -> Option<GcRef<LuaThread>> { todo!("phase-b-reconcile: to_thread_at") }
272    fn type_name_str_at(&mut self, idx: i32) -> &'static [u8] { todo!("phase-b-reconcile: type_name_str_at") }
273    fn is_c_function_at(&mut self, idx: i32) -> bool { todo!("phase-b-reconcile: is_c_function_at") }
274
275    fn compare(&mut self, idx1: i32, idx2: i32, op: CompareOp) -> Result<bool, LuaError> { todo!("phase-b-reconcile: compare") }
276    fn compare_lt(&mut self, idx1: i32, idx2: i32) -> Result<bool, LuaError> { todo!("phase-b-reconcile: compare_lt") }
277
278    fn get_field_registry(&mut self, name: &[u8]) -> Result<LuaType, LuaError> { todo!("phase-b-reconcile: get_field_registry") }
279    fn get_registry_field(&mut self, name: &[u8]) -> Result<LuaType, LuaError> { todo!("phase-b-reconcile: get_registry_field") }
280    fn get_subtable_registry(&mut self, name: &[u8]) -> Result<bool, LuaError> { todo!("phase-b-reconcile: get_subtable_registry") }
281    fn get_or_create_registry_subtable(&mut self, name: &[u8]) -> Result<bool, LuaError> { todo!("phase-b-reconcile: get_or_create_registry_subtable") }
282    fn registry_get(&mut self, key: &[u8]) -> Result<LuaType, LuaError> { todo!("phase-b-reconcile: registry_get") }
283    fn registry_set(&mut self, key: &[u8]) -> Result<(), LuaError> { todo!("phase-b-reconcile: registry_set") }
284
285    fn new_lib<F: Copy>(&mut self, funcs: &[(&[u8], F)]) -> Result<(), LuaError> { todo!("phase-b-reconcile: new_lib") }
286    fn new_lib_table<F: Copy>(&mut self, funcs: &[(&[u8], F)]) -> Result<(), LuaError> { todo!("phase-b-reconcile: new_lib_table") }
287    fn new_metatable(&mut self, name: &[u8]) -> Result<bool, LuaError> { todo!("phase-b-reconcile: new_metatable") }
288    fn set_metatable_by_name(&mut self, name: &[u8]) -> Result<(), LuaError> { todo!("phase-b-reconcile: set_metatable_by_name") }
289    fn register_funcs<F: Copy>(&mut self, funcs: &[(&[u8], F)]) -> Result<(), LuaError> { todo!("phase-b-reconcile: register_funcs") }
290    fn register_lib<F: Copy>(&mut self, name: &[u8], funcs: &[(&[u8], F)]) -> Result<(), LuaError> { todo!("phase-b-reconcile: register_lib") }
291    fn set_funcs_with_upvalues<F: Copy>(&mut self, funcs: &[(&[u8], F)], nup: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: set_funcs_with_upvalues") }
292
293    fn new_userdata_typed(&mut self, name: &[u8], size: usize, nuvalue: i32) -> Result<GcRef<LuaUserData>, LuaError> { todo!("phase-b-reconcile: new_userdata_typed") }
294    fn get_iuservalue(&mut self, idx: i32, n: i32) -> Result<LuaType, LuaError> { todo!("phase-b-reconcile: get_iuservalue") }
295    fn set_iuservalue(&mut self, idx: i32, n: i32) -> Result<bool, LuaError> { todo!("phase-b-reconcile: set_iuservalue") }
296    fn test_arg_userdata(&mut self, arg: i32, name: &[u8]) -> Option<GcRef<LuaUserData>> { todo!("phase-b-reconcile: test_arg_userdata") }
297
298    fn get_upvalue(&mut self, fidx: i32, n: i32) -> Result<Option<Vec<u8>>, LuaError> { todo!("phase-b-reconcile: get_upvalue") }
299    fn upvalue_id(&mut self, fidx: i32, n: i32) -> Result<*mut std::ffi::c_void, LuaError> { todo!("phase-b-reconcile: upvalue_id") }
300    fn join_upvalues(&mut self, fidx1: i32, n1: i32, fidx2: i32, n2: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: join_upvalues") }
301    fn upvalue_index(&mut self, i: i32) -> i32 { upvalue_index(i) }
302    fn close(&mut self) { todo!("phase-b-reconcile: close") }
303    fn set_hook_full(&mut self, f: Option<lua_CFunction>, mask: u32, count: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: set_hook_full") }
304
305    fn get_local_at(&mut self, ar: &LuaDebug, n: i32) -> Result<Option<Vec<u8>>, LuaError> { todo!("phase-b-reconcile: get_local_at") }
306    fn set_local_at(&mut self, ar: &LuaDebug, n: i32) -> Result<Option<Vec<u8>>, LuaError> { todo!("phase-b-reconcile: set_local_at") }
307    fn get_param_name(&mut self, fidx: i32, n: i32) -> Result<Option<Vec<u8>>, LuaError> { todo!("phase-b-reconcile: get_param_name") }
308
309    fn get_debug_info(&mut self, what: &[u8], ar: &mut LuaDebug) -> Result<(), LuaError> { todo!("phase-b-reconcile: get_debug_info") }
310    fn get_stack_level(&mut self, level: i32, ar: &mut LuaDebug) -> bool { todo!("phase-b-reconcile: get_stack_level") }
311    fn has_frames(&mut self) -> bool { todo!("phase-b-reconcile: has_frames") }
312    fn lua_traceback(&mut self, other: &mut LuaState, msg: Option<&[u8]>, level: i32) -> Result<(), LuaError> { todo!("phase-b-reconcile: lua_traceback") }
313
314    fn get_hook_count(&mut self) -> i32 { todo!("phase-b-reconcile: get_hook_count") }
315    fn get_hook_mask(&mut self) -> u32 { todo!("phase-b-reconcile: get_hook_mask") }
316    fn hook_is_set(&mut self) -> bool { todo!("phase-b-reconcile: hook_is_set") }
317    fn hook_is_internal_lua_hook(&mut self) -> bool { todo!("phase-b-reconcile: hook_is_internal_lua_hook") }
318    fn set_c_stack_limit(&mut self, limit: i32) -> Result<i32, LuaError> { todo!("phase-b-reconcile: set_c_stack_limit") }
319
320    fn new_thread(&mut self, initial_body: Option<LuaValue>) -> Result<GcRef<LuaThread>, LuaError> {
321        let _ = initial_body;
322        todo!("phase-b-reconcile: new_thread")
323    }
324    fn is_same_thread(&mut self, other: &LuaState) -> bool { todo!("phase-b-reconcile: is_same_thread") }
325    fn thread_status(&mut self) -> LuaStatus { todo!("phase-b-reconcile: thread_status") }
326
327    fn load_buffer(&mut self, buf: &[u8], name: &[u8], mode: Option<&[u8]>) -> Result<LuaStatus, LuaError> { todo!("phase-b-reconcile: load_buffer") }
328    fn where_error(&mut self, level: i32, msg: &[u8]) -> LuaError { todo!("phase-b-reconcile: where_error") }
329    fn arg(&mut self, n: i32) -> LuaValue { todo!("phase-b-reconcile: arg") }
330    fn as_bytes_or_coerce(&mut self, idx: i32) -> Option<Vec<u8>> { todo!("phase-b-reconcile: as_bytes_or_coerce") }
331    fn as_bytes(&mut self, idx: i32) -> Option<Vec<u8>> { todo!("phase-b-reconcile: as_bytes") }
332}
333
334impl LuaStateStubExt for LuaState {
335    fn require_lib(&mut self, name: &[u8], openf: lua_CFunction, glb: bool) -> Result<(), LuaError> {
336        crate::auxlib::requiref(self, name, openf, glb)
337    }
338
339    fn get_field(&mut self, idx: i32, k: &[u8]) -> Result<LuaType, LuaError> {
340        lua_vm::api::get_field(self, idx, k)
341    }
342
343    fn abs_index(&mut self, idx: i32) -> i32 {
344        lua_vm::api::abs_index(self, idx)
345    }
346
347    fn push_value(&mut self, idx: i32) -> Result<(), LuaError> {
348        lua_vm::api::push_value(self, idx);
349        Ok(())
350    }
351
352    fn set_field(&mut self, idx: i32, k: &[u8]) -> Result<(), LuaError> {
353        lua_vm::api::set_field(self, idx, k)
354    }
355
356    fn set_global(&mut self, name: &[u8]) -> Result<(), LuaError> {
357        lua_vm::api::set_global(self, name)
358    }
359
360    fn to_boolean(&mut self, idx: i32) -> bool {
361        lua_vm::api::to_boolean(self, idx)
362    }
363
364    fn top(&mut self) -> i32 {
365        lua_vm::api::get_top(self)
366    }
367
368    fn push_c_function(&mut self, f: lua_CFunction) -> Result<(), LuaError> {
369        let idx: LuaCFnPtr = {
370            let mut g = self.global_mut();
371            match g.c_functions.iter().position(|existing| {
372                existing
373                    .as_bare()
374                    .is_some_and(|existing| std::ptr::fn_addr_eq(existing, f))
375            }) {
376                Some(i) => i,
377                None => {
378                    let i = g.c_functions.len();
379                    g.c_functions.push(LuaCallable::bare(f));
380                    i
381                }
382            }
383        };
384        self.push(LuaValue::Function(LuaClosure::LightC(idx)));
385        Ok(())
386    }
387
388    fn push_bytes(&mut self, s: &[u8]) -> Result<(), LuaError> {
389        lua_vm::api::push_lstring(self, s)?;
390        Ok(())
391    }
392
393    fn call(&mut self, nargs: i32, nresults: i32) -> Result<(), LuaError> {
394        lua_vm::api::call_k(self, nargs, nresults, 0, None)
395    }
396
397    fn call_k(
398        &mut self,
399        nargs: i32,
400        nresults: i32,
401        ctx: isize,
402        k: Option<fn(&mut LuaState, i32, isize) -> Result<usize, LuaError>>,
403    ) -> Result<(), LuaError> {
404        lua_vm::api::call_k(self, nargs, nresults, ctx, k)
405    }
406
407    fn remove(&mut self, idx: i32) -> Result<(), LuaError> {
408        lua_vm::api::rotate(self, idx, -1);
409        lua_vm::api::set_top(self, -2)
410    }
411
412    fn get_upvalue(&mut self, fidx: i32, n: i32) -> Result<Option<Vec<u8>>, LuaError> {
413        Ok(lua_vm::api::get_upvalue(self, fidx, n))
414    }
415
416    fn set_upvalue(&mut self, fidx: i32, n: i32) -> Result<Option<Vec<u8>>, LuaError> {
417        Ok(lua_vm::api::setup_value(self, fidx, n))
418    }
419
420    fn load(&mut self, chunk: &[u8], name: &[u8], mode: Option<&[u8]>) -> Result<bool, LuaError> {
421        let mut remaining = Some(chunk.to_vec());
422        let reader: Box<dyn FnMut() -> Option<Vec<u8>>> = Box::new(move || remaining.take());
423        let status = lua_vm::api::load(self, reader, Some(name), mode)?;
424        Ok(status == LuaStatus::Ok)
425    }
426
427    fn push_globals(&mut self) -> Result<(), LuaError> {
428        let g = self.global().globals.clone();
429        self.push(g);
430        Ok(())
431    }
432
433    fn set_funcs(&mut self, funcs: &[(&[u8], lua_CFunction)], nup: i32) -> Result<(), LuaError> {
434        lua_vm::api::check_stack(self, nup);
435        for (name, f) in funcs {
436            for _ in 0..nup {
437                lua_vm::api::push_value(self, -nup);
438            }
439            lua_vm::api::push_cclosure(self, *f, nup)?;
440            lua_vm::api::set_field(self, -(nup + 2), name)?;
441        }
442        self.pop_n(nup as usize);
443        Ok(())
444    }
445
446    fn arg_to_bool(&mut self, arg: i32) -> bool {
447        lua_vm::api::to_boolean(self, arg)
448    }
449
450    fn value_at(&mut self, idx: i32) -> LuaValue {
451        lua_vm::api::push_value(self, idx);
452        self.pop()
453    }
454
455    fn check_arg_type(&mut self, arg: i32, t: LuaType) -> Result<(), LuaError> {
456        if lua_vm::api::lua_type_at(self, arg) != t {
457            lua_vm::api::push_value(self, arg);
458            let got = self.pop();
459            let expected: &str = match t {
460                LuaType::None => "no value",
461                LuaType::Nil => "nil",
462                LuaType::Boolean => "boolean",
463                LuaType::LightUserData => "userdata",
464                LuaType::Number => "number",
465                LuaType::String => "string",
466                LuaType::Table => "table",
467                LuaType::Function => "function",
468                LuaType::UserData => "userdata",
469                LuaType::Thread => "thread",
470            };
471            let got_name = if lua_vm::api::lua_type_at(self, arg) == LuaType::None {
472                b"no value".to_vec()
473            } else {
474                self.full_type_name(&got)?
475            };
476            let extramsg = format!(
477                "{} expected, got {}",
478                expected, String::from_utf8_lossy(&got_name)
479            );
480            return Err(lua_vm::debug::arg_error_impl(self, arg, extramsg.as_bytes()));
481        }
482        Ok(())
483    }
484
485    fn opt_arg_string(&mut self, arg: i32, def: &[u8]) -> Result<Vec<u8>, LuaError> {
486        match lua_vm::api::lua_type_at(self, arg) {
487            LuaType::None | LuaType::Nil => Ok(def.to_vec()),
488            _ => self.check_arg_string(arg),
489        }
490    }
491
492    fn get_metafield(&mut self, idx: i32, name: &[u8]) -> Result<LuaType, LuaError> {
493        let abs = lua_vm::api::abs_index(self, idx);
494        if !lua_vm::api::get_metatable(self, abs) {
495            return Ok(LuaType::Nil);
496        }
497        lua_vm::api::push_lstring(self, name)?;
498        let tt = lua_vm::api::raw_get(self, -2);
499        if tt == LuaType::Nil {
500            self.pop_n(2);
501        } else {
502            self.remove(-2)?;
503        }
504        Ok(tt)
505    }
506
507    fn table_get_i(&mut self, idx: i32, n: i64) -> Result<LuaType, LuaError> {
508        lua_vm::api::get_i(self, idx, n)
509    }
510
511    fn table_get_i_value(&mut self, t: &LuaValue, n: i64) -> Result<LuaType, LuaError> {
512        lua_vm::api::get_i_value(self, t, n)
513    }
514
515    fn table_set_i_value(&mut self, t: &LuaValue, n: i64) -> Result<(), LuaError> {
516        lua_vm::api::set_i_value(self, t, n)
517    }
518
519    fn compare_lt(&mut self, idx1: i32, idx2: i32) -> Result<bool, LuaError> {
520        lua_vm::api::compare(self, idx1, idx2, 1)
521    }
522
523    fn check_arg_any(&mut self, arg: i32) -> Result<(), LuaError> {
524        if lua_vm::api::lua_type_at(self, arg) == LuaType::None {
525            return Err(LuaError::arg_error(arg, "value expected"));
526        }
527        Ok(())
528    }
529
530    fn check_arg_integer(&mut self, arg: i32) -> Result<i64, LuaError> {
531        match lua_vm::api::to_integer_x(self, arg) {
532            Some(d) => Ok(d),
533            None => {
534                if lua_vm::api::is_number(self, arg) {
535                    Err(LuaError::arg_error(
536                        arg,
537                        "number has no integer representation",
538                    ))
539                } else {
540                    let got = self.value_at(arg);
541                    let got_name = if lua_vm::api::lua_type_at(self, arg) == LuaType::None {
542                        b"no value".to_vec()
543                    } else {
544                        self.full_type_name(&got)?
545                    };
546                    let extramsg = format!(
547                        "number expected, got {}",
548                        String::from_utf8_lossy(&got_name)
549                    );
550                    Err(lua_vm::debug::arg_error_impl(self, arg, extramsg.as_bytes()))
551                }
552            }
553        }
554    }
555
556    fn check_arg_string(&mut self, arg: i32) -> Result<Vec<u8>, LuaError> {
557        match lua_vm::api::to_lua_string(self, arg)? {
558            Some(s) => Ok(s.as_bytes().to_vec()),
559            None => {
560                let got = self.value_at(arg);
561                let got_name = if lua_vm::api::lua_type_at(self, arg) == LuaType::None {
562                    b"no value".to_vec()
563                } else {
564                    self.full_type_name(&got)?
565                };
566                let extramsg = format!(
567                    "string expected, got {}",
568                    String::from_utf8_lossy(&got_name)
569                );
570                Err(lua_vm::debug::arg_error_impl(self, arg, extramsg.as_bytes()))
571            }
572        }
573    }
574
575    fn check_arg_number(&mut self, arg: i32) -> Result<f64, LuaError> {
576        match lua_vm::api::to_number_x(self, arg) {
577            Some(d) => Ok(d),
578            None => {
579                let got = self.value_at(arg);
580                let got_name = if lua_vm::api::lua_type_at(self, arg) == LuaType::None {
581                    b"no value".to_vec()
582                } else {
583                    self.full_type_name(&got)?
584                };
585                let extramsg = format!(
586                    "number expected, got {}",
587                    String::from_utf8_lossy(&got_name)
588                );
589                Err(lua_vm::debug::arg_error_impl(self, arg, extramsg.as_bytes()))
590            }
591        }
592    }
593
594    fn check_number(&mut self, arg: i32) -> Result<f64, LuaError> {
595        self.check_arg_number(arg)
596    }
597
598    fn check_integer(&mut self, arg: i32) -> Result<i64, LuaError> {
599        self.check_arg_integer(arg)
600    }
601
602    fn check_any(&mut self, arg: i32) -> Result<(), LuaError> {
603        self.check_arg_any(arg)
604    }
605
606    fn opt_arg_integer(&mut self, arg: i32, def: i64) -> Result<i64, LuaError> {
607        match lua_vm::api::lua_type_at(self, arg) {
608            LuaType::None | LuaType::Nil => Ok(def),
609            _ => self.check_arg_integer(arg),
610        }
611    }
612
613    fn opt_integer(&mut self, arg: i32, def: i64) -> Result<i64, LuaError> {
614        self.opt_arg_integer(arg, def)
615    }
616
617    fn opt_number(&mut self, arg: i32, def: f64) -> Result<f64, LuaError> {
618        match lua_vm::api::lua_type_at(self, arg) {
619            LuaType::None | LuaType::Nil => Ok(def),
620            _ => self.check_arg_number(arg),
621        }
622    }
623
624    fn opt_arg_string_bytes(&mut self, arg: i32) -> Result<Vec<u8>, LuaError> {
625        match lua_vm::api::lua_type_at(self, arg) {
626            LuaType::None | LuaType::Nil => Ok(Vec::new()),
627            _ => self.check_arg_string(arg),
628        }
629    }
630
631    fn opt_arg_lstring(&mut self, arg: i32, def: Option<&[u8]>) -> Result<Option<Vec<u8>>, LuaError> {
632        match lua_vm::api::lua_type_at(self, arg) {
633            LuaType::None | LuaType::Nil => Ok(def.map(|d| d.to_vec())),
634            _ => Ok(Some(self.check_arg_string(arg)?)),
635        }
636    }
637
638    fn check_arg_option(
639        &mut self,
640        arg: i32,
641        def: Option<&[u8]>,
642        lst: &[&[u8]],
643    ) -> Result<usize, LuaError> {
644        let name: Vec<u8> = match def {
645            Some(d) if matches!(
646                lua_vm::api::lua_type_at(self, arg),
647                LuaType::None | LuaType::Nil
648            ) =>
649            {
650                d.to_vec()
651            }
652            _ => self.check_arg_string(arg)?,
653        };
654        for (i, entry) in lst.iter().enumerate() {
655            if *entry == name.as_slice() {
656                return Ok(i);
657            }
658        }
659        let extramsg = format!("invalid option '{}'", String::from_utf8_lossy(&name));
660        Err(lua_vm::debug::arg_error_impl(self, arg, extramsg.as_bytes()))
661    }
662
663    fn arg(&mut self, n: i32) -> LuaValue {
664        self.value_at(n)
665    }
666
667    fn type_at(&mut self, idx: i32) -> LuaType {
668        lua_vm::api::lua_type_at(self, idx)
669    }
670
671    fn type_name(&mut self, t: LuaType) -> &'static [u8] {
672        lua_vm::api::type_name(self, t)
673    }
674
675    fn type_name_at(&mut self, idx: i32) -> &'static [u8] {
676        let t = lua_vm::api::lua_type_at(self, idx);
677        lua_vm::api::type_name(self, t)
678    }
679
680    fn is_integer(&mut self, idx: i32) -> bool {
681        lua_vm::api::is_integer(self, idx)
682    }
683
684    fn is_number(&mut self, idx: i32) -> bool {
685        lua_vm::api::is_number(self, idx)
686    }
687
688    fn is_none_or_nil(&mut self, idx: i32) -> bool {
689        matches!(
690            lua_vm::api::lua_type_at(self, idx),
691            LuaType::None | LuaType::Nil
692        )
693    }
694
695    fn to_integer_x(&mut self, idx: i32) -> Option<i64> {
696        lua_vm::api::to_integer_x(self, idx)
697    }
698
699    fn to_number_x(&mut self, idx: i32) -> Option<f64> {
700        lua_vm::api::to_number_x(self, idx)
701    }
702
703    fn to_integer(&mut self, idx: i32) -> Option<i64> {
704        lua_vm::api::to_integer_x(self, idx)
705    }
706
707    fn to_integer_opt(&mut self, idx: i32) -> Option<i64> {
708        lua_vm::api::to_integer_x(self, idx)
709    }
710
711    fn to_number(&mut self, idx: i32) -> Option<f64> {
712        lua_vm::api::to_number_x(self, idx)
713    }
714
715    fn to_lua_string(&mut self, idx: i32) -> Option<GcRef<LuaString>> {
716        lua_vm::api::to_lua_string(self, idx).ok().flatten()
717    }
718
719    fn to_lua_string_bytes(&mut self, idx: i32) -> Option<Vec<u8>> {
720        lua_vm::api::to_lua_string(self, idx)
721            .ok()
722            .flatten()
723            .map(|s| s.as_bytes().to_vec())
724    }
725
726    fn to_lua_string_len(&mut self, idx: i32) -> Option<usize> {
727        lua_vm::api::to_lua_string(self, idx)
728            .ok()
729            .flatten()
730            .map(|s| s.len())
731    }
732
733    fn to_bytes(&mut self, idx: i32) -> Option<Vec<u8>> {
734        self.to_lua_string_bytes(idx)
735    }
736
737    fn to_bytes_at(&mut self, idx: i32) -> Option<Vec<u8>> {
738        self.to_lua_string_bytes(idx)
739    }
740
741    fn raw_equal(&mut self, idx1: i32, idx2: i32) -> Result<bool, LuaError> {
742        Ok(lua_vm::api::raw_equal(self, idx1, idx2))
743    }
744
745    fn raw_geti(&mut self, idx: i32, n: i64) -> Result<LuaType, LuaError> {
746        Ok(lua_vm::api::raw_get_i(self, idx, n))
747    }
748
749    fn raw_get_i(&mut self, idx: i32, n: i64) -> Result<LuaType, LuaError> {
750        Ok(lua_vm::api::raw_get_i(self, idx, n))
751    }
752
753    fn raw_seti(&mut self, idx: i32, n: i64) -> Result<(), LuaError> {
754        lua_vm::api::raw_set_i(self, idx, n)
755    }
756
757    fn raw_set_i(&mut self, idx: i32, n: i64) -> Result<(), LuaError> {
758        lua_vm::api::raw_set_i(self, idx, n)
759    }
760
761    fn raw_len(&mut self, idx: i32) -> i64 {
762        lua_vm::api::raw_len(self, idx) as i64
763    }
764
765    fn get_i(&mut self, idx: i32, n: i64) -> Result<LuaType, LuaError> {
766        lua_vm::api::get_i(self, idx, n)
767    }
768
769    fn get_metatable(&mut self, idx: i32) -> Result<bool, LuaError> {
770        Ok(lua_vm::api::get_metatable(self, idx))
771    }
772
773    fn set_metatable(&mut self, idx: i32) -> Result<(), LuaError> {
774        lua_vm::api::set_metatable(self, idx)?;
775        Ok(())
776    }
777
778    fn compare(&mut self, idx1: i32, idx2: i32, op: CompareOp) -> Result<bool, LuaError> {
779        let op_i = match op {
780            CompareOp::Eq => 0,
781            CompareOp::Lt => 1,
782            CompareOp::Le => 2,
783        };
784        lua_vm::api::compare(self, idx1, idx2, op_i)
785    }
786
787    fn protected_call(&mut self, nargs: i32, nresults: i32, msgh: i32) -> Result<(), LuaError> {
788        lua_vm::api::pcall_k(self, nargs, nresults, msgh, 0, None)?;
789        Ok(())
790    }
791    fn protected_call_k(
792        &mut self,
793        nargs: i32,
794        nresults: i32,
795        msgh: i32,
796        ctx: isize,
797        k: Option<fn(&mut LuaState, i32, isize) -> Result<usize, LuaError>>,
798    ) -> Result<(), LuaError> {
799        lua_vm::api::pcall_k(self, nargs, nresults, msgh, ctx, k)?;
800        Ok(())
801    }
802
803    fn push_value_at(&mut self, idx: i32) -> Result<(), LuaError> {
804        lua_vm::api::push_value(self, idx);
805        Ok(())
806    }
807
808    fn push_thread(&mut self) -> Result<bool, LuaError> {
809        Ok(lua_vm::api::push_thread(self))
810    }
811
812    fn push_cclosure(&mut self, f: lua_CFunction, n: i32) -> Result<(), LuaError> {
813        lua_vm::api::push_cclosure(self, f, n)
814    }
815
816    fn push_c_closure(&mut self, f: lua_CFunction, n: i32) -> Result<(), LuaError> {
817        lua_vm::api::push_cclosure(self, f, n)
818    }
819
820    fn push_lstring(&mut self, s: &[u8]) -> Result<(), LuaError> {
821        lua_vm::api::push_lstring(self, s)?;
822        Ok(())
823    }
824
825    fn push_string(&mut self, s: &[u8]) -> Result<(), LuaError> {
826        lua_vm::api::push_lstring(self, s)?;
827        Ok(())
828    }
829
830    fn get_top(&mut self) -> i32 {
831        lua_vm::api::get_top(self)
832    }
833
834    fn stack_top(&mut self) -> i32 {
835        lua_vm::api::get_top(self)
836    }
837
838    fn top_count(&mut self) -> i32 {
839        lua_vm::api::get_top(self)
840    }
841
842    fn check_stack_space(&mut self, n: i32) -> bool {
843        lua_vm::api::check_stack(self, n)
844    }
845
846    fn rotate(&mut self, idx: i32, n: i32) -> Result<(), LuaError> {
847        lua_vm::api::rotate(self, idx, n);
848        Ok(())
849    }
850
851    fn insert(&mut self, idx: i32) -> Result<(), LuaError> {
852        lua_vm::api::rotate(self, idx, 1);
853        Ok(())
854    }
855
856    fn copy_value(&mut self, from: i32, to: i32) -> Result<(), LuaError> {
857        lua_vm::api::copy(self, from, to);
858        Ok(())
859    }
860
861    fn replace(&mut self, idx: i32) -> Result<(), LuaError> {
862        lua_vm::api::copy(self, -1, idx);
863        lua_vm::api::set_top(self, -2)
864    }
865
866    fn len_op(&mut self, idx: i32) -> Result<(), LuaError> {
867        lua_vm::api::len(self, idx)
868    }
869
870    fn table_next(&mut self, idx: i32) -> Result<bool, LuaError> {
871        lua_vm::api::next(self, idx)
872    }
873
874    fn create_table(&mut self, narr: i32, nrec: i32) -> Result<(), LuaError> {
875        lua_vm::api::create_table(self, narr, nrec)
876    }
877
878    fn to_userdata(&mut self, idx: i32) -> Option<GcRef<LuaUserData>> {
879        let v = self.value_at(idx);
880        if let LuaValue::UserData(u) = v { Some(u) } else { None }
881    }
882
883    fn to_light_userdata(&mut self, idx: i32) -> Option<*mut std::ffi::c_void> {
884        lua_vm::api::to_userdata(self, idx)
885    }
886
887    fn to_thread(&mut self, idx: i32) -> Option<GcRef<LuaThread>> {
888        lua_vm::api::to_thread(self, idx)
889    }
890
891    fn to_thread_at(&mut self, idx: i32) -> Option<GcRef<LuaThread>> {
892        lua_vm::api::to_thread(self, idx)
893    }
894
895    fn len_at(&mut self, idx: i32) -> i64 {
896        lua_vm::api::raw_len(self, idx) as i64
897    }
898
899    fn length_at(&mut self, idx: i32) -> Result<i64, LuaError> {
900        lua_vm::api::len(self, idx)?;
901        let v = lua_vm::api::to_integer_x(self, -1);
902        self.pop_n(1);
903        match v {
904            Some(l) => Ok(l),
905            None => Err(LuaError::runtime(format_args!(
906                "object length is not an integer"
907            ))),
908        }
909    }
910
911    fn peek_bytes(&mut self, idx: i32) -> Option<Vec<u8>> {
912        self.to_lua_string_bytes(idx)
913    }
914
915    fn to_string_coerced(&mut self, idx: i32) -> Option<Vec<u8>> {
916        self.to_lua_string_bytes(idx)
917    }
918
919    fn raw_get(&mut self, idx: i32) -> Result<LuaType, LuaError> {
920        Ok(lua_vm::api::raw_get(self, idx))
921    }
922
923    fn raw_set(&mut self, idx: i32) -> Result<(), LuaError> {
924        lua_vm::api::raw_set(self, idx)
925    }
926
927    fn is_c_function_at(&mut self, idx: i32) -> bool {
928        lua_vm::api::is_cfunction(self, idx)
929    }
930
931    fn type_name_str_at(&mut self, idx: i32) -> &'static [u8] {
932        let t = lua_vm::api::lua_type_at(self, idx);
933        lua_vm::api::type_name(self, t)
934    }
935
936    fn push_fstring(&mut self, args: std::fmt::Arguments<'_>) -> Result<(), LuaError> {
937        let formatted = std::fmt::format(args);
938        lua_vm::api::push_fstring(self, formatted.as_bytes())?;
939        Ok(())
940    }
941
942    fn arith(&mut self, op: ArithOp) -> Result<(), LuaError> {
943        lua_vm::api::arith(self, op as i32)
944    }
945
946    fn lua_version(&mut self) -> f64 {
947        504.0
948    }
949
950    fn push_fail(&mut self) -> Result<(), LuaError> {
951        self.push(LuaValue::Nil);
952        Ok(())
953    }
954
955    fn push_registry(&mut self) -> Result<(), LuaError> {
956        let r = self.registry_value();
957        self.push(r);
958        Ok(())
959    }
960
961    fn push_upvalue(&mut self, idx: i32) -> Result<(), LuaError> {
962        lua_vm::api::push_value(self, upvalue_index(idx));
963        Ok(())
964    }
965
966    fn pop_bytes(&mut self) -> Vec<u8> {
967        match self.pop() {
968            LuaValue::Str(s) => s.as_bytes().to_vec(),
969            _ => Vec::new(),
970        }
971    }
972
973    fn push_where(&mut self, level: i32) -> Result<(), LuaError> {
974        let mut ar = lua_vm::debug::LuaDebug::default();
975        if lua_vm::debug::get_stack(self, level, &mut ar) {
976            lua_vm::debug::get_info(self, b"Sl", &mut ar);
977            if ar.currentline > 0 {
978                let zero = ar
979                    .short_src
980                    .iter()
981                    .position(|&b| b == 0)
982                    .unwrap_or(ar.short_src.len());
983                let mut buf: Vec<u8> = ar.short_src[..zero].to_vec();
984                buf.push(b':');
985                buf.extend_from_slice(ar.currentline.to_string().as_bytes());
986                buf.extend_from_slice(b": ");
987                lua_vm::api::push_lstring(self, &buf)?;
988                return Ok(());
989            }
990        }
991        lua_vm::api::push_lstring(self, b"")?;
992        Ok(())
993    }
994
995    fn where_error(&mut self, level: i32, msg: &[u8]) -> LuaError {
996        if self.push_where(level).is_err() {
997            return LuaError::runtime(format_args!("{}", StubBStr(msg)));
998        }
999        let mut full = self.pop_bytes();
1000        full.extend_from_slice(msg);
1001        LuaError::runtime(format_args!("{}", StubBStr(&full)))
1002    }
1003
1004    fn registry_get(&mut self, key: &[u8]) -> Result<LuaType, LuaError> {
1005        lua_vm::api::get_field(self, STUB_LUA_REGISTRYINDEX, key)
1006    }
1007
1008    fn get_field_registry(&mut self, name: &[u8]) -> Result<LuaType, LuaError> {
1009        lua_vm::api::get_field(self, STUB_LUA_REGISTRYINDEX, name)
1010    }
1011
1012    fn get_registry_field(&mut self, name: &[u8]) -> Result<LuaType, LuaError> {
1013        lua_vm::api::get_field(self, STUB_LUA_REGISTRYINDEX, name)
1014    }
1015
1016    fn get_or_create_registry_subtable(&mut self, name: &[u8]) -> Result<bool, LuaError> {
1017        self.get_subtable_registry(name)
1018    }
1019
1020    fn registry_set(&mut self, key: &[u8]) -> Result<(), LuaError> {
1021        lua_vm::api::set_field(self, STUB_LUA_REGISTRYINDEX, key)
1022    }
1023
1024    fn check_stack_growth(&mut self, n: i32) -> bool {
1025        lua_vm::api::check_stack(self, n)
1026    }
1027
1028    fn ensure_stack<S: AsRef<[u8]> + ?Sized>(&mut self, n: i32, msg: &S) -> Result<(), LuaError> {
1029        if lua_vm::api::check_stack(self, n) {
1030            return Ok(());
1031        }
1032        let m = msg.as_ref();
1033        if m.is_empty() {
1034            Err(LuaError::runtime(format_args!("stack overflow")))
1035        } else {
1036            Err(LuaError::runtime(format_args!(
1037                "stack overflow ({})",
1038                StubBStr(m)
1039            )))
1040        }
1041    }
1042
1043    fn push_copy(&mut self, idx: i32) -> Result<(), LuaError> {
1044        lua_vm::api::push_value(self, idx);
1045        Ok(())
1046    }
1047
1048    fn as_bytes(&mut self, idx: i32) -> Option<Vec<u8>> {
1049        self.to_lua_string_bytes(idx)
1050    }
1051
1052    fn as_bytes_or_coerce(&mut self, idx: i32) -> Option<Vec<u8>> {
1053        self.to_lua_string_bytes(idx)
1054    }
1055
1056    fn thread_status(&mut self) -> LuaStatus {
1057        lua_vm::api::status(self)
1058    }
1059
1060    fn new_thread(&mut self, initial_body: Option<LuaValue>) -> Result<GcRef<LuaThread>, LuaError> {
1061        lua_vm::state::new_thread(self, initial_body)?;
1062        let th = lua_vm::api::to_thread(self, -1)
1063            .ok_or_else(|| LuaError::runtime(format_args!("new_thread: missing thread on top")))?;
1064        Ok(th)
1065    }
1066
1067    fn is_same_thread(&mut self, other: &LuaState) -> bool {
1068        std::ptr::eq(self as *const LuaState, other as *const LuaState)
1069    }
1070
1071    fn load_buffer(&mut self, buf: &[u8], name: &[u8], mode: Option<&[u8]>) -> Result<LuaStatus, LuaError> {
1072        let mut remaining = Some(buf.to_vec());
1073        let reader: Box<dyn FnMut() -> Option<Vec<u8>>> = Box::new(move || remaining.take());
1074        lua_vm::api::load(self, reader, Some(name), mode)
1075    }
1076
1077    fn load_buffer_ex<M: ?Sized>(&mut self, buf: &[u8], name: &[u8], mode: &M) -> Result<bool, LuaError>
1078    where
1079        M: AsRef<[u8]>,
1080    {
1081        let mut remaining = Some(buf.to_vec());
1082        let reader: Box<dyn FnMut() -> Option<Vec<u8>>> = Box::new(move || remaining.take());
1083        let mode_bytes = mode.as_ref();
1084        let status = lua_vm::api::load(self, reader, Some(name), Some(mode_bytes))?;
1085        Ok(status == LuaStatus::Ok)
1086    }
1087
1088    fn dump_function(&mut self, strip: bool) -> Result<Vec<u8>, LuaError> {
1089        let mut out: Vec<u8> = Vec::new();
1090        let mut writer = |chunk: &[u8]| -> Result<(), LuaError> {
1091            out.extend_from_slice(chunk);
1092            Ok(())
1093        };
1094        let ok = lua_vm::api::dump(self, &mut writer, strip)?;
1095        if !ok {
1096            return Err(LuaError::runtime(format_args!(
1097                "unable to dump given function"
1098            )));
1099        }
1100        Ok(out)
1101    }
1102
1103    fn warning(&mut self, msg: &[u8], to_cont: bool) -> Result<(), LuaError> {
1104        lua_vm::api::warning(self, msg, to_cont);
1105        Ok(())
1106    }
1107
1108    fn string_to_number(&mut self, idx: i32) -> Option<usize> {
1109        let bytes = lua_vm::api::to_lua_string(self, idx)
1110            .ok()
1111            .flatten()?
1112            .as_bytes()
1113            .to_vec();
1114        let consumed = lua_vm::api::string_to_number(self, &bytes);
1115        if consumed == 0 {
1116            None
1117        } else {
1118            Some(consumed)
1119        }
1120    }
1121
1122    fn string_to_number_push<S: AsRef<[u8]> + ?Sized>(&mut self, s: &S) -> Result<usize, LuaError> {
1123        Ok(lua_vm::api::string_to_number(self, s.as_ref()))
1124    }
1125
1126    fn gc_count(&mut self) -> Result<i32, LuaError> {
1127        Ok(lua_vm::api::gc(self, lua_vm::api::GcArgs::Count))
1128    }
1129
1130    fn gc_count_b(&mut self) -> Result<i32, LuaError> {
1131        Ok(lua_vm::api::gc(self, lua_vm::api::GcArgs::CountB))
1132    }
1133
1134    fn gc_step(&mut self, data: i32) -> Result<i32, LuaError> {
1135        Ok(lua_vm::api::gc(self, lua_vm::api::GcArgs::Step { data }))
1136    }
1137
1138    fn gc_is_running(&mut self) -> Result<bool, LuaError> {
1139        Ok(lua_vm::api::gc(self, lua_vm::api::GcArgs::IsRunning) != 0)
1140    }
1141
1142    fn gc_control_simple(&mut self, op: i32) -> Result<i32, LuaError> {
1143        let args = match op {
1144            0 => lua_vm::api::GcArgs::Stop,
1145            1 => lua_vm::api::GcArgs::Restart,
1146            2 => lua_vm::api::GcArgs::Collect,
1147            _ => return Err(LuaError::runtime(format_args!(
1148                "invalid GC option {}", op
1149            ))),
1150        };
1151        let res = lua_vm::api::gc(self, args);
1152        // 5.2/5.3 `collectgarbage("collect")` re-raises a `__gc` finalizer
1153        // error parked by the explicit-collect path (C `GCTM` propagation).
1154        if let Some(err) = self.global_mut().gc_finalizer_error.take() {
1155            return Err(LuaError::from_value(err));
1156        }
1157        Ok(res)
1158    }
1159
1160    fn gc_set_param(&mut self, op: i32, value: i32) -> Result<i32, LuaError> {
1161        let args = match op {
1162            6 => lua_vm::api::GcArgs::SetPause { value },
1163            7 => lua_vm::api::GcArgs::SetStepMul { value },
1164            _ => return Err(LuaError::runtime(format_args!(
1165                "invalid GC param option {}", op
1166            ))),
1167        };
1168        Ok(lua_vm::api::gc(self, args))
1169    }
1170
1171    fn gc_gen(&mut self, minor_mul: i32, major_mul: i32) -> Result<i32, LuaError> {
1172        Ok(lua_vm::api::gc(
1173            self,
1174            lua_vm::api::GcArgs::Gen { minormul: minor_mul, majormul: major_mul },
1175        ))
1176    }
1177
1178    fn gc_inc(&mut self, pause: i32, step_mul: i32, step_size: i32) -> Result<i32, LuaError> {
1179        Ok(lua_vm::api::gc(
1180            self,
1181            lua_vm::api::GcArgs::Inc { pause, stepmul: step_mul, stepsize: step_size },
1182        ))
1183    }
1184
1185    fn gc_param(&mut self, param: usize, value: i64) -> Result<i64, LuaError> {
1186        Ok(lua_vm::api::gc(self, lua_vm::api::GcArgs::Param { param, value }) as i64)
1187    }
1188
1189    fn get_meta_field(&mut self, idx: i32, name: &[u8]) -> Result<bool, LuaError> {
1190        Ok(crate::auxlib::get_metafield(self, idx, name)? != LuaType::Nil)
1191    }
1192
1193    fn to_display_string(&mut self, idx: i32) -> Result<Vec<u8>, LuaError> {
1194        crate::auxlib::to_lua_string(self, idx)
1195    }
1196
1197    fn get_subtable_registry(&mut self, name: &[u8]) -> Result<bool, LuaError> {
1198        crate::auxlib::get_subtable(self, STUB_LUA_REGISTRYINDEX, name)
1199    }
1200
1201    fn new_metatable(&mut self, name: &[u8]) -> Result<bool, LuaError> {
1202        crate::auxlib::new_metatable(self, name)
1203    }
1204
1205    fn set_metatable_by_name(&mut self, name: &[u8]) -> Result<(), LuaError> {
1206        crate::auxlib::set_metatable(self, name)
1207    }
1208
1209    fn check_arg_userdata(&mut self, arg: i32, name: &[u8]) -> Result<GcRef<LuaUserData>, LuaError> {
1210        crate::auxlib::check_udata(self, arg, name)
1211    }
1212
1213    fn test_arg_userdata(&mut self, arg: i32, name: &[u8]) -> Option<GcRef<LuaUserData>> {
1214        crate::auxlib::test_udata(self, arg, name).ok().flatten()
1215    }
1216
1217    fn get_table(&mut self, idx: i32) -> Result<LuaType, LuaError> {
1218        lua_vm::api::get_table(self, idx)
1219    }
1220
1221    fn get_stack(&mut self, level: i32, ar: &mut LuaDebug) -> bool {
1222        let mut lvm_ar = lua_vm::debug::LuaDebug::default();
1223        let ok = lua_vm::debug::get_stack(self, level, &mut lvm_ar);
1224        if ok {
1225            ar.i_ci_idx = lvm_ar.i_ci;
1226        } else {
1227            ar.i_ci_idx = None;
1228        }
1229        ok
1230    }
1231
1232    fn get_stack_level(&mut self, level: i32, ar: &mut LuaDebug) -> bool {
1233        LuaStateStubExt::get_stack(self, level, ar)
1234    }
1235
1236    fn get_info(&mut self, what: &[u8], ar: &mut LuaDebug) -> Result<(), LuaError> {
1237        let mut lvm_ar = lua_vm::debug::LuaDebug::default();
1238        lvm_ar.i_ci = ar.i_ci_idx;
1239        let ok = lua_vm::debug::get_info(self, what, &mut lvm_ar);
1240        copy_lvm_debug_to_stub_selective(&lvm_ar, ar, what);
1241        if ok {
1242            Ok(())
1243        } else {
1244            Err(LuaError::runtime(format_args!("invalid option")))
1245        }
1246    }
1247
1248    fn get_debug_info(&mut self, what: &[u8], ar: &mut LuaDebug) -> Result<(), LuaError> {
1249        LuaStateStubExt::get_info(self, what, ar)
1250    }
1251
1252    fn get_local_at(&mut self, ar: &LuaDebug, n: i32) -> Result<Option<Vec<u8>>, LuaError> {
1253        let mut lvm_ar = lua_vm::debug::LuaDebug::default();
1254        lvm_ar.i_ci = ar.i_ci_idx;
1255        Ok(lua_vm::debug::get_local(self, Some(&lvm_ar), n))
1256    }
1257
1258    fn set_local_at(&mut self, ar: &LuaDebug, n: i32) -> Result<Option<Vec<u8>>, LuaError> {
1259        let mut lvm_ar = lua_vm::debug::LuaDebug::default();
1260        lvm_ar.i_ci = ar.i_ci_idx;
1261        Ok(lua_vm::debug::set_local(self, &lvm_ar, n))
1262    }
1263
1264    fn get_param_name(&mut self, fidx: i32, n: i32) -> Result<Option<Vec<u8>>, LuaError> {
1265        let _ = fidx;
1266        Ok(lua_vm::debug::get_local(self, None, n))
1267    }
1268
1269    fn has_frames(&mut self) -> bool {
1270        !self.is_base_ci(self.current_ci_idx())
1271    }
1272
1273    fn lua_traceback(
1274        &mut self,
1275        other: &mut LuaState,
1276        msg: Option<&[u8]>,
1277        level: i32,
1278    ) -> Result<(), LuaError> {
1279        crate::auxlib::traceback(self, Some(other), msg, level)
1280    }
1281
1282    fn upvalue_id(&mut self, fidx: i32, n: i32) -> Result<*mut std::ffi::c_void, LuaError> {
1283        match lua_vm::api::upvalue_id(self, fidx, n) {
1284            Some(id) => Ok(id as *mut std::ffi::c_void),
1285            None => Ok(std::ptr::null_mut()),
1286        }
1287    }
1288
1289    fn join_upvalues(&mut self, fidx1: i32, n1: i32, fidx2: i32, n2: i32) -> Result<(), LuaError> {
1290        lua_vm::api::upvalue_join(self, fidx1, n1, fidx2, n2);
1291        Ok(())
1292    }
1293
1294    /// Pre-collect the chunks supplied by `reader` (a state-aware callback)
1295    /// and forward the accumulated buffer to `lua_vm::api::load`. The streaming
1296    /// loader in `lua_vm::api::load` consumes a `Box<dyn FnMut() -> Option<Vec<u8>>>`
1297    /// that does not take a `&mut LuaState`, so the state-touching reader
1298    /// (e.g. `generic_reader`, which calls a Lua function to produce each
1299    /// chunk) is drained first. C-Lua streams chunks directly through
1300    /// `lua_load`; the materialised path here is observable only for very
1301    /// large source files and is intentional for the Phase-B shim.
1302    fn load_with_reader<F, M: ?Sized>(&mut self, mut reader: F, name: &[u8], mode: &M) -> Result<bool, LuaError>
1303    where
1304        F: FnMut(&mut LuaState) -> Result<Option<Vec<u8>>, LuaError>,
1305        M: AsRef<[u8]>,
1306    {
1307        let mut buf: Vec<u8> = Vec::new();
1308        let mut reader_err: Option<LuaError> = None;
1309        loop {
1310            match reader(self) {
1311                Err(e) => {
1312                    reader_err = Some(e);
1313                    break;
1314                }
1315                Ok(None) => break,
1316                Ok(Some(piece)) => {
1317                    if piece.is_empty() {
1318                        break;
1319                    }
1320                    buf.extend_from_slice(&piece);
1321                }
1322            }
1323        }
1324        if let Some(e) = reader_err {
1325            let msg_value = match e {
1326                LuaError::Runtime(v) | LuaError::Syntax(v) => v,
1327                LuaError::Memory => {
1328                    let s = self.intern_str(b"not enough memory")?;
1329                    LuaValue::Str(s)
1330                }
1331                _ => {
1332                    let s = self.intern_str(b"error in reader function")?;
1333                    LuaValue::Str(s)
1334                }
1335            };
1336            self.push(msg_value);
1337            return Ok(false);
1338        }
1339        let mut once = Some(buf);
1340        let boxed: Box<dyn FnMut() -> Option<Vec<u8>>> = Box::new(move || once.take());
1341        let mode_bytes = mode.as_ref();
1342        let status = lua_vm::api::load(self, boxed, Some(name), Some(mode_bytes))?;
1343        Ok(status == LuaStatus::Ok)
1344    }
1345
1346    fn load_file_ex(&mut self, path: Option<&[u8]>, mode: Option<&[u8]>) -> Result<bool, LuaError> {
1347        let status = crate::auxlib::load_filex(self, path, mode)?;
1348        Ok(status == 0)
1349    }
1350
1351    fn load_file(&mut self, path: Option<&[u8]>) -> Result<bool, LuaError> {
1352        LuaStateStubExt::load_file_ex(self, path, None)
1353    }
1354
1355    fn get_iuservalue(&mut self, idx: i32, n: i32) -> Result<LuaType, LuaError> {
1356        Ok(lua_vm::api::get_i_uservalue(self, idx, n))
1357    }
1358
1359    fn set_iuservalue(&mut self, idx: i32, n: i32) -> Result<bool, LuaError> {
1360        lua_vm::api::set_i_uservalue(self, idx, n)
1361    }
1362
1363    fn get_hook_mask(&mut self) -> u32 {
1364        lua_vm::debug::get_hook_mask(self) as u32
1365    }
1366
1367    fn get_hook_count(&mut self) -> i32 {
1368        lua_vm::debug::get_hook_count(self)
1369    }
1370
1371    /// Approximate "is a debug hook installed?" using the hook event mask.
1372    /// `lua_sethook` clears the mask whenever the hook is uninstalled, so a
1373    /// non-zero mask is equivalent to a non-NULL `L->hook` for the
1374    /// `debug.gethook` call site. Avoids invoking `state.hook()`, which is
1375    /// still a Phase-B `todo!` on `LuaState`.
1376    fn hook_is_set(&mut self) -> bool {
1377        lua_vm::debug::get_hook_mask(self) != 0
1378    }
1379
1380    /// Hooks installed through the debug library use the Lua hook trampoline
1381    /// and store the real Lua callback in registry[HOOKKEY].
1382    fn hook_is_internal_lua_hook(&mut self) -> bool {
1383        lua_vm::debug::get_hook_mask(self) != 0
1384    }
1385
1386    fn set_c_stack_limit(&mut self, limit: i32) -> Result<i32, LuaError> {
1387        let clamped = if limit < 0 { 0u32 } else { limit as u32 };
1388        Ok(lua_vm::state::set_c_stack_limit(self, clamped))
1389    }
1390
1391    /// `lua_close(L)` destroys a Lua state. In Rust the state's resources are
1392    /// released by `Drop` when the owning value goes out of scope, so the
1393    /// in-place `&mut self` form is a no-op. The consuming free function
1394    /// `lua_vm::state::close(state)` is reserved for the top-level shutdown
1395    /// path in `lua-cli`.
1396    fn close(&mut self) {
1397        let _ = self;
1398    }
1399
1400    /// Install (or clear) a debug hook on this thread.
1401    ///
1402    /// (`ldebug.c`).
1403    ///
1404    /// The Phase-B `LuaStateStubExt` signature uses `lua_CFunction` (the
1405    /// stdlib C-function shape: `fn(&mut LuaState) -> Result<usize, LuaError>`)
1406    /// for `f`, whereas the canonical `lua_vm::debug::set_hook` takes a
1407    /// `Box<dyn FnMut(&mut LuaState, &LuaDebug)>` (a true Lua hook, which has
1408    /// access to the active `lua_Debug`). To bridge the two, an installed
1409    /// `lua_CFunction` is wrapped in a trampoline closure that calls it with
1410    /// `state` and discards both the activation record and the
1411    /// `Result<usize, LuaError>` (a hook's return value is ignored by C-Lua).
1412    fn set_hook_full(
1413        &mut self,
1414        f: Option<lua_CFunction>,
1415        mask: u32,
1416        count: i32,
1417    ) -> Result<(), LuaError> {
1418        let hook: Option<Box<dyn FnMut(&mut LuaState, &lua_vm::debug::LuaDebug)>> = match f {
1419            None => None,
1420            Some(func) => Some(Box::new(move |state, _ar| {
1421                let _ = func(state);
1422            })),
1423        };
1424        lua_vm::debug::set_hook(self, hook, mask as i32, count);
1425        Ok(())
1426    }
1427
1428    /// Write `msg` to the host's standard output stream.
1429    ///
1430    /// `fwrite(s, 1, l, stdout)`).
1431    ///
1432    /// Delegates to the canonical inherent `LuaState::write_output`. UFCS is
1433    /// used to disambiguate from the trait method (this method) which would
1434    /// otherwise recurse.
1435    fn write_output(&mut self, msg: &[u8]) -> Result<(), LuaError> {
1436        LuaState::write_output(self, msg)
1437    }
1438
1439    /// `t[n] = v`, where `t` is the value at `idx` and `v` is popped from the
1440    /// stack top. Honours `__newindex`.
1441    ///
1442    fn table_set_i(&mut self, idx: i32, n: i64) -> Result<(), LuaError> {
1443        LuaState::table_set_i(self, idx, n)
1444    }
1445
1446    /// Allocate a fresh full-userdata, push it on the stack, and return a
1447    /// `GcRef` to it. `name` is advisory (callers typically follow up with
1448    /// `set_metatable_by_name(name)`).
1449    ///
1450    /// C-correspondent: `lua_newuserdatauv(L, size, nuvalue)` plus the
1451    /// auxiliary `luaL_setmetatable` pattern. The Rust signature carries
1452    /// `name` for caller convenience as documented on the inherent method.
1453    fn new_userdata_typed(
1454        &mut self,
1455        name: &[u8],
1456        size: usize,
1457        nuvalue: i32,
1458    ) -> Result<GcRef<LuaUserData>, LuaError> {
1459        LuaState::new_userdata_typed(self, name, size, nuvalue)
1460    }
1461}
1462
1463/// Copy populated fields from the canonical `lua_vm::debug::LuaDebug` into
1464/// the Phase-B stub `LuaDebug`. The two structs diverge on a few field types
1465/// (e.g. `what` is a single byte tag in the stub vs. `Option<&'static [u8]>`
1466/// in the canonical struct, `short_src` is `Vec<u8>` vs. fixed array).
1467/// Copy only the fields that `lua_getinfo`'s `what` string actually populates
1468/// in C. Mirrors `auxgetinfo` in `ldebug.c`: each option byte writes a disjoint
1469/// subset of `lua_Debug`. Calling `get_info` with one option string must not
1470/// clobber fields populated by an earlier call with a different option string
1471/// (a pattern the auxiliary library relies on — `pushglobalfuncname` calls
1472/// `lua_getinfo(L, "f", ar)` and expects the previously-set `namewhat`/`what`/
1473/// `short_src`/`linedefined` to survive).
1474fn copy_lvm_debug_to_stub_selective(
1475    src: &lua_vm::debug::LuaDebug,
1476    dst: &mut LuaDebug,
1477    what: &[u8],
1478) {
1479    dst.i_ci_idx = src.i_ci;
1480    for &ch in what {
1481        match ch {
1482            b'S' => {
1483                dst.what = match src.what {
1484                    Some(b"Lua") => b'L',
1485                    Some(b"C") => b'C',
1486                    Some(b"main") => b'm',
1487                    _ => 0,
1488                };
1489                dst.source = src.source.clone().unwrap_or_default();
1490                let zero = src
1491                    .short_src
1492                    .iter()
1493                    .position(|&b| b == 0)
1494                    .unwrap_or(src.short_src.len());
1495                dst.short_src = src.short_src[..zero].to_vec();
1496                dst.linedefined = src.linedefined;
1497                dst.lastlinedefined = src.lastlinedefined;
1498            }
1499            b'l' => {
1500                dst.currentline = src.currentline;
1501            }
1502            b'u' => {
1503                dst.nups = src.nups;
1504                dst.nparams = src.nparams;
1505                dst.isvararg = src.isvararg;
1506            }
1507            b't' => {
1508                dst.istailcall = src.istailcall;
1509            }
1510            b'n' => {
1511                dst.name = src.name.clone();
1512                dst.namewhat = src.namewhat.map(|s| s.to_vec()).unwrap_or_default();
1513            }
1514            b'r' => {
1515                dst.ftransfer = src.ftransfer;
1516                dst.ntransfer = src.ntransfer;
1517            }
1518            _ => {}
1519        }
1520    }
1521}
1522
1523const STUB_LUA_REGISTRYINDEX: i32 = -(1_000_000) - 1000;
1524
1525struct StubBStr<'a>(&'a [u8]);
1526
1527impl<'a> std::fmt::Display for StubBStr<'a> {
1528    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1529        use std::fmt::Write as _;
1530        for &b in self.0 {
1531            if b.is_ascii() {
1532                f.write_char(b as char)?;
1533            } else {
1534                write!(f, "\\x{:02x}", b)?;
1535            }
1536        }
1537        Ok(())
1538    }
1539}
1540
1541// ──────────────────────────────────────────────────────────────────────────
1542// PORT STATUS
1543//   source:        (Phase-B reconcile shim; no C source)
1544//   target_crate:  lua-stdlib
1545//   confidence:    high
1546//   todos:         0
1547//   port_notes:    3
1548//   unsafe_blocks: 0
1549//   notes:         Re-exports lua_vm::state::LuaState (canonical owner per
1550//                  harness/type-vocabulary.tsv); the LuaStateStubExt trait
1551//                  carries every Phase-A stub method as a
1552//                  todo!("phase-b-reconcile: …") body so the rest of
1553//                  lua-stdlib keeps compiling while the canonical API
1554//                  catches up.
1555// ──────────────────────────────────────────────────────────────────────────