Skip to main content

ffi_utils/
test_utils.rs

1// Copyright 2019 MaidSafe.net limited.
2//
3// This SAFE Network Software is licensed to you under the MIT license <LICENSE-MIT
4// http://opensource.org/licenses/MIT> or the Modified BSD license <LICENSE-BSD
5// https://opensource.org/licenses/BSD-3-Clause>, at your option. This file may not be copied,
6// modified, or distributed except according to those terms. Please review the Licences for the
7// specific language governing permissions and limitations relating to use of the SAFE Network
8// Software.
9
10//! Test utilities.
11
12// These functions specifically used for FFI are missing safety documentation.
13// It is probably not necessary for us to provide this for every single function
14// as that would be repetitive and verbose.
15#![allow(clippy::missing_safety_doc)]
16
17use crate::repr_c::ReprC;
18use crate::{ErrorCode, FfiResult};
19use std::fmt::{Debug, Display};
20use std::os::raw::c_void;
21use std::sync::mpsc::{self, Sender};
22use std::{fmt, ptr, slice};
23use unwrap::unwrap;
24
25/// User data wrapper.
26pub struct UserData {
27    /// Common field, used by standard callbacks.
28    pub common: *mut c_void,
29    /// Custom field, used by additional callbacks.
30    pub custom: *mut c_void,
31}
32
33impl Default for UserData {
34    fn default() -> Self {
35        let common: *const c_void = ptr::null();
36        let custom: *const c_void = ptr::null();
37
38        UserData {
39            common: common as *mut c_void,
40            custom: custom as *mut c_void,
41        }
42    }
43}
44
45/// Convert a `UserData` to a void pointer which can be passed to ffi functions.
46pub fn user_data_as_void(ud: &UserData) -> *mut c_void {
47    let ptr: *const _ = ud;
48    ptr as *mut c_void
49}
50
51/// Convert a `mpsc::Sender<T>` to a void ptr which is then stored in the `UserData` struct and
52/// passed to ffi functions.
53pub fn sender_as_user_data<T>(tx: &Sender<T>, ud: &mut UserData) -> *mut c_void {
54    let ptr: *const _ = tx;
55    ud.common = ptr as *mut c_void;
56    user_data_as_void(ud)
57}
58
59/// Send through a `mpsc::Sender` pointed to by the user data's common pointer.
60pub unsafe fn send_via_user_data<T>(user_data: *mut c_void, value: T)
61where
62    T: Send,
63{
64    let ud = user_data as *mut UserData;
65    let tx = (*ud).common as *mut Sender<T>;
66    unwrap!((*tx).send(value));
67}
68
69/// Send through a `mpsc::Sender` pointed to by the user data's custom pointer.
70pub unsafe fn send_via_user_data_custom<T>(user_data: *mut c_void, value: T)
71where
72    T: Send,
73{
74    let ud = user_data as *mut UserData;
75    let tx = (*ud).custom as *mut Sender<T>;
76    unwrap!((*tx).send(value));
77}
78
79/// Call a FFI function and block until its callback gets called.
80/// Use this if the callback accepts no arguments in addition to `user_data`
81/// and `error_code`.
82pub fn call_0<F>(f: F) -> Result<(), i32>
83where
84    F: FnOnce(*mut c_void, extern "C" fn(user_data: *mut c_void, result: *const FfiResult)),
85{
86    let mut ud = Default::default();
87    call_0_with_custom(&mut ud, f)
88}
89
90/// Call a FFI function and block until its callback gets called.
91/// Use this if the callback accepts no arguments in addition to `user_data`
92/// and `error_code`.
93/// This version of the function takes a `UserData` with custom inner data.
94pub fn call_0_with_custom<F>(ud: &mut UserData, f: F) -> Result<(), i32>
95where
96    F: FnOnce(*mut c_void, extern "C" fn(user_data: *mut c_void, result: *const FfiResult)),
97{
98    let (tx, rx) = mpsc::channel::<i32>();
99    f(sender_as_user_data(&tx, ud), callback_0);
100
101    let error = unwrap!(rx.recv());
102    if error == 0 {
103        Ok(())
104    } else {
105        Err(error)
106    }
107}
108
109/// Call an FFI function and block until its callback gets called, then return
110/// the argument which were passed to that callback.
111/// Use this if the callback accepts one argument in addition to `user_data`
112/// and `error_code`.
113pub unsafe fn call_1<F, E: Debug, T>(f: F) -> Result<T, i32>
114where
115    F: FnOnce(*mut c_void, extern "C" fn(user_data: *mut c_void, result: *const FfiResult, T::C)),
116    T: ReprC<Error = E>,
117{
118    let mut ud = Default::default();
119    call_1_with_custom(&mut ud, f)
120}
121
122/// Call an FFI function and block until its callback gets called, then return
123/// the argument which were passed to that callback.
124/// Use this if the callback accepts one argument in addition to `user_data`
125/// and `error_code`.
126/// This version of the function takes a `UserData` with custom inner data.
127pub fn call_1_with_custom<F, E: Debug, T>(ud: &mut UserData, f: F) -> Result<T, i32>
128where
129    F: FnOnce(*mut c_void, extern "C" fn(user_data: *mut c_void, result: *const FfiResult, T::C)),
130    T: ReprC<Error = E>,
131{
132    let (tx, rx) = mpsc::channel::<SendWrapper<Result<T, i32>>>();
133    f(sender_as_user_data(&tx, ud), callback_1::<E, T>);
134    unwrap!(rx.recv()).0
135}
136
137/// Call a FFI function and block until its callback gets called, then return
138/// the argument which were passed to that callback.
139/// Use this if the callback accepts two arguments in addition to `user_data`
140/// and `error_code`.
141pub unsafe fn call_2<F, E0, E1, T0, T1>(f: F) -> Result<(T0, T1), i32>
142where
143    F: FnOnce(
144        *mut c_void,
145        extern "C" fn(user_data: *mut c_void, result: *const FfiResult, T0::C, T1::C),
146    ),
147    E0: Debug,
148    E1: Debug,
149    T0: ReprC<Error = E0>,
150    T1: ReprC<Error = E1>,
151{
152    let mut ud = Default::default();
153    call_2_with_custom(&mut ud, f)
154}
155
156/// Call a FFI function and block until its callback gets called, then return
157/// the argument which were passed to that callback.
158/// Use this if the callback accepts two arguments in addition to `user_data`
159/// and `error_code`.
160/// This version of the function takes a `UserData` with custom inner data.
161pub unsafe fn call_2_with_custom<F, E0, E1, T0, T1>(
162    ud: &mut UserData,
163    f: F,
164) -> Result<(T0, T1), i32>
165where
166    F: FnOnce(
167        *mut c_void,
168        extern "C" fn(user_data: *mut c_void, result: *const FfiResult, T0::C, T1::C),
169    ),
170    E0: Debug,
171    E1: Debug,
172    T0: ReprC<Error = E0>,
173    T1: ReprC<Error = E1>,
174{
175    let (tx, rx) = mpsc::channel::<SendWrapper<Result<(T0, T1), i32>>>();
176    f(sender_as_user_data(&tx, ud), callback_2::<E0, E1, T0, T1>);
177    unwrap!(rx.recv()).0
178}
179
180/// Call a FFI function and block until its callback gets called, then copy
181/// the array argument which was passed to `Vec<T>` and return the result.
182/// Use this if the callback accepts `*const T` and `usize` (length) arguments in addition
183/// to `user_data` and `error_code`.
184pub unsafe fn call_vec<F, E, T, U>(f: F) -> Result<Vec<T>, i32>
185where
186    F: FnOnce(
187        *mut c_void,
188        extern "C" fn(user_data: *mut c_void, result: *const FfiResult, T::C, usize),
189    ),
190    E: Debug,
191    T: ReprC<C = *const U, Error = E>,
192{
193    let mut ud = Default::default();
194    call_vec_with_custom(&mut ud, f)
195}
196
197/// Call a FFI function and block until its callback gets called, then copy
198/// the array argument which was passed to `Vec<T>` and return the result.
199/// Use this if the callback accepts `*const T` and `usize` (length) arguments in addition
200/// to `user_data` and `error_code`.
201/// This version of the function takes a `UserData` with custom inner data.
202pub unsafe fn call_vec_with_custom<F, E, T, U>(ud: &mut UserData, f: F) -> Result<Vec<T>, i32>
203where
204    F: FnOnce(
205        *mut c_void,
206        extern "C" fn(user_data: *mut c_void, result: *const FfiResult, T::C, usize),
207    ),
208    E: Debug,
209    T: ReprC<C = *const U, Error = E>,
210{
211    let (tx, rx) = mpsc::channel::<SendWrapper<Result<Vec<T>, i32>>>();
212    f(sender_as_user_data(&tx, ud), callback_vec::<E, T, U>);
213    unwrap!(rx.recv()).0
214}
215
216/// Call a FFI function and block until its callback gets called, then copy
217/// the byte array argument which was passed to `Vec<u8>` and return the result.
218pub unsafe fn call_vec_u8<F>(f: F) -> Result<Vec<u8>, i32>
219where
220    F: FnOnce(
221        *mut c_void,
222        extern "C" fn(user_data: *mut c_void, result: *const FfiResult, *const u8, usize),
223    ),
224{
225    let mut ud = Default::default();
226    call_vec_u8_with_custom(&mut ud, f)
227}
228
229/// Call a FFI function and block until its callback gets called, then copy
230/// the byte array argument which was passed to `Vec<u8>` and return the result.
231/// This version of the function takes a `UserData` with custom inner data.
232/// This version of the function takes a `UserData` with custom inner data.
233pub unsafe fn call_vec_u8_with_custom<F>(ud: &mut UserData, f: F) -> Result<Vec<u8>, i32>
234where
235    F: FnOnce(
236        *mut c_void,
237        extern "C" fn(user_data: *mut c_void, result: *const FfiResult, *const u8, usize),
238    ),
239{
240    let (tx, rx) = mpsc::channel::<Result<Vec<u8>, i32>>();
241    f(sender_as_user_data(&tx, ud), callback_vec_u8);
242    unwrap!(rx.recv())
243}
244
245extern "C" fn callback_0(user_data: *mut c_void, res: *const FfiResult) {
246    unsafe { send_via_user_data(user_data, (*res).error_code) }
247}
248
249extern "C" fn callback_1<E, T>(user_data: *mut c_void, res: *const FfiResult, arg: T::C)
250where
251    E: Debug,
252    T: ReprC<Error = E>,
253{
254    unsafe {
255        let result: Result<T, i32> = if (*res).error_code == 0 {
256            Ok(unwrap!(T::clone_from_repr_c(arg)))
257        } else {
258            Err((*res).error_code)
259        };
260        send_via_user_data(user_data, SendWrapper(result));
261    }
262}
263
264extern "C" fn callback_2<E0, E1, T0, T1>(
265    user_data: *mut c_void,
266    res: *const FfiResult,
267    arg0: T0::C,
268    arg1: T1::C,
269) where
270    E0: Debug,
271    E1: Debug,
272    T0: ReprC<Error = E0>,
273    T1: ReprC<Error = E1>,
274{
275    unsafe {
276        let result: Result<(T0, T1), i32> = if (*res).error_code == 0 {
277            Ok((
278                unwrap!(T0::clone_from_repr_c(arg0)),
279                unwrap!(T1::clone_from_repr_c(arg1)),
280            ))
281        } else {
282            Err((*res).error_code)
283        };
284        send_via_user_data(user_data, SendWrapper(result))
285    }
286}
287
288extern "C" fn callback_vec<E, T, U>(
289    user_data: *mut c_void,
290    res: *const FfiResult,
291    array: *const U,
292    size: usize,
293) where
294    E: Debug,
295    T: ReprC<C = *const U, Error = E>,
296{
297    unsafe {
298        let result: Result<Vec<T>, i32> = if (*res).error_code == 0 {
299            let slice_ffi = slice::from_raw_parts(array, size);
300            let mut vec = Vec::with_capacity(slice_ffi.len());
301            for elt in slice_ffi {
302                vec.push(unwrap!(T::clone_from_repr_c(elt)));
303            }
304            Ok(vec)
305        } else {
306            Err((*res).error_code)
307        };
308
309        send_via_user_data(user_data, SendWrapper(result))
310    }
311}
312
313extern "C" fn callback_vec_u8(
314    user_data: *mut c_void,
315    res: *const FfiResult,
316    ptr: *const u8,
317    len: usize,
318) {
319    unsafe {
320        let result = if (*res).error_code == 0 {
321            Ok(slice::from_raw_parts(ptr, len).to_vec())
322        } else {
323            Err((*res).error_code)
324        };
325
326        send_via_user_data(user_data, result)
327    }
328}
329
330/// Unsafe wrapper for passing non-Send types through mpsc channels.
331/// Use with caution!
332pub struct SendWrapper<T>(pub T);
333unsafe impl<T> Send for SendWrapper<T> {}
334
335/// Dummy error type for testing that implements ErrorCode.
336#[derive(Debug)]
337pub enum TestError {
338    /// Error from a string.
339    FromStr(String),
340    /// Simple test error.
341    Test,
342}
343
344impl<'a> From<&'a str> for TestError {
345    fn from(s: &'a str) -> Self {
346        TestError::FromStr(s.into())
347    }
348}
349
350impl ErrorCode for TestError {
351    fn error_code(&self) -> i32 {
352        use TestError::*;
353
354        match *self {
355            Test => -1,
356            FromStr(_) => -2,
357        }
358    }
359}
360
361impl Display for TestError {
362    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
363        use TestError::*;
364
365        match self {
366            Test => write!(f, "Test Error"),
367            FromStr(s) => write!(f, "{}", s),
368        }
369    }
370}