neotron_ffi/buffer.rs
1//! Types representing mutable borrowed byte slices.
2
3// ============================================================================
4// Imports
5// ============================================================================
6
7// None
8
9// ============================================================================
10// Constants
11// ============================================================================
12
13// None
14
15// ============================================================================
16// Types
17// ============================================================================
18
19/// A Rust u8 mutable slice, but compatible with FFI. Assume the lifetime is
20/// only valid until the callee returns to the caller.
21#[repr(C)]
22#[derive(Clone)]
23pub struct FfiBuffer<'a> {
24 /// A pointer to where the data can be put
25 pub data: *mut u8,
26 /// The maximum number of bytes we can store in this buffer
27 pub data_len: usize,
28 /// A phantom object to hold the lifetime
29 _phantom: core::marker::PhantomData<&'a [u8]>,
30}
31
32impl<'a> FfiBuffer<'a> {
33 /// Create a new buffer we can send over the FFI.
34 ///
35 /// This buffer is a mutable borrow of some storage space allocated
36 /// elsewhere. If you are given this type in an API, assume it is only
37 /// valid for as long as the function call you were given in it.
38 pub fn new(s: &'a mut [u8]) -> FfiBuffer<'a> {
39 FfiBuffer {
40 data: s.as_mut_ptr(),
41 data_len: s.len(),
42 _phantom: core::marker::PhantomData,
43 }
44 }
45
46 /// Make an empty slice.
47 pub fn empty() -> FfiBuffer<'static> {
48 FfiBuffer {
49 data: core::ptr::null_mut(),
50 data_len: 0,
51 _phantom: core::marker::PhantomData,
52 }
53 }
54
55 /// Turn this buffer into a Rust byte slice.
56 pub fn as_slice(&self) -> &[u8] {
57 if self.data.is_null() {
58 &[]
59 } else {
60 unsafe { core::slice::from_raw_parts(self.data, self.data_len) }
61 }
62 }
63
64 /// Turn this buffer into a Rust mutable byte slice.
65 ///
66 /// You will get `None` if the buffer is empty (i.e. has zero length).
67 pub fn as_mut_slice(&mut self) -> core::option::Option<&mut [u8]> {
68 if self.data.is_null() {
69 None
70 } else {
71 Some(unsafe { core::slice::from_raw_parts_mut(self.data, self.data_len) })
72 }
73 }
74}
75
76impl core::fmt::Debug for FfiBuffer<'_> {
77 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
78 let slice = self.as_slice();
79 write!(f, "[ ")?;
80 if let Some((last, rest)) = slice.split_last() {
81 for i in rest.iter() {
82 write!(f, "0x{:02x}, ", i)?;
83 }
84 write!(f, "0x{:02x} ", last)?;
85 }
86 write!(f, "]")
87 }
88}
89
90impl<'a> From<&'a mut [u8]> for FfiBuffer<'a> {
91 /// Convert from a Rust byte slice into an FFI compatible byte slice
92 fn from(input: &'a mut [u8]) -> FfiBuffer<'a> {
93 FfiBuffer::new(input)
94 }
95}
96
97impl<'a> core::cmp::PartialEq for FfiBuffer<'a> {
98 /// Check if two ApiBuffers are equal.
99 ///
100 /// We just make some actual slices and compare then.
101 fn eq(&self, rhs: &Self) -> bool {
102 if self.data_len != rhs.data_len {
103 return false;
104 }
105 let this_slice = self.as_slice();
106 let that_slice = rhs.as_slice();
107 this_slice == that_slice
108 }
109}
110
111impl<'a> core::cmp::Eq for FfiBuffer<'a> {}
112
113impl<'a> core::cmp::Ord for FfiBuffer<'a> {
114 /// Compare two ApiBuffers.
115 ///
116 /// We just make some actual slices and compare then.
117 fn cmp(&self, rhs: &Self) -> core::cmp::Ordering {
118 let this_slice = self.as_slice();
119 let that_slice = rhs.as_slice();
120 this_slice.cmp(that_slice)
121 }
122}
123
124impl<'a> core::cmp::PartialOrd for FfiBuffer<'a> {
125 /// Compare two ApiBuffers.
126 ///
127 /// We are `Ord` so we can defer to that.
128 fn partial_cmp(&self, rhs: &Self) -> core::option::Option<core::cmp::Ordering> {
129 Some(self.cmp(rhs))
130 }
131}
132
133// ============================================================================
134// Tests
135// ============================================================================
136
137#[cfg(test)]
138mod test {
139 use super::*;
140
141 #[test]
142 fn make_buffers() {
143 let data1 = &mut [1, 2, 3, 4];
144 let data2 = &mut [1, 2, 3, 4];
145 let mut data3 = vec![1, 2, 3, 5];
146 let mut buffer1 = FfiBuffer::new(data1);
147 let buffer2 = FfiBuffer::new(data2);
148 let buffer3 = FfiBuffer::new(&mut data3);
149 assert_eq!(buffer1, buffer2);
150 assert_ne!(buffer1, buffer3);
151 // This should be a compile failure because we drop the data source and
152 // use the ApiBuffer again.
153 // drop(data3);
154 assert!(buffer1 < buffer3);
155
156 let output1 = buffer1.as_mut_slice().unwrap();
157 assert_eq!(output1, &[1, 2, 3, 4]);
158 }
159}
160
161// ============================================================================
162// End of File
163// ============================================================================