Skip to content

Commit cfa6ea8

Browse files
committed
Add RefCounter trait
1 parent abe9c27 commit cfa6ea8

File tree

1 file changed

+78
-1
lines changed
  • library/alloc/src/raw_rc

1 file changed

+78
-1
lines changed

library/alloc/src/raw_rc/mod.rs

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,10 @@
6464

6565
use core::alloc::{AllocError, Allocator};
6666
use core::cell::UnsafeCell;
67-
#[cfg(not(no_global_oom_handling))]
6867
use core::mem;
6968
#[cfg(not(no_global_oom_handling))]
7069
use core::ptr::{self, NonNull};
70+
use core::sync::atomic::Atomic;
7171

7272
#[cfg(not(no_global_oom_handling))]
7373
use crate::alloc;
@@ -438,3 +438,80 @@ where
438438

439439
unsafe { alloc.deallocate(allocation_ptr.cast(), rc_layout.get()) }
440440
}
441+
442+
/// The return value type for `RefCounter::make_mut`.
443+
#[cfg(not(no_global_oom_handling))]
444+
pub(crate) enum MakeMutStrategy {
445+
/// The strong reference count is 1, but weak reference count (including the one shared by all
446+
/// strong reference count) is more than 1. Before returning, the strong reference count has
447+
/// been set to zero to prevent new strong pointers from being created through upgrading from
448+
/// weak pointers.
449+
Move,
450+
/// The strong count is more than 1.
451+
Clone,
452+
}
453+
454+
/// A trait for `rc` and `sync` modules to define their reference-counting behaviors.
455+
///
456+
/// # Safety
457+
///
458+
/// - Each method must be implemented according to its description.
459+
/// - `Self` must have transparent representation over `UnsafeCell<usize>` and every valid
460+
/// `UnsafeCell<usize>` can also be reinterpreted as a valid `Self`.
461+
/// - `Self` must have alignment no greater than `align_of::<Atomic<usize>>()`.
462+
pub(crate) unsafe trait RefCounter: Sized {
463+
const VERIFY_LAYOUT: () = {
464+
assert!(size_of::<Self>() == size_of::<UnsafeCell<usize>>());
465+
assert!(align_of::<Self>() <= align_of::<Atomic<usize>>());
466+
};
467+
468+
/// Returns a reference to `Self` from
469+
///
470+
/// # Safety
471+
///
472+
/// - `count` must only be handled by the same `RefCounter` implementation.
473+
/// - The location of `count` must have enough alignment for storing `Atomic<usize>`.
474+
unsafe fn from_raw_counter(count: &UnsafeCell<usize>) -> &Self {
475+
() = Self::VERIFY_LAYOUT;
476+
477+
// SAFETY: Caller guarantees `count` be safely reinterpreted as `Self`.
478+
unsafe { mem::transmute(count) }
479+
}
480+
481+
/// Increments the reference counter. The process will abort if overflow happens.
482+
fn increment(&self);
483+
484+
/// Decrements the reference counter. Returns whether the reference count becomes zero after
485+
/// decrementing.
486+
fn decrement(&self) -> bool;
487+
488+
/// Increments the reference counter if and only if the reference count is non-zero. Returns
489+
/// whether incrementing is performed.
490+
fn upgrade(&self) -> bool;
491+
492+
/// Increments the reference counter. If the same reference counter is called concurrently by
493+
/// both `downgrade` and by `is_unique` as the `weak` argument. Both operations will be
494+
/// performed atomically.
495+
fn downgrade(&self);
496+
497+
/// Decrements the reference counter if and only if the reference count is 1. Returns true if
498+
/// decrementing is performed.
499+
fn lock_strong_count(&self) -> bool;
500+
501+
/// Sets the reference count to 1.
502+
fn unlock_strong_count(&self);
503+
504+
/// Returns whether both `strong_count` are 1 and `weak_count` is 1. If the same reference
505+
/// counter is called concurrently by both `downgrade` and by `is_unique` as the `weak`
506+
/// argument. Both operations will be performed atomically.
507+
fn is_unique(strong_count: &Self, weak_count: &Self) -> bool;
508+
509+
/// Determines how to make a mutable reference safely to a reference counted value.
510+
///
511+
/// - If both strong count and weak count are 1, returns `None`.
512+
/// - If strong count is 1 and weak count is greater than 1, returns
513+
/// `Some(MakeMutStrategy::Move)`.
514+
/// - If strong count is greater than 1, returns `Some(MakeMutStrategy::Clone)`.
515+
#[cfg(not(no_global_oom_handling))]
516+
fn make_mut(strong_count: &Self, weak_count: &Self) -> Option<MakeMutStrategy>;
517+
}

0 commit comments

Comments
 (0)