pub trait PassByPointer: Sized {
    unsafe fn take_from_ptr_arg(arg: *mut Self) -> Self { ... }
    unsafe fn from_ptr_arg_ref<'a>(arg: *const Self) -> &'a Self { ... }
    unsafe fn from_ptr_arg_ref_mut<'a>(arg: *mut Self) -> &'a mut Self { ... }
    unsafe fn return_ptr(self) -> *mut Self { ... }
    unsafe fn ptr_to_arg_out(self, arg_out: *mut *mut Self) { ... }
}
Expand description

This trait supports values passed to Rust by pointer. These values are represented as in C, and always handled as pointers.

Typically PassByPointer is used to model objects managed entirely by Rust. These are represented in the C API by a pointer to an opaque struct, with “new” and “free” functions handling creation and destruction.

Provided Methods

Take a value from C as an argument.

This function is typically used to handle arguments passed from C, but because it takes ownership of the passed value, while leaving the C code with a pointer, it can lead to use-after-free errors if not used carefully. It is most common in “free” functions, but can also be used in contexts where it is clearl that the called function consumes the value. For example, a database connections’s execute method might reasonably consume a query argument.

db_query_t q = db_query_new();
db_query_set_filter(q, "x = 10");
db_query_add_column(q, "y");
db_result_t res = db_execute(db, q);

Here it’s natural to assume (but should also be documented) that the db_execute function takes ownership of the query.

Safety
  • arg must not be NULL
  • arg must be a value returned from Box::into_raw (via return_ptr or ptr_to_arg_out)
  • arg becomes invalid and must not be used after this call
Examples found in repository?
examples/status.rs (line 166)
162
163
164
165
166
167
168
pub unsafe extern "C" fn hittr_system_free(system: *mut hittr_system_t) {
    // SAFETY:
    //  - system is valid and not NULL (see docstring)
    //  - caller will not use system after this call (see docstring)
    let system = unsafe { hittr_system_t::take_from_ptr_arg(system) };
    drop(system); // (Rust would do this anyway, but let's be explicit)
}

Borrow a value from C as an argument.

This represents an immutable (shared) borrow. Use from_ptr_arg_ref_mut for mutable (exclusive) borrows. The safety requirements of the two methods differ slightly: this method requires that the value not be concurrently modified, while from_ptr_arg_ref_mut requires that the value not be accessed at all.

Safety
  • arg must not be NULL
  • *arg must be a valid instance of Self
  • arg must be valid for the lifetime assigned by the caller
  • arg must not be modified by anything else during that lifetime
Examples found in repository?
examples/status.rs (line 214)
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() }
}

Mutably borrow a value from C as an argument.

Because this is a mutable (exclusive) reference, the C caller must ensure that no other threads access the contained value during the lifetime of this reference. This includes read-only access

Safety
  • arg must not be NULL
  • *arg must be a valid instance of Self
  • arg must be valid for the lifetime assigned by the caller
  • arg must not be accessed by anything else during that lifetime
Examples found in repository?
examples/status.rs (line 183)
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
pub unsafe extern "C" fn hittr_system_run(system: *mut hittr_system_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 accessed during the life of this function (documented as not threadsafe)
    let system = &mut unsafe { hittr_system_t::from_ptr_arg_ref_mut(system) }.0;
    system.run();
}

/// Record a hit on thi Hittr system.
///
/// If the sytem is not running, it will enter the failed state.  If it counts 5
/// or more hits, it will enter the failed.state.
///
/// # Safety
///
/// The system must be non-NULL and point to a valid hittr_system_t.
#[no_mangle]
pub unsafe extern "C" fn hittr_system_count_hit(system: *mut hittr_system_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 accessed during the life of this function (documented as not threadsafe)
    let system = &mut unsafe { hittr_system_t::from_ptr_arg_ref_mut(system) }.0;
    system.count_hit();
}

Return a value to C, transferring ownership.

This method is most often used in constructors, to return the built value.

Safety
  • the caller must ensure that the value is eventually freed
Examples found in repository?
examples/status.rs (line 131)
128
129
130
131
132
pub unsafe extern "C" fn hittr_system_new() -> *mut hittr_system_t {
    let sys = System::new();
    // SAFETY: function docs indicate value must be freed
    unsafe { hittr_system_t(sys).return_ptr() }
}

Return a value to C, transferring ownership, via an “output parameter”.

Safety
  • the caller must ensure that the value is eventually freed
  • arg_out must not be NULL
  • arg_out must point to valid, properly aligned memory for a pointer value
Examples found in repository?
examples/status.rs (line 148)
142
143
144
145
146
147
148
149
150
151
152
153
pub unsafe extern "C" fn hittr_system_new_network(
    system_out: *mut *mut hittr_system_t,
    port: u16,
) -> bool {
    if let Ok(sys) = System::new_network(port) {
        // SAFETY: see docstring
        unsafe { hittr_system_t(sys).ptr_to_arg_out(system_out) }
        true
    } else {
        false
    }
}

Implementors