pub trait PassByValue: Sized {
    type CType: Sized;

    unsafe fn from_ctype(cval: Self::CType) -> Self;
    fn into_ctype(self) -> Self::CType;

    unsafe fn val_from_arg(arg: Self::CType) -> Self { ... }
    unsafe fn return_val(self) -> Self::CType { ... }
    unsafe fn val_to_arg_out(self, arg_out: *mut Self::CType) { ... }
}
Expand description

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::into_ctype converting between them. These typically provide some simple conversion between a C-style data structure and a more ergonomic Rust type.

Required Associated Types

The C representation of this type.

Required Methods

Convert a C value to a Rust value.

Safety

The implementation of this method assumes that cval is a valid instance of Self::CType.

Convert a Rust value to a C value.

Provided Methods

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.
Examples found in repository?
examples/uuid.rs (line 58)
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
pub unsafe extern "C" fn uuid_version(uuid: uuid_t) -> usize {
    // SAFETY:
    //  - tcuuid is a valid uuid_t (all byte patterns are valid)
    let uuid: Uuid = unsafe { Uuid::val_from_arg(uuid) };
    uuid.0.get_version_num()
}

/// Write the string representation of a uuid_t into the given buffer, which must be
/// at least UUID_STRING_BYTES long.  No NUL terminator is added.
///
/// # Safety
///
/// * buf must point to at least UUID_STRING_BYTES of valid memory.
#[no_mangle]
pub unsafe extern "C" fn uuid_to_buf(tcuuid: uuid_t, buf: *mut c_char) {
    debug_assert!(!buf.is_null());
    // SAFETY:
    //  - buf is valid for len bytes (by C convention)
    //  - (no alignment requirements for a byte slice)
    //  - content of buf will not be mutated during the lifetime of this slice (lifetime
    //    does not outlive this function call)
    //  - the length of the buffer is less than isize::MAX (see docstring)
    let buf: &mut [u8] =
        unsafe { std::slice::from_raw_parts_mut(buf as *mut u8, UUID_STRING_BYTES) };
    // SAFETY:
    //  - tcuuid is a valid uuid_t (all byte patterns are valid)
    let uuid: Uuid = unsafe { Uuid::val_from_arg(tcuuid) };
    uuid.0.as_hyphenated().encode_lower(buf);
}

Return a value to C

Safety
  • if the value is allocated, the caller must ensure that the value is eventually freed
Examples found in repository?
examples/uuid.rs (line 42)
39
40
41
42
43
44
45
46
47
48
49
50
51
pub unsafe extern "C" fn uuid_new_v4() -> uuid_t {
    // SAFETY:
    // - value is not allocated
    unsafe { Uuid(uuid::Uuid::new_v4()).return_val() }
}

/// Create a new UUID with the nil value.
#[no_mangle]
pub unsafe extern "C" fn uuid_nil() -> uuid_t {
    // SAFETY:
    // - value is not allocated
    unsafe { Uuid(uuid::Uuid::nil()).return_val() }
}
More examples
Hide additional examples
examples/status.rs (line 217)
209
210
211
212
213
214
215
216
217
218
pub unsafe extern "C" fn hittr_system_status(system: *const hittr_system_t) -> hittr_status_t {
    // SAFETY:
    // - system is not NULL and valid (see docstring)
    // - system is valid for the life of this function (documented as not threadsafe)
    // - system will not be modified during the life of this function (documented as not threadsafe)
    let system = &unsafe { hittr_system_t::from_ptr_arg_ref(system) }.0;
    // SAFETY:
    // - hittr_status_t is not allocated, so no issues
    unsafe { system.status.return_val() }
}

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.
Examples found in repository?
examples/uuid.rs (line 105)
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
pub unsafe extern "C" fn uuid_from_str(s: *const c_char, uuid_out: *mut uuid_t) -> bool {
    debug_assert!(!s.is_null());
    debug_assert!(!uuid_out.is_null());
    // SAFETY:
    //  - s is valid (see docstring)
    let s = unsafe { CStr::from_ptr(s) };
    if let Ok(s) = s.to_str() {
        if let Ok(u) = uuid::Uuid::parse_str(s) {
            // SAFETY:
            //  - uuid_out is not NULL (see docstring)
            //  - alignment is not required
            unsafe { Uuid::val_to_arg_out(Uuid(u), uuid_out) };
            return true;
        }
    }
    false
}

Implementors