ft_sys/
memory.rs

1/// Allocate memory into the wasm linear memory
2/// and return the offset to the start of the block.
3/// # Safety
4///
5/// This function is unsafe because it dereferences the pointer. There is no way to
6/// make this function unsafe.
7#[unsafe(no_mangle)]
8#[allow(clippy::uninit_vec)]
9pub fn alloc(len: i32) -> i32 {
10    // create a new mutable buffer with capacity len
11    // we allocate 4 more bytes than asked and store len on the first 4 bytes
12    let mut buf: Vec<u8> = Vec::with_capacity(len as usize + 4);
13
14    unsafe {
15        buf.set_len(len as usize + 4);
16    }
17
18    let b = len.to_ne_bytes();
19    buf[0] = b[0];
20    buf[1] = b[1];
21    buf[2] = b[2];
22    buf[3] = b[3];
23
24    // take a mutable pointer to the buffer
25    let ptr = buf.as_mut_ptr();
26    // // take ownership of the memory block and
27    // // ensure that its destructor is not
28    // // called when the object goes out of scope
29    // // at the end of the function
30    std::mem::forget(buf);
31    ptr as i32
32}
33
34/// de-allocating the memory
35/// # Safety
36///
37/// This function is unsafe because it dereferences the pointer. There is no way to
38/// make this function unsafe.
39#[unsafe(no_mangle)]
40pub unsafe fn dealloc(ptr: i32) {
41    let size = unsafe { ptr_len(ptr) };
42
43    let data = unsafe { Vec::from_raw_parts(ptr as *mut u8, size as usize + 4, size as usize + 4) };
44    drop(data);
45}
46
47/// de-allocating the memory
48/// # Safety
49///
50/// This function is unsafe because it dereferences the pointer. There is no way to
51/// make this function unsafe.
52#[unsafe(no_mangle)]
53pub unsafe fn dealloc_with_len(ptr: i32, len: i32) {
54    let data = unsafe { Vec::from_raw_parts(ptr as *mut u8, len as usize, len as usize) };
55    drop(data);
56}
57
58/// # Safety
59///
60/// This function is unsafe because it dereferences the pointer. There is no way to
61/// make this function unsafe.
62pub unsafe fn ptr_len(ptr: i32) -> i32 {
63    let len_bytes = unsafe { Vec::from_raw_parts(ptr as *mut u8, 4, 4) };
64    let len = i32::from_ne_bytes([len_bytes[0], len_bytes[1], len_bytes[2], len_bytes[3]]);
65    std::mem::forget(len_bytes);
66    len
67}
68
69/// # Safety
70///
71/// This function is unsafe because it dereferences the pointer. There is no way to
72/// make this function unsafe.
73pub(crate) fn string_from_ptr(ptr: i32) -> String {
74    unsafe { String::from_utf8_unchecked(bytes_from_ptr(ptr).into()) }
75}
76
77/// # Safety
78///
79/// This function is unsafe because it dereferences the pointer. There is no way to
80/// make this function unsafe.
81fn bytes_from_ptr(ptr: i32) -> bytes::Bytes {
82    unsafe {
83        let len = ptr_len(ptr);
84        let v = Vec::from_raw_parts(ptr as *mut u8, len as usize + 4, len as usize + 4);
85        let bytes = bytes::Bytes::from(v);
86        bytes.slice(4..)
87    }
88}
89
90pub fn bytes_to_ptr(mut d: Vec<u8>) -> (i32, i32) {
91    let len = d.len() as i32;
92    let data = d.as_mut_ptr() as i32;
93
94    std::mem::forget(d);
95
96    (data, len)
97}
98
99pub fn string_to_bytes_ptr(s: String) -> (i32, i32) {
100    bytes_to_ptr(s.into_bytes())
101}
102
103pub fn json_ptr(d: impl serde::Serialize) -> (i32, i32) {
104    let bytes = serde_json::to_vec(&d)
105        .inspect_err(|e| ft_sys::println!("failed to serialise: {e:?}"))
106        .unwrap();
107    bytes_to_ptr(bytes)
108}
109
110pub fn json_from_ptr<T: serde::de::DeserializeOwned>(ptr: i32) -> T {
111    let bytes = bytes_from_ptr(ptr);
112    match serde_json::from_slice(&bytes) {
113        Ok(v) => v,
114        Err(e) => {
115            ft_sys::println!(
116                "got error when deserializing: {e:?}, json: {}",
117                String::from_utf8_lossy(&bytes)
118            );
119            panic!()
120        }
121    }
122}