fp_bindgen_support/guest/
io.rs

1use crate::common::mem::*;
2use rmp_serde::{Deserializer, Serializer};
3use serde::{Deserialize, Serialize};
4use std::alloc::Layout;
5
6#[doc(hidden)]
7pub fn export_value_to_host<T: Serialize>(value: &T) -> FatPtr {
8    let mut buffer = Vec::new();
9    value
10        .serialize(
11            &mut Serializer::new(&mut buffer)
12                .with_struct_map()
13                .with_human_readable(),
14        )
15        .expect("Serialization error");
16
17    let len = buffer.len();
18
19    if buffer.capacity() > len {
20        buffer.shrink_to_fit();
21
22        // If there is still no exact fit, we will perform a copy to guarantee
23        // the capacity does not exceed the length. This is to make sure we
24        // don't have to lie to `Vec::from_raw_parts()` in `__fp_free()` below:
25        if buffer.capacity() > len {
26            buffer = {
27                let mut exact_buffer = Vec::with_capacity(len);
28                exact_buffer.append(&mut buffer);
29                exact_buffer
30            }
31        }
32    }
33
34    // Make sure the length marker does not run into our extension bits:
35    if len & 0xff000000 != 0 {
36        panic!("Buffer too large ({} bytes)", len);
37    }
38
39    let ptr = buffer.as_ptr();
40    std::mem::forget(buffer);
41    to_fat_ptr(ptr, len as u32)
42}
43
44/// # Safety
45///
46/// This function is only safe if passed a valid pointer given to us by the
47/// host. After this call, the pointer is no longer valid.
48#[doc(hidden)]
49pub unsafe fn import_value_from_host<'de, T: Deserialize<'de>>(fat_ptr: FatPtr) -> T {
50    let (ptr, len) = from_fat_ptr(fat_ptr);
51    if len & 0xff000000 != 0 {
52        panic!("Unknown extension bits");
53    }
54
55    let slice = std::slice::from_raw_parts(ptr, len as usize);
56    let mut deserializer = Deserializer::new(slice).with_human_readable();
57    let value = T::deserialize(&mut deserializer).unwrap();
58
59    __fp_free(fat_ptr);
60
61    value
62}
63
64const MALLOC_ALIGNMENT: usize = 16;
65
66#[doc(hidden)]
67#[no_mangle]
68pub fn __fp_malloc(len: u32) -> FatPtr {
69    let ptr = unsafe {
70        std::alloc::alloc(
71            Layout::from_size_align(len as usize, MALLOC_ALIGNMENT)
72                .expect("Allocation failed unexpectedly, check requested allocation size"),
73        )
74    };
75    to_fat_ptr(ptr, len)
76}
77
78/// # Safety
79///
80/// This function is only safe if passed a valid pointer from `__fp_malloc()`.
81/// Any pointer returned by `__fp_malloc()` may only be passed exactly once,
82/// after which it becomes invalid. Because this function can be called from
83/// both the guest (us) and the host, we need to keep ownership rules in
84/// account:
85/// - When we allocate and pass to the host, the host frees the object.
86/// - When the host allocates and passes to us, we free the object.
87#[doc(hidden)]
88#[no_mangle]
89pub unsafe fn __fp_free(ptr: FatPtr) {
90    let (ptr, len) = from_fat_ptr(ptr);
91
92    assert_eq!(
93        len & 0xff000000,
94        0,
95        "__fp_free() failed: unknown extension bits"
96    );
97
98    std::alloc::dealloc(
99        ptr as *mut u8,
100        Layout::from_size_align(len as usize, MALLOC_ALIGNMENT)
101            .expect("Deallocation failed unexpectedly, check the pointer is valid"),
102    );
103}