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