rust: init: update expanded macro explanation
The previous patches changed the internals of the macros resulting in the example expanded code being outdated. This patch updates the example and only changes documentation. Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com> Signed-off-by: Benno Lossin <benno.lossin@proton.me> Link: https://lore.kernel.org/r/20230814084602.25699-14-benno.lossin@proton.me Reviewed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
parent
7f8977a7fe
commit
4af84c6a85
|
@ -45,7 +45,7 @@
|
|||
//! #[pinned_drop]
|
||||
//! impl PinnedDrop for Foo {
|
||||
//! fn drop(self: Pin<&mut Self>) {
|
||||
//! println!("{self:p} is getting dropped.");
|
||||
//! pr_info!("{self:p} is getting dropped.");
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
|
@ -170,8 +170,10 @@
|
|||
//! t: T,
|
||||
//! }
|
||||
//! #[doc(hidden)]
|
||||
//! impl<'__pin, T>
|
||||
//! ::core::marker::Unpin for Bar<T> where __Unpin<'__pin, T>: ::core::marker::Unpin {}
|
||||
//! impl<'__pin, T> ::core::marker::Unpin for Bar<T>
|
||||
//! where
|
||||
//! __Unpin<'__pin, T>: ::core::marker::Unpin,
|
||||
//! {}
|
||||
//! // Now we need to ensure that `Bar` does not implement `Drop`, since that would give users
|
||||
//! // access to `&mut self` inside of `drop` even if the struct was pinned. This could lead to
|
||||
//! // UB with only safe code, so we disallow this by giving a trait implementation error using
|
||||
|
@ -188,8 +190,9 @@
|
|||
//! // for safety, but a good sanity check, since no normal code calls `PinnedDrop::drop`.
|
||||
//! #[allow(non_camel_case_types)]
|
||||
//! trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {}
|
||||
//! impl<T: ::kernel::init::PinnedDrop>
|
||||
//! UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {}
|
||||
//! impl<
|
||||
//! T: ::kernel::init::PinnedDrop,
|
||||
//! > UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {}
|
||||
//! impl<T> UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for Bar<T> {}
|
||||
//! };
|
||||
//! ```
|
||||
|
@ -219,7 +222,7 @@
|
|||
//! // 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 type from the initialized type.
|
||||
//! // Get the data about fields from the supplied type.
|
||||
//! // - the function is unsafe, hence the unsafe block
|
||||
//! // - we `use` the `HasPinData` trait in the block, it is only available in that
|
||||
//! // scope.
|
||||
|
@ -227,8 +230,7 @@
|
|||
//! use ::kernel::init::__internal::HasPinData;
|
||||
//! Self::__pin_data()
|
||||
//! };
|
||||
//! // Use `data` to help with type inference, the closure supplied will have the type
|
||||
//! // `FnOnce(*mut Self) -> Result<__InitOk, Infallible>`.
|
||||
//! // Ensure that `data` really is of type `PinData` and help with type inference:
|
||||
//! let init = ::kernel::init::__internal::PinData::make_closure::<
|
||||
//! _,
|
||||
//! __InitOk,
|
||||
|
@ -236,71 +238,75 @@
|
|||
//! >(data, move |slot| {
|
||||
//! {
|
||||
//! // Shadow the structure so it cannot be used to return early. If a user
|
||||
//! // tries to write `return Ok(__InitOk)`, then they get a type error, since
|
||||
//! // that will refer to this struct instead of the one defined above.
|
||||
//! // tries to write `return Ok(__InitOk)`, then they get a type error,
|
||||
//! // since that will refer to this struct instead of the one defined
|
||||
//! // above.
|
||||
//! struct __InitOk;
|
||||
//! // This is the expansion of `t,`, which is syntactic sugar for `t: t,`.
|
||||
//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).t), t) };
|
||||
//! // Since initialization could fail later (not in this case, since the error
|
||||
//! // type is `Infallible`) we will need to drop this field if there is an
|
||||
//! // error later. This `DropGuard` will drop the field when it gets dropped
|
||||
//! // and has not yet been forgotten. We make a reference to it, so users
|
||||
//! // cannot `mem::forget` it from the initializer, since the name is the same
|
||||
//! // as the field (including hygiene).
|
||||
//! let t = &unsafe {
|
||||
//! ::kernel::init::__internal::DropGuard::new(
|
||||
//! ::core::addr_of_mut!((*slot).t),
|
||||
//! )
|
||||
//! {
|
||||
//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).t), t) };
|
||||
//! }
|
||||
//! // Since initialization could fail later (not in this case, since the
|
||||
//! // error type is `Infallible`) we will need to drop this field if there
|
||||
//! // is an error later. This `DropGuard` will drop the field when it gets
|
||||
//! // dropped and has not yet been forgotten.
|
||||
//! let t = unsafe {
|
||||
//! ::pinned_init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).t))
|
||||
//! };
|
||||
//! // Expansion of `x: 0,`:
|
||||
//! // Since this can be an arbitrary expression we cannot place it inside of
|
||||
//! // the `unsafe` block, so we bind it here.
|
||||
//! let x = 0;
|
||||
//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).x), x) };
|
||||
//! // Since this can be an arbitrary expression we cannot place it inside
|
||||
//! // of the `unsafe` block, so we bind it here.
|
||||
//! {
|
||||
//! let x = 0;
|
||||
//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).x), x) };
|
||||
//! }
|
||||
//! // We again create a `DropGuard`.
|
||||
//! let x = &unsafe {
|
||||
//! ::kernel::init::__internal::DropGuard::new(
|
||||
//! ::core::addr_of_mut!((*slot).x),
|
||||
//! )
|
||||
//! let x = unsafe {
|
||||
//! ::kernel::init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).x))
|
||||
//! };
|
||||
//!
|
||||
//! // Since initialization has successfully completed, we can now forget
|
||||
//! // the guards. This is not `mem::forget`, since we only have
|
||||
//! // `&DropGuard`.
|
||||
//! ::core::mem::forget(x);
|
||||
//! ::core::mem::forget(t);
|
||||
//! // Here we use the type checker to ensure that every field has been
|
||||
//! // initialized exactly once, since this is `if false` it will never get
|
||||
//! // executed, but still type-checked.
|
||||
//! // Additionally we abuse `slot` to automatically infer the correct type for
|
||||
//! // the struct. This is also another check that every field is accessible
|
||||
//! // from this scope.
|
||||
//! // Additionally we abuse `slot` to automatically infer the correct type
|
||||
//! // for the struct. This is also another check that every field is
|
||||
//! // accessible from this scope.
|
||||
//! #[allow(unreachable_code, clippy::diverging_sub_expression)]
|
||||
//! if false {
|
||||
//! let _ = || {
|
||||
//! unsafe {
|
||||
//! ::core::ptr::write(
|
||||
//! slot,
|
||||
//! Self {
|
||||
//! // We only care about typecheck finding every field here,
|
||||
//! // the expression does not matter, just conjure one using
|
||||
//! // `panic!()`:
|
||||
//! // We only care about typecheck finding every field
|
||||
//! // here, the expression does not matter, just conjure
|
||||
//! // one using `panic!()`:
|
||||
//! t: ::core::panic!(),
|
||||
//! x: ::core::panic!(),
|
||||
//! },
|
||||
//! );
|
||||
//! };
|
||||
//! }
|
||||
//! // Since initialization has successfully completed, we can now forget the
|
||||
//! // guards. This is not `mem::forget`, since we only have `&DropGuard`.
|
||||
//! unsafe { ::kernel::init::__internal::DropGuard::forget(t) };
|
||||
//! unsafe { ::kernel::init::__internal::DropGuard::forget(x) };
|
||||
//! };
|
||||
//! }
|
||||
//! // We leave the scope above and gain access to the previously shadowed
|
||||
//! // `__InitOk` that we need to return.
|
||||
//! Ok(__InitOk)
|
||||
//! });
|
||||
//! // Change the return type from `__InitOk` to `()`.
|
||||
//! let init = move |slot| -> ::core::result::Result<(), ::core::convert::Infallible> {
|
||||
//! let init = move |
|
||||
//! slot,
|
||||
//! | -> ::core::result::Result<(), ::core::convert::Infallible> {
|
||||
//! init(slot).map(|__InitOk| ())
|
||||
//! };
|
||||
//! // Construct the initializer.
|
||||
//! let init = unsafe {
|
||||
//! ::kernel::init::pin_init_from_closure::<_, ::core::convert::Infallible>(init)
|
||||
//! ::kernel::init::pin_init_from_closure::<
|
||||
//! _,
|
||||
//! ::core::convert::Infallible,
|
||||
//! >(init)
|
||||
//! };
|
||||
//! init
|
||||
//! }
|
||||
|
@ -374,7 +380,10 @@
|
|||
//! b: Bar<u32>,
|
||||
//! }
|
||||
//! #[doc(hidden)]
|
||||
//! impl<'__pin> ::core::marker::Unpin for Foo where __Unpin<'__pin>: ::core::marker::Unpin {}
|
||||
//! impl<'__pin> ::core::marker::Unpin for Foo
|
||||
//! where
|
||||
//! __Unpin<'__pin>: ::core::marker::Unpin,
|
||||
//! {}
|
||||
//! // Since we specified `PinnedDrop` as the argument to `#[pin_data]`, we expect `Foo` to
|
||||
//! // implement `PinnedDrop`. Thus we do not need to prevent `Drop` implementations like
|
||||
//! // before, instead we implement `Drop` here and delegate to `PinnedDrop`.
|
||||
|
@ -403,7 +412,7 @@
|
|||
//! #[pinned_drop]
|
||||
//! impl PinnedDrop for Foo {
|
||||
//! fn drop(self: Pin<&mut Self>) {
|
||||
//! println!("{self:p} is getting dropped.");
|
||||
//! pr_info!("{self:p} is getting dropped.");
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
@ -414,7 +423,7 @@
|
|||
//! // `unsafe`, full path and the token parameter are added, everything else stays the same.
|
||||
//! unsafe impl ::kernel::init::PinnedDrop for Foo {
|
||||
//! fn drop(self: Pin<&mut Self>, _: ::kernel::init::__internal::OnlyCallFromDrop) {
|
||||
//! println!("{self:p} is getting dropped.");
|
||||
//! pr_info!("{self:p} is getting dropped.");
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
|
@ -449,18 +458,21 @@
|
|||
//! >(data, move |slot| {
|
||||
//! {
|
||||
//! struct __InitOk;
|
||||
//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).a), a) };
|
||||
//! let a = &unsafe {
|
||||
//! {
|
||||
//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).a), a) };
|
||||
//! }
|
||||
//! let a = unsafe {
|
||||
//! ::kernel::init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).a))
|
||||
//! };
|
||||
//! let b = Bar::new(36);
|
||||
//! let init = Bar::new(36);
|
||||
//! unsafe { data.b(::core::addr_of_mut!((*slot).b), b)? };
|
||||
//! let b = &unsafe {
|
||||
//! let b = unsafe {
|
||||
//! ::kernel::init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).b))
|
||||
//! };
|
||||
//!
|
||||
//! ::core::mem::forget(b);
|
||||
//! ::core::mem::forget(a);
|
||||
//! #[allow(unreachable_code, clippy::diverging_sub_expression)]
|
||||
//! if false {
|
||||
//! let _ = || {
|
||||
//! unsafe {
|
||||
//! ::core::ptr::write(
|
||||
//! slot,
|
||||
|
@ -470,13 +482,13 @@
|
|||
//! },
|
||||
//! );
|
||||
//! };
|
||||
//! }
|
||||
//! unsafe { ::kernel::init::__internal::DropGuard::forget(a) };
|
||||
//! unsafe { ::kernel::init::__internal::DropGuard::forget(b) };
|
||||
//! };
|
||||
//! }
|
||||
//! Ok(__InitOk)
|
||||
//! });
|
||||
//! let init = move |slot| -> ::core::result::Result<(), ::core::convert::Infallible> {
|
||||
//! let init = move |
|
||||
//! slot,
|
||||
//! | -> ::core::result::Result<(), ::core::convert::Infallible> {
|
||||
//! init(slot).map(|__InitOk| ())
|
||||
//! };
|
||||
//! let init = unsafe {
|
||||
|
|
Loading…
Reference in New Issue