Skip to main content

rcuninit/
lib.rs

1//! Defines `RcUninit`, an `Rc` with deferred initialization.
2//!
3//! [RcUninit] solves two problems with [Rc::new_cyclic], namely:
4//!
5//! 1. Inability to use across await points - `new_cyclic` takes a closure that
6//!    is not async.
7//! 2. Instantiation of complex cyclic structures is cumbersome and has a high
8//!    mental overhead.
9//!
10//! # Examples #
11//!
12//! ```
13//! use rcuninit::RcUninit;
14//! use std::rc::Rc;
15//!
16//! // Must be called at least once per program invocation.
17//! unsafe {
18//!     rcuninit::check_sanity();
19//! }
20//!
21//! let rcuninit = RcUninit::new();
22//!
23//! // Acquire a weak pointer.
24//! let weak = rcuninit.weak();
25//!
26//! assert!(weak.upgrade().is_none());
27//!
28//! // Now initialize, returns an Rc and makes associated Weaks upgradable.
29//! let strong = rcuninit.init(String::from("lorem ipsum"));
30//!
31//! assert_eq!(*weak.upgrade().unwrap(), "lorem ipsum");
32//! assert!(Rc::ptr_eq(&strong, &weak.upgrade().unwrap()));
33//! ```
34//!
35//! Here's an example of initialization across an `await` point. This is not
36//! possible with `Rc::new_cyclic`.
37//!
38//! ```
39//! use rcuninit::RcUninit;
40//! use std::{future::poll_fn, rc::Rc, task::Poll};
41//!
42//! async fn f() {
43//!     let rcuninit = RcUninit::new();
44//!     let weak = rcuninit.weak();
45//!
46//!     poll_fn(|_| Poll::Ready(())).await;
47//!
48//!     let strong = rcuninit.init(String::from("lorem ipsum"));
49//!     assert_eq!(*weak.upgrade().unwrap(), "lorem ipsum");
50//! }
51//! ```
52//!
53//! # Complex Cyclic Structures #
54//!
55//! The other issue mentioned regarding `Rc::new_cyclic` is its cumbersome
56//! nature when attempting to declare complex cyclic structures. Suppose we want
57//! to construct a structure `A => B => C -> A`, where `=>` and `->` denote a
58//! strong and weak pointer, respectively. The following two examples show the
59//! difference between [RcUninit] and [Rc::new_cyclic].
60//!
61//! ```
62//! use rcuninit::RcUninit;
63//! use std::rc::{Rc, Weak};
64//!
65//! unsafe {
66//!     rcuninit::check_sanity();
67//! }
68//!
69//! let a_un = RcUninit::new();
70//! let b_un = RcUninit::new();
71//! let c_un = RcUninit::new();
72//!
73//! let c = c_un.init(C { a: a_un.weak() });
74//! let b = b_un.init(B { c });
75//! let a = a_un.init(A { b });
76//!
77//! assert!(Rc::ptr_eq(&a.b.c.a.upgrade().unwrap(), &a));
78//!
79//! struct A {
80//!     b: Rc<B>,
81//! }
82//! struct B {
83//!     c: Rc<C>,
84//! }
85//! struct C {
86//!     a: Weak<A>,
87//! }
88//! ```
89//!
90//! Now compare this to the construction of the same structure using
91//! `Rc::new_cyclic`. Structure definitions hidden for brevity, but they are
92//! identical as above.
93//!
94//! ```
95//! use std::rc::{Rc, Weak};
96//!
97//! let mut b: Option<Rc<B>> = None;
98//! let mut c: Option<Rc<C>> = None;
99//!
100//! let a = Rc::new_cyclic(|a_weak| {
101//!     let b_rc = Rc::new_cyclic(|b_weak| {
102//!         let c_rc = Rc::new(C { a: a_weak.clone() });
103//!         c = Some(c_rc.clone());
104//!         B { c: c_rc }
105//!     });
106//!
107//!     b = Some(b_rc.clone());
108//!     A { b: b_rc }
109//! });
110//!
111//! let b = b.unwrap();
112//! let c = c.unwrap();
113//!
114//! assert!(Rc::ptr_eq(&a.b.c.a.upgrade().unwrap(), &a));
115//!
116//! # struct A { b: Rc<B> }
117//! # struct B { c: Rc<C> }
118//! # struct C { a: Weak<A> }
119//! ```
120//!
121//! Note that we store `a`, `b`, and `c` into variables because we imagine the
122//! code having some use for them later on.
123//!
124//! One alternative in the last example
125//! is to implement `get` methods on the structs to get the values out, but that
126//! is still noisy and cumbersome. This example only grows more difficult to
127//! mentally process when there are more pointers, eventually becoming unwieldy
128//! to deal with.
129//!
130//! Another option here is to use interior mutability and use `set_weak_pointer`
131//! on these structs to get the desired effect, but that requires us to set
132//! pointers after initialization which is prone to the inadvertent creation of
133//! reference cycles.
134//!
135//! # Sanity Checking #
136//!
137//! This crate makes assumptions about how data inside [Rc] is laid out. As of
138//! writing this documentation, `Rc` holds a pointer to `RcInner`.
139//!
140//! ```no_run
141//! # use std::cell::Cell;
142//! #[repr(C)]
143//! struct RcInner<T: ?Sized> {
144//!     strong: Cell<usize>,
145//!     weak: Cell<usize>,
146//!     value: T,
147//! }
148//! ```
149//!
150//! Internally, we consume an `Rc<MaybeUninit<T>>` via [Rc::into_raw], which
151//! gives us a pointer to `value` field. We then calculate the offsets manually
152//! (accounting for padding) to reach `strong` and `weak` such that these fields
153//! can be manipulated directly to serve the purposes of [RcUninit].
154//!
155//! To guard against future changes in the standard library, we must perform a
156//! sanity check every time the program is run. This is to test whether the
157//! values we are reaching into are actually located where we believe they
158//! should be located.
159//!
160//! This sanity checking is performed by calling:
161//!
162//! ```
163//! use rcuninit::check_sanity;
164//!
165//! unsafe {
166//!     check_sanity();
167//! }
168//! ```
169//!
170//! See [check_sanity] for more details.
171//!
172//! # Native Rust Support #
173//!
174//! There are ongoing discussions on getting `RcUninit` and related features
175//! (`UniqueRc`) into std. This crate will be superceded once `RcUninit` is
176//! natively supported.
177//!
178//! - <https://github.com/rust-lang/libs-team/issues/90>
179//! - <https://github.com/rust-lang/rust/issues/112566>
180#![feature(ptr_alignment_type)]
181use std::{
182    alloc::Layout,
183    cell::Cell,
184    mem::{MaybeUninit, forget, transmute},
185    ptr::Alignment,
186    rc::{Rc, Weak},
187    sync::atomic::{AtomicBool, Ordering},
188};
189
190static SANITY_CHECKED: AtomicBool = AtomicBool::new(false);
191
192/// Check whether the assumptions about the internals of [Rc] made in this
193/// library are correct.
194///
195/// Note that we can't verify exactly whether we are out-of-sync with the
196/// current version of std, instead, we perform some sanity testing that should
197/// give us a "good enough" indicator that our assumptions are correct.
198///
199/// As such, this function is marked unsafe, because it can invoke undefined
200/// behavior if our assumptions are wrong.
201///
202/// Once this check has passed, a global variable is set that allows the
203/// creation of [RcUninit]. Note that even with sanity tests, this might still
204/// invoke undefined behavior if some detail is not caught. [Rc] could decide to
205/// reorder fields at will after some call, or do something else that
206/// invalidates the assumptions made in this library. As such, use of
207/// `RcUninit` _could_ be unsound, however unlikely. The functions on `RcUninit`
208/// are thus not marked as unsafe as `check_sanity` intends to provide
209/// sufficient shielding against potential undefined behavior.
210///
211/// # Safety #
212///
213/// This function is only sound if the standard library used with this crate
214/// matches this crate's assumptions about [Rc], as such, it's up to the caller
215/// to inspect the standard library to confirm that it matches what this crate
216/// expects.
217///
218/// Here are the conditions that need to be satisfied by [Rc] and [Weak].
219///
220/// 1. `RcInner` definitions inside `std::rc` and this crate must match exactly.
221/// 2. The pointer to `RcInner` that [Rc] constructs must be `*mut`.
222/// 3. The value pointer that [Rc::into_raw] returns must point to the value
223///    inside `RcInner`.
224/// 4. Offset calculations used by [Rc::increment_strong_count] and
225///    [Rc::decrement_strong_count] must match with how this crate calculates
226///    offsets from the value in `RcInner` to the counts.
227/// 5. All operations that [Weak] exposes must not invalidate the pointer to
228///    `RcInner`.
229pub unsafe fn check_sanity() {
230    {
231        let uninit = RcUninit::new_assume_sane();
232
233        let weak = uninit.weak();
234        assert_eq!(0, Weak::strong_count(&weak));
235        // Returns 0 when the strong count is 0, but internally a true weak count is
236        // stored.
237        assert_eq!(0, Weak::weak_count(&weak));
238
239        let inner_ptr = uninit.ptr();
240        let inner = unsafe { get_inner(inner_ptr) };
241
242        assert_eq!(inner.strong.get(), 0);
243        assert_eq!(inner.weak.get(), 3);
244
245        let weak2 = weak.clone();
246
247        assert_eq!(inner.strong.get(), 0);
248        assert_eq!(inner.weak.get(), 4);
249
250        assert_eq!(0, Weak::strong_count(&weak));
251        // Returns 0 when the strong count is 0, but internally a true weak count is
252        // stored.
253        assert_eq!(0, Weak::weak_count(&weak));
254
255        assert!(weak.upgrade().is_none());
256        assert!(weak2.upgrade().is_none());
257
258        // init acquires a mutable references to inner, so we must drop our inner and
259        // then reacquire it to avoid mutable aliasing.
260        let _ = inner;
261        let rc = uninit.init(123);
262        let inner = unsafe { get_inner(inner_ptr) };
263
264        assert_eq!(inner.strong.get(), 1);
265        // RcUninit's internal Weak is dropped, so the count has decreased.
266        assert_eq!(inner.weak.get(), 3);
267
268        let rc2 = rc.clone();
269        assert_eq!(inner.strong.get(), 2);
270        assert_eq!(inner.weak.get(), 3);
271        assert_eq!(2, Weak::strong_count(&weak));
272        assert_eq!(2, Weak::weak_count(&weak)); // NOTE: Weak count is 1 less than the actual value
273        // stored.
274
275        assert!(Rc::ptr_eq(&rc, &rc2));
276        assert!(Rc::ptr_eq(&rc, &weak.upgrade().unwrap()));
277        assert!(Rc::ptr_eq(&rc, &weak2.upgrade().unwrap()));
278
279        drop(rc2);
280        assert_eq!(inner.strong.get(), 1);
281        assert_eq!(inner.weak.get(), 3);
282        assert_eq!(1, Weak::strong_count(&weak));
283        assert_eq!(2, Weak::weak_count(&weak));
284
285        drop(weak2);
286        assert_eq!(inner.strong.get(), 1);
287        assert_eq!(inner.weak.get(), 2);
288        assert_eq!(1, Weak::strong_count(&weak));
289        assert_eq!(1, Weak::weak_count(&weak));
290
291        drop(rc);
292        assert_eq!(inner.strong.get(), 0);
293        assert_eq!(inner.weak.get(), 1);
294        assert_eq!(0, Weak::strong_count(&weak));
295        assert_eq!(0, Weak::weak_count(&weak));
296    }
297
298    SANITY_CHECKED.store(true, Ordering::Relaxed);
299}
300
301/// RcInner type used in std, this should reflect the exact same type and
302/// ordering.
303#[repr(C)]
304struct RcInner<T: ?Sized> {
305    strong: Cell<usize>,
306    weak: Cell<usize>,
307    value: T,
308}
309
310/// Defer initialization of [Rc] while providing [Weak] pointers to the
311/// allocation.
312pub struct RcUninit<T> {
313    ptr: *const MaybeUninit<T>,
314    weak: Weak<T>,
315}
316
317impl<T> RcUninit<T> {
318    /// Creates a new `RcUninit`.
319    ///
320    /// # Panics #
321    ///
322    /// Panics if [check_sanity] has not been called at least once.
323    ///
324    /// # Examples #
325    ///
326    /// ```
327    /// use rcuninit::RcUninit;
328    /// unsafe {
329    ///     rcuninit::check_sanity();
330    /// }
331    /// RcUninit::<i32>::new();
332    /// ```
333    pub fn new() -> Self {
334        assert!(
335            SANITY_CHECKED.load(Ordering::Relaxed),
336            "must call check_sanity() before using this library"
337        );
338
339        Self::new_assume_sane()
340    }
341
342    fn ptr(&self) -> *const MaybeUninit<T> {
343        self.ptr
344    }
345
346    fn new_assume_sane() -> Self {
347        let rc: Rc<MaybeUninit<T>> = Rc::new(MaybeUninit::uninit());
348
349        // SAFETY: Transmuting from a Weak<MaybeUninit<T>> into a Weak<T> should safe
350        // since MaybeUninit is #[repr(transparent)], and the user will not be
351        // able to upgrade this weak pointer until init is called to access
352        // uninitialized data since we set the strong count to zero.
353        let weak: Weak<T> = unsafe { transmute(Rc::downgrade(&rc)) };
354
355        let ptr = Rc::into_raw(rc);
356
357        // SAFETY: Subtracting the offset should point us to the actual RcInner used in
358        // std, which should have the same layout as our RcInner.
359        let inner: &RcInner<MaybeUninit<T>> = unsafe { get_inner(ptr) };
360
361        // The following checks can't guarantee soundness since they occur after
362        // acquiring RcInner, but they will stop the program from running if we
363        // point to nonsensical values. Note that if undefined behavior was
364        // triggered, then these values can be as expected.
365        //
366        // We make sure that we can read `1` from this location.
367        assert_eq!(inner.strong.get(), 1);
368
369        // We make sure that we can read `2` from this location, since we have created a
370        // Weak, and all Rcs share a single shared weak reference by themselves.
371        assert_eq!(inner.weak.get(), 2);
372
373        // Set the strong count to 0, preventing upgrades of Weak to this allocation.
374        // We do not use Rc::decrement_strong_count since that causes weaks to be
375        // upgradable because it reconstructs the "strong weak" pointer which
376        // drops the contained value.
377        inner.strong.set(0);
378
379        Self { ptr, weak }
380    }
381
382    /// Returns a [Weak] pointer that cannot be upgraded until [RcUninit::init]
383    /// is called.
384    ///
385    /// # Examples #
386    ///
387    /// ```
388    /// use rcuninit::RcUninit;
389    /// use std::rc::Weak;
390    ///
391    /// unsafe {
392    ///     rcuninit::check_sanity();
393    /// }
394    ///
395    /// let uninit = RcUninit::<i32>::new();
396    /// let weak: Weak<i32> = uninit.weak();
397    /// ```
398    pub fn weak(&self) -> Weak<T> {
399        // The user won't be able to upgrade this weak pointer until `init` gets called,
400        // since the strong count was set to zero in RcUninit::new.
401        self.weak.clone()
402    }
403
404    /// Initializes the pointer.
405    ///
406    /// # Examples #
407    ///
408    /// ```
409    /// use rcuninit::RcUninit;
410    /// use std::rc::Rc;
411    ///
412    /// unsafe {
413    ///     rcuninit::check_sanity();
414    /// }
415    ///
416    /// let uninit = RcUninit::new();
417    /// let rc: Rc<i32> = uninit.init(123);
418    /// ```
419    pub fn init(self, value: T) -> Rc<T> {
420        let ptr = self.ptr;
421
422        // SAFETY: There are no current borrows of the RcInner, so we can dereference as
423        // mutable. This should point to a valid RcInner since the layouts are
424        // the same.
425        let inner: &mut RcInner<MaybeUninit<T>> = unsafe { get_inner_mut(ptr) };
426
427        // Perform some extra sanity checks, at this point, we should point to a valid
428        // `RcInner`, the strong count must be zero, and the weak count can be
429        // anything above or equal to 2, since we have the initial Rc, as well
430        // as the Weak stored by this struct.
431        assert_eq!(inner.strong.get(), 0);
432        assert!(inner.weak.get() >= 2);
433
434        inner.strong.set(1);
435
436        // We decrement the weak reference count here because we are about to forget
437        // self which skips running drop for self, which would run drop for
438        // weak.
439        inner.weak.set(inner.weak.get() - 1);
440
441        inner.value.write(value);
442
443        // SAFETY: Since the pointer was created from Rc::into_raw, this call should be
444        // sound.
445        let rc = unsafe { Rc::from_raw(ptr) };
446
447        // Skip running the destructor since re-acquire the Rc and return it. Rc's
448        // destructor will perform the cleanup instead.
449        forget(self);
450
451        // SAFETY: We convert Rc<MaybeUninit<T>> into Rc<T>, which should be sound given
452        // that MaybeUninit has now been written to.
453        unsafe { rc.assume_init() }
454    }
455
456    /// Initializes the pointer and provides the weak pointer.
457    ///
458    /// # Examples #
459    ///
460    /// ```
461    /// use rcuninit::RcUninit;
462    /// use std::rc::Rc;
463    ///
464    /// unsafe {
465    ///     rcuninit::check_sanity();
466    /// }
467    ///
468    /// let uninit = RcUninit::new();
469    /// let rc: Rc<i32> = uninit.init_with(|weak| {
470    ///     // Do something with weak
471    ///     123
472    /// });
473    /// ```
474    pub fn init_with<F>(self, constructor: F) -> Rc<T>
475    where
476        F: FnOnce(Weak<T>) -> T,
477    {
478        let weak = self.weak();
479        self.init(constructor(weak))
480    }
481}
482
483impl<T> Default for RcUninit<T> {
484    fn default() -> Self {
485        Self::new()
486    }
487}
488
489impl<T> Drop for RcUninit<T> {
490    fn drop(&mut self) {
491        let offset = data_offset::<T>();
492
493        // SAFETY: Pointer should point to a valid RcInner<MaybeUninit<T>>. It's
494        // important to declare this as a pointer to MaybeUninit<_> so we do not
495        // run the desctructor since the data has not been initialized.
496        let inner = unsafe { &mut *(self.ptr.byte_sub(offset) as *mut RcInner<MaybeUninit<T>>) };
497
498        inner.strong.set(1);
499
500        // SAFETY: Pointer was created with into_raw.
501        unsafe { Rc::from_raw(self.ptr) };
502    }
503}
504
505fn data_offset<T>() -> usize {
506    let layout = Layout::new::<RcInner<()>>();
507    layout.size() + layout.padding_needed_for(Alignment::of::<T>())
508}
509
510unsafe fn get_inner<'a, T>(ptr: *const MaybeUninit<T>) -> &'a RcInner<MaybeUninit<T>> {
511    let offset = data_offset::<T>();
512
513    // SAFETY: Subtracting the offset should point us to the actual RcInner used in
514    // std, which should have the same layout as our RcInner.
515    unsafe { &*(ptr.byte_sub(offset) as *const RcInner<MaybeUninit<T>>) }
516}
517
518unsafe fn get_inner_mut<'a, T>(ptr: *const MaybeUninit<T>) -> &'a mut RcInner<MaybeUninit<T>> {
519    let offset = data_offset::<T>();
520
521    // SAFETY: Subtracting the offset should point us to the actual RcInner used in
522    // std, which should have the same layout as our RcInner.
523    unsafe { &mut *(ptr.byte_sub(offset) as *mut RcInner<MaybeUninit<T>>) }
524}
525
526#[test]
527fn basic() {
528    unsafe { check_sanity() };
529
530    let x = RcUninit::new();
531
532    let weak = x.weak();
533    assert!(weak.upgrade().is_none());
534
535    let rc = x.init(123);
536    assert_eq!(weak.upgrade().map(|x| *x), Some(123));
537
538    drop(rc);
539
540    assert!(weak.upgrade().is_none());
541}
542
543#[test]
544fn dst() {
545    unsafe { check_sanity() };
546
547    let x = RcUninit::<i32>::new();
548
549    let weak = x.weak();
550    let weak: Weak<dyn std::fmt::Debug> = weak;
551    assert!(weak.upgrade().is_none());
552
553    let _rc = x.init(123);
554
555    let upgraded = weak.upgrade();
556    assert!(upgraded.is_some());
557
558    assert_eq!("123", format!("{:?}", upgraded.unwrap()));
559}
560
561#[test]
562fn zst() {
563    unsafe { check_sanity() };
564
565    let x = RcUninit::<()>::new();
566
567    let weak = x.weak();
568    assert!(weak.upgrade().is_none());
569
570    let _rc = x.init(());
571
572    let upgraded = weak.upgrade();
573    assert!(upgraded.is_some());
574}
575
576#[test]
577fn odd_sized_type() {
578    unsafe { check_sanity() };
579
580    let x = RcUninit::<[u8; 33]>::new();
581
582    let weak = x.weak();
583    assert!(weak.upgrade().is_none());
584
585    let rc = x.init([137u8; 33]);
586
587    let upgraded = weak.upgrade();
588    assert!(upgraded.is_some());
589
590    assert_eq!(33, rc.len());
591    for value in *rc {
592        assert_eq!(137u8, value);
593    }
594}
595
596#[test]
597fn panic_on_drop_not_initialized() {
598    unsafe { check_sanity() };
599
600    struct PanicOnDrop;
601    impl Drop for PanicOnDrop {
602        fn drop(&mut self) {
603            panic!();
604        }
605    }
606
607    RcUninit::<PanicOnDrop>::new();
608}
609
610#[test]
611fn count_drops() {
612    unsafe { check_sanity() };
613
614    let counter = Rc::new(Cell::new(0));
615
616    struct DropCounter(Rc<Cell<usize>>);
617
618    impl Drop for DropCounter {
619        fn drop(&mut self) {
620            self.0.set(self.0.get() + 1);
621        }
622    }
623
624    let uninit = RcUninit::<DropCounter>::new();
625    assert_eq!(counter.get(), 0);
626
627    uninit.weak();
628    assert_eq!(counter.get(), 0);
629
630    uninit.init(DropCounter(counter.clone()));
631    assert_eq!(counter.get(), 1);
632
633    let _ = RcUninit::<DropCounter>::new();
634    assert_eq!(counter.get(), 1);
635}