1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 use crate::ffi::{rust_call, ForeignBytes, RustCallStatus};
6
7 /// Support for passing an allocated-by-Rust buffer of bytes over the FFI.
8 ///
9 /// We can pass a `Vec<u8>` to foreign language code by decomposing it into
10 /// its raw parts (buffer pointer, length, and capacity) and passing those
11 /// around as a struct. Naturally, this can be tremendously unsafe! So here
12 /// are the details:
13 ///
14 /// * `RustBuffer` structs must only ever be constructed from a `Vec<u8>`,
15 /// either explicitly via `RustBuffer::from_vec` or indirectly by calling
16 /// one of the `RustBuffer::new*` constructors.
17 ///
18 /// * `RustBuffer` structs do not implement `Drop`, since they are intended
19 /// to be passed to foreign-language code outside of the control of Rust's
20 /// ownership system. To avoid memory leaks they *must* passed back into
21 /// Rust and either explicitly destroyed using `RustBuffer::destroy`, or
22 /// converted back to a `Vec<u8>` using `RustBuffer::destroy_into_vec`
23 /// (which will then be dropped via Rust's usual ownership-tracking system).
24 ///
25 /// Foreign-language code should not construct `RustBuffer` structs other than
26 /// by receiving them from a call into the Rust code, and should not modify them
27 /// apart from the following safe operations:
28 ///
29 /// * Writing bytes into the buffer pointed to by `data`, without writing
30 /// beyond the indicated `capacity`.
31 ///
32 /// * Adjusting the `len` property to indicate the amount of data written,
33 /// while ensuring that 0 <= `len` <= `capacity`.
34 ///
35 /// * As a special case, constructing a `RustBuffer` with zero capacity, zero
36 /// length, and a null `data` pointer to indicate an empty buffer.
37 ///
38 /// In particular, it is not safe for foreign-language code to construct a `RustBuffer`
39 /// that points to its own allocated memory; use the `ForeignBytes` struct to
40 /// pass a view of foreign-owned memory in to Rust code.
41 ///
42 /// Implementation note: all the fields of this struct are private, so you can't
43 /// manually construct instances that don't come from a `Vec<u8>`. If you've got
44 /// a `RustBuffer` then it either came from a public constructor (all of which
45 /// are safe) or it came from foreign-language code (which should have in turn
46 /// received it by calling some Rust function, and should be respecting the
47 /// invariants listed above).
48 ///
49 /// This struct is based on `ByteBuffer` from the `ffi-support` crate, but modified
50 /// to retain unallocated capacity rather than truncating to the occupied length.
51 #[repr(C)]
52 #[derive(Debug)]
53 pub struct RustBuffer {
54 /// The allocated capacity of the underlying `Vec<u8>`.
55 /// In Rust this is a `usize`, but we use an `u64` to keep the foreign binding code simple.
56 capacity: u64,
57 /// The occupied length of the underlying `Vec<u8>`.
58 /// In Rust this is a `usize`, but we use an `u64` to keep the foreign binding code simple.
59 len: u64,
60 /// The pointer to the allocated buffer of the `Vec<u8>`.
61 data: *mut u8,
62 }
63
64 // Mark `RustBuffer` as safe to send between threads, despite the `u8` pointer. The only mutable
65 // use of that pointer is in `destroy_into_vec()` which requires a &mut on the `RustBuffer`. This
66 // is required to send `RustBuffer` inside a `RustFuture`
67 unsafe impl Send for RustBuffer {}
68
69 impl RustBuffer {
70 /// Creates an empty `RustBuffer`.
71 ///
72 /// The buffer will not allocate.
73 /// The resulting vector will not be automatically dropped; you must
74 /// arrange to call `destroy` or `destroy_into_vec` when finished with it.
new() -> Self75 pub fn new() -> Self {
76 Self::from_vec(Vec::new())
77 }
78
79 /// Creates a `RustBuffer` from its constituent fields.
80 ///
81 /// This is intended mainly as an internal convenience function and should not
82 /// be used outside of this module.
83 ///
84 /// # Safety
85 ///
86 /// You must ensure that the raw parts uphold the documented invariants of this class.
from_raw_parts(data: *mut u8, len: u64, capacity: u64) -> Self87 pub unsafe fn from_raw_parts(data: *mut u8, len: u64, capacity: u64) -> Self {
88 Self {
89 capacity,
90 len,
91 data,
92 }
93 }
94
95 /// Get the current length of the buffer, as a `usize`.
96 ///
97 /// This is mostly a helper function to convert the `i32` length field
98 /// into a `usize`, which is what Rust code usually expects.
99 ///
100 /// # Panics
101 ///
102 /// Panics if called on an invalid struct obtained from foreign-language code,
103 /// in which the `len` field is negative.
len(&self) -> usize104 pub fn len(&self) -> usize {
105 self.len
106 .try_into()
107 .expect("buffer length negative or overflowed")
108 }
109
110 /// Get a pointer to the data
data_pointer(&self) -> *const u8111 pub fn data_pointer(&self) -> *const u8 {
112 self.data
113 }
114
115 /// Returns true if the length of the buffer is 0.
is_empty(&self) -> bool116 pub fn is_empty(&self) -> bool {
117 self.len == 0
118 }
119
120 /// Creates a `RustBuffer` zero-filed to the requested size.
121 ///
122 /// The resulting vector will not be automatically dropped; you must
123 /// arrange to call `destroy` or `destroy_into_vec` when finished with it.
124 ///
125 /// # Panics
126 ///
127 /// Panics if the requested size is too large to fit in an `i32`, and
128 /// hence would risk incompatibility with some foreign-language code.
new_with_size(size: u64) -> Self129 pub fn new_with_size(size: u64) -> Self {
130 Self::from_vec(vec![0u8; size as usize])
131 }
132
133 /// Consumes a `Vec<u8>` and returns its raw parts as a `RustBuffer`.
134 ///
135 /// The resulting vector will not be automatically dropped; you must
136 /// arrange to call `destroy` or `destroy_into_vec` when finished with it.
137 ///
138 /// # Panics
139 ///
140 /// Panics if the vector's length or capacity are too large to fit in an `i32`,
141 /// and hence would risk incompatibility with some foreign-language code.
from_vec(v: Vec<u8>) -> Self142 pub fn from_vec(v: Vec<u8>) -> Self {
143 let capacity = u64::try_from(v.capacity()).expect("buffer capacity cannot fit into a u64.");
144 let len = u64::try_from(v.len()).expect("buffer length cannot fit into a u64.");
145 let mut v = std::mem::ManuallyDrop::new(v);
146 unsafe { Self::from_raw_parts(v.as_mut_ptr(), len, capacity) }
147 }
148
149 /// Converts this `RustBuffer` back into an owned `Vec<u8>`.
150 ///
151 /// This restores ownership of the underlying buffer to Rust, meaning it will
152 /// be dropped when the `Vec<u8>` is dropped. The `RustBuffer` *must* have been
153 /// previously obtained from a valid `Vec<u8>` owned by this Rust code.
154 ///
155 /// # Panics
156 ///
157 /// Panics if called on an invalid struct obtained from foreign-language code,
158 /// which does not respect the invairiants on `len` and `capacity`.
destroy_into_vec(self) -> Vec<u8>159 pub fn destroy_into_vec(self) -> Vec<u8> {
160 // Rust will never give us a null `data` pointer for a `Vec`, but
161 // foreign-language code can use it to cheaply pass an empty buffer.
162 if self.data.is_null() {
163 assert!(self.capacity == 0, "null RustBuffer had non-zero capacity");
164 assert!(self.len == 0, "null RustBuffer had non-zero length");
165 vec![]
166 } else {
167 let capacity: usize = self
168 .capacity
169 .try_into()
170 .expect("buffer capacity negative or overflowed");
171 let len: usize = self
172 .len
173 .try_into()
174 .expect("buffer length negative or overflowed");
175 assert!(len <= capacity, "RustBuffer length exceeds capacity");
176 unsafe { Vec::from_raw_parts(self.data, len, capacity) }
177 }
178 }
179
180 /// Reclaim memory stored in this `RustBuffer`.
181 ///
182 /// # Panics
183 ///
184 /// Panics if called on an invalid struct obtained from foreign-language code,
185 /// which does not respect the invairiants on `len` and `capacity`.
destroy(self)186 pub fn destroy(self) {
187 drop(self.destroy_into_vec());
188 }
189 }
190
191 impl Default for RustBuffer {
default() -> Self192 fn default() -> Self {
193 Self::new()
194 }
195 }
196
197 // Functions for the RustBuffer functionality.
198 //
199 // The scaffolding code re-exports these functions, prefixed with the component name and UDL hash
200 // This creates a separate set of functions for each UniFFIed component, which is needed in the
201 // case where we create multiple dylib artifacts since each dylib will have its own allocator.
202
203 /// This helper allocates a new byte buffer owned by the Rust code, and returns it
204 /// to the foreign-language code as a `RustBuffer` struct. Callers must eventually
205 /// free the resulting buffer, either by explicitly calling [`uniffi_rustbuffer_free`] defined
206 /// below, or by passing ownership of the buffer back into Rust code.
uniffi_rustbuffer_alloc(size: u64, call_status: &mut RustCallStatus) -> RustBuffer207 pub fn uniffi_rustbuffer_alloc(size: u64, call_status: &mut RustCallStatus) -> RustBuffer {
208 rust_call(call_status, || Ok(RustBuffer::new_with_size(size)))
209 }
210
211 /// This helper copies bytes owned by the foreign-language code into a new byte buffer owned
212 /// by the Rust code, and returns it as a `RustBuffer` struct. Callers must eventually
213 /// free the resulting buffer, either by explicitly calling the destructor defined below,
214 /// or by passing ownership of the buffer back into Rust code.
215 ///
216 /// # Safety
217 /// This function will dereference a provided pointer in order to copy bytes from it, so
218 /// make sure the `ForeignBytes` struct contains a valid pointer and length.
uniffi_rustbuffer_from_bytes( bytes: ForeignBytes, call_status: &mut RustCallStatus, ) -> RustBuffer219 pub fn uniffi_rustbuffer_from_bytes(
220 bytes: ForeignBytes,
221 call_status: &mut RustCallStatus,
222 ) -> RustBuffer {
223 rust_call(call_status, || {
224 let bytes = bytes.as_slice();
225 Ok(RustBuffer::from_vec(bytes.to_vec()))
226 })
227 }
228
229 /// Free a byte buffer that had previously been passed to the foreign language code.
230 ///
231 /// # Safety
232 /// The argument *must* be a uniquely-owned `RustBuffer` previously obtained from a call
233 /// into the Rust code that returned a buffer, or you'll risk freeing unowned memory or
234 /// corrupting the allocator state.
uniffi_rustbuffer_free(buf: RustBuffer, call_status: &mut RustCallStatus)235 pub fn uniffi_rustbuffer_free(buf: RustBuffer, call_status: &mut RustCallStatus) {
236 rust_call(call_status, || {
237 RustBuffer::destroy(buf);
238 Ok(())
239 })
240 }
241
242 /// Reserve additional capacity in a byte buffer that had previously been passed to the
243 /// foreign language code.
244 ///
245 /// The first argument *must* be a uniquely-owned `RustBuffer` previously
246 /// obtained from a call into the Rust code that returned a buffer. Its underlying data pointer
247 /// will be reallocated if necessary and returned in a new `RustBuffer` struct.
248 ///
249 /// The second argument must be the minimum number of *additional* bytes to reserve
250 /// capacity for in the buffer; it is likely to reserve additional capacity in practice
251 /// due to amortized growth strategy of Rust vectors.
252 ///
253 /// # Safety
254 /// The first argument *must* be a uniquely-owned `RustBuffer` previously obtained from a call
255 /// into the Rust code that returned a buffer, or you'll risk freeing unowned memory or
256 /// corrupting the allocator state.
uniffi_rustbuffer_reserve( buf: RustBuffer, additional: u64, call_status: &mut RustCallStatus, ) -> RustBuffer257 pub fn uniffi_rustbuffer_reserve(
258 buf: RustBuffer,
259 additional: u64,
260 call_status: &mut RustCallStatus,
261 ) -> RustBuffer {
262 rust_call(call_status, || {
263 let additional: usize = additional
264 .try_into()
265 .expect("additional buffer length negative or overflowed");
266 let mut v = buf.destroy_into_vec();
267 v.reserve(additional);
268 Ok(RustBuffer::from_vec(v))
269 })
270 }
271
272 #[cfg(test)]
273 mod test {
274 use super::*;
275 #[test]
test_rustbuffer_from_vec()276 fn test_rustbuffer_from_vec() {
277 let rbuf = RustBuffer::from_vec(vec![1u8, 2, 3]);
278 assert_eq!(rbuf.len(), 3);
279 assert_eq!(rbuf.destroy_into_vec(), vec![1u8, 2, 3]);
280 }
281
282 #[test]
test_rustbuffer_empty()283 fn test_rustbuffer_empty() {
284 let rbuf = RustBuffer::new();
285 assert_eq!(rbuf.len(), 0);
286 // Rust will never give us a null pointer, even for an empty buffer.
287 assert!(!rbuf.data.is_null());
288 assert_eq!(rbuf.destroy_into_vec(), Vec::<u8>::new());
289 }
290
291 #[test]
test_rustbuffer_new_with_size()292 fn test_rustbuffer_new_with_size() {
293 let rbuf = RustBuffer::new_with_size(5);
294 assert_eq!(rbuf.destroy_into_vec().as_slice(), &[0u8, 0, 0, 0, 0]);
295
296 let rbuf = RustBuffer::new_with_size(0);
297 assert!(!rbuf.data.is_null());
298 assert_eq!(rbuf.destroy_into_vec().as_slice(), &[0u8; 0]);
299 }
300
301 #[test]
test_rustbuffer_null_means_empty()302 fn test_rustbuffer_null_means_empty() {
303 // This is how foreign-language code might cheaply indicate an empty buffer.
304 let rbuf = unsafe { RustBuffer::from_raw_parts(std::ptr::null_mut(), 0, 0) };
305 assert_eq!(rbuf.destroy_into_vec().as_slice(), &[0u8; 0]);
306 }
307
308 #[test]
309 #[should_panic]
test_rustbuffer_null_must_have_no_capacity()310 fn test_rustbuffer_null_must_have_no_capacity() {
311 // We guard against foreign-language code providing this kind of invalid struct.
312 let rbuf = unsafe { RustBuffer::from_raw_parts(std::ptr::null_mut(), 0, 1) };
313 rbuf.destroy_into_vec();
314 }
315 #[test]
316 #[should_panic]
test_rustbuffer_null_must_have_zero_length()317 fn test_rustbuffer_null_must_have_zero_length() {
318 // We guard against foreign-language code providing this kind of invalid struct.
319 let rbuf = unsafe { RustBuffer::from_raw_parts(std::ptr::null_mut(), 12, 0) };
320 rbuf.destroy_into_vec();
321 }
322
323 #[test]
324 #[should_panic]
test_rustbuffer_provided_len_must_not_exceed_capacity()325 fn test_rustbuffer_provided_len_must_not_exceed_capacity() {
326 // We guard against foreign-language code providing this kind of invalid struct.
327 let mut v = vec![0u8, 1, 2];
328 let rbuf = unsafe { RustBuffer::from_raw_parts(v.as_mut_ptr(), 3, 2) };
329 rbuf.destroy_into_vec();
330 }
331 }
332