Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- `Wrapper<T>` trait added for creating wrapper structs with a structurally pinned value.

### Changed

- `InPlaceInit` now only exists when the `alloc` or `std` features are enabled
Expand Down
7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pin-init-internal = { path = "./internal", version = "=0.0.5" }
default = ["std", "alloc"]
std = []
alloc = []
unsafe-pinned = []

[build-dependencies]
rustc_version = "0.4"
Expand All @@ -34,7 +35,11 @@ prettyplease = { version = "0.2", features = ["verbatim"] }

[lints.rust]
non_ascii_idents = "deny"
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(NO_UI_TESTS)', 'cfg(NO_ALLOC_FAIL_TESTS)', 'cfg(kernel)'] }
unexpected_cfgs = { level = "warn", check-cfg = [
'cfg(NO_UI_TESTS)',
'cfg(NO_ALLOC_FAIL_TESTS)',
'cfg(kernel)',
] }
Comment thread
onestacked marked this conversation as resolved.
unsafe_op_in_unsafe_fn = "deny"
unused_attributes = "deny"
warnings = "deny"
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ However, using the crate on stable compilers is possible by disabling `alloc`. I
will require the `std` feature, because stable compilers have neither `Box` nor `Arc` in no-std
mode.

### Nightly needed for `unsafe-pinned` feature

This feature enables the `Wrapper` implementation on the unstable `core::pin::UnsafePinned` type.
This requires the [`unsafe_pinned` unstable feature](https://github.com/rust-lang/rust/issues/125735)
and therefore a nightly compiler. Note that this feature is not enabled by default.

## Overview

To initialize a `struct` with an in-place constructor you will need two things:
Expand Down Expand Up @@ -216,7 +222,7 @@ the `kernel` crate. The [`sync`] module is a good starting point.

[`sync`]: https://rust.docs.kernel.org/kernel/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
[structurally pinned fields]: https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning
[stack]: https://docs.rs/pin-init/latest/pin_init/macro.stack_pin_init.html
[`impl PinInit<Foo>`]: https://docs.rs/pin-init/latest/pin_init/trait.PinInit.html
[`impl PinInit<T, E>`]: https://docs.rs/pin-init/latest/pin_init/trait.PinInit.html
Expand Down
4 changes: 4 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use rustc_version::{version, Version};
fn main() {
println!("cargo::rustc-check-cfg=cfg(RUSTC_LINT_REASONS_IS_STABLE)");
println!("cargo::rustc-check-cfg=cfg(RUSTC_NEW_UNINIT_IS_STABLE)");
println!("cargo::rustc-check-cfg=cfg(CONFIG_RUSTC_HAS_UNSAFE_PINNED)");
if version().unwrap() >= Version::parse("1.81.0").unwrap()
|| version().unwrap() >= Version::parse("1.81.0-nightly").unwrap()
{
Expand All @@ -11,4 +12,7 @@ fn main() {
if version().unwrap() >= Version::parse("1.82.0").unwrap() {
println!("cargo:rustc-cfg=RUSTC_NEW_UNINIT_IS_STABLE");
}
if version().unwrap() >= Version::parse("1.88.0-nightly").unwrap() {
Comment thread
onestacked marked this conversation as resolved.
println!("cargo:rustc-cfg=CONFIG_RUSTC_HAS_UNSAFE_PINNED");
}
}
64 changes: 63 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
//! will require the `std` feature, because stable compilers have neither `Box` nor `Arc` in no-std
//! mode.
//!
//! ## Nightly needed for `unsafe-pinned` feature
//!
//! This feature enables the `Wrapper` implementation on the unstable `core::pin::UnsafePinned` type.
//! This requires the [`unsafe_pinned` unstable feature](https://github.com/rust-lang/rust/issues/125735)
//! and therefore a nightly compiler. Note that this feature is not enabled by default.
//!
//! # Overview
//!
//! To initialize a `struct` with an in-place constructor you will need two things:
Expand Down Expand Up @@ -241,7 +247,7 @@
//! [`sync`]: https://rust.docs.kernel.org/kernel/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
//! https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning
//! [stack]: crate::stack_pin_init
#![cfg_attr(
kernel,
Expand Down Expand Up @@ -269,6 +275,10 @@
#![forbid(missing_docs, unsafe_op_in_unsafe_fn)]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(feature = "alloc", feature(allocator_api))]
#![cfg_attr(
all(feature = "unsafe-pinned", CONFIG_RUSTC_HAS_UNSAFE_PINNED),
feature(unsafe_pinned)
)]

use core::{
cell::UnsafeCell,
Expand Down Expand Up @@ -1513,3 +1523,55 @@ macro_rules! impl_tuple_zeroable {
}

impl_tuple_zeroable!(A, B, C, D, E, F, G, H, I, J);

/// This trait allows creating an instance of `Self` which contains exactly one
/// [structurally pinned value](https://doc.rust-lang.org/std/pin/index.html#projections-and-structural-pinning).
///
/// This is useful when using wrapper `struct`s like [`UnsafeCell`] or with new-type `struct`s.
///
Comment thread
onestacked marked this conversation as resolved.
/// # Examples
///
/// ```
/// # use core::cell::UnsafeCell;
/// # use pin_init::{pin_data, pin_init, Wrapper};
///
/// #[pin_data]
/// struct Foo {}
///
/// #[pin_data]
/// struct Bar {
/// #[pin]
/// content: UnsafeCell<Foo>
/// };
///
/// let foo_initializer = pin_init!(Foo{});
/// let initializer = pin_init!(Bar {
/// content <- UnsafeCell::pin_init(foo_initializer)
/// });
/// ```
pub trait Wrapper<T> {
/// Create an pin-initializer for a [`Self`] containing `T` form the `value_init` initializer.
fn pin_init<E>(value_init: impl PinInit<T, E>) -> impl PinInit<Self, E>;
}

impl<T> Wrapper<T> for UnsafeCell<T> {
fn pin_init<E>(value_init: impl PinInit<T, E>) -> impl PinInit<Self, E> {
// SAFETY: `UnsafeCell<T>` has a compatible layout to `T`.
unsafe { cast_pin_init(value_init) }
}
}

impl<T> Wrapper<T> for MaybeUninit<T> {
fn pin_init<E>(value_init: impl PinInit<T, E>) -> impl PinInit<Self, E> {
// SAFETY: `MaybeUninit<T>` has a compatible layout to `T`.
unsafe { cast_pin_init(value_init) }
}
}

#[cfg(all(feature = "unsafe-pinned", CONFIG_RUSTC_HAS_UNSAFE_PINNED))]
impl<T> Wrapper<T> for core::pin::UnsafePinned<T> {
fn pin_init<E>(init: impl PinInit<T, E>) -> impl PinInit<Self, E> {
// SAFETY: `UnsafePinned<T>` has a compatible layout to `T`.
unsafe { cast_pin_init(init) }
}
}