Skip to content

Commit

Permalink
Improve docs
Browse files Browse the repository at this point in the history
  • Loading branch information
y86-dev committed Oct 13, 2022
1 parent 43f296c commit 8e3fa16
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 35 deletions.
115 changes: 80 additions & 35 deletions rust/kernel/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,21 @@
//!
//! ## Directly creating an in-place constructor
//!
//! If you want to use [`PinInit`], then you will have to annotate your struct with [`#[pin_project]`].
//! It is a macro that uses `#[pin]` as a marker for [structurally pinned fields].
//!
//! ```rust
//! # use kernel::prelude::*;
//! use kernel::{prelude::*, sync::Mutex, new_mutex};
//! # use core::pin::Pin;
//! #[pin_project]
//! struct Foo {
//! a: usize,
//! #[pin]
//! a: Mutex<usize>,
//! b: u32,
//! }
//!
//! let foo = pin_init!(Foo {
//! a: 42,
//! a: new_mutex!(42, "Foo::a"),
//! b: 24,
//! });
//! # let foo: Result<Pin<Box<Foo>>> = Box::pin_init::<core::convert::Infallible>(foo);
Expand All @@ -42,15 +46,16 @@
//! (or just the stack) to actually initialize a `Foo`:
//!
//! ```rust
//! # use kernel::prelude::*;
//! # use kernel::{prelude::*, sync::Mutex, new_mutex};
//! # use core::pin::Pin;
//! # #[pin_project]
//! # struct Foo {
//! # a: usize,
//! # #[pin]
//! # a: Mutex<usize>,
//! # b: u32,
//! # }
//! # let foo = pin_init!(Foo {
//! # a: 42,
//! # a: new_mutex!(42, "Foo::a"),
//! # b: 24,
//! # });
//! let foo: Result<Pin<Box<Foo>>> = Box::pin_init::<core::convert::Infallible>(foo);
Expand Down Expand Up @@ -91,6 +96,7 @@
//!
//! [sync]: ../sync/index.html
//! [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_init
//! [`Arc<T>`]: crate::sync::Arc
Expand All @@ -111,17 +117,18 @@ use core::{
pub mod __private;
mod pin_project;

/// Initialize a type on the stack.
/// Initialize a type directly on the stack.
///
/// # Examples
///
/// ```rust
/// # #![allow(clippy::blacklisted_name, clippy::new_ret_no_self)]
/// # use kernel::{init, pin_init, stack_init, init::*, macros::pin_project};
/// # use kernel::{init, pin_init, stack_init, init::*, macros::pin_project, sync::Mutex, new_mutex};
/// # use core::pin::Pin;
/// #[pin_project]
/// struct Foo {
/// a: usize,
/// #[pin]
/// a: Mutex<usize>,
/// b: Bar,
/// }
///
Expand All @@ -130,7 +137,7 @@ mod pin_project;
/// x: u32,
/// }
///
/// let a = 42;
/// let a = new_mutex!(42, "Foo::a");
///
/// stack_init!(let foo = pin_init!(Foo {
/// a,
Expand Down Expand Up @@ -514,18 +521,29 @@ macro_rules! init {
}}
}

//include!("init/pin_project.rs");

/// An initializer for `T`.
/// A pinned 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_init!`]). Use the
/// `pin_init` function of a smart pointer like [`Arc::pin_init`] 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 [`from_value`] and
/// [`pin_init_from_closure`] where possible.
///
/// The [`PinInit::__pinned_init`] function
/// - returns `Ok(())` iff it initialized every field of slot,
/// - returns `Err(err)` iff it encountered an error and then cleaned slot, this means:
/// - slot can be deallocated without UB ocurring,
/// - slot does not need to be dropped,
/// - slot is not partially initialized.
///
/// [`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, E = Infallible>: Sized {
/// Initializes `slot`.
Expand All @@ -541,8 +559,19 @@ pub unsafe trait PinInit<T, E = Infallible>: Sized {

/// 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_init!`]). Use the
/// `init` function of a smart pointer like [`Box::init`] 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 [`from_value`] and
/// [`init_from_closure`] where possible.
///
/// The [`Init::__init`] function
/// - returns `Ok(())` iff it initialized every field of slot,
/// - returns `Err(err)` iff it encountered an error and then cleaned slot, this means:
Expand All @@ -555,6 +584,8 @@ pub unsafe trait PinInit<T, E = Infallible>: Sized {
///
/// 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, E = Infallible>: PinInit<T, E> {
/// Initializes `slot`.
Expand All @@ -571,7 +602,25 @@ type Invariant<T> = PhantomData<fn(T) -> T>;

struct InitClosure<F, T, E>(F, Invariant<(T, E)>);

/// Creates a new Init from the given closure
unsafe impl<T, F, E> PinInit<T, E> for InitClosure<F, T, E>
where
F: FnOnce(*mut T) -> Result<(), E>,
{
unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> {
(self.0)(slot)
}
}

unsafe impl<T, F, E> Init<T, E> for InitClosure<F, T, E>
where
F: FnOnce(*mut T) -> Result<(), E>,
{
unsafe fn __init(self, slot: *mut T) -> Result<(), E> {
(self.0)(slot)
}
}

/// Creates a new [`Init<T, E>`] from the given closure.
///
/// # Safety
///
Expand All @@ -587,7 +636,7 @@ pub const unsafe fn init_from_closure<T, E>(
) -> impl Init<T, E> {
InitClosure(f, PhantomData)
}
/// Creates a new PinInit from the given closure
/// Creates a new [`PinInit<T, E>`] from the given closure.
///
/// # Safety
///
Expand All @@ -604,24 +653,6 @@ pub const unsafe fn pin_init_from_closure<T, E>(
InitClosure(f, PhantomData)
}

unsafe impl<T, F, E> PinInit<T, E> for InitClosure<F, T, E>
where
F: FnOnce(*mut T) -> Result<(), E>,
{
unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> {
(self.0)(slot)
}
}

unsafe impl<T, F, E> Init<T, E> for InitClosure<F, T, E>
where
F: FnOnce(*mut T) -> Result<(), E>,
{
unsafe fn __init(self, slot: *mut T) -> Result<(), E> {
(self.0)(slot)
}
}

/// Trait facilitating pinned destruction.
///
/// Use [`pinned_drop`] to implement this trait safely:
Expand All @@ -648,10 +679,14 @@ where
///
/// [`pinned_drop`]: kernel::macros::pinned_drop
pub unsafe trait PinnedDrop {
/// Executes the pinned destructor of this type.
///
/// # Safety
///
/// Only call this from `<Self as Drop>::drop`.
unsafe fn drop(self: Pin<&mut Self>);

// used by `pinned_drop` to ensure that only safe operations are used in `drop`.
#[doc(hidden)]
fn __ensure_no_unsafe_op_in_drop(self: Pin<&mut Self>);
}
Expand Down Expand Up @@ -734,8 +769,12 @@ impl<T> InPlaceInit<T> for UniqueArc<T> {
/// The bit pattern consisting of only zeroes must be a valid bit pattern for the type.
pub unsafe trait Zeroable {}

/// Create a new zeroed T
/// Create a new zeroed T.
///
/// The returned initializer will write `0x00` to every byte of the given slot.
pub fn zeroed<T: Zeroable + Unpin>() -> 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);
Expand All @@ -745,12 +784,18 @@ pub fn zeroed<T: Zeroable + Unpin>() -> impl Init<T> {
}

/// An initializer that leaves the memory uninitialized.
///
/// The initializer is a no-op. The slot memory is not changed.
pub fn uninit<T>() -> impl Init<MaybeUninit<T>> {
// SAFETY: The memory is allowed to be uninitialized.
unsafe { init_from_closure(|_| Ok(())) }
}

/// Convert a value into an initializer
/// Convert a value into an initializer.
///
/// Directly moves the value into the given slot.
pub fn from_value<T>(value: T) -> impl Init<T> {
// SAFETY: we use the value to initialize the slot.
unsafe {
init_from_closure(move |slot: *mut T| {
slot.write(value);
Expand Down
1 change: 1 addition & 0 deletions rust/kernel/init/pin_project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ macro_rules! pin_project {
$($pinned)*
}

#[doc(hidden)]
impl<'__pin, $($impl_generics)*> ::core::marker::Unpin for $name<$($ty_generics)*>
where
__Unpin<'__pin, $($ty_generics)*>: ::core::marker::Unpin,
Expand Down

0 comments on commit 8e3fa16

Please sign in to comment.