@@ -165,11 +165,78 @@ pub struct GcTable {
165165 pub data : LuaTable ,
166166}
167167
168- /// Lua function with embedded GC header
168+ /// C Function type - Rust function callable from Lua
169+ pub type CFunction = fn ( & mut crate :: lua_vm:: LuaVM ) -> crate :: lua_vm:: LuaResult < crate :: lua_value:: MultiValue > ;
170+
171+ /// Function body - either Lua bytecode or C function
172+ pub enum FunctionBody {
173+ /// Lua function with bytecode chunk
174+ Lua ( Rc < Chunk > ) ,
175+ /// C function (native Rust function) - no upvalues
176+ C ( CFunction ) ,
177+ /// C closure with single inline upvalue (fast path for common case)
178+ /// Used by coroutine.wrap, ipairs iterator, etc.
179+ CClosureInline1 ( CFunction , LuaValue ) ,
180+ }
181+
182+ /// Unified function with embedded GC header
183+ /// Supports both Lua closures and C closures (with upvalues)
169184pub struct GcFunction {
170185 pub header : GcHeader ,
171- pub chunk : Rc < Chunk > ,
172- pub upvalues : Vec < UpvalueId > , // Upvalue IDs, not Rc
186+ pub body : FunctionBody ,
187+ pub upvalues : Vec < UpvalueId > , // Upvalue IDs - used for Lua closures and C closures with >1 upvalue
188+ }
189+
190+ impl GcFunction {
191+ /// Check if this is a C function (any C variant)
192+ #[ inline( always) ]
193+ pub fn is_c_function ( & self ) -> bool {
194+ matches ! ( self . body, FunctionBody :: C ( _) | FunctionBody :: CClosureInline1 ( _, _) )
195+ }
196+
197+ /// Check if this is a Lua function
198+ #[ inline( always) ]
199+ pub fn is_lua_function ( & self ) -> bool {
200+ matches ! ( self . body, FunctionBody :: Lua ( _) )
201+ }
202+
203+ /// Get the chunk if this is a Lua function
204+ #[ inline( always) ]
205+ pub fn chunk ( & self ) -> Option < & Rc < Chunk > > {
206+ match & self . body {
207+ FunctionBody :: Lua ( chunk) => Some ( chunk) ,
208+ _ => None ,
209+ }
210+ }
211+
212+ /// Get the chunk reference for Lua functions (panics if C function)
213+ /// Use this in contexts where we know it's a Lua function
214+ #[ inline( always) ]
215+ pub fn lua_chunk ( & self ) -> & Rc < Chunk > {
216+ match & self . body {
217+ FunctionBody :: Lua ( chunk) => chunk,
218+ _ => panic ! ( "Called lua_chunk() on a C function" ) ,
219+ }
220+ }
221+
222+ /// Get the C function pointer if this is any C function variant
223+ #[ inline( always) ]
224+ pub fn c_function ( & self ) -> Option < CFunction > {
225+ match & self . body {
226+ FunctionBody :: C ( f) => Some ( * f) ,
227+ FunctionBody :: CClosureInline1 ( f, _) => Some ( * f) ,
228+ FunctionBody :: Lua ( _) => None ,
229+ }
230+ }
231+
232+ /// Get inline upvalue 1 for CClosureInline1
233+ #[ inline( always) ]
234+ pub fn inline_upvalue1 ( & self ) -> Option < LuaValue > {
235+ match & self . body {
236+ FunctionBody :: CClosureInline1 ( _, uv) => Some ( * uv) ,
237+ _ => None ,
238+ }
239+ }
173240}
174241
175242/// Upvalue state - uses absolute stack index like Lua C implementation
0 commit comments