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}