rust: init: add assert_pinned macro

Add a macro to statically check if a field of a struct is marked with
`#[pin]` ie that it is structurally pinned. This can be used when
`unsafe` code needs to rely on fields being structurally pinned.

The macro has a special "inline" mode for the case where the type
depends on generic parameters from the surrounding scope.

Signed-off-by: Benno Lossin <benno.lossin@proton.me>
Co-developed-by: Alice Ryhl <aliceryhl@google.com>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20240814-linked-list-v5-1-f5f5e8075da0@google.com
[ Replaced `compile_fail` with `ignore` and a TODO note. Removed
  `pub` from example to clean `unreachable_pub` lint. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
Benno Lossin
2024-08-14 08:05:20 +00:00
committed by Miguel Ojeda
parent c6945acad7
commit 0528ca0a4f
2 changed files with 97 additions and 0 deletions
+29
View File
@@ -228,3 +228,32 @@ impl OnlyCallFromDrop {
Self(())
}
}
/// Initializer that always fails.
///
/// Used by [`assert_pinned!`].
///
/// [`assert_pinned!`]: crate::assert_pinned
pub struct AlwaysFail<T: ?Sized> {
_t: PhantomData<T>,
}
impl<T: ?Sized> AlwaysFail<T> {
/// Creates a new initializer that always fails.
pub fn new() -> Self {
Self { _t: PhantomData }
}
}
impl<T: ?Sized> Default for AlwaysFail<T> {
fn default() -> Self {
Self::new()
}
}
// SAFETY: `__pinned_init` always fails, which is always okay.
unsafe impl<T: ?Sized> PinInit<T, ()> for AlwaysFail<T> {
unsafe fn __pinned_init(self, _slot: *mut T) -> Result<(), ()> {
Err(())
}
}