Skip to main content

luaur_vm/functions/
lua_r_createobject.rs

1use crate::enums::lua_type::lua_Type;
2use crate::functions::lua_gettop::lua_gettop;
3use crate::functions::lua_l_checktype::lua_l_checktype;
4use crate::macros::getstr::getstr;
5use crate::macros::lua_c_barrierfast::luaC_barrierfast;
6use crate::macros::lua_c_init::luaC_init;
7use crate::macros::lua_m_newarray::luaM_newarray;
8use crate::macros::setnilvalue::setnilvalue;
9use crate::macros::setobj::setobj;
10use crate::macros::setobjectvalue::setobjectvalue;
11use crate::macros::setsvalue::setsvalue;
12use crate::type_aliases::lua_state::lua_State;
13use crate::type_aliases::t_value::TValue;
14
15#[allow(non_snake_case)]
16pub unsafe fn lua_r_createobject(L: *mut lua_State) -> core::ffi::c_int {
17    lua_l_checktype(L, 1, lua_Type::LUA_TCLASS as core::ffi::c_int);
18    let classobject = core::ptr::addr_of_mut!((*(*(*L).base).value.gc).lclass)
19        as *mut crate::records::luau_class::LuauClass;
20    let classinst = crate::functions::lua_m_newgco::luaM_newgco_(
21        L,
22        core::mem::size_of::<crate::records::luau_object::LuauObject>(),
23        (*L).activememcat,
24    ) as *mut crate::records::luau_object::LuauObject;
25    luaC_init!(L, classinst, lua_Type::LUA_TOBJECT as core::ffi::c_int);
26    (*classinst).lclass = classobject;
27    (*classinst).numberofmembers = (*classobject).numberofinstancemembers;
28    (*classinst).members =
29        luaM_newarray!(L, (*classinst).numberofmembers, TValue, (*L).activememcat);
30    let numargs: core::ffi::c_int = lua_gettop(L);
31
32    // We need to initialize all of the instance members to `nil` to start.
33    for idx in 0..(*classobject).numberofinstancemembers as core::ffi::c_int {
34        setnilvalue!((*classinst).members.add(idx as usize));
35    }
36
37    // Push the class object onto the stack. We do this prior to setting the
38    // fields as we may reallocate the stack as part of indexing into the
39    // second argument (if present).
40    setobjectvalue!(L, (*L).top, classinst);
41    (*L).top = (*L).top.wrapping_add(1);
42
43    // Stack location to hold the table lookup result
44    setnilvalue!((*L).top);
45    (*L).top = (*L).top.wrapping_add(1);
46
47    match numargs {
48        1 => {
49            // If given no second argument, assume all class members are `nil`.
50        }
51        2 => {
52            // If given a second argument, use it to initialize all class members.
53            for idx in 0..(*classobject).numberofinstancemembers as core::ffi::c_int {
54                let mut key: TValue = TValue::default();
55                setsvalue!(
56                    L,
57                    &mut key,
58                    *(*classobject).offsettomember.add(idx as usize)
59                );
60                crate::functions::lua_v_gettable::lua_v_gettable(
61                    L,
62                    (*L).base.add(1),
63                    &mut key,
64                    (*L).top.wrapping_sub(1),
65                );
66                setobj!(
67                    L,
68                    (*classinst).members.add(idx as usize),
69                    (*L).top.wrapping_sub(1)
70                );
71            }
72        }
73        _ => {
74            crate::functions::lua_l_error_l::lua_l_error_l(
75                L,
76                c"wrong number of arguments for constructing a '%s'".as_ptr(),
77                core::format_args!(
78                    "wrong number of arguments for constructing a '{}'",
79                    unsafe {
80                        core::ffi::CStr::from_ptr(getstr((*classobject).name)).to_string_lossy()
81                    }
82                ),
83            );
84        }
85    }
86
87    (*L).top = (*L).top.wrapping_sub(1);
88
89    // Preserve the GC invariant, moving barrier back once after writing multiple objects (similar to SETLIST)
90    luaC_barrierfast!(L, classinst);
91
92    1
93}