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