use crate::{
Chunk, UpvaluePtr,
lua_value::{UpvalueDesc, UpvalueStore},
lua_vm::{LuaError, LuaResult, LuaState},
};
pub fn push_closure(
lua_state: &mut LuaState,
base: usize,
a: usize,
bx: usize,
current_chunk: &Chunk,
parent_upvalues: &[UpvaluePtr],
) -> LuaResult<()> {
if bx >= current_chunk.child_protos.len() {
return Err(LuaError::RuntimeError);
}
let proto = current_chunk.child_protos[bx];
let upvalue_descs = &proto.as_ref().data.upvalue_descs;
let num_upvalues = upvalue_descs.len();
let upvalue_store = match num_upvalues {
0 => UpvalueStore::Empty,
1 => {
let uv = resolve_upvalue(lua_state, base, &upvalue_descs[0], parent_upvalues)?;
UpvalueStore::One(uv)
}
_ => {
let mut upvalue_vec = Vec::with_capacity(num_upvalues);
for desc in upvalue_descs {
upvalue_vec.push(resolve_upvalue(lua_state, base, desc, parent_upvalues)?);
}
UpvalueStore::Many(upvalue_vec.into_boxed_slice())
}
};
let closure_value = lua_state.create_function(proto, upvalue_store)?;
lua_state.stack_mut()[base + a] = closure_value;
Ok(())
}
#[inline]
fn resolve_upvalue(
lua_state: &mut LuaState,
base: usize,
desc: &UpvalueDesc,
parent_upvalues: &[UpvaluePtr],
) -> LuaResult<UpvaluePtr> {
if desc.is_local {
let stack_index = base + desc.index as usize;
lua_state.find_or_create_upvalue(stack_index)
} else {
let parent_idx = desc.index as usize;
if parent_idx >= parent_upvalues.len() {
return Err(LuaError::RuntimeError);
}
Ok(parent_upvalues[parent_idx])
}
}