tfhe_c_api_dynamic_buffer/
lib.rs1#![cfg_attr(all(doc, not(doctest)), feature(doc_auto_cfg))]
13#![cfg_attr(all(doc, not(doctest)), feature(doc_cfg))]
14#![warn(rustdoc::broken_intra_doc_links)]
15
16use std::ffi::c_int;
17
18#[repr(C)]
19pub struct DynamicBufferView {
20 pub pointer: *const u8,
21 pub length: usize,
22}
23
24impl DynamicBufferView {
25 pub unsafe fn as_slice(&self) -> &[u8] {
32 std::slice::from_raw_parts(self.pointer, self.length)
33 }
34}
35
36impl From<&[u8]> for DynamicBufferView {
37 fn from(a: &[u8]) -> Self {
38 Self {
39 pointer: a.as_ptr(),
40 length: a.len(),
41 }
42 }
43}
44
45#[repr(C)]
46pub struct DynamicBuffer {
47 pub pointer: *mut u8,
48 pub length: usize,
49 pub destructor: Option<unsafe extern "C" fn(*mut u8, usize) -> c_int>,
50}
51
52impl DynamicBuffer {
53 pub unsafe fn destroy(&mut self) -> Result<(), &str> {
70 if self.pointer.is_null() {
71 self.length = 0;
73 self.destructor = None;
74 return Ok(());
75 }
76
77 match self.destructor {
78 Some(destructor_callback) => {
79 let res = destructor_callback(self.pointer, self.length);
80 if res == 0 {
81 self.pointer = std::ptr::null_mut();
83 self.length = 0;
84 self.destructor = None;
85 return Ok(());
86 }
87 Err("destructor returned a non 0 error code")
88 }
89 None => Err("destructor is NULL, could not destroy DynamicBuffer"),
91 }
92 }
93}
94
95unsafe extern "C" fn free_u8_ptr_built_from_vec_u8(pointer: *mut u8, length: usize) -> c_int {
96 if pointer.is_null() {
97 return 0;
98 }
99
100 let slice = std::slice::from_raw_parts_mut(pointer, length);
101
102 drop(Box::from_raw(slice));
103
104 0
105}
106
107impl From<Vec<u8>> for DynamicBuffer {
108 fn from(value: Vec<u8>) -> Self {
109 let boxed_slice = value.into_boxed_slice();
110 let length = boxed_slice.len();
111 let pointer = Box::leak(boxed_slice);
112
113 Self {
114 pointer: pointer.as_mut_ptr(),
115 length,
116 destructor: Some(free_u8_ptr_built_from_vec_u8),
117 }
118 }
119}
120
121fn check_ptr_is_non_null_and_aligned<T>(ptr: *const T) -> Result<(), String> {
122 if ptr.is_null() {
123 return Err(format!("pointer is null, got: {ptr:p}"));
124 }
125 let expected_alignment = std::mem::align_of::<T>();
126 if ptr as usize % expected_alignment != 0 {
127 return Err(format!(
128 "pointer is misaligned, expected {expected_alignment} bytes alignment, got pointer: \
129 {ptr:p}. You May have mixed some pointers in your function call.",
130 ));
131 }
132 Ok(())
133}
134
135unsafe fn get_mut_checked<'a, T>(ptr: *mut T) -> Result<&'a mut T, String> {
150 match check_ptr_is_non_null_and_aligned(ptr) {
151 Ok(()) => ptr
152 .as_mut()
153 .ok_or_else(|| "Error while converting to mut reference".into()),
154 Err(e) => Err(e),
155 }
156}
157
158#[no_mangle]
164pub unsafe extern "C" fn destroy_dynamic_buffer(dynamic_buffer: *mut DynamicBuffer) -> c_int {
165 if dynamic_buffer.is_null() {
167 return 0;
168 }
169
170 let dynamic_buffer = match get_mut_checked(dynamic_buffer) {
171 Ok(dynamic_buffer) => dynamic_buffer,
172 Err(cause) => {
173 if cfg!(feature = "c_api_print_error_source") {
174 println!("{cause}");
175 }
176
177 return 1;
178 }
179 };
180
181 match dynamic_buffer.destroy() {
182 Ok(_) => 0,
183 Err(cause) => {
184 if cfg!(feature = "c_api_print_error_source") {
185 println!("{cause}");
186 }
187
188 1
189 }
190 }
191}
192
193#[cfg(test)]
194mod test {
195 use super::*;
196
197 #[test]
198 fn test_dynamic_buffer_vec_u8_custom_destructor() {
199 let vec = vec![99u8; 1000];
200 let len = vec.len();
201 let ptr = vec.leak();
202
203 unsafe extern "C" fn custom_destroy_vec_u8_buffer(
204 pointer: *mut u8,
205 length: usize,
206 ) -> c_int {
207 if pointer.is_null() {
208 return 0;
209 }
210
211 let slice = std::slice::from_raw_parts_mut(pointer, length);
212
213 drop(Box::from_raw(slice));
214
215 0
216 }
217
218 let mut dynamic_buffer = DynamicBuffer {
219 pointer: ptr.as_mut_ptr(),
220 length: len,
221 destructor: Some(custom_destroy_vec_u8_buffer),
222 };
223
224 let res = unsafe { destroy_dynamic_buffer(&mut dynamic_buffer as *mut DynamicBuffer) };
225
226 assert_eq!(res, 0);
227 assert!(dynamic_buffer.pointer.is_null());
228 assert_eq!(dynamic_buffer.length, 0);
229 assert!(dynamic_buffer.destructor.is_none());
230
231 assert!(dynamic_buffer.pointer.is_null());
232 let res = unsafe { destroy_dynamic_buffer(&mut dynamic_buffer as *mut DynamicBuffer) };
233 assert_eq!(res, 0);
235 assert!(dynamic_buffer.pointer.is_null());
236 assert_eq!(dynamic_buffer.length, 0);
237 assert!(dynamic_buffer.destructor.is_none());
238
239 let mut some_u8 = 0u8;
240
241 dynamic_buffer.pointer = &mut some_u8 as *mut u8;
242
243 assert!(dynamic_buffer.destructor.is_none());
244 let res = unsafe { destroy_dynamic_buffer(&mut dynamic_buffer as *mut DynamicBuffer) };
245 assert_eq!(res, 1);
246 }
247
248 #[test]
249 fn test_dynamic_buffer_vec_u8_default_destructor() {
250 let vec = vec![99u8; 1000];
251
252 let mut dynamic_buffer: DynamicBuffer = vec.clone().into();
253
254 let res = unsafe { destroy_dynamic_buffer(&mut dynamic_buffer as *mut DynamicBuffer) };
255
256 assert_eq!(res, 0);
257 assert!(dynamic_buffer.pointer.is_null());
258 assert_eq!(dynamic_buffer.length, 0);
259 assert!(dynamic_buffer.destructor.is_none());
260
261 let mut dynamic_buffer: DynamicBuffer = vec.into();
262
263 let res = unsafe { dynamic_buffer.destroy() };
264
265 assert!(res.is_ok());
266 assert!(dynamic_buffer.pointer.is_null());
267 assert_eq!(dynamic_buffer.length, 0);
268 assert!(dynamic_buffer.destructor.is_none());
269 }
270}