Skip to main content

obkrnl/mem/
strong.rs

1use core::ops::Deref;
2use core::ptr::NonNull;
3
4/// Strong reference to reference-counted memory block.
5///
6/// The main different from [alloc::sync::Arc] is this type store the number of references alongside
7/// the data.
8pub struct Strong<T: RefCnt + ?Sized>(NonNull<T>);
9
10impl<T: RefCnt + ?Sized> Strong<T> {
11    /// # Safety
12    /// `v` cannot be null and must point to initialized value.
13    pub unsafe fn new(v: *const T) -> Self {
14        unsafe { (*v).increase_ref() };
15
16        Self(unsafe { NonNull::new_unchecked(v.cast_mut()) })
17    }
18
19    pub fn as_ptr(this: &Self) -> NonNull<T> {
20        this.0
21    }
22}
23
24impl<T: RefCnt + ?Sized> Drop for Strong<T> {
25    fn drop(&mut self) {
26        let v = self.0.as_ptr();
27        let r = unsafe { (*v).decrease_ref() };
28
29        if r == 1 {
30            unsafe { core::ptr::drop_in_place(v) };
31        }
32    }
33}
34
35impl<T: RefCnt + ?Sized> Deref for Strong<T> {
36    type Target = T;
37
38    fn deref(&self) -> &Self::Target {
39        unsafe { self.0.as_ref() }
40    }
41}
42
43impl<T: RefCnt + ?Sized> Clone for Strong<T> {
44    fn clone(&self) -> Self {
45        let v = self.0.as_ptr();
46
47        unsafe { (*v).increase_ref() };
48
49        Self(unsafe { NonNull::new_unchecked(v) })
50    }
51}
52
53unsafe impl<T: RefCnt + Send + ?Sized> Send for Strong<T> {}
54unsafe impl<T: RefCnt + Sync + ?Sized> Sync for Strong<T> {}
55
56/// Provides methods to increase/decrease a strong reference to reference-counted mmemory block.
57///
58/// # Safety
59/// The number of strong references store on the memory can only modified by [Self::increase_ref()]
60/// and [Self::decrease_ref()]. The initial value must be zero.
61pub unsafe trait RefCnt {
62    /// Increments the strong reference count on the memory.
63    ///
64    /// # Panics
65    /// If reference count already at [usize::MAX].
66    fn increase_ref(&self);
67
68    /// Decrements the strong reference count on the memory and returns number of references before
69    /// the decreasement.
70    fn decrease_ref(&self) -> usize;
71}