Skip to main content

rustbridge_ffi/
buffer.rs

1//! FFI buffer for passing data across the boundary
2
3use std::ptr;
4
5/// Buffer for passing data across FFI boundary
6///
7/// This structure follows the "Rust allocates, host frees" pattern:
8/// - Rust creates the buffer and populates it with data
9/// - Host copies the data to its managed heap
10/// - Host calls `plugin_free_buffer` to release the memory
11///
12/// # Memory Safety
13///
14/// The buffer owns its memory. When `plugin_free_buffer` is called, the
15/// memory is deallocated. The host must not use the buffer after freeing it.
16#[repr(C)]
17pub struct FfiBuffer {
18    /// Pointer to the data
19    pub data: *mut u8,
20    /// Length of valid data in bytes
21    pub len: usize,
22    /// Total capacity of the allocation
23    pub capacity: usize,
24    /// Error code (0 = success)
25    pub error_code: u32,
26}
27
28impl FfiBuffer {
29    /// Create an empty buffer
30    pub fn empty() -> Self {
31        Self {
32            data: ptr::null_mut(),
33            len: 0,
34            capacity: 0,
35            error_code: 0,
36        }
37    }
38
39    /// Create a buffer from a Vec
40    ///
41    /// This transfers ownership of the Vec's memory to the buffer.
42    pub fn from_vec(mut vec: Vec<u8>) -> Self {
43        let data = vec.as_mut_ptr();
44        let len = vec.len();
45        let capacity = vec.capacity();
46
47        // Prevent Vec from deallocating the memory
48        std::mem::forget(vec);
49
50        Self {
51            data,
52            len,
53            capacity,
54            error_code: 0,
55        }
56    }
57
58    /// Create an error buffer
59    ///
60    /// The error message is stored in the buffer data.
61    pub fn error(code: u32, message: &str) -> Self {
62        let mut buffer = Self::from_vec(message.as_bytes().to_vec());
63        buffer.error_code = code;
64        buffer
65    }
66
67    /// Create a success buffer with JSON data
68    pub fn success_json<T: serde::Serialize>(value: &T) -> Self {
69        match serde_json::to_vec(value) {
70            Ok(data) => Self::from_vec(data),
71            Err(e) => Self::error(5, &format!("Serialization error: {}", e)),
72        }
73    }
74
75    /// Check if this buffer represents an error
76    pub fn is_error(&self) -> bool {
77        self.error_code != 0
78    }
79
80    /// Check if this buffer is empty
81    pub fn is_empty(&self) -> bool {
82        self.data.is_null() || self.len == 0
83    }
84
85    /// Get the data as a slice (unsafe - caller must ensure buffer is valid)
86    ///
87    /// # Safety
88    ///
89    /// The buffer must contain valid data and not have been freed.
90    pub unsafe fn as_slice(&self) -> &[u8] {
91        unsafe {
92            if self.data.is_null() {
93                &[]
94            } else {
95                std::slice::from_raw_parts(self.data, self.len)
96            }
97        }
98    }
99
100    /// Free the buffer's memory
101    ///
102    /// # Safety
103    ///
104    /// This must only be called once per buffer. After calling, the buffer
105    /// is invalid and must not be used.
106    pub unsafe fn free(&mut self) {
107        unsafe {
108            if !self.data.is_null() && self.capacity > 0 {
109                // Reconstruct the Vec and let it drop
110                let _ = Vec::from_raw_parts(self.data, self.len, self.capacity);
111            }
112            self.data = ptr::null_mut();
113            self.len = 0;
114            self.capacity = 0;
115        }
116    }
117}
118
119impl Default for FfiBuffer {
120    fn default() -> Self {
121        Self::empty()
122    }
123}
124
125// FfiBuffer is not Clone because it owns memory
126// FfiBuffer is Send because it owns its data
127unsafe impl Send for FfiBuffer {}
128
129#[cfg(test)]
130#[path = "buffer/buffer_tests.rs"]
131mod buffer_tests;