1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/// This trait supports passing data to Rust by value.
///
/// Pass-by-values implies that values are copyable, via assignment in C, so this
/// trait is typically used to represent Copy values, and in particular values that
/// do not contain pointers.
///
/// The Rust and C types may differ, with [`PassByValue::from_ctype`] and [`PassByValue::as_ctype`]
/// converting between them.  These typically provide some simple conversion between a C-style
/// data structure and a more ergonomic Rust type.
pub trait PassByValue: Sized {
    /// The C representation of this type.
    type CType: Sized;

    /// Convert a C value to a Rust value.
    ///
    /// # Safety
    ///
    /// The implementation of this method assumes that `cval` is a valid instance of Self::CType.
    unsafe fn from_ctype(cval: Self::CType) -> Self;

    /// Convert a Rust value to a C value.
    fn as_ctype(self) -> Self::CType;

    /// Copy a value from C as an argument.
    ///
    /// # Safety
    ///
    /// - `self` must be a valid instance of the C type.  This is typically ensured either by
    ///   requiring that C code not modify it, or by defining the valid values in C comments.
    unsafe fn val_from_arg(arg: Self::CType) -> Self {
        // SAFETY:
        //  - arg is a valid CType (see docstring)
        unsafe { Self::from_ctype(arg) }
    }

    /// Return a value to C
    ///
    /// # Safety
    ///
    /// - if the value is allocated, the caller must ensure that the value is eventually freed
    unsafe fn return_val(self) -> Self::CType {
        self.as_ctype()
    }

    /// Return a value to C, via an "output parameter".
    ///
    /// This is common in functions returning a new value along with some success indication.
    ///
    /// # Safety
    ///
    /// - `arg_out` must not be NULL and must be properly aligned and pointing to valid memory
    ///   of the size of CType.
    unsafe fn val_to_arg_out(self, arg_out: *mut Self::CType) {
        debug_assert!(!arg_out.is_null());
        // SAFETY:
        //  - arg_out is not NULL (see docstring)
        //  - arg_out is properly aligned and points to valid memory (see docstring)
        unsafe { *arg_out = self.as_ctype() };
    }
}