diff --git a/src/lib.rs b/src/lib.rs index bf1a0a5..224a8e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,13 @@ #![doc = include_str!("../README.md")] +// Uses unstable features for `docs.rs`. +// This is okay, `docs.rs` uses a nightly compiler, and doesn't need to re-build documentation later. +// To avoid broken `docs.rs` pages with new uploads, before publishing a new version to `crates.io`, +// always check if `cargo docs-rs` (https://crates.io/crates/cargo-docs-rs) still works, +// (with `rustup override set nightly` set locally to a current nightly). #![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(clone_to_uninit))] #![no_std] @@ -38,16 +44,25 @@ pub mod features { //! Enables usage of the `alloc` crate, and a public dependency on //! [`stable_deref_trait`] at version `1.*` //! - #![cfg_attr(not(feature = "alloc"), doc = "Enables the `MutCursorVec` and `MutCursorRootedVec` APIs.")] - #![cfg_attr(feature = "alloc", doc = "Enables the [`MutCursorVec`] and [`MutCursorRootedVec`] APIs.")] + #![cfg_attr(not(feature = "alloc"), doc = "Enables the `MutCursorVec` and `MutCursorRootedVec` APIs,")] + #![cfg_attr(not(feature = "alloc"), doc = "as well as the `unique` module.")] + #![cfg_attr(feature = "alloc", doc = "Enables the [`MutCursorVec`] and [`MutCursorRootedVec`] APIs,")] + #![cfg_attr(feature = "alloc", doc = "as well as the [`unique`](crate::unique) module.")] //! ## `std` //! Enables `std` support for [`StableDeref`], so you use std-only stable pointers //! without needing to depend on [`stable_deref_trait`] yourself. //! + //! Also extends our re-implementation of [`CloneToUninit`] (used for [`make_unique`] in the + //! `unique` module) to support `std`-only types (`OsStr`, `Path`). + //! #![cfg_attr(feature = "alloc", doc = "[`stable_deref_trait`]: stable_deref_trait")] #![cfg_attr(feature = "alloc", doc = "[`StableDeref`]: stable_deref_trait::StableDeref")] + #![cfg_attr(feature = "alloc", doc = "[`make_unique`]: crate::unique::UniqueExt::make_unique")] + #![cfg_attr(docsrs, doc = "[`CloneToUninit`]: std::clone::CloneToUninit")] //! [`stable_deref_trait`]: https://docs.rs/stable_deref_trait/1/stable_deref_trait/ //! [`StableDeref`]: https://docs.rs/stable_deref_trait/1/stable_deref_trait/trait.StableDeref.html + //! [`make_unique`]: #alloc + //! [`CloneToUninit`]: https://doc.rust-lang.org/nightly/std/clone/trait.CloneToUninit.html use super::*; } @@ -61,6 +76,11 @@ mod mut_cursor_vec; #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] pub use mut_cursor_vec::*; + +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +pub mod unique; + #[cfg(feature = "alloc")] mod rooted_vec; #[cfg(feature = "alloc")] diff --git a/src/unique.rs b/src/unique.rs new file mode 100644 index 0000000..393ee04 --- /dev/null +++ b/src/unique.rs @@ -0,0 +1,192 @@ +//! Tools for using [`Rc`] and [`Arc`] to prove a stably-dereferencing level +//! of indirection in [`MutCursorRootedVec`](super::MutCursorRootedVec)'s API. +//! +//! While `Rc` and `Arc` are generally only offering *shared, immutable* access +//! to their interior, while [`MutCursorRootedVec`](super::MutCursorRootedVec) works +//! with *mutable* access, the standard library *does* offer a limited mutable-access +//! API in the form of the {[Arc](Arc::get_mut), [Rc](Rc::get_mut)}::get_mut +//! and {[Arc](Arc::make_mut), [Rc](Rc::make_mut)}::make_mut methods. +//! +//! These methods succeed when the reference-counted pointer is *unique*; in this +//! module, we provide an API to encode this uniqueness property into a separate type +//! which can fit the [DerefMut] + [StableDeref] +//! interface. + +mod polyfill { + use core::ffi::CStr; + + #[cfg(feature = "std")] + use std::{ffi::OsStr, path::Path}; + + use alloc::{rc::Rc, sync::Arc}; + /// Polyfill for unstable `CloneToUninit` in `std`. + /// + /// # SAFETY + /// the `_make_mut` implementation must ensure uniqueness; + /// after the method call without panicking, mutable access through`::as_ptr()` + /// must be sound, as long as the Rc/Arc is not cloned or otherwise shared. + pub unsafe trait CloneToUninit { + fn rc_make_mut(rc: &mut Rc); + fn arc_make_mut(rc: &mut Arc); + } + + macro_rules! impl_ { + ($($({$($t:tt)*})? $Self:ty)*) => {$( + unsafe impl$(<$($t)*>)? CloneToUninit for $Self { + fn rc_make_mut(rc: &mut Rc) { + Rc::make_mut(rc); + } + fn arc_make_mut(rc: &mut Arc) { + Arc::make_mut(rc); + } + } + )*}; + } + impl_! { + str CStr + {T: Clone} [T] + {T: Clone} T + } + #[cfg(feature = "std")] + impl_! { + OsStr Path + } +} +#[cfg(docsrs)] +use core::clone::CloneToUninit; +// Use the *real* `CloneToUninit` for `docs.rs`, to make the `T: CloneToUninit` bounds below +// easier to understand for users (because this way the link becomes clickable). +#[cfg(not(docsrs))] +use polyfill::CloneToUninit; + +use alloc::{rc::Rc, sync::Arc}; +use stable_deref_trait::StableDeref; +use core::{ + ops::{Deref, DerefMut}, + panic::{RefUnwindSafe, UnwindSafe}, +}; + +/// Extension trait for creating [`UniqueRc`]/[`UniqueArc`] +/// +/// Take a look at the implementations below, to see the concrete type signatures +/// of these methods [for `Rc`](#impl-UniqueExt-for-Rc) and [for `Arc`](#impl-UniqueExt-for-Arc), respectively. +pub trait UniqueExt: Deref { + type Unique; + /// This function behaves like [`Rc::get_mut`]/[`Arc::get_mut`], but returns + /// a reference that keeps the double-indirection necessary + /// for use with [`MutCursorRootedVec`](super::MutCursorRootedVec). + fn get_unique(this: &mut Self) -> Option<&mut Self::Unique>; + /// This function behaves like [`Rc::make_mut`]/[`Arc::make_mut`], but returns + /// a reference that keeps the double-indirection necessary + /// for use with [`MutCursorRootedVec`](super::MutCursorRootedVec). + fn make_unique(this: &mut Self) -> &mut Self::Unique + where + Self::Target: CloneToUninit; +} + +impl UniqueExt for Rc { + type Unique = UniqueRc; + + /// This function behaves like [`Rc::get_mut`], but returns + /// a reference that keeps the double-indirection necessary + /// for use with [`MutCursorRootedVec`](super::MutCursorRootedVec). + fn get_unique(this: &mut Self) -> Option<&mut UniqueRc> { + Rc::get_mut(this) + .is_some() + .then(|| unsafe { &mut *(this as *mut Rc as *mut UniqueRc) }) + } + + /// This function behaves like [`Rc::make_mut`], but returns + /// a reference that keeps the double-indirection necessary + /// for use with [`MutCursorRootedVec`](super::MutCursorRootedVec). + fn make_unique(this: &mut Self) -> &mut UniqueRc + where + T: CloneToUninit, + { + #[cfg(not(docsrs))] + T::rc_make_mut(this); + #[cfg(docsrs)] + Rc::make_mut(this); + unsafe { &mut *(this as *mut Rc as *mut UniqueRc) } + } +} + +impl UniqueExt for Arc { + type Unique = UniqueArc; + + /// This function behaves like [`Arc::get_mut`], but returns + /// a reference that keeps the double-indirection necessary + /// for use with [`MutCursorRootedVec`](super::MutCursorRootedVec). + fn get_unique(this: &mut Self) -> Option<&mut UniqueArc> { + Arc::get_mut(this) + .is_some() + .then(|| unsafe { &mut *(this as *mut Arc as *mut UniqueArc) }) + } + + /// This function behaves like [`Arc::make_mut`], but returns + /// a reference that keeps the double-indirection necessary + /// for use with [`MutCursorRootedVec`](super::MutCursorRootedVec). + fn make_unique(this: &mut Self) -> &mut UniqueArc + where + T: CloneToUninit, + { + #[cfg(not(docsrs))] + T::arc_make_mut(this); + #[cfg(docsrs)] + Arc::make_mut(this); + unsafe { &mut *(this as *mut Arc as *mut UniqueArc) } + } +} + +#[repr(transparent)] +pub struct UniqueRc(Rc); + +#[repr(transparent)] +pub struct UniqueArc(Arc); + +// adjust trait impls to match uniquely owned reference (compare e.g. `Box`) + +impl UnwindSafe for UniqueRc where T: UnwindSafe {} +impl RefUnwindSafe for UniqueRc where T: RefUnwindSafe {} + +impl UnwindSafe for UniqueArc where T: UnwindSafe {} +impl RefUnwindSafe for UniqueArc where T: RefUnwindSafe {} + +// yes, uniquely-owned Rc is completely thread-safe, too +unsafe impl Send for UniqueRc where T: Send {} +unsafe impl Sync for UniqueRc where T: Sync {} + +unsafe impl Send for UniqueArc where T: Send {} +unsafe impl Sync for UniqueArc where T: Sync {} + +impl Deref for UniqueRc { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &*Rc::as_ptr(&self.0) } + } +} + +impl DerefMut for UniqueRc { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *(Rc::as_ptr(&self.0) as *mut T) } + } +} + +unsafe impl StableDeref for UniqueRc {} + +impl Deref for UniqueArc { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &*Arc::as_ptr(&self.0) } + } +} + +impl DerefMut for UniqueArc { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *(Arc::as_ptr(&self.0) as *mut T) } + } +} + +unsafe impl StableDeref for UniqueArc {}