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:
- it wraps the inner value in
MaybeUninitand thus is entirely oblivious of its initialization state. COpaque::gettakes aPinand thus prevents accidental moves.- it utilizes
UnsafePinnedto relax the aliasing guarantees of mutable references to theCOpaque.
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 TGets 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) -> TReturns the argument unchanged.
impl<T> SizeHint for COpaque<T>
where
T: ?Sized,
fn lower_bound(&self) -> usizefn 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) -> UCalls
U::from(self).That is, this conversion is whatever the implementation of
[From]<T> for Uchooses 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>