|
64 | 64 |
|
65 | 65 | use core::alloc::{AllocError, Allocator};
|
66 | 66 | use core::cell::UnsafeCell;
|
67 |
| -#[cfg(not(no_global_oom_handling))] |
68 | 67 | use core::mem;
|
69 | 68 | #[cfg(not(no_global_oom_handling))]
|
70 | 69 | use core::ptr::{self, NonNull};
|
| 70 | +use core::sync::atomic::Atomic; |
71 | 71 |
|
72 | 72 | #[cfg(not(no_global_oom_handling))]
|
73 | 73 | use crate::alloc;
|
@@ -438,3 +438,80 @@ where
|
438 | 438 |
|
439 | 439 | unsafe { alloc.deallocate(allocation_ptr.cast(), rc_layout.get()) }
|
440 | 440 | }
|
| 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