Skip to content

Commit e09eba9

Browse files
committed
Add RefCounter trait
1 parent 284aa72 commit e09eba9

File tree

1 file changed

+82
-0
lines changed
  • library/alloc/src/raw_rc

1 file changed

+82
-0
lines changed

library/alloc/src/raw_rc/mod.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@
6363
#![allow(dead_code)]
6464

6565
use core::cell::UnsafeCell;
66+
use core::mem;
67+
use core::sync::atomic::Atomic;
6668

6769
mod rc_alloc;
6870
mod rc_layout;
@@ -85,3 +87,83 @@ impl RefCounts {
8587
Self { weak: UnsafeCell::new(1), strong: UnsafeCell::new(strong_count) }
8688
}
8789
}
90+
91+
/// The return value type for `RefCounter::make_mut`.
92+
#[cfg(not(no_global_oom_handling))]
93+
pub(crate) enum MakeMutStrategy {
94+
/// The strong reference count is 1, but weak reference count (including the one shared by all
95+
/// strong reference count) is more than 1. Before returning, the strong reference count has
96+
/// been set to zero to prevent new strong pointers from being created through upgrading from
97+
/// weak pointers.
98+
Move,
99+
/// The strong count is more than 1.
100+
Clone,
101+
}
102+
103+
/// A trait for `rc` and `sync` modules to define their reference-counting behaviors.
104+
///
105+
/// # Safety
106+
///
107+
/// - Each method must be implemented according to its description.
108+
/// - `Self` must have transparent representation over `UnsafeCell<usize>` and every valid
109+
/// `UnsafeCell<usize>` can also be reinterpreted as a valid `Self`.
110+
/// - `Self` must have alignment no greater than `align_of::<Atomic<usize>>()`.
111+
pub(crate) unsafe trait RefCounter: Sized {
112+
const VERIFY_LAYOUT: () = {
113+
assert!(size_of::<Self>() == size_of::<UnsafeCell<usize>>());
114+
assert!(align_of::<Self>() <= align_of::<Atomic<usize>>());
115+
};
116+
117+
/// Returns a reference to `Self` from a reference to `UnsafeCell<usize>`.
118+
///
119+
/// # Safety
120+
///
121+
/// - `count` must only be handled by the same `RefCounter` implementation.
122+
/// - The location of `count` must have enough alignment for storing `Atomic<usize>`.
123+
unsafe fn from_raw_counter(count: &UnsafeCell<usize>) -> &Self {
124+
() = Self::VERIFY_LAYOUT;
125+
126+
// SAFETY: The alignment requirement is guaranteed by both trait implementor and caller.
127+
// Trait implementor guarantees the alignment of `Self` is not greater than the alignment of
128+
// `Atomic<usize>`, and caller guarantees that the alignment of `count` is enough for
129+
// storing `Atomic<usize>`.
130+
unsafe { mem::transmute(count) }
131+
}
132+
133+
/// Increments the reference counter. The process will abort if overflow happens.
134+
fn increment(&self);
135+
136+
/// Decrements the reference counter. Returns whether the reference count becomes zero after
137+
/// decrementing.
138+
fn decrement(&self) -> bool;
139+
140+
/// Increments the reference counter if and only if the reference count is non-zero. Returns
141+
/// whether incrementing is performed.
142+
fn try_upgrade(&self) -> bool;
143+
144+
/// Increments the reference counter. If `self` needs to be called with by both
145+
/// `downgrade_increment_weak` and `is_unique` as the `weak_count` argument concurrently, both
146+
/// operations will be performed atomically.
147+
fn downgrade_increment_weak(&self);
148+
149+
/// Decrements the reference counter if and only if the reference count is 1. Returns true if
150+
/// decrementing is performed.
151+
fn try_lock_strong_count(&self) -> bool;
152+
153+
/// Sets the reference count to 1.
154+
fn unlock_strong_count(&self);
155+
156+
/// Returns whether both `strong_count` and `weak_count` are 1. If `weak_count` needs to be
157+
/// called with by both `downgrade_increment_weak` and `is_unique` concurrently, both operations
158+
/// will be performed atomically.
159+
fn is_unique(strong_count: &Self, weak_count: &Self) -> bool;
160+
161+
/// Determines how to make a mutable reference safely to a reference counted value.
162+
///
163+
/// - If both strong count and weak count are 1, returns `None`.
164+
/// - If strong count is 1 and weak count is greater than 1, returns
165+
/// `Some(MakeMutStrategy::Move)`.
166+
/// - If strong count is greater than 1, returns `Some(MakeMutStrategy::Clone)`.
167+
#[cfg(not(no_global_oom_handling))]
168+
fn make_mut(strong_count: &Self, weak_count: &Self) -> Option<MakeMutStrategy>;
169+
}

0 commit comments

Comments
 (0)