Skip to content

Commit 418ff77

Browse files
Merge pull request #6 from steffahn/unique_arc
add unique-(a)rc APIs
2 parents dfe7704 + a3b2807 commit 418ff77

File tree

2 files changed

+214
-2
lines changed

2 files changed

+214
-2
lines changed

src/lib.rs

+22-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,13 @@
1717
1818
#![doc = include_str!("../README.md")]
1919

20+
// Uses unstable features for `docs.rs`.
21+
// This is okay, `docs.rs` uses a nightly compiler, and doesn't need to re-build documentation later.
22+
// To avoid broken `docs.rs` pages with new uploads, before publishing a new version to `crates.io`,
23+
// always check if `cargo docs-rs` (https://crates.io/crates/cargo-docs-rs) still works,
24+
// (with `rustup override set nightly` set locally to a current nightly).
2025
#![cfg_attr(docsrs, feature(doc_cfg))]
26+
#![cfg_attr(docsrs, feature(clone_to_uninit))]
2127

2228
#![no_std]
2329

@@ -38,16 +44,25 @@ pub mod features {
3844
//! Enables usage of the `alloc` crate, and a public dependency on
3945
//! [`stable_deref_trait`] at version `1.*`
4046
//!
41-
#![cfg_attr(not(feature = "alloc"), doc = "Enables the `MutCursorVec` and `MutCursorRootedVec` APIs.")]
42-
#![cfg_attr(feature = "alloc", doc = "Enables the [`MutCursorVec`] and [`MutCursorRootedVec`] APIs.")]
47+
#![cfg_attr(not(feature = "alloc"), doc = "Enables the `MutCursorVec` and `MutCursorRootedVec` APIs,")]
48+
#![cfg_attr(not(feature = "alloc"), doc = "as well as the `unique` module.")]
49+
#![cfg_attr(feature = "alloc", doc = "Enables the [`MutCursorVec`] and [`MutCursorRootedVec`] APIs,")]
50+
#![cfg_attr(feature = "alloc", doc = "as well as the [`unique`](crate::unique) module.")]
4351
//! ## `std`
4452
//! Enables `std` support for [`StableDeref`], so you use std-only stable pointers
4553
//! without needing to depend on [`stable_deref_trait`] yourself.
4654
//!
55+
//! Also extends our re-implementation of [`CloneToUninit`] (used for [`make_unique`] in the
56+
//! `unique` module) to support `std`-only types (`OsStr`, `Path`).
57+
//!
4758
#![cfg_attr(feature = "alloc", doc = "[`stable_deref_trait`]: stable_deref_trait")]
4859
#![cfg_attr(feature = "alloc", doc = "[`StableDeref`]: stable_deref_trait::StableDeref")]
60+
#![cfg_attr(feature = "alloc", doc = "[`make_unique`]: crate::unique::UniqueExt::make_unique")]
61+
#![cfg_attr(docsrs, doc = "[`CloneToUninit`]: std::clone::CloneToUninit")]
4962
//! [`stable_deref_trait`]: https://docs.rs/stable_deref_trait/1/stable_deref_trait/
5063
//! [`StableDeref`]: https://docs.rs/stable_deref_trait/1/stable_deref_trait/trait.StableDeref.html
64+
//! [`make_unique`]: #alloc
65+
//! [`CloneToUninit`]: https://doc.rust-lang.org/nightly/std/clone/trait.CloneToUninit.html
5166
use super::*;
5267
}
5368

@@ -61,6 +76,11 @@ mod mut_cursor_vec;
6176
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
6277
pub use mut_cursor_vec::*;
6378

79+
80+
#[cfg(feature = "alloc")]
81+
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
82+
pub mod unique;
83+
6484
#[cfg(feature = "alloc")]
6585
mod rooted_vec;
6686
#[cfg(feature = "alloc")]

src/unique.rs

+192
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
//! Tools for using [`Rc`] and [`Arc`] to prove a stably-dereferencing level
2+
//! of indirection in [`MutCursorRootedVec`](super::MutCursorRootedVec)'s API.
3+
//!
4+
//! While `Rc` and `Arc` are generally only offering *shared, immutable* access
5+
//! to their interior, while [`MutCursorRootedVec`](super::MutCursorRootedVec) works
6+
//! with *mutable* access, the standard library *does* offer a limited mutable-access
7+
//! API in the form of the <code>{[Arc](Arc::get_mut), [Rc](Rc::get_mut)}::get_mut</code>
8+
//! and <code>{[Arc](Arc::make_mut), [Rc](Rc::make_mut)}::make_mut</code> methods.
9+
//!
10+
//! These methods succeed when the reference-counted pointer is *unique*; in this
11+
//! module, we provide an API to encode this uniqueness property into a separate type
12+
//! which can fit the <code>[DerefMut] + [StableDeref]</code>
13+
//! interface.
14+
15+
mod polyfill {
16+
use core::ffi::CStr;
17+
18+
#[cfg(feature = "std")]
19+
use std::{ffi::OsStr, path::Path};
20+
21+
use alloc::{rc::Rc, sync::Arc};
22+
/// Polyfill for unstable `CloneToUninit` in `std`.
23+
///
24+
/// # SAFETY
25+
/// the `_make_mut` implementation must ensure uniqueness;
26+
/// after the method call without panicking, mutable access through`::as_ptr()`
27+
/// must be sound, as long as the Rc/Arc is not cloned or otherwise shared.
28+
pub unsafe trait CloneToUninit {
29+
fn rc_make_mut(rc: &mut Rc<Self>);
30+
fn arc_make_mut(rc: &mut Arc<Self>);
31+
}
32+
33+
macro_rules! impl_ {
34+
($($({$($t:tt)*})? $Self:ty)*) => {$(
35+
unsafe impl$(<$($t)*>)? CloneToUninit for $Self {
36+
fn rc_make_mut(rc: &mut Rc<Self>) {
37+
Rc::make_mut(rc);
38+
}
39+
fn arc_make_mut(rc: &mut Arc<Self>) {
40+
Arc::make_mut(rc);
41+
}
42+
}
43+
)*};
44+
}
45+
impl_! {
46+
str CStr
47+
{T: Clone} [T]
48+
{T: Clone} T
49+
}
50+
#[cfg(feature = "std")]
51+
impl_! {
52+
OsStr Path
53+
}
54+
}
55+
#[cfg(docsrs)]
56+
use core::clone::CloneToUninit;
57+
// Use the *real* `CloneToUninit` for `docs.rs`, to make the `T: CloneToUninit` bounds below
58+
// easier to understand for users (because this way the link becomes clickable).
59+
#[cfg(not(docsrs))]
60+
use polyfill::CloneToUninit;
61+
62+
use alloc::{rc::Rc, sync::Arc};
63+
use stable_deref_trait::StableDeref;
64+
use core::{
65+
ops::{Deref, DerefMut},
66+
panic::{RefUnwindSafe, UnwindSafe},
67+
};
68+
69+
/// Extension trait for creating [`UniqueRc`]/[`UniqueArc`]
70+
///
71+
/// Take a look at the implementations below, to see the concrete type signatures
72+
/// of these methods [for `Rc`](#impl-UniqueExt-for-Rc<T>) and [for `Arc`](#impl-UniqueExt-for-Arc<T>), respectively.
73+
pub trait UniqueExt: Deref {
74+
type Unique;
75+
/// This function behaves like [`Rc::get_mut`]/[`Arc::get_mut`], but returns
76+
/// a reference that keeps the double-indirection necessary
77+
/// for use with [`MutCursorRootedVec`](super::MutCursorRootedVec).
78+
fn get_unique(this: &mut Self) -> Option<&mut Self::Unique>;
79+
/// This function behaves like [`Rc::make_mut`]/[`Arc::make_mut`], but returns
80+
/// a reference that keeps the double-indirection necessary
81+
/// for use with [`MutCursorRootedVec`](super::MutCursorRootedVec).
82+
fn make_unique(this: &mut Self) -> &mut Self::Unique
83+
where
84+
Self::Target: CloneToUninit;
85+
}
86+
87+
impl<T: ?Sized> UniqueExt for Rc<T> {
88+
type Unique = UniqueRc<T>;
89+
90+
/// This function behaves like [`Rc::get_mut`], but returns
91+
/// a reference that keeps the double-indirection necessary
92+
/// for use with [`MutCursorRootedVec`](super::MutCursorRootedVec).
93+
fn get_unique(this: &mut Self) -> Option<&mut UniqueRc<T>> {
94+
Rc::get_mut(this)
95+
.is_some()
96+
.then(|| unsafe { &mut *(this as *mut Rc<T> as *mut UniqueRc<T>) })
97+
}
98+
99+
/// This function behaves like [`Rc::make_mut`], but returns
100+
/// a reference that keeps the double-indirection necessary
101+
/// for use with [`MutCursorRootedVec`](super::MutCursorRootedVec).
102+
fn make_unique(this: &mut Self) -> &mut UniqueRc<T>
103+
where
104+
T: CloneToUninit,
105+
{
106+
#[cfg(not(docsrs))]
107+
T::rc_make_mut(this);
108+
#[cfg(docsrs)]
109+
Rc::make_mut(this);
110+
unsafe { &mut *(this as *mut Rc<T> as *mut UniqueRc<T>) }
111+
}
112+
}
113+
114+
impl<T: ?Sized> UniqueExt for Arc<T> {
115+
type Unique = UniqueArc<T>;
116+
117+
/// This function behaves like [`Arc::get_mut`], but returns
118+
/// a reference that keeps the double-indirection necessary
119+
/// for use with [`MutCursorRootedVec`](super::MutCursorRootedVec).
120+
fn get_unique(this: &mut Self) -> Option<&mut UniqueArc<T>> {
121+
Arc::get_mut(this)
122+
.is_some()
123+
.then(|| unsafe { &mut *(this as *mut Arc<T> as *mut UniqueArc<T>) })
124+
}
125+
126+
/// This function behaves like [`Arc::make_mut`], but returns
127+
/// a reference that keeps the double-indirection necessary
128+
/// for use with [`MutCursorRootedVec`](super::MutCursorRootedVec).
129+
fn make_unique(this: &mut Self) -> &mut UniqueArc<T>
130+
where
131+
T: CloneToUninit,
132+
{
133+
#[cfg(not(docsrs))]
134+
T::arc_make_mut(this);
135+
#[cfg(docsrs)]
136+
Arc::make_mut(this);
137+
unsafe { &mut *(this as *mut Arc<T> as *mut UniqueArc<T>) }
138+
}
139+
}
140+
141+
#[repr(transparent)]
142+
pub struct UniqueRc<T: ?Sized>(Rc<T>);
143+
144+
#[repr(transparent)]
145+
pub struct UniqueArc<T: ?Sized>(Arc<T>);
146+
147+
// adjust trait impls to match uniquely owned reference (compare e.g. `Box<T>`)
148+
149+
impl<T: ?Sized> UnwindSafe for UniqueRc<T> where T: UnwindSafe {}
150+
impl<T: ?Sized> RefUnwindSafe for UniqueRc<T> where T: RefUnwindSafe {}
151+
152+
impl<T: ?Sized> UnwindSafe for UniqueArc<T> where T: UnwindSafe {}
153+
impl<T: ?Sized> RefUnwindSafe for UniqueArc<T> where T: RefUnwindSafe {}
154+
155+
// yes, uniquely-owned Rc is completely thread-safe, too
156+
unsafe impl<T: ?Sized> Send for UniqueRc<T> where T: Send {}
157+
unsafe impl<T: ?Sized> Sync for UniqueRc<T> where T: Sync {}
158+
159+
unsafe impl<T: ?Sized> Send for UniqueArc<T> where T: Send {}
160+
unsafe impl<T: ?Sized> Sync for UniqueArc<T> where T: Sync {}
161+
162+
impl<T: ?Sized> Deref for UniqueRc<T> {
163+
type Target = T;
164+
165+
fn deref(&self) -> &T {
166+
unsafe { &*Rc::as_ptr(&self.0) }
167+
}
168+
}
169+
170+
impl<T: ?Sized> DerefMut for UniqueRc<T> {
171+
fn deref_mut(&mut self) -> &mut T {
172+
unsafe { &mut *(Rc::as_ptr(&self.0) as *mut T) }
173+
}
174+
}
175+
176+
unsafe impl<T: ?Sized> StableDeref for UniqueRc<T> {}
177+
178+
impl<T: ?Sized> Deref for UniqueArc<T> {
179+
type Target = T;
180+
181+
fn deref(&self) -> &T {
182+
unsafe { &*Arc::as_ptr(&self.0) }
183+
}
184+
}
185+
186+
impl<T: ?Sized> DerefMut for UniqueArc<T> {
187+
fn deref_mut(&mut self) -> &mut T {
188+
unsafe { &mut *(Arc::as_ptr(&self.0) as *mut T) }
189+
}
190+
}
191+
192+
unsafe impl<T: ?Sized> StableDeref for UniqueArc<T> {}

0 commit comments

Comments
 (0)