luaur_code_gen/functions/userdata_remapper_wrap.rs
1use crate::functions::get_code_gen_context::get_code_gen_context;
2use crate::type_aliases::lua_state::lua_State;
3use luaur_common::enums::luau_bytecode_type::LuauBytecodeType;
4
5/// C trampoline installed into `global_State::ecb.gettypemapping` so the VM's
6/// bytecode loader can map userdata type names through the registered remapper.
7///
8/// Mirrors `userdataRemapperWrap` (CodeGen/src/CodeGenContext.cpp):
9/// ```cpp
10/// static uint8_t userdataRemapperWrap(lua_State* L, const char* str, size_t len) {
11/// if (BaseCodeGenContext* codegenCtx = getCodeGenContext(L)) {
12/// uint8_t index = codegenCtx->userdataRemapper(codegenCtx->userdataRemappingContext, str, len);
13/// if (index < (LBC_TYPE_TAGGED_USERDATA_END - LBC_TYPE_TAGGED_USERDATA_BASE))
14/// return LBC_TYPE_TAGGED_USERDATA_BASE + index;
15/// }
16/// return LBC_TYPE_USERDATA;
17/// }
18/// ```
19///
20/// # Safety
21/// `l` must be a valid `lua_State` pointer (or null, which is handled). This is
22/// invoked by the VM through a function pointer, hence `extern "C"`.
23pub unsafe extern "C" fn userdata_remapper_wrap(
24 l: *mut lua_State,
25 str: *const core::ffi::c_char,
26 len: usize,
27) -> u8 {
28 let codegen_ctx = get_code_gen_context(l);
29 if !codegen_ctx.is_null() {
30 let ctx = &*codegen_ctx;
31
32 // The wrapper is only installed as `gettypemapping` when a remapper is
33 // present, so `userdata_remapper` is `Some` here; this mirrors the C++
34 // direct call and falls through to LBC_TYPE_USERDATA otherwise.
35 if let Some(remapper) = ctx.userdata_remapper {
36 let index = remapper(ctx.userdata_remapping_context, str, len);
37
38 let base = LuauBytecodeType::LBC_TYPE_TAGGED_USERDATA_BASE.0 as u8;
39 let end = LuauBytecodeType::LBC_TYPE_TAGGED_USERDATA_END.0 as u8;
40
41 if (index as u16) < (end as u16 - base as u16) {
42 return base.wrapping_add(index as u8);
43 }
44 }
45 }
46
47 LuauBytecodeType::LBC_TYPE_USERDATA.0 as u8
48}