Skip to main content

luaur_vm/functions/
buffer_writefp.rs

1use luaur_common::macros::luau_big_endian::LUAU_BIG_ENDIAN;
2
3use crate::functions::buffer_swapbe::buffer_swapbe;
4use crate::functions::lua_l_checkbuffer::lua_l_checkbuffer;
5use crate::functions::lua_l_checkinteger::lua_l_checkinteger;
6use crate::functions::lua_l_checknumber::lua_l_checknumber;
7use crate::macros::isoutofbounds::isoutofbounds;
8use crate::macros::lua_l_error::luaL_error;
9use crate::type_aliases::lua_state::lua_State;
10
11#[allow(non_snake_case)]
12pub unsafe fn buffer_writefp<T, StorageType>(L: *mut lua_State) -> core::ffi::c_int
13where
14    T: Copy + BufferFloat,
15    StorageType: Copy,
16{
17    let mut len: usize = 0;
18    let buf = lua_l_checkbuffer(L, 1, &mut len);
19
20    let offset = lua_l_checkinteger(L, 2);
21    let value = lua_l_checknumber(L, 3);
22
23    if isoutofbounds(offset, len, core::mem::size_of::<T>()) {
24        luaL_error!(L, "buffer access out of bounds");
25    }
26
27    let val: T = T::from_f64(value);
28
29    if LUAU_BIG_ENDIAN {
30        static_assert_size_match::<T, StorageType>();
31        let mut tmp: StorageType =
32            core::ptr::read_unaligned(&val as *const T as *const StorageType);
33        tmp = buffer_swapbe(tmp);
34        core::ptr::copy_nonoverlapping(
35            &tmp as *const StorageType as *const u8,
36            (buf as *mut u8).add(offset as usize),
37            core::mem::size_of::<StorageType>(),
38        );
39    } else {
40        core::ptr::copy_nonoverlapping(
41            &val as *const T as *const u8,
42            (buf as *mut u8).add(offset as usize),
43            core::mem::size_of::<T>(),
44        );
45    }
46
47    0
48}
49
50// Helper to enforce sizeof(T) == sizeof(StorageType) at compile time
51#[allow(dead_code)]
52fn static_assert_size_match<T, StorageType>() {
53    assert!(core::mem::size_of::<T>() == core::mem::size_of::<StorageType>());
54}
55
56pub trait BufferFloat {
57    fn from_f64(value: f64) -> Self;
58}
59
60impl BufferFloat for f32 {
61    fn from_f64(value: f64) -> Self {
62        value as f32
63    }
64}
65
66impl BufferFloat for f64 {
67    fn from_f64(value: f64) -> Self {
68        value
69    }
70}