plugy_core/guest.rs
1use crate::bitwise::{from_bitwise, into_bitwise};
2
3/// Allocates a buffer of the specified length and returns a pointer to it.
4///
5/// This function allocates a buffer of `len` bytes using a `Vec<u8>` and returns a
6/// mutable pointer to the allocated buffer. The `Vec` is created with a capacity of
7/// `len`, and its ownership is immediately transferred to the caller through the
8/// returned pointer. The allocated buffer must be deallocated using the `dealloc`
9/// function to prevent memory leaks.
10///
11/// # Arguments
12///
13/// * `len` - The length of the buffer to allocate, in bytes.
14///
15/// # Returns
16///
17/// A mutable pointer to the allocated buffer of the specified length.
18///
19/// # Safety
20///
21/// This function is marked as `unsafe` because it returns a raw pointer to memory,
22/// and the caller is responsible for ensuring the proper deallocation of the buffer
23/// to avoid memory leaks.
24///
25/// # Examples
26///
27/// ```no_run
28/// use plugy_core::guest::dealloc;
29/// use plugy_core::guest::alloc;
30/// let len: u32 = 1024;
31/// let buffer_ptr = alloc(len);
32/// // Use the allocated buffer...
33/// // Remember to deallocate the buffer when it's no longer needed.
34/// unsafe { dealloc(buffer_ptr as u64) };
35/// ```
36#[inline]
37#[no_mangle]
38pub extern "C" fn alloc(len: u32) -> *mut u8 {
39 let mut buf = Vec::with_capacity(len as _);
40 let ptr = buf.as_mut_ptr();
41 std::mem::forget(buf);
42 ptr
43}
44
45/// Deallocates a buffer previously allocated by the `alloc` function.
46///
47/// This function takes a value `value` obtained from a previous call to the `alloc`
48/// function. The value is expected to be a combined representation of a pointer and
49/// a length, obtained using the `into_bitwise` function. The function properly
50/// deallocates the buffer and frees the associated memory.
51///
52/// # Arguments
53///
54/// * `value` - The value representing the pointer and length of the buffer to
55/// deallocate, obtained from the `alloc` function.
56///
57/// # Safety
58///
59/// This function is marked as `unsafe` because it performs a deallocation of memory.
60/// The `value` parameter must be a valid representation obtained from the `alloc`
61/// function, and improper usage can lead to memory corruption.
62///
63/// # Examples
64///
65/// ```no_run
66/// use plugy_core::guest::dealloc;
67/// use plugy_core::guest::alloc;
68/// let len: u32 = 1024;
69/// let buffer_ptr = alloc(len);
70/// // Use the allocated buffer...
71/// unsafe { dealloc(buffer_ptr as u64) };
72/// ```
73#[inline]
74#[no_mangle]
75pub unsafe extern "C" fn dealloc(value: u64) {
76 let (ptr, len) = from_bitwise(value);
77 #[allow(clippy::useless_transmute)]
78 let ptr = std::mem::transmute::<usize, *mut u8>(ptr as _);
79 let buffer = Vec::from_raw_parts(ptr, len as _, len as _);
80 std::mem::drop(buffer);
81}
82
83/// Serializes a value using bincode and returns a combined representation.
84///
85/// This function serializes a value implementing the `serde::ser::Serialize` trait
86/// using the bincode serialization format. The serialized data is stored in a `Vec<u8>`
87/// buffer, and a combined representation of the buffer's pointer and length is
88/// obtained using the `into_bitwise` function. The ownership of the buffer is
89/// transferred to the caller, who is responsible for deallocating it using the
90/// `dealloc` function.
91///
92/// # Arguments
93///
94/// * `value` - A reference to the value to be serialized.
95///
96/// # Returns
97///
98/// A combined representation of the serialized buffer's pointer and length.
99///
100/// # Examples
101///
102/// ```
103/// use plugy_core::guest::dealloc;
104/// use plugy_core::guest::write_msg;
105/// #[derive(serde::Serialize)]
106/// struct MyStruct {
107/// // Fields of MyStruct...
108/// }
109///
110/// let my_instance = MyStruct { /* initialize fields */ };
111/// let combined = write_msg(&my_instance);
112/// // Deallocate the buffer when no longer needed.
113/// unsafe { dealloc(combined) };
114/// ```
115pub fn write_msg<T: serde::ser::Serialize>(value: &T) -> u64 {
116 let mut buffer = bincode::serialize(value).expect("could not serialize");
117 let len = buffer.len();
118 let ptr = buffer.as_mut_ptr();
119 std::mem::forget(buffer);
120 into_bitwise(ptr as _, len as _)
121}
122
123/// Deserializes a value using bincode from a combined representation.
124///
125/// This function takes a combined representation obtained from the `write_msg`
126/// function, which includes a pointer and length of a serialized buffer. The
127/// function safely deserializes the buffer back into a value implementing the
128/// `serde::de::DeserializeOwned` trait and returns it. The ownership of the buffer
129/// is transferred to the function, which takes care of proper deallocation.
130///
131/// # Arguments
132///
133/// * `value` - The combined representation of the serialized buffer's pointer and
134/// length, obtained from the `write_msg` function.
135///
136/// # Returns
137///
138/// The deserialized value of type `T`.
139///
140/// # Safety
141///
142/// This function is marked as `unsafe` because it involves working with raw pointers
143/// and memory management. The provided `value` parameter must be a valid combined
144/// representation obtained from the `write_msg` function, and incorrect usage can lead
145/// to memory corruption or other issues.
146///
147/// # Examples
148///
149/// ```
150/// use plugy_core::guest::read_msg;
151/// #[derive(serde::Deserialize)]
152/// struct MyStruct {
153/// // Fields of MyStruct...
154/// }
155///
156/// let combined: u64 = 0;/* ptr on the host side */;
157/// let my_instance: MyStruct = unsafe { read_msg(combined) };
158/// ```
159pub unsafe fn read_msg<T: serde::de::DeserializeOwned>(value: u64) -> T {
160 let (ptr, len) = from_bitwise(value);
161 #[allow(clippy::useless_transmute)]
162 let ptr = std::mem::transmute::<usize, *mut u8>(ptr as _);
163 let buffer = Vec::from_raw_parts(ptr, len as _, len as _);
164 bincode::deserialize(&buffer).expect("invalid bytes provided")
165}