| // SPDX-License-Identifier: Apache-2.0 OR MIT |
| |
| //! API to safely and fallibly initialize pinned `struct`s using in-place constructors. |
| //! |
| //! It also allows in-place initialization of big `struct`s that would otherwise produce a stack |
| //! overflow. |
| //! |
| //! Most `struct`s from the [`sync`] module need to be pinned, because they contain self-referential |
| //! `struct`s from C. [Pinning][pinning] is Rust's way of ensuring data does not move. |
| //! |
| //! # Overview |
| //! |
| //! To initialize a `struct` with an in-place constructor you will need two things: |
| //! - an in-place constructor, |
| //! - a memory location that can hold your `struct` (this can be the [stack], an [`Arc<T>`], |
| //! [`UniqueArc<T>`], [`Box<T>`] or any other smart pointer that implements [`InPlaceInit`]). |
| //! |
| //! To get an in-place constructor there are generally three options: |
| //! - directly creating an in-place constructor using the [`pin_init!`] macro, |
| //! - a custom function/macro returning an in-place constructor provided by someone else, |
| //! - using the unsafe function [`pin_init_from_closure()`] to manually create an initializer. |
| //! |
| //! Aside from pinned initialization, this API also supports in-place construction without pinning, |
| //! the macros/types/functions are generally named like the pinned variants without the `pin` |
| //! prefix. |
| //! |
| //! # Examples |
| //! |
| //! ## Using the [`pin_init!`] macro |
| //! |
| //! If you want to use [`PinInit`], then you will have to annotate your `struct` with |
| //! `#[`[`pin_data`]`]`. It is a macro that uses `#[pin]` as a marker for |
| //! [structurally pinned fields]. After doing this, you can then create an in-place constructor via |
| //! [`pin_init!`]. The syntax is almost the same as normal `struct` initializers. The difference is |
| //! that you need to write `<-` instead of `:` for fields that you want to initialize in-place. |
| //! |
| //! ```rust |
| //! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] |
| //! use kernel::{prelude::*, sync::Mutex, new_mutex}; |
| //! # use core::pin::Pin; |
| //! #[pin_data] |
| //! struct Foo { |
| //! #[pin] |
| //! a: Mutex<usize>, |
| //! b: u32, |
| //! } |
| //! |
| //! let foo = pin_init!(Foo { |
| //! a <- new_mutex!(42, "Foo::a"), |
| //! b: 24, |
| //! }); |
| //! ``` |
| //! |
| //! `foo` now is of the type [`impl PinInit<Foo>`]. We can now use any smart pointer that we like |
| //! (or just the stack) to actually initialize a `Foo`: |
| //! |
| //! ```rust |
| //! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] |
| //! # use kernel::{prelude::*, sync::Mutex, new_mutex}; |
| //! # use core::pin::Pin; |
| //! # #[pin_data] |
| //! # struct Foo { |
| //! # #[pin] |
| //! # a: Mutex<usize>, |
| //! # b: u32, |
| //! # } |
| //! # let foo = pin_init!(Foo { |
| //! # a <- new_mutex!(42, "Foo::a"), |
| //! # b: 24, |
| //! # }); |
| //! let foo: Result<Pin<Box<Foo>>> = Box::pin_init(foo); |
| //! ``` |
| //! |
| //! For more information see the [`pin_init!`] macro. |
| //! |
| //! ## Using a custom function/macro that returns an initializer |
| //! |
| //! Many types from the kernel supply a function/macro that returns an initializer, because the |
| //! above method only works for types where you can access the fields. |
| //! |
| //! ```rust |
| //! # use kernel::{new_mutex, sync::{Arc, Mutex}}; |
| //! let mtx: Result<Arc<Mutex<usize>>> = Arc::pin_init(new_mutex!(42, "example::mtx")); |
| //! ``` |
| //! |
| //! To declare an init macro/function you just return an [`impl PinInit<T, E>`]: |
| //! |
| //! ```rust |
| //! # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] |
| //! # use kernel::{sync::Mutex, prelude::*, new_mutex, init::PinInit, try_pin_init}; |
| //! #[pin_data] |
| //! struct DriverData { |
| //! #[pin] |
| //! status: Mutex<i32>, |
| //! buffer: Box<[u8; 1_000_000]>, |
| //! } |
| //! |
| //! impl DriverData { |
| //! fn new() -> impl PinInit<Self, Error> { |
| //! try_pin_init!(Self { |
| //! status <- new_mutex!(0, "DriverData::status"), |
| //! buffer: Box::init(kernel::init::zeroed())?, |
| //! }) |
| //! } |
| //! } |
| //! ``` |
| //! |
| //! ## Manual creation of an initializer |
| //! |
| //! Often when working with primitives the previous approaches are not sufficient. That is where |
| //! [`pin_init_from_closure()`] comes in. This `unsafe` function allows you to create a |
| //! [`impl PinInit<T, E>`] directly from a closure. Of course you have to ensure that the closure |
| //! actually does the initialization in the correct way. Here are the things to look out for |
| //! (we are calling the parameter to the closure `slot`): |
| //! - when the closure returns `Ok(())`, then it has completed the initialization successfully, so |
| //! `slot` now contains a valid bit pattern for the type `T`, |
| //! - when the closure returns `Err(e)`, then the caller may deallocate the memory at `slot`, so |
| //! you need to take care to clean up anything if your initialization fails mid-way, |
| //! - you may assume that `slot` will stay pinned even after the closure returns until `drop` of |
| //! `slot` gets called. |
| //! |
| //! ```rust |
| //! use kernel::{prelude::*, init}; |
| //! use core::{ptr::addr_of_mut, marker::PhantomPinned, pin::Pin}; |
| //! # mod bindings { |
| //! # pub struct foo; |
| //! # pub unsafe fn init_foo(_ptr: *mut foo) {} |
| //! # pub unsafe fn destroy_foo(_ptr: *mut foo) {} |
| //! # pub unsafe fn enable_foo(_ptr: *mut foo, _flags: u32) -> i32 { 0 } |
| //! # } |
| //! /// # Invariants |
| //! /// |
| //! /// `foo` is always initialized |
| //! #[pin_data(PinnedDrop)] |
| //! pub struct RawFoo { |
| //! #[pin] |
| //! foo: Opaque<bindings::foo>, |
| //! #[pin] |
| //! _p: PhantomPinned, |
| //! } |
| //! |
| //! impl RawFoo { |
| //! pub fn new(flags: u32) -> impl PinInit<Self, Error> { |
| //! // SAFETY: |
| //! // - when the closure returns `Ok(())`, then it has successfully initialized and |
| //! // enabled `foo`, |
| //! // - when it returns `Err(e)`, then it has cleaned up before |
| //! unsafe { |
| //! init::pin_init_from_closure(move |slot: *mut Self| { |
| //! // `slot` contains uninit memory, avoid creating a reference. |
| //! let foo = addr_of_mut!((*slot).foo); |
| //! |
| //! // Initialize the `foo` |
| //! bindings::init_foo(Opaque::raw_get(foo)); |
| //! |
| //! // Try to enable it. |
| //! let err = bindings::enable_foo(Opaque::raw_get(foo), flags); |
| //! if err != 0 { |
| //! // Enabling has failed, first clean up the foo and then return the error. |
| //! bindings::destroy_foo(Opaque::raw_get(foo)); |
| //! return Err(Error::from_kernel_errno(err)); |
| //! } |
| //! |
| //! // All fields of `RawFoo` have been initialized, since `_p` is a ZST. |
| //! Ok(()) |
| //! }) |
| //! } |
| //! } |
| //! } |
| //! |
| //! #[pinned_drop] |
| //! impl PinnedDrop for RawFoo { |
| //! fn drop(self: Pin<&mut Self>) { |
| //! // SAFETY: Since `foo` is initialized, destroying is safe. |
| //! unsafe { bindings::destroy_foo(self.foo.get()) }; |
| //! } |
| //! } |
| //! ``` |
| //! |
| //! For the special case where initializing a field is a single FFI-function call that cannot fail, |
| //! there exist the helper function [`Opaque::ffi_init`]. This function initialize a single |
| //! [`Opaque`] field by just delegating to the supplied closure. You can use these in combination |
| //! with [`pin_init!`]. |
| //! |
| //! For more information on how to use [`pin_init_from_closure()`], take a look at the uses inside |
| //! the `kernel` crate. The [`sync`] module is a good starting point. |
| //! |
| //! [`sync`]: kernel::sync |
| //! [pinning]: https://doc.rust-lang.org/std/pin/index.html |
| //! [structurally pinned fields]: |
| //! https://doc.rust-lang.org/std/pin/index.html#pinning-is-structural-for-field |
| //! [stack]: crate::stack_pin_init |
| //! [`Arc<T>`]: crate::sync::Arc |
| //! [`impl PinInit<Foo>`]: PinInit |
| //! [`impl PinInit<T, E>`]: PinInit |
| //! [`impl Init<T, E>`]: Init |
| //! [`Opaque`]: kernel::types::Opaque |
| //! [`Opaque::ffi_init`]: kernel::types::Opaque::ffi_init |
| //! [`pin_data`]: ::macros::pin_data |
| |
| use crate::{ |
| error::{self, Error}, |
| sync::UniqueArc, |
| }; |
| use alloc::boxed::Box; |
| use core::{ |
| alloc::AllocError, |
| cell::Cell, |
| convert::Infallible, |
| marker::PhantomData, |
| mem::MaybeUninit, |
| num::*, |
| pin::Pin, |
| ptr::{self, NonNull}, |
| }; |
| |
| #[doc(hidden)] |
| pub mod __internal; |
| #[doc(hidden)] |
| pub mod macros; |
| |
| /// Initialize and pin a type directly on the stack. |
| /// |
| /// # Examples |
| /// |
| /// ```rust |
| /// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] |
| /// # use kernel::{init, pin_init, stack_pin_init, init::*, sync::Mutex, new_mutex}; |
| /// # use macros::pin_data; |
| /// # use core::pin::Pin; |
| /// #[pin_data] |
| /// struct Foo { |
| /// #[pin] |
| /// a: Mutex<usize>, |
| /// b: Bar, |
| /// } |
| /// |
| /// #[pin_data] |
| /// struct Bar { |
| /// x: u32, |
| /// } |
| /// |
| /// stack_pin_init!(let foo = pin_init!(Foo { |
| /// a <- new_mutex!(42), |
| /// b: Bar { |
| /// x: 64, |
| /// }, |
| /// })); |
| /// let foo: Pin<&mut Foo> = foo; |
| /// pr_info!("a: {}", &*foo.a.lock()); |
| /// ``` |
| /// |
| /// # Syntax |
| /// |
| /// A normal `let` binding with optional type annotation. The expression is expected to implement |
| /// [`PinInit`]/[`Init`] with the error type [`Infallible`]. If you want to use a different error |
| /// type, then use [`stack_try_pin_init!`]. |
| #[macro_export] |
| macro_rules! stack_pin_init { |
| (let $var:ident $(: $t:ty)? = $val:expr) => { |
| let val = $val; |
| let mut $var = ::core::pin::pin!($crate::init::__internal::StackInit$(::<$t>)?::uninit()); |
| let mut $var = match $crate::init::__internal::StackInit::init($var, val) { |
| Ok(res) => res, |
| Err(x) => { |
| let x: ::core::convert::Infallible = x; |
| match x {} |
| } |
| }; |
| }; |
| } |
| |
| /// Initialize and pin a type directly on the stack. |
| /// |
| /// # Examples |
| /// |
| /// ```rust |
| /// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] |
| /// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex}; |
| /// # use macros::pin_data; |
| /// # use core::{alloc::AllocError, pin::Pin}; |
| /// #[pin_data] |
| /// struct Foo { |
| /// #[pin] |
| /// a: Mutex<usize>, |
| /// b: Box<Bar>, |
| /// } |
| /// |
| /// struct Bar { |
| /// x: u32, |
| /// } |
| /// |
| /// stack_try_pin_init!(let foo: Result<Pin<&mut Foo>, AllocError> = pin_init!(Foo { |
| /// a <- new_mutex!(42), |
| /// b: Box::try_new(Bar { |
| /// x: 64, |
| /// })?, |
| /// })); |
| /// let foo = foo.unwrap(); |
| /// pr_info!("a: {}", &*foo.a.lock()); |
| /// ``` |
| /// |
| /// ```rust |
| /// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] |
| /// # use kernel::{init, pin_init, stack_try_pin_init, init::*, sync::Mutex, new_mutex}; |
| /// # use macros::pin_data; |
| /// # use core::{alloc::AllocError, pin::Pin}; |
| /// #[pin_data] |
| /// struct Foo { |
| /// #[pin] |
| /// a: Mutex<usize>, |
| /// b: Box<Bar>, |
| /// } |
| /// |
| /// struct Bar { |
| /// x: u32, |
| /// } |
| /// |
| /// stack_try_pin_init!(let foo: Pin<&mut Foo> =? pin_init!(Foo { |
| /// a <- new_mutex!(42), |
| /// b: Box::try_new(Bar { |
| /// x: 64, |
| /// })?, |
| /// })); |
| /// pr_info!("a: {}", &*foo.a.lock()); |
| /// # Ok::<_, AllocError>(()) |
| /// ``` |
| /// |
| /// # Syntax |
| /// |
| /// A normal `let` binding with optional type annotation. The expression is expected to implement |
| /// [`PinInit`]/[`Init`]. This macro assigns a result to the given variable, adding a `?` after the |
| /// `=` will propagate this error. |
| #[macro_export] |
| macro_rules! stack_try_pin_init { |
| (let $var:ident $(: $t:ty)? = $val:expr) => { |
| let val = $val; |
| let mut $var = ::core::pin::pin!($crate::init::__internal::StackInit$(::<$t>)?::uninit()); |
| let mut $var = $crate::init::__internal::StackInit::init($var, val); |
| }; |
| (let $var:ident $(: $t:ty)? =? $val:expr) => { |
| let val = $val; |
| let mut $var = ::core::pin::pin!($crate::init::__internal::StackInit$(::<$t>)?::uninit()); |
| let mut $var = $crate::init::__internal::StackInit::init($var, val)?; |
| }; |
| } |
| |
| /// Construct an in-place, pinned initializer for `struct`s. |
| /// |
| /// This macro defaults the error to [`Infallible`]. If you need [`Error`], then use |
| /// [`try_pin_init!`]. |
| /// |
| /// The syntax is almost identical to that of a normal `struct` initializer: |
| /// |
| /// ```rust |
| /// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] |
| /// # use kernel::{init, pin_init, macros::pin_data, init::*}; |
| /// # use core::pin::Pin; |
| /// #[pin_data] |
| /// struct Foo { |
| /// a: usize, |
| /// b: Bar, |
| /// } |
| /// |
| /// #[pin_data] |
| /// struct Bar { |
| /// x: u32, |
| /// } |
| /// |
| /// # fn demo() -> impl PinInit<Foo> { |
| /// let a = 42; |
| /// |
| /// let initializer = pin_init!(Foo { |
| /// a, |
| /// b: Bar { |
| /// x: 64, |
| /// }, |
| /// }); |
| /// # initializer } |
| /// # Box::pin_init(demo()).unwrap(); |
| /// ``` |
| /// |
| /// Arbitrary Rust expressions can be used to set the value of a variable. |
| /// |
| /// The fields are initialized in the order that they appear in the initializer. So it is possible |
| /// to read already initialized fields using raw pointers. |
| /// |
| /// IMPORTANT: You are not allowed to create references to fields of the struct inside of the |
| /// initializer. |
| /// |
| /// # Init-functions |
| /// |
| /// When working with this API it is often desired to let others construct your types without |
| /// giving access to all fields. This is where you would normally write a plain function `new` |
| /// that would return a new instance of your type. With this API that is also possible. |
| /// However, there are a few extra things to keep in mind. |
| /// |
| /// To create an initializer function, simply declare it like this: |
| /// |
| /// ```rust |
| /// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] |
| /// # use kernel::{init, pin_init, prelude::*, init::*}; |
| /// # use core::pin::Pin; |
| /// # #[pin_data] |
| /// # struct Foo { |
| /// # a: usize, |
| /// # b: Bar, |
| /// # } |
| /// # #[pin_data] |
| /// # struct Bar { |
| /// # x: u32, |
| /// # } |
| /// impl Foo { |
| /// fn new() -> impl PinInit<Self> { |
| /// pin_init!(Self { |
| /// a: 42, |
| /// b: Bar { |
| /// x: 64, |
| /// }, |
| /// }) |
| /// } |
| /// } |
| /// ``` |
| /// |
| /// Users of `Foo` can now create it like this: |
| /// |
| /// ```rust |
| /// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] |
| /// # use kernel::{init, pin_init, macros::pin_data, init::*}; |
| /// # use core::pin::Pin; |
| /// # #[pin_data] |
| /// # struct Foo { |
| /// # a: usize, |
| /// # b: Bar, |
| /// # } |
| /// # #[pin_data] |
| /// # struct Bar { |
| /// # x: u32, |
| /// # } |
| /// # impl Foo { |
| /// # fn new() -> impl PinInit<Self> { |
| /// # pin_init!(Self { |
| /// # a: 42, |
| /// # b: Bar { |
| /// # x: 64, |
| /// # }, |
| /// # }) |
| /// # } |
| /// # } |
| /// let foo = Box::pin_init(Foo::new()); |
| /// ``` |
| /// |
| /// They can also easily embed it into their own `struct`s: |
| /// |
| /// ```rust |
| /// # #![allow(clippy::disallowed_names, clippy::new_ret_no_self)] |
| /// # use kernel::{init, pin_init, macros::pin_data, init::*}; |
| /// # use core::pin::Pin; |
| /// # #[pin_data] |
| /// # struct Foo { |
| /// # a: usize, |
| /// # b: Bar, |
| /// # } |
| /// # #[pin_data] |
| /// # struct Bar { |
| /// # x: u32, |
| /// # } |
| /// # impl Foo { |
| /// # fn new() -> impl PinInit<Self> { |
| /// # pin_init!(Self { |
| /// # a: 42, |
| /// # b: Bar { |
| /// # x: 64, |
| /// # }, |
| /// # }) |
| /// # } |
| /// # } |
| /// #[pin_data] |
| /// struct FooContainer { |
| /// #[pin] |
| /// foo1: Foo, |
| /// #[pin] |
| /// foo2: Foo, |
| /// other: u32, |
| /// } |
| /// |
| /// impl FooContainer { |
| /// fn new(other: u32) -> impl PinInit<Self> { |
| /// pin_init!(Self { |
| /// foo1 <- Foo::new(), |
| /// foo2 <- Foo::new(), |
| /// other, |
| /// }) |
| /// } |
| /// } |
| /// ``` |
| /// |
| /// Here we see that when using `pin_init!` with `PinInit`, one needs to write `<-` instead of `:`. |
| /// This signifies that the given field is initialized in-place. As with `struct` initializers, just |
| /// writing the field (in this case `other`) without `:` or `<-` means `other: other,`. |
| /// |
| /// # Syntax |
| /// |
| /// As already mentioned in the examples above, inside of `pin_init!` a `struct` initializer with |
| /// the following modifications is expected: |
| /// - Fields that you want to initialize in-place have to use `<-` instead of `:`. |
| /// - In front of the initializer you can write `&this in` to have access to a [`NonNull<Self>`] |
| /// pointer named `this` inside of the initializer. |
| /// |
| /// For instance: |
| /// |
| /// ```rust |
| /// # use kernel::pin_init; |
| /// # use macros::pin_data; |
| /// # use core::{ptr::addr_of_mut, marker::PhantomPinned}; |
| /// #[pin_data] |
| /// struct Buf { |
| /// // `ptr` points into `buf`. |
| /// ptr: *mut u8, |
| /// buf: [u8; 64], |
| /// #[pin] |
| /// pin: PhantomPinned, |
| /// } |
| /// pin_init!(&this in Buf { |
| /// buf: [0; 64], |
| /// ptr: unsafe { addr_of_mut!((*this.as_ptr()).buf).cast() }, |
| /// pin: PhantomPinned, |
| /// }); |
| /// ``` |
| /// |
| /// [`try_pin_init!`]: kernel::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 `__internal` inside of `init/__internal.rs`. |
| #[macro_export] |
| macro_rules! pin_init { |
| ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { |
| $($fields:tt)* |
| }) => { |
| $crate::try_pin_init!( |
| @this($($this)?), |
| @typ($t $(::<$($generics),*>)?), |
| @fields($($fields)*), |
| @error(::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. |
| /// |
| /// This macro defaults the error to [`Error`]. |
| /// |
| /// The syntax is identical to [`pin_init!`] with the following exception: you can append `? $type` |
| /// after the `struct` initializer to specify the error type you want to use. |
| /// |
| /// # Examples |
| /// |
| /// ```rust |
| /// # #![feature(new_uninit)] |
| /// use kernel::{init::{self, PinInit}, error::Error}; |
| /// #[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) |
| /// } |
| /// } |
| /// ``` |
| // For a detailed example of how this macro works, see the module documentation of the hidden |
| // module `__internal` inside of `init/__internal.rs`. |
| #[macro_export] |
| macro_rules! try_pin_init { |
| ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { |
| $($fields:tt)* |
| }) => { |
| $crate::try_pin_init!( |
| @this($($this)?), |
| @typ($t $(::<$($generics),*>)? ), |
| @fields($($fields)*), |
| @error($crate::error::Error), |
| ) |
| }; |
| ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { |
| $($fields:tt)* |
| }? $err:ty) => { |
| $crate::try_pin_init!( |
| @this($($this)?), |
| @typ($t $(::<$($generics),*>)? ), |
| @fields($($fields)*), |
| @error($err), |
| ) |
| }; |
| ( |
| @this($($this:ident)?), |
| @typ($t:ident $(::<$($generics:ty),*>)?), |
| @fields($($fields:tt)*), |
| @error($err:ty), |
| ) => {{ |
| // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return |
| // type and shadow it later when we insert the arbitrary user code. That way there will be |
| // no possibility of returning without `unsafe`. |
| struct __InitOk; |
| // Get the pin data from the supplied type. |
| let data = unsafe { |
| use $crate::init::__internal::HasPinData; |
| $t$(::<$($generics),*>)?::__pin_data() |
| }; |
| // Ensure that `data` really is of type `PinData` and help with type inference: |
| let init = $crate::init::__internal::PinData::make_closure::<_, __InitOk, $err>( |
| data, |
| move |slot| { |
| { |
| // Shadow the structure so it cannot be used to return early. |
| struct __InitOk; |
| // Create the `this` so it can be referenced by the user inside of the |
| // expressions creating the individual fields. |
| $(let $this = unsafe { ::core::ptr::NonNull::new_unchecked(slot) };)? |
| // Initialize every field. |
| $crate::try_pin_init!(init_slot: |
| @data(data), |
| @slot(slot), |
| @munch_fields($($fields)*,), |
| ); |
| // We use unreachable code to ensure that all fields have been mentioned exactly |
| // once, this struct initializer will still be type-checked and complain with a |
| // very natural error message if a field is forgotten/mentioned more than once. |
| #[allow(unreachable_code, clippy::diverging_sub_expression)] |
| if false { |
| $crate::try_pin_init!(make_initializer: |
| @slot(slot), |
| @type_name($t), |
| @munch_fields($($fields)*,), |
| @acc(), |
| ); |
| } |
| // Forget all guards, since initialization was a success. |
| $crate::try_pin_init!(forget_guards: |
| @munch_fields($($fields)*,), |
| ); |
| } |
| Ok(__InitOk) |
| } |
| ); |
| let init = move |slot| -> ::core::result::Result<(), $err> { |
| init(slot).map(|__InitOk| ()) |
| }; |
| let init = unsafe { $crate::init::pin_init_from_closure::<_, $err>(init) }; |
| init |
| }}; |
| (init_slot: |
| @data($data:ident), |
| @slot($slot:ident), |
| @munch_fields($(,)?), |
| ) => { |
| // Endpoint of munching, no fields are left. |
| }; |
| (init_slot: |
| @data($data:ident), |
| @slot($slot:ident), |
| // In-place initialization syntax. |
| @munch_fields($field:ident <- $val:expr, $($rest:tt)*), |
| ) => { |
| let $field = $val; |
| // Call the initializer. |
| // |
| // SAFETY: `slot` is valid, because we are inside of an initializer closure, we |
| // return when an error/panic occurs. |
| // We also use the `data` to require the correct trait (`Init` or `PinInit`) for `$field`. |
| unsafe { $data.$field(::core::ptr::addr_of_mut!((*$slot).$field), $field)? }; |
| // Create the drop guard. |
| // |
| // We only give access to `&DropGuard`, so it cannot be forgotten via safe code. |
| // |
| // SAFETY: We forget the guard later when initialization has succeeded. |
| let $field = &unsafe { |
| $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) |
| }; |
| |
| $crate::try_pin_init!(init_slot: |
| @data($data), |
| @slot($slot), |
| @munch_fields($($rest)*), |
| ); |
| }; |
| (init_slot: |
| @data($data:ident), |
| @slot($slot:ident), |
| // Direct value init, this is safe for every field. |
| @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), |
| ) => { |
| $(let $field = $val;)? |
| // Initialize the field. |
| // |
| // SAFETY: The memory at `slot` is uninitialized. |
| unsafe { ::core::ptr::write(::core::ptr::addr_of_mut!((*$slot).$field), $field) }; |
| // Create the drop guard: |
| // |
| // We only give access to `&DropGuard`, so it cannot be accidentally forgotten. |
| // |
| // SAFETY: We forget the guard later when initialization has succeeded. |
| let $field = &unsafe { |
| $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) |
| }; |
| |
| $crate::try_pin_init!(init_slot: |
| @data($data), |
| @slot($slot), |
| @munch_fields($($rest)*), |
| ); |
| }; |
| (make_initializer: |
| @slot($slot:ident), |
| @type_name($t:ident), |
| @munch_fields($(,)?), |
| @acc($($acc:tt)*), |
| ) => { |
| // Endpoint, nothing more to munch, create the initializer. |
| // Since we are in the `if false` branch, this will never get executed. We abuse `slot` to |
| // get the correct type inference here: |
| unsafe { |
| ::core::ptr::write($slot, $t { |
| $($acc)* |
| }); |
| } |
| }; |
| (make_initializer: |
| @slot($slot:ident), |
| @type_name($t:ident), |
| @munch_fields($field:ident <- $val:expr, $($rest:tt)*), |
| @acc($($acc:tt)*), |
| ) => { |
| $crate::try_pin_init!(make_initializer: |
| @slot($slot), |
| @type_name($t), |
| @munch_fields($($rest)*), |
| @acc($($acc)* $field: ::core::panic!(),), |
| ); |
| }; |
| (make_initializer: |
| @slot($slot:ident), |
| @type_name($t:ident), |
| @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), |
| @acc($($acc:tt)*), |
| ) => { |
| $crate::try_pin_init!(make_initializer: |
| @slot($slot), |
| @type_name($t), |
| @munch_fields($($rest)*), |
| @acc($($acc)* $field: ::core::panic!(),), |
| ); |
| }; |
| (forget_guards: |
| @munch_fields($(,)?), |
| ) => { |
| // Munching finished. |
| }; |
| (forget_guards: |
| @munch_fields($field:ident <- $val:expr, $($rest:tt)*), |
| ) => { |
| unsafe { $crate::init::__internal::DropGuard::forget($field) }; |
| |
| $crate::try_pin_init!(forget_guards: |
| @munch_fields($($rest)*), |
| ); |
| }; |
| (forget_guards: |
| @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), |
| ) => { |
| unsafe { $crate::init::__internal::DropGuard::forget($field) }; |
| |
| $crate::try_pin_init!(forget_guards: |
| @munch_fields($($rest)*), |
| ); |
| }; |
| } |
| |
| /// Construct an in-place initializer for `struct`s. |
| /// |
| /// This macro defaults the error to [`Infallible`]. If you need [`Error`], then use |
| /// [`try_init!`]. |
| /// |
| /// 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 |
| /// 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. |
| /// |
| /// This initializer is for initializing data in-place that might later be moved. If you want to |
| /// pin-initialize, use [`pin_init!`]. |
| // For a detailed example of how this macro works, see the module documentation of the hidden |
| // module `__internal` inside of `init/__internal.rs`. |
| #[macro_export] |
| macro_rules! init { |
| ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { |
| $($fields:tt)* |
| }) => { |
| $crate::try_init!( |
| @this($($this)?), |
| @typ($t $(::<$($generics),*>)?), |
| @fields($($fields)*), |
| @error(::core::convert::Infallible), |
| ) |
| } |
| } |
| |
| /// Construct an in-place fallible initializer for `struct`s. |
| /// |
| /// This macro defaults the error to [`Error`]. If you need [`Infallible`], then use |
| /// [`init!`]. |
| /// |
| /// The syntax is identical to [`try_pin_init!`]. If you want to specify a custom error, |
| /// append `? $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 |
| /// use kernel::{init::PinInit, error::Error, InPlaceInit}; |
| /// struct BigBuf { |
| /// big: Box<[u8; 1024 * 1024 * 1024]>, |
| /// small: [u8; 1024 * 1024], |
| /// } |
| /// |
| /// impl BigBuf { |
| /// fn new() -> impl Init<Self, Error> { |
| /// try_init!(Self { |
| /// big: Box::init(zeroed())?, |
| /// small: [0; 1024 * 1024], |
| /// }? Error) |
| /// } |
| /// } |
| /// ``` |
| // For a detailed example of how this macro works, see the module documentation of the hidden |
| // module `__internal` inside of `init/__internal.rs`. |
| #[macro_export] |
| macro_rules! try_init { |
| ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { |
| $($fields:tt)* |
| }) => { |
| $crate::try_init!( |
| @this($($this)?), |
| @typ($t $(::<$($generics),*>)?), |
| @fields($($fields)*), |
| @error($crate::error::Error), |
| ) |
| }; |
| ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { |
| $($fields:tt)* |
| }? $err:ty) => { |
| $crate::try_init!( |
| @this($($this)?), |
| @typ($t $(::<$($generics),*>)?), |
| @fields($($fields)*), |
| @error($err), |
| ) |
| }; |
| ( |
| @this($($this:ident)?), |
| @typ($t:ident $(::<$($generics:ty),*>)?), |
| @fields($($fields:tt)*), |
| @error($err:ty), |
| ) => {{ |
| // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return |
| // type and shadow it later when we insert the arbitrary user code. That way there will be |
| // no possibility of returning without `unsafe`. |
| struct __InitOk; |
| // Get the init data from the supplied type. |
| let data = unsafe { |
| use $crate::init::__internal::HasInitData; |
| $t$(::<$($generics),*>)?::__init_data() |
| }; |
| // Ensure that `data` really is of type `InitData` and help with type inference: |
| let init = $crate::init::__internal::InitData::make_closure::<_, __InitOk, $err>( |
| data, |
| move |slot| { |
| { |
| // Shadow the structure so it cannot be used to return early. |
| struct __InitOk; |
| // Create the `this` so it can be referenced by the user inside of the |
| // expressions creating the individual fields. |
| $(let $this = unsafe { ::core::ptr::NonNull::new_unchecked(slot) };)? |
| // Initialize every field. |
| $crate::try_init!(init_slot: |
| @slot(slot), |
| @munch_fields($($fields)*,), |
| ); |
| // We use unreachable code to ensure that all fields have been mentioned exactly |
| // once, this struct initializer will still be type-checked and complain with a |
| // very natural error message if a field is forgotten/mentioned more than once. |
| #[allow(unreachable_code, clippy::diverging_sub_expression)] |
| if false { |
| $crate::try_init!(make_initializer: |
| @slot(slot), |
| @type_name($t), |
| @munch_fields($($fields)*,), |
| @acc(), |
| ); |
| } |
| // Forget all guards, since initialization was a success. |
| $crate::try_init!(forget_guards: |
| @munch_fields($($fields)*,), |
| ); |
| } |
| Ok(__InitOk) |
| } |
| ); |
| let init = move |slot| -> ::core::result::Result<(), $err> { |
| init(slot).map(|__InitOk| ()) |
| }; |
| let init = unsafe { $crate::init::init_from_closure::<_, $err>(init) }; |
| init |
| }}; |
| (init_slot: |
| @slot($slot:ident), |
| @munch_fields( $(,)?), |
| ) => { |
| // Endpoint of munching, no fields are left. |
| }; |
| (init_slot: |
| @slot($slot:ident), |
| @munch_fields($field:ident <- $val:expr, $($rest:tt)*), |
| ) => { |
| let $field = $val; |
| // Call the initializer. |
| // |
| // SAFETY: `slot` is valid, because we are inside of an initializer closure, we |
| // return when an error/panic occurs. |
| unsafe { |
| $crate::init::Init::__init($field, ::core::ptr::addr_of_mut!((*$slot).$field))?; |
| } |
| // Create the drop guard. |
| // |
| // We only give access to `&DropGuard`, so it cannot be accidentally forgotten. |
| // |
| // SAFETY: We forget the guard later when initialization has succeeded. |
| let $field = &unsafe { |
| $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) |
| }; |
| |
| $crate::try_init!(init_slot: |
| @slot($slot), |
| @munch_fields($($rest)*), |
| ); |
| }; |
| (init_slot: |
| @slot($slot:ident), |
| // Direct value init. |
| @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), |
| ) => { |
| $(let $field = $val;)? |
| // Call the initializer. |
| // |
| // SAFETY: The memory at `slot` is uninitialized. |
| unsafe { ::core::ptr::write(::core::ptr::addr_of_mut!((*$slot).$field), $field) }; |
| // Create the drop guard. |
| // |
| // We only give access to `&DropGuard`, so it cannot be accidentally forgotten. |
| // |
| // SAFETY: We forget the guard later when initialization has succeeded. |
| let $field = &unsafe { |
| $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) |
| }; |
| |
| $crate::try_init!(init_slot: |
| @slot($slot), |
| @munch_fields($($rest)*), |
| ); |
| }; |
| (make_initializer: |
| @slot($slot:ident), |
| @type_name($t:ident), |
| @munch_fields( $(,)?), |
| @acc($($acc:tt)*), |
| ) => { |
| // Endpoint, nothing more to munch, create the initializer. |
| // Since we are in the `if false` branch, this will never get executed. We abuse `slot` to |
| // get the correct type inference here: |
| unsafe { |
| ::core::ptr::write($slot, $t { |
| $($acc)* |
| }); |
| } |
| }; |
| (make_initializer: |
| @slot($slot:ident), |
| @type_name($t:ident), |
| @munch_fields($field:ident <- $val:expr, $($rest:tt)*), |
| @acc($($acc:tt)*), |
| ) => { |
| $crate::try_init!(make_initializer: |
| @slot($slot), |
| @type_name($t), |
| @munch_fields($($rest)*), |
| @acc($($acc)*$field: ::core::panic!(),), |
| ); |
| }; |
| (make_initializer: |
| @slot($slot:ident), |
| @type_name($t:ident), |
| @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), |
| @acc($($acc:tt)*), |
| ) => { |
| $crate::try_init!(make_initializer: |
| @slot($slot), |
| @type_name($t), |
| @munch_fields($($rest)*), |
| @acc($($acc)*$field: ::core::panic!(),), |
| ); |
| }; |
| (forget_guards: |
| @munch_fields($(,)?), |
| ) => { |
| // Munching finished. |
| }; |
| (forget_guards: |
| @munch_fields($field:ident <- $val:expr, $($rest:tt)*), |
| ) => { |
| unsafe { $crate::init::__internal::DropGuard::forget($field) }; |
| |
| $crate::try_init!(forget_guards: |
| @munch_fields($($rest)*), |
| ); |
| }; |
| (forget_guards: |
| @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), |
| ) => { |
| unsafe { $crate::init::__internal::DropGuard::forget($field) }; |
| |
| $crate::try_init!(forget_guards: |
| @munch_fields($($rest)*), |
| ); |
| }; |
| } |
| |
| /// A pin-initializer for the type `T`. |
| /// |
| /// To use this initializer, you will need a suitable memory location that can hold a `T`. This can |
| /// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`] or even the stack (see [`stack_pin_init!`]). Use the |
| /// [`InPlaceInit::pin_init`] function of a smart pointer like [`Arc<T>`] on this. |
| /// |
| /// Also see the [module description](self). |
| /// |
| /// # Safety |
| /// |
| /// When implementing this type you will need to take great care. Also there are probably very few |
| /// cases where a manual implementation is necessary. Use [`pin_init_from_closure`] where possible. |
| /// |
| /// The [`PinInit::__pinned_init`] function |
| /// - returns `Ok(())` if it initialized every field of `slot`, |
| /// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means: |
| /// - `slot` can be deallocated without UB occurring, |
| /// - `slot` does not need to be dropped, |
| /// - `slot` is not partially initialized. |
| /// - while constructing the `T` at `slot` it upholds the pinning invariants of `T`. |
| /// |
| /// [`Arc<T>`]: crate::sync::Arc |
| /// [`Arc::pin_init`]: crate::sync::Arc::pin_init |
| #[must_use = "An initializer must be used in order to create its value."] |
| pub unsafe trait PinInit<T: ?Sized, E = Infallible>: Sized { |
| /// Initializes `slot`. |
| /// |
| /// # Safety |
| /// |
| /// - `slot` is a valid pointer to uninitialized memory. |
| /// - the caller does not touch `slot` when `Err` is returned, they are only permitted to |
| /// deallocate. |
| /// - `slot` will not move until it is dropped, i.e. it will be pinned. |
| unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E>; |
| } |
| |
| /// An initializer for `T`. |
| /// |
| /// To use this initializer, you will need a suitable memory location that can hold a `T`. This can |
| /// be [`Box<T>`], [`Arc<T>`], [`UniqueArc<T>`] or even the stack (see [`stack_pin_init!`]). Use the |
| /// [`InPlaceInit::init`] function of a smart pointer like [`Arc<T>`] on this. Because |
| /// [`PinInit<T, E>`] is a super trait, you can use every function that takes it as well. |
| /// |
| /// Also see the [module description](self). |
| /// |
| /// # Safety |
| /// |
| /// When implementing this type you will need to take great care. Also there are probably very few |
| /// cases where a manual implementation is necessary. Use [`init_from_closure`] where possible. |
| /// |
| /// The [`Init::__init`] function |
| /// - returns `Ok(())` if it initialized every field of `slot`, |
| /// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means: |
| /// - `slot` can be deallocated without UB occurring, |
| /// - `slot` does not need to be dropped, |
| /// - `slot` is not partially initialized. |
| /// - while constructing the `T` at `slot` it upholds the pinning invariants of `T`. |
| /// |
| /// The `__pinned_init` function from the supertrait [`PinInit`] needs to execute the exact same |
| /// code as `__init`. |
| /// |
| /// Contrary to its supertype [`PinInit<T, E>`] the caller is allowed to |
| /// move the pointee after initialization. |
| /// |
| /// [`Arc<T>`]: crate::sync::Arc |
| #[must_use = "An initializer must be used in order to create its value."] |
| pub unsafe trait Init<T: ?Sized, E = Infallible>: Sized { |
| /// Initializes `slot`. |
| /// |
| /// # Safety |
| /// |
| /// - `slot` is a valid pointer to uninitialized memory. |
| /// - the caller does not touch `slot` when `Err` is returned, they are only permitted to |
| /// deallocate. |
| unsafe fn __init(self, slot: *mut T) -> Result<(), E>; |
| } |
| |
| // SAFETY: Every in-place initializer can also be used as a pin-initializer. |
| unsafe impl<T: ?Sized, E, I> PinInit<T, E> for I |
| where |
| I: Init<T, E>, |
| { |
| unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { |
| // SAFETY: `__init` meets the same requirements as `__pinned_init`, except that it does not |
| // require `slot` to not move after init. |
| unsafe { self.__init(slot) } |
| } |
| } |
| |
| /// Creates a new [`PinInit<T, E>`] from the given closure. |
| /// |
| /// # Safety |
| /// |
| /// The closure: |
| /// - returns `Ok(())` if it initialized every field of `slot`, |
| /// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means: |
| /// - `slot` can be deallocated without UB occurring, |
| /// - `slot` does not need to be dropped, |
| /// - `slot` is not partially initialized. |
| /// - may assume that the `slot` does not move if `T: !Unpin`, |
| /// - while constructing the `T` at `slot` it upholds the pinning invariants of `T`. |
| #[inline] |
| pub const unsafe fn pin_init_from_closure<T: ?Sized, E>( |
| f: impl FnOnce(*mut T) -> Result<(), E>, |
| ) -> impl PinInit<T, E> { |
| __internal::InitClosure(f, PhantomData) |
| } |
| |
| /// Creates a new [`Init<T, E>`] from the given closure. |
| /// |
| /// # Safety |
| /// |
| /// The closure: |
| /// - returns `Ok(())` if it initialized every field of `slot`, |
| /// - returns `Err(err)` if it encountered an error and then cleaned `slot`, this means: |
| /// - `slot` can be deallocated without UB occurring, |
| /// - `slot` does not need to be dropped, |
| /// - `slot` is not partially initialized. |
| /// - the `slot` may move after initialization. |
| /// - while constructing the `T` at `slot` it upholds the pinning invariants of `T`. |
| #[inline] |
| pub const unsafe fn init_from_closure<T: ?Sized, E>( |
| f: impl FnOnce(*mut T) -> Result<(), E>, |
| ) -> impl Init<T, E> { |
| __internal::InitClosure(f, PhantomData) |
| } |
| |
| /// An initializer that leaves the memory uninitialized. |
| /// |
| /// The initializer is a no-op. The `slot` memory is not changed. |
| #[inline] |
| pub fn uninit<T, E>() -> impl Init<MaybeUninit<T>, E> { |
| // SAFETY: The memory is allowed to be uninitialized. |
| unsafe { init_from_closure(|_| Ok(())) } |
| } |
| |
| // SAFETY: Every type can be initialized by-value. |
| unsafe impl<T, E> Init<T, E> for T { |
| unsafe fn __init(self, slot: *mut T) -> Result<(), E> { |
| unsafe { slot.write(self) }; |
| Ok(()) |
| } |
| } |
| |
| /// Smart pointer that can initialize memory in-place. |
| pub trait InPlaceInit<T>: Sized { |
| /// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this |
| /// type. |
| /// |
| /// If `T: !Unpin` it will not be able to move afterwards. |
| fn try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E> |
| where |
| E: From<AllocError>; |
| |
| /// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this |
| /// type. |
| /// |
| /// If `T: !Unpin` it will not be able to move afterwards. |
| fn pin_init<E>(init: impl PinInit<T, E>) -> error::Result<Pin<Self>> |
| where |
| Error: From<E>, |
| { |
| // SAFETY: We delegate to `init` and only change the error type. |
| let init = unsafe { |
| pin_init_from_closure(|slot| init.__pinned_init(slot).map_err(|e| Error::from(e))) |
| }; |
| Self::try_pin_init(init) |
| } |
| |
| /// Use the given initializer to in-place initialize a `T`. |
| fn try_init<E>(init: impl Init<T, E>) -> Result<Self, E> |
| where |
| E: From<AllocError>; |
| |
| /// Use the given initializer to in-place initialize a `T`. |
| fn init<E>(init: impl Init<T, E>) -> error::Result<Self> |
| where |
| Error: From<E>, |
| { |
| // SAFETY: We delegate to `init` and only change the error type. |
| let init = unsafe { |
| init_from_closure(|slot| init.__pinned_init(slot).map_err(|e| Error::from(e))) |
| }; |
| Self::try_init(init) |
| } |
| } |
| |
| impl<T> InPlaceInit<T> for Box<T> { |
| #[inline] |
| fn try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E> |
| where |
| E: From<AllocError>, |
| { |
| let mut this = Box::try_new_uninit()?; |
| let slot = this.as_mut_ptr(); |
| // SAFETY: When init errors/panics, slot will get deallocated but not dropped, |
| // slot is valid and will not be moved, because we pin it later. |
| unsafe { init.__pinned_init(slot)? }; |
| // SAFETY: All fields have been initialized. |
| Ok(unsafe { this.assume_init() }.into()) |
| } |
| |
| #[inline] |
| fn try_init<E>(init: impl Init<T, E>) -> Result<Self, E> |
| where |
| E: From<AllocError>, |
| { |
| let mut this = Box::try_new_uninit()?; |
| let slot = this.as_mut_ptr(); |
| // SAFETY: When init errors/panics, slot will get deallocated but not dropped, |
| // slot is valid. |
| unsafe { init.__init(slot)? }; |
| // SAFETY: All fields have been initialized. |
| Ok(unsafe { this.assume_init() }) |
| } |
| } |
| |
| impl<T> InPlaceInit<T> for UniqueArc<T> { |
| #[inline] |
| fn try_pin_init<E>(init: impl PinInit<T, E>) -> Result<Pin<Self>, E> |
| where |
| E: From<AllocError>, |
| { |
| let mut this = UniqueArc::try_new_uninit()?; |
| let slot = this.as_mut_ptr(); |
| // SAFETY: When init errors/panics, slot will get deallocated but not dropped, |
| // slot is valid and will not be moved, because we pin it later. |
| unsafe { init.__pinned_init(slot)? }; |
| // SAFETY: All fields have been initialized. |
| Ok(unsafe { this.assume_init() }.into()) |
| } |
| |
| #[inline] |
| fn try_init<E>(init: impl Init<T, E>) -> Result<Self, E> |
| where |
| E: From<AllocError>, |
| { |
| let mut this = UniqueArc::try_new_uninit()?; |
| let slot = this.as_mut_ptr(); |
| // SAFETY: When init errors/panics, slot will get deallocated but not dropped, |
| // slot is valid. |
| unsafe { init.__init(slot)? }; |
| // SAFETY: All fields have been initialized. |
| Ok(unsafe { this.assume_init() }) |
| } |
| } |
| |
| /// Trait facilitating pinned destruction. |
| /// |
| /// Use [`pinned_drop`] to implement this trait safely: |
| /// |
| /// ```rust |
| /// # use kernel::sync::Mutex; |
| /// use kernel::macros::pinned_drop; |
| /// use core::pin::Pin; |
| /// #[pin_data(PinnedDrop)] |
| /// struct Foo { |
| /// #[pin] |
| /// mtx: Mutex<usize>, |
| /// } |
| /// |
| /// #[pinned_drop] |
| /// impl PinnedDrop for Foo { |
| /// fn drop(self: Pin<&mut Self>) { |
| /// pr_info!("Foo is being dropped!"); |
| /// } |
| /// } |
| /// ``` |
| /// |
| /// # Safety |
| /// |
| /// This trait must be implemented via the [`pinned_drop`] proc-macro attribute on the impl. |
| /// |
| /// [`pinned_drop`]: kernel::macros::pinned_drop |
| pub unsafe trait PinnedDrop: __internal::HasPinData { |
| /// Executes the pinned destructor of this type. |
| /// |
| /// While this function is marked safe, it is actually unsafe to call it manually. For this |
| /// reason it takes an additional parameter. This type can only be constructed by `unsafe` code |
| /// and thus prevents this function from being called where it should not. |
| /// |
| /// This extra parameter will be generated by the `#[pinned_drop]` proc-macro attribute |
| /// automatically. |
| fn drop(self: Pin<&mut Self>, only_call_from_drop: __internal::OnlyCallFromDrop); |
| } |
| |
| /// Marker trait for types that can be initialized by writing just zeroes. |
| /// |
| /// # Safety |
| /// |
| /// The bit pattern consisting of only zeroes is a valid bit pattern for this type. In other words, |
| /// this is not UB: |
| /// |
| /// ```rust,ignore |
| /// let val: Self = unsafe { core::mem::zeroed() }; |
| /// ``` |
| pub unsafe trait Zeroable {} |
| |
| /// Create a new zeroed T. |
| /// |
| /// The returned initializer will write `0x00` to every byte of the given `slot`. |
| #[inline] |
| pub fn zeroed<T: Zeroable>() -> impl Init<T> { |
| // SAFETY: Because `T: Zeroable`, all bytes zero is a valid bit pattern for `T` |
| // and because we write all zeroes, the memory is initialized. |
| unsafe { |
| init_from_closure(|slot: *mut T| { |
| slot.write_bytes(0, 1); |
| Ok(()) |
| }) |
| } |
| } |
| |
| macro_rules! impl_zeroable { |
| ($($({$($generics:tt)*})? $t:ty, )*) => { |
| $(unsafe impl$($($generics)*)? Zeroable for $t {})* |
| }; |
| } |
| |
| impl_zeroable! { |
| // SAFETY: All primitives that are allowed to be zero. |
| bool, |
| char, |
| u8, u16, u32, u64, u128, usize, |
| i8, i16, i32, i64, i128, isize, |
| f32, f64, |
| |
| // SAFETY: These are ZSTs, there is nothing to zero. |
| {<T: ?Sized>} PhantomData<T>, core::marker::PhantomPinned, Infallible, (), |
| |
| // SAFETY: Type is allowed to take any value, including all zeros. |
| {<T>} MaybeUninit<T>, |
| |
| // SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee). |
| Option<NonZeroU8>, Option<NonZeroU16>, Option<NonZeroU32>, Option<NonZeroU64>, |
| Option<NonZeroU128>, Option<NonZeroUsize>, |
| Option<NonZeroI8>, Option<NonZeroI16>, Option<NonZeroI32>, Option<NonZeroI64>, |
| Option<NonZeroI128>, Option<NonZeroIsize>, |
| |
| // SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee). |
| // |
| // In this case we are allowed to use `T: ?Sized`, since all zeros is the `None` variant. |
| {<T: ?Sized>} Option<NonNull<T>>, |
| {<T: ?Sized>} Option<Box<T>>, |
| |
| // SAFETY: `null` pointer is valid. |
| // |
| // We cannot use `T: ?Sized`, since the VTABLE pointer part of fat pointers is not allowed to be |
| // null. |
| // |
| // When `Pointee` gets stabilized, we could use |
| // `T: ?Sized where <T as Pointee>::Metadata: Zeroable` |
| {<T>} *mut T, {<T>} *const T, |
| |
| // SAFETY: `null` pointer is valid and the metadata part of these fat pointers is allowed to be |
| // zero. |
| {<T>} *mut [T], {<T>} *const [T], *mut str, *const str, |
| |
| // SAFETY: `T` is `Zeroable`. |
| {<const N: usize, T: Zeroable>} [T; N], {<T: Zeroable>} Wrapping<T>, |
| } |
| |
| macro_rules! impl_tuple_zeroable { |
| ($(,)?) => {}; |
| ($first:ident, $($t:ident),* $(,)?) => { |
| // SAFETY: All elements are zeroable and padding can be zero. |
| unsafe impl<$first: Zeroable, $($t: Zeroable),*> Zeroable for ($first, $($t),*) {} |
| impl_tuple_zeroable!($($t),* ,); |
| } |
| } |
| |
| impl_tuple_zeroable!(A, B, C, D, E, F, G, H, I, J); |