summaryrefslogtreecommitdiff
path: root/rust/pin-init/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rust/pin-init/src/lib.rs')
-rw-r--r--rust/pin-init/src/lib.rs200
1 files changed, 47 insertions, 153 deletions
diff --git a/rust/pin-init/src/lib.rs b/rust/pin-init/src/lib.rs
index 8dc9dd5ac6fd..49945fc07f25 100644
--- a/rust/pin-init/src/lib.rs
+++ b/rust/pin-init/src/lib.rs
@@ -146,7 +146,7 @@
//!
//! impl DriverData {
//! fn new() -> impl PinInit<Self, Error> {
-//! try_pin_init!(Self {
+//! pin_init!(Self {
//! status <- CMutex::new(0),
//! buffer: Box::init(pin_init::init_zeroed())?,
//! }? Error)
@@ -290,10 +290,13 @@ use core::{
ptr::{self, NonNull},
};
+// This is used by doc-tests -- the proc-macros expand to `::pin_init::...` and without this the
+// doc-tests wouldn't have an extern crate named `pin_init`.
+#[allow(unused_extern_crates)]
+extern crate self as pin_init;
+
#[doc(hidden)]
pub mod __internal;
-#[doc(hidden)]
-pub mod macros;
#[cfg(any(feature = "std", feature = "alloc"))]
mod alloc;
@@ -528,7 +531,7 @@ macro_rules! stack_pin_init {
/// x: u32,
/// }
///
-/// stack_try_pin_init!(let foo: Foo = try_pin_init!(Foo {
+/// stack_try_pin_init!(let foo: Foo = pin_init!(Foo {
/// a <- CMutex::new(42),
/// b: Box::try_new(Bar {
/// x: 64,
@@ -555,7 +558,7 @@ macro_rules! stack_pin_init {
/// x: u32,
/// }
///
-/// stack_try_pin_init!(let foo: Foo =? try_pin_init!(Foo {
+/// stack_try_pin_init!(let foo: Foo =? pin_init!(Foo {
/// a <- CMutex::new(42),
/// b: Box::try_new(Bar {
/// x: 64,
@@ -584,10 +587,10 @@ macro_rules! stack_try_pin_init {
};
}
-/// Construct an in-place, pinned initializer for `struct`s.
+/// Construct an in-place, fallible pinned initializer for `struct`s.
///
-/// This macro defaults the error to [`Infallible`]. If you need a different error, then use
-/// [`try_pin_init!`].
+/// The error type defaults to [`Infallible`]; if you need a different one, write `? Error` at the
+/// end, after the struct initializer.
///
/// The syntax is almost identical to that of a normal `struct` initializer:
///
@@ -776,81 +779,12 @@ macro_rules! stack_try_pin_init {
/// ```
///
/// [`NonNull<Self>`]: core::ptr::NonNull
-// For a detailed example of how this macro works, see the module documentation of the hidden
-// module `macros` inside of `macros.rs`.
-#[macro_export]
-macro_rules! pin_init {
- ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
- $($fields:tt)*
- }) => {
- $crate::try_pin_init!($(&$this in)? $t $(::<$($generics),*>)? {
- $($fields)*
- }? ::core::convert::Infallible)
- };
-}
-
-/// Construct an in-place, fallible pinned initializer for `struct`s.
-///
-/// If the initialization can complete without error (or [`Infallible`]), then use [`pin_init!`].
-///
-/// You can use the `?` operator or use `return Err(err)` inside the initializer to stop
-/// initialization and return the error.
-///
-/// IMPORTANT: if you have `unsafe` code inside of the initializer you have to ensure that when
-/// initialization fails, the memory can be safely deallocated without any further modifications.
-///
-/// The syntax is identical to [`pin_init!`] with the following exception: you must append `? $type`
-/// after the `struct` initializer to specify the error type you want to use.
-///
-/// # Examples
-///
-/// ```rust
-/// # #![feature(allocator_api)]
-/// # #[path = "../examples/error.rs"] mod error; use error::Error;
-/// use pin_init::{pin_data, try_pin_init, PinInit, InPlaceInit, init_zeroed};
-///
-/// #[pin_data]
-/// struct BigBuf {
-/// big: Box<[u8; 1024 * 1024 * 1024]>,
-/// small: [u8; 1024 * 1024],
-/// ptr: *mut u8,
-/// }
-///
-/// impl BigBuf {
-/// fn new() -> impl PinInit<Self, Error> {
-/// try_pin_init!(Self {
-/// big: Box::init(init_zeroed())?,
-/// small: [0; 1024 * 1024],
-/// ptr: core::ptr::null_mut(),
-/// }? Error)
-/// }
-/// }
-/// # let _ = Box::pin_init(BigBuf::new());
-/// ```
-// For a detailed example of how this macro works, see the module documentation of the hidden
-// module `macros` inside of `macros.rs`.
-#[macro_export]
-macro_rules! try_pin_init {
- ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
- $($fields:tt)*
- }? $err:ty) => {
- $crate::__init_internal!(
- @this($($this)?),
- @typ($t $(::<$($generics),*>)? ),
- @fields($($fields)*),
- @error($err),
- @data(PinData, use_data),
- @has_data(HasPinData, __pin_data),
- @construct_closure(pin_init_from_closure),
- @munch_fields($($fields)*),
- )
- }
-}
+pub use pin_init_internal::pin_init;
-/// Construct an in-place initializer for `struct`s.
+/// Construct an in-place, fallible initializer for `struct`s.
///
-/// This macro defaults the error to [`Infallible`]. If you need a different error, then use
-/// [`try_init!`].
+/// This macro defaults the error to [`Infallible`]; if you need a different one, write `? Error`
+/// at the end, after the struct initializer.
///
/// The syntax is identical to [`pin_init!`] and its safety caveats also apply:
/// - `unsafe` code must guarantee either full initialization or return an error and allow
@@ -883,74 +817,7 @@ macro_rules! try_pin_init {
/// }
/// # let _ = Box::init(BigBuf::new());
/// ```
-// For a detailed example of how this macro works, see the module documentation of the hidden
-// module `macros` inside of `macros.rs`.
-#[macro_export]
-macro_rules! init {
- ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
- $($fields:tt)*
- }) => {
- $crate::try_init!($(&$this in)? $t $(::<$($generics),*>)? {
- $($fields)*
- }? ::core::convert::Infallible)
- }
-}
-
-/// Construct an in-place fallible initializer for `struct`s.
-///
-/// If the initialization can complete without error (or [`Infallible`]), then use
-/// [`init!`].
-///
-/// The syntax is identical to [`try_pin_init!`]. You need to specify a custom error
-/// via `? $type` after the `struct` initializer.
-/// The safety caveats from [`try_pin_init!`] also apply:
-/// - `unsafe` code must guarantee either full initialization or return an error and allow
-/// deallocation of the memory.
-/// - the fields are initialized in the order given in the initializer.
-/// - no references to fields are allowed to be created inside of the initializer.
-///
-/// # Examples
-///
-/// ```rust
-/// # #![feature(allocator_api)]
-/// # use core::alloc::AllocError;
-/// # use pin_init::InPlaceInit;
-/// use pin_init::{try_init, Init, init_zeroed};
-///
-/// struct BigBuf {
-/// big: Box<[u8; 1024 * 1024 * 1024]>,
-/// small: [u8; 1024 * 1024],
-/// }
-///
-/// impl BigBuf {
-/// fn new() -> impl Init<Self, AllocError> {
-/// try_init!(Self {
-/// big: Box::init(init_zeroed())?,
-/// small: [0; 1024 * 1024],
-/// }? AllocError)
-/// }
-/// }
-/// # let _ = Box::init(BigBuf::new());
-/// ```
-// For a detailed example of how this macro works, see the module documentation of the hidden
-// module `macros` inside of `macros.rs`.
-#[macro_export]
-macro_rules! try_init {
- ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? {
- $($fields:tt)*
- }? $err:ty) => {
- $crate::__init_internal!(
- @this($($this)?),
- @typ($t $(::<$($generics),*>)?),
- @fields($($fields)*),
- @error($err),
- @data(InitData, /*no use_data*/),
- @has_data(HasInitData, __init_data),
- @construct_closure(init_from_closure),
- @munch_fields($($fields)*),
- )
- }
-}
+pub use pin_init_internal::init;
/// Asserts that a field on a struct using `#[pin_data]` is marked with `#[pin]` ie. that it is
/// structurally pinned.
@@ -1410,14 +1277,14 @@ where
/// fn init_foo() -> impl PinInit<Foo, Error> {
/// pin_init_scope(|| {
/// let bar = lookup_bar()?;
-/// Ok(try_pin_init!(Foo { a: bar.a.into(), b: bar.b }? Error))
+/// Ok(pin_init!(Foo { a: bar.a.into(), b: bar.b }? Error))
/// })
/// }
/// ```
///
/// This initializer will first execute `lookup_bar()`, match on it, if it returned an error, the
/// initializer itself will fail with that error. If it returned `Ok`, then it will run the
-/// initializer returned by the [`try_pin_init!`] invocation.
+/// initializer returned by the [`pin_init!`] invocation.
pub fn pin_init_scope<T, E, F, I>(make_init: F) -> impl PinInit<T, E>
where
F: FnOnce() -> Result<I, E>,
@@ -1453,14 +1320,14 @@ where
/// fn init_foo() -> impl Init<Foo, Error> {
/// init_scope(|| {
/// let bar = lookup_bar()?;
-/// Ok(try_init!(Foo { a: bar.a.into(), b: bar.b }? Error))
+/// Ok(init!(Foo { a: bar.a.into(), b: bar.b }? Error))
/// })
/// }
/// ```
///
/// This initializer will first execute `lookup_bar()`, match on it, if it returned an error, the
/// initializer itself will fail with that error. If it returned `Ok`, then it will run the
-/// initializer returned by the [`try_init!`] invocation.
+/// initializer returned by the [`init!`] invocation.
pub fn init_scope<T, E, F, I>(make_init: F) -> impl Init<T, E>
where
F: FnOnce() -> Result<I, E>,
@@ -1536,6 +1403,33 @@ pub trait InPlaceWrite<T> {
fn write_pin_init<E>(self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E>;
}
+impl<T> InPlaceWrite<T> for &'static mut MaybeUninit<T> {
+ type Initialized = &'static mut T;
+
+ fn write_init<E>(self, init: impl Init<T, E>) -> Result<Self::Initialized, E> {
+ let slot = self.as_mut_ptr();
+
+ // SAFETY: `slot` is a valid pointer to uninitialized memory.
+ unsafe { init.__init(slot)? };
+
+ // SAFETY: The above call initialized the memory.
+ unsafe { Ok(self.assume_init_mut()) }
+ }
+
+ fn write_pin_init<E>(self, init: impl PinInit<T, E>) -> Result<Pin<Self::Initialized>, E> {
+ let slot = self.as_mut_ptr();
+
+ // SAFETY: `slot` is a valid pointer to uninitialized memory.
+ //
+ // The `'static` borrow guarantees the data will not be
+ // moved/invalidated until it gets dropped (which is never).
+ unsafe { init.__pinned_init(slot)? };
+
+ // SAFETY: The above call initialized the memory.
+ Ok(Pin::static_mut(unsafe { self.assume_init_mut() }))
+ }
+}
+
/// Trait facilitating pinned destruction.
///
/// Use [`pinned_drop`] to implement this trait safely: