Struct COpaque

pub struct COpaque<T> { pub(in ::sys::helpers::c_opaque) inner: UnsafePinned<MaybeUninit<T>> }

A wrapper for an opaque C object.

Some libraries like UNIX's pthread have data types that must be treated as entirely opaque. Soundly wrapping these types is very hard since Rust's operational semantics are much stricter when it comes to e.g. the initialization state of data types and pointer aliasing. For instance, a function like pthread_mutexattr_init might not fully initialize the libc::pthread_mutexattr_t passed to it, so doing e.g.

let mut attr = MaybeUninit::uninit();
pthread_mutexattr_init(attr.as_mut_ptr());
let attr = attr.assume_init();

is unsound. Another example: on platforms like macOS a pthread_mutex_t cannot be moved because the implementation will dynamically align some inner fields to a higher alignment than required by the definition. And furthermore, some implementations (e.g. AIX) of pthread_cond_t use intrinsically linked lists, and hence doing

pub struct Condvar(UnsafeCell<libc::pthread_cont_t>);

/* initialization and usage omitted for brevity */

impl Drop for Condvar {
    fn drop(&mut self) {
        unsafe { libc::pthread_cond_destroy(self.0.get()) };
    }
}

results in undefined behaviour (even when utilizing Pin to ensure immovability) because the creation of the &mut Condvar passed to drop invalidates other pointers in the linked list.

COpaque helps with avoiding all these caveats:

The only way to access the inner value is via COpaque::get. It returns a pointer which should be directly passed to the platform functions.

In effect, a pinned instance of this wrapper acts very much like a C variable.

Fields

inner: UnsafePinned<MaybeUninit<T>>

Implementations

impl<T> COpaque<T>

fn uninit() -> COpaque<T>

Creates an uninitialized C-like storage for T.

If you'd write

T var;

in C, the equivalent Rust code is

let var = pin!(COpaque::uninit());
fn zeroed() -> COpaque<T>

Creates a zero-initialized C-like storage for T.

If you'd write

T var = {};

in C, the equivalent Rust code is

let var = pin!(COpaque::zeroed());
fn new(initializer: T) -> COpaque<T>

Creates a pre-initialized C-like storage for T.

If you'd write

T var = T_INITIALIZER;

in C, the equivalent Rust code is

let var = pin!(COpaque::new(T_INITIALIZER));
fn get(self: Pin<&Self>) -> *mut T

Gets a pointer to the value.

Use this as a replacement for C's ampersand operator.

Auto Trait Implementations

impl<T> !Freeze for COpaque<T>

impl<T> !RefUnwindSafe for COpaque<T>

impl<T> !Unpin for COpaque<T>

impl<T> !UnsafeUnpin for COpaque<T>

impl<T> Send for COpaque<T> where UnsafePinned<MaybeUninit<T>>: Send,

impl<T> Sync for COpaque<T> where UnsafePinned<MaybeUninit<T>>: Sync,

impl<T> UnwindSafe for COpaque<T> where UnsafePinned<MaybeUninit<T>>: UnwindSafe,

Blanket Implementations

impl<T> Any for COpaque<T> where T: 'static + ?Sized,

fn type_id(&self) -> TypeId

impl<T> Borrow<T> for COpaque<T> where T: ?Sized,

fn borrow(&self) -> &T

impl<T> BorrowMut<T> for COpaque<T> where T: ?Sized,

fn borrow_mut(&mut self) -> &mut T

impl<T> From<T> for COpaque<T>

fn from(t: T) -> T

Returns the argument unchanged.

impl<T> SizeHint for COpaque<T> where T: ?Sized,

fn lower_bound(&self) -> usize
fn upper_bound(&self) -> Option<usize>

impl<T> SizedTypeProperties for COpaque<T>

impl<T, U> Into<U> for COpaque<T> where U: From<T>,

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of [From]<T> for U chooses to do.

impl<T, U> TryFrom<U> for COpaque<T> where U: Into<T>,

type Error = never;
fn try_from(value: U) -> Result<T, never>

impl<T, U> TryInto<U> for COpaque<T> where U: TryFrom<T>,

type Error = <U as TryFrom<T>>::Error;
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>