luaur_code_gen/functions/set_userdata_remapper.rs
1use crate::functions::get_code_gen_context::get_code_gen_context;
2use crate::functions::userdata_remapper_wrap::userdata_remapper_wrap;
3use crate::type_aliases::lua_state::lua_State;
4use crate::type_aliases::userdata_remapper_callback::UserdataRemapperCallback;
5use core::ffi::c_void;
6
7/// Sets the userdata remapper callback and context on the code generation context.
8///
9/// Mirrors `setUserdataRemapper` (CodeGen/src/CodeGenContext.cpp):
10/// ```cpp
11/// void setUserdataRemapper(lua_State* L, void* context, UserdataRemapperCallback cb) {
12/// if (BaseCodeGenContext* codegenCtx = getCodeGenContext(L)) {
13/// codegenCtx->userdataRemappingContext = context;
14/// codegenCtx->userdataRemapper = cb;
15/// L->global->ecb.gettypemapping = cb ? userdataRemapperWrap : nullptr;
16/// }
17/// }
18/// ```
19///
20/// # Safety
21///
22/// - `L` must be a valid, non-null pointer to a `lua_State`.
23/// - The global state (`L->global`) must be valid and initialized.
24/// - The code generation context must be valid and properly initialized.
25/// - The callback `cb` must be a valid function pointer.
26#[inline]
27pub fn set_userdata_remapper(
28 L: *mut lua_State,
29 context: *mut c_void,
30 cb: UserdataRemapperCallback,
31) {
32 // get_code_gen_context handles the null checks (L / global / context) internally.
33 let codegen_ctx = get_code_gen_context(L);
34 if codegen_ctx.is_null() {
35 return;
36 }
37
38 // SAFETY: codegen_ctx is non-null and points to a valid BaseCodeGenContext;
39 // the caller guarantees L (and L->global) are valid per the contract above.
40 unsafe {
41 (*codegen_ctx).userdata_remapping_context = context;
42 // C++ stores the function pointer directly (`userdataRemapper = cb`).
43 // The Rust field is `Option<UserdataRemapperCallback>`, so wrap the value
44 // itself rather than taking the address of the local `cb`.
45 (*codegen_ctx).userdata_remapper = Some(cb);
46
47 // C++: L->global->ecb.gettypemapping = cb ? userdataRemapperWrap : nullptr;
48 // The translated `cb` parameter is a non-nullable function pointer, so a
49 // remapper is always present here and the wrapper trampoline is installed.
50 let global = (*L).global;
51 if !global.is_null() {
52 (*global).ecb.gettypemapping = Some(userdata_remapper_wrap);
53 }
54 }
55}