Skip to main content

lua_stdlib/
state_stub.rs

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