diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
commit | 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch) | |
tree | a31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /third_party/rust/pin-project/src/lib.rs | |
parent | Initial commit. (diff) | |
download | firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip |
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/pin-project/src/lib.rs')
-rw-r--r-- | third_party/rust/pin-project/src/lib.rs | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/third_party/rust/pin-project/src/lib.rs b/third_party/rust/pin-project/src/lib.rs new file mode 100644 index 0000000000..5fa9298011 --- /dev/null +++ b/third_party/rust/pin-project/src/lib.rs @@ -0,0 +1,315 @@ +//! A crate for safe and ergonomic [pin-projection]. +//! +//! # Examples +//! +//! [`#[pin_project]`][`pin_project`] attribute creates projection types +//! covering all the fields of struct or enum. +//! +//! ```rust +//! use std::pin::Pin; +//! +//! use pin_project::pin_project; +//! +//! #[pin_project] +//! struct Struct<T, U> { +//! #[pin] +//! pinned: T, +//! unpinned: U, +//! } +//! +//! impl<T, U> Struct<T, U> { +//! fn method(self: Pin<&mut Self>) { +//! let this = self.project(); +//! let _: Pin<&mut T> = this.pinned; // Pinned reference to the field +//! let _: &mut U = this.unpinned; // Normal reference to the field +//! } +//! } +//! ``` +//! +//! [*code like this will be generated*][struct-default-expanded] +//! +//! To use `#[pin_project]` on enums, you need to name the projection type +//! returned from the method. +//! +//! ```rust +//! use std::pin::Pin; +//! +//! use pin_project::pin_project; +//! +//! #[pin_project(project = EnumProj)] +//! enum Enum<T, U> { +//! Pinned(#[pin] T), +//! Unpinned(U), +//! } +//! +//! impl<T, U> Enum<T, U> { +//! fn method(self: Pin<&mut Self>) { +//! match self.project() { +//! EnumProj::Pinned(x) => { +//! let _: Pin<&mut T> = x; +//! } +//! EnumProj::Unpinned(y) => { +//! let _: &mut U = y; +//! } +//! } +//! } +//! } +//! ``` +//! +//! [*code like this will be generated*][enum-default-expanded] +//! +//! See [`#[pin_project]`][`pin_project`] attribute for more details, and +//! see [examples] directory for more examples and generated code. +//! +//! [examples]: https://github.com/taiki-e/pin-project/blob/HEAD/examples/README.md +//! [enum-default-expanded]: https://github.com/taiki-e/pin-project/blob/HEAD/examples/enum-default-expanded.rs +//! [pin-projection]: core::pin#projections-and-structural-pinning +//! [struct-default-expanded]: https://github.com/taiki-e/pin-project/blob/HEAD/examples/struct-default-expanded.rs + +#![no_std] +#![doc(test( + no_crate_inject, + attr( + deny(warnings, rust_2018_idioms, single_use_lifetimes), + allow(dead_code, unused_variables) + ) +))] +#![warn(missing_docs, rust_2018_idioms, single_use_lifetimes, unreachable_pub)] +#![warn( + clippy::pedantic, + // lints for public library + clippy::alloc_instead_of_core, + clippy::exhaustive_enums, + clippy::exhaustive_structs, + clippy::std_instead_of_alloc, + clippy::std_instead_of_core, + // lints that help writing unsafe code + clippy::default_union_representation, + clippy::trailing_empty_array, + clippy::transmute_undefined_repr, + clippy::undocumented_unsafe_blocks, +)] +#![allow(clippy::needless_doctest_main)] + +#[doc(inline)] +pub use pin_project_internal::pin_project; +#[doc(inline)] +pub use pin_project_internal::pinned_drop; + +/// A trait used for custom implementations of [`Unpin`]. +/// +/// This trait is used in conjunction with the `UnsafeUnpin` argument to +/// the [`#[pin_project]`][macro@pin_project] attribute. +/// +/// # Safety +/// +/// The Rust [`Unpin`] trait is safe to implement - by itself, +/// implementing it cannot lead to [undefined behavior][undefined-behavior]. +/// Undefined behavior can only occur when other unsafe code is used. +/// +/// It turns out that using pin projections, which requires unsafe code, +/// imposes additional requirements on an [`Unpin`] impl. Normally, all of this +/// unsafety is contained within this crate, ensuring that it's impossible for +/// you to violate any of the guarantees required by pin projection. +/// +/// However, things change if you want to provide a custom [`Unpin`] impl +/// for your `#[pin_project]` type. As stated in [the Rust +/// documentation][pin-projection], you must be sure to only implement [`Unpin`] +/// when all of your `#[pin]` fields (i.e. structurally pinned fields) are also +/// [`Unpin`]. +/// +/// To help highlight this unsafety, the `UnsafeUnpin` trait is provided. +/// Implementing this trait is logically equivalent to implementing [`Unpin`] - +/// this crate will generate an [`Unpin`] impl for your type that 'forwards' to +/// your `UnsafeUnpin` impl. However, this trait is `unsafe` - since your type +/// uses structural pinning (otherwise, you wouldn't be using this crate!), +/// you must be sure that your `UnsafeUnpin` impls follows all of +/// the requirements for an [`Unpin`] impl of a structurally-pinned type. +/// +/// Note that if you specify `#[pin_project(UnsafeUnpin)]`, but do *not* +/// provide an impl of `UnsafeUnpin`, your type will never implement [`Unpin`]. +/// This is effectively the same thing as adding a [`PhantomPinned`] to your +/// type. +/// +/// Since this trait is `unsafe`, impls of it will be detected by the +/// `unsafe_code` lint, and by tools like [`cargo geiger`][cargo-geiger]. +/// +/// # Examples +/// +/// An `UnsafeUnpin` impl which, in addition to requiring that structurally +/// pinned fields be [`Unpin`], imposes an additional requirement: +/// +/// ```rust +/// use pin_project::{pin_project, UnsafeUnpin}; +/// +/// #[pin_project(UnsafeUnpin)] +/// struct Struct<K, V> { +/// #[pin] +/// field_1: K, +/// field_2: V, +/// } +/// +/// unsafe impl<K, V> UnsafeUnpin for Struct<K, V> where K: Unpin + Clone {} +/// ``` +/// +/// [`PhantomPinned`]: core::marker::PhantomPinned +/// [cargo-geiger]: https://github.com/rust-secure-code/cargo-geiger +/// [pin-projection]: core::pin#projections-and-structural-pinning +/// [undefined-behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html +pub unsafe trait UnsafeUnpin {} + +// Not public API. +#[doc(hidden)] +pub mod __private { + use core::mem::ManuallyDrop; + #[doc(hidden)] + pub use core::{ + marker::{PhantomData, PhantomPinned, Unpin}, + ops::Drop, + pin::Pin, + ptr, + }; + + #[doc(hidden)] + pub use pin_project_internal::__PinProjectInternalDerive; + + use super::UnsafeUnpin; + + // An internal trait used for custom implementations of [`Drop`]. + // + // **Do not call or implement this trait directly.** + // + // # Why this trait is private and `#[pinned_drop]` attribute is needed? + // + // Implementing `PinnedDrop::drop` is safe, but calling it is not safe. + // This is because destructors can be called multiple times in safe code and + // [double dropping is unsound][rust-lang/rust#62360]. + // + // Ideally, it would be desirable to be able to forbid manual calls in + // the same way as [`Drop::drop`], but the library cannot do it. So, by using + // macros and replacing them with private traits, + // this crate prevent users from calling `PinnedDrop::drop` in safe code. + // + // This allows implementing [`Drop`] safely using `#[pinned_drop]`. + // Also by using the [`drop`] function just like dropping a type that directly + // implements [`Drop`], can drop safely a type that implements `PinnedDrop`. + // + // [rust-lang/rust#62360]: https://github.com/rust-lang/rust/pull/62360 + #[doc(hidden)] + pub trait PinnedDrop { + #[doc(hidden)] + unsafe fn drop(self: Pin<&mut Self>); + } + + // This is an internal helper struct used by `pin-project-internal`. + // This allows us to force an error if the user tries to provide + // a regular `Unpin` impl when they specify the `UnsafeUnpin` argument. + // This is why we need Wrapper: + // + // Supposed we have the following code: + // + // ```rust + // #[pin_project(UnsafeUnpin)] + // struct MyStruct<T> { + // #[pin] field: T + // } + // + // impl<T> Unpin for MyStruct<T> where MyStruct<T>: UnsafeUnpin {} // generated by pin-project-internal + // impl<T> Unpin for MyStruct<T> where T: Copy // written by the user + // ``` + // + // We want this code to be rejected - the user is completely bypassing + // `UnsafeUnpin`, and providing an unsound Unpin impl in safe code! + // + // Unfortunately, the Rust compiler will accept the above code. + // Because MyStruct is declared in the same crate as the user-provided impl, + // the compiler will notice that `MyStruct<T>: UnsafeUnpin` never holds. + // + // The solution is to introduce the `Wrapper` struct, which is defined + // in the `pin-project` crate. + // + // We now have code that looks like this: + // + // ```rust + // impl<T> Unpin for MyStruct<T> where Wrapper<MyStruct<T>>: UnsafeUnpin {} // generated by pin-project-internal + // impl<T> Unpin for MyStruct<T> where T: Copy // written by the user + // ``` + // + // We also have `unsafe impl<T> UnsafeUnpin for Wrapper<T> where T: UnsafeUnpin {}` + // in the `pin-project` crate. + // + // Now, our generated impl has a bound involving a type defined in another + // crate - Wrapper. This will cause rust to conservatively assume that + // `Wrapper<MyStruct<T>>: UnsafeUnpin` holds, in the interest of preserving + // forwards compatibility (in case such an impl is added for Wrapper<T> in + // a new version of the crate). + // + // This will cause rust to reject any other `Unpin` impls for MyStruct<T>, + // since it will assume that our generated impl could potentially apply in + // any situation. + // + // This achieves the desired effect - when the user writes + // `#[pin_project(UnsafeUnpin)]`, the user must either provide no impl of + // `UnsafeUnpin` (which is equivalent to making the type never implement + // Unpin), or provide an impl of `UnsafeUnpin`. It is impossible for them to + // provide an impl of `Unpin` + #[doc(hidden)] + pub struct Wrapper<'a, T: ?Sized>(PhantomData<&'a ()>, T); + + // SAFETY: `T` implements UnsafeUnpin. + unsafe impl<T: ?Sized + UnsafeUnpin> UnsafeUnpin for Wrapper<'_, T> {} + + // This is an internal helper struct used by `pin-project-internal`. + // + // See https://github.com/taiki-e/pin-project/pull/53 for more details. + #[doc(hidden)] + pub struct AlwaysUnpin<'a, T>(PhantomData<&'a ()>, PhantomData<T>); + + impl<T> Unpin for AlwaysUnpin<'_, T> {} + + // This is an internal helper used to ensure a value is dropped. + #[doc(hidden)] + pub struct UnsafeDropInPlaceGuard<T: ?Sized>(*mut T); + + impl<T: ?Sized> UnsafeDropInPlaceGuard<T> { + #[doc(hidden)] + pub unsafe fn new(ptr: *mut T) -> Self { + Self(ptr) + } + } + + impl<T: ?Sized> Drop for UnsafeDropInPlaceGuard<T> { + fn drop(&mut self) { + // SAFETY: the caller of `UnsafeDropInPlaceGuard::new` must guarantee + // that `ptr` is valid for drop when this guard is destructed. + unsafe { + ptr::drop_in_place(self.0); + } + } + } + + // This is an internal helper used to ensure a value is overwritten without + // its destructor being called. + #[doc(hidden)] + pub struct UnsafeOverwriteGuard<T> { + target: *mut T, + value: ManuallyDrop<T>, + } + + impl<T> UnsafeOverwriteGuard<T> { + #[doc(hidden)] + pub unsafe fn new(target: *mut T, value: T) -> Self { + Self { target, value: ManuallyDrop::new(value) } + } + } + + impl<T> Drop for UnsafeOverwriteGuard<T> { + fn drop(&mut self) { + // SAFETY: the caller of `UnsafeOverwriteGuard::new` must guarantee + // that `target` is valid for writes when this guard is destructed. + unsafe { + ptr::write(self.target, ptr::read(&*self.value)); + } + } + } +} |