Skip to main content

lua_types/
proto.rs

1//! `LuaProto` — compiled function prototype. Mirrors C-Lua's `Proto` struct
2//! but uses Rust idioms (Vec instead of pointer+size pairs).
3
4use crate::closure::LuaLClosure;
5use crate::gc::GcRef;
6use crate::opcode::Instruction;
7use crate::string::LuaString;
8use crate::value::LuaValue;
9use core::cell::RefCell;
10
11#[derive(Debug)]
12pub struct LuaProto {
13    pub numparams: u8,
14    pub is_vararg: bool,
15    pub maxstacksize: u8,
16    pub upvalues: Vec<UpvalDesc>,
17    pub k: Vec<LuaValue>,
18    pub code: Vec<Instruction>,
19    pub p: Vec<GcRef<LuaProto>>,
20    pub lineinfo: Vec<i8>,
21    pub abslineinfo: Vec<AbsLineInfo>,
22    pub locvars: Vec<LocalVar>,
23    pub linedefined: i32,
24    pub lastlinedefined: i32,
25    pub source: Option<GcRef<LuaString>>,
26    /// Last closure instantiated from this proto, reused by `OP_CLOSURE` when a
27    /// new instantiation would capture the identical upvalues. Mirrors C-Lua's
28    /// `Proto.cache` (5.2/5.3 only — added in 5.2, removed in 5.4), which is why
29    /// loop-built closures with shared upvalues compare `==` on those versions.
30    /// Populated only under 5.2/5.3 in `push_closure`; `None` otherwise. Traced
31    /// (so it cannot dangle); unlike C's GC-cleared weak cache this pins the one
32    /// cached closure to the proto's lifetime, which is bounded and safe.
33    pub cache: RefCell<Option<GcRef<LuaLClosure>>>,
34    /// Lua 5.5 named varargs (`function f(...t)`): the register holding the
35    /// packed vararg table `t`. When set, `...` unpacks live from that table
36    /// (count = its `n` field) rather than the frame's extra-arg slots, so
37    /// mutating `t` is observable through a later `...` (shared storage). `None`
38    /// for ordinary `...` and all pre-5.5 functions. Mirrors upstream's
39    /// `needvatab` proto flag + the vararg-table register.
40    pub vararg_table_reg: Option<u8>,
41    /// Whether the named vararg parameter must be materialized as a real table.
42    /// If false, indexed reads can be served directly from hidden vararg slots.
43    pub vararg_table_needed: bool,
44}
45
46impl LuaProto {
47    pub fn placeholder() -> Self {
48        LuaProto {
49            numparams: 0,
50            is_vararg: false,
51            maxstacksize: 2,
52            upvalues: Vec::new(),
53            k: Vec::new(),
54            code: Vec::new(),
55            p: Vec::new(),
56            lineinfo: Vec::new(),
57            abslineinfo: Vec::new(),
58            locvars: Vec::new(),
59            linedefined: 0,
60            lastlinedefined: 0,
61            source: None,
62            cache: RefCell::new(None),
63            vararg_table_reg: None,
64            vararg_table_needed: false,
65        }
66    }
67
68    /// Bytes owned outside the `GcBox` header/object allocation.
69    ///
70    /// C allocates these arrays through Lua's allocator. The Rust port stores
71    /// them as `Vec`s, so GC byte accounting charges their backing capacity
72    /// explicitly when a populated proto is wrapped in `GcRef`.
73    pub fn buffer_bytes(&self) -> usize {
74        self.upvalues.capacity() * std::mem::size_of::<UpvalDesc>()
75            + self.k.capacity() * std::mem::size_of::<LuaValue>()
76            + self.code.capacity() * std::mem::size_of::<Instruction>()
77            + self.p.capacity() * std::mem::size_of::<GcRef<LuaProto>>()
78            + self.lineinfo.capacity() * std::mem::size_of::<i8>()
79            + self.abslineinfo.capacity() * std::mem::size_of::<AbsLineInfo>()
80            + self.locvars.capacity() * std::mem::size_of::<LocalVar>()
81    }
82}
83
84#[derive(Debug, Clone)]
85pub struct UpvalDesc {
86    pub name: Option<GcRef<LuaString>>,
87    pub instack: bool,
88    pub idx: u8,
89    pub kind: u8,
90}
91
92#[derive(Debug, Clone)]
93pub struct LocalVar {
94    pub varname: GcRef<LuaString>,
95    pub startpc: i32,
96    pub endpc: i32,
97}
98
99#[derive(Debug, Clone, Copy)]
100pub struct AbsLineInfo {
101    pub pc: i32,
102    pub line: i32,
103}
104
105// ──────────────────────────────────────────────────────────────────────────────
106// PORT STATUS
107//   source:        src/lobject.h (Proto struct)
108//   target_crate:  lua-types
109//   confidence:    high
110//   todos:         0
111//   port_notes:    0
112//   unsafe_blocks: 0
113//   notes:         Function prototype: bytecode, constants, line info, debug info,
114//                  upvalue descriptors. Faithful layout of C's Proto struct using
115//                  Vec<T> in place of T*+size pairs.
116// ──────────────────────────────────────────────────────────────────────────────