| use crate::mem::MaybeUninit; |
| use crate::pin::{Pin, UnsafePinned}; |
| |
| /// 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. |
| /// ```ignore (for-illustration-purposes-only) |
| /// 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 |
| /// ```ignore (for-illustration-purposes-only) |
| /// 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 `MaybeUninit` and thus is entirely oblivious |
| /// of its initialization state. |
| /// * [`COpaque::get`] takes a `Pin` and thus prevents accidental moves. |
| /// * it utilizes `UnsafePinned` to relax the aliasing guarantees of mutable |
| /// references to the `COpaque`. |
| /// |
| /// 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. |
| pub struct COpaque<T> { |
| inner: UnsafePinned<MaybeUninit<T>>, |
| } |
| |
| impl<T> COpaque<T> { |
| /// Creates an uninitialized C-like storage for `T`. |
| /// |
| /// If you'd write |
| /// ```c |
| /// T var; |
| /// ``` |
| /// in C, the equivalent Rust code is |
| /// ```ignore (for-illustration-purposes-only) |
| /// let var = pin!(COpaque::uninit()); |
| /// ``` |
| pub fn uninit() -> COpaque<T> { |
| COpaque { inner: UnsafePinned::new(MaybeUninit::uninit()) } |
| } |
| |
| /// Creates a zero-initialized C-like storage for `T`. |
| /// |
| /// If you'd write |
| /// ```c |
| /// T var = {}; |
| /// ``` |
| /// in C, the equivalent Rust code is |
| /// ```ignore (for-illustration-purposes-only) |
| /// let var = pin!(COpaque::zeroed()); |
| /// ``` |
| pub fn zeroed() -> COpaque<T> { |
| COpaque { inner: UnsafePinned::new(MaybeUninit::zeroed()) } |
| } |
| |
| /// Creates a pre-initialized C-like storage for `T`. |
| /// |
| /// If you'd write |
| /// ```c |
| /// T var = T_INITIALIZER; |
| /// ``` |
| /// in C, the equivalent Rust code is |
| /// ```ignore (for-illustration-purposes-only) |
| /// let var = pin!(COpaque::new(T_INITIALIZER)); |
| /// ``` |
| pub fn new(initializer: T) -> COpaque<T> { |
| COpaque { inner: UnsafePinned::new(MaybeUninit::new(initializer)) } |
| } |
| |
| /// Gets a pointer to the value. |
| /// |
| /// Use this as a replacement for C's ampersand operator. |
| pub fn get(self: Pin<&Self>) -> *mut T { |
| self.inner.get().cast_init() |
| } |
| } |