ribir_algo/
sc.rs

1use std::{
2  any::Any,
3  cell::Cell,
4  fmt::{Debug, Display, Formatter, Pointer},
5  ptr::NonNull,
6};
7
8/// A single-thread smart pointer with strong reference count only.
9/// This is a simplified version of `std::rc::Sc` with the weak reference count.
10/// Use it when you are sure that there is no cycle in the reference graph or in
11/// a inner resource manage that will break the cycle by itself.
12pub struct Sc<T: ?Sized>(NonNull<ScBox<T>>);
13
14struct ScBox<T: ?Sized> {
15  ref_cnt: Cell<usize>,
16  value: T,
17}
18
19impl<T> Sc<T> {
20  /// Constructs a new `Sc<T>`.
21  ///
22  /// # Examples
23  ///
24  /// ```
25  /// use ribir_algo::Sc;
26  ///
27  /// let five = Sc::new(5);
28  /// ```
29  #[inline]
30  pub fn new(value: T) -> Self {
31    Self::from_inner(Box::leak(Box::new(ScBox { ref_cnt: Cell::new(1), value })).into())
32  }
33
34  /// Returns the inner value, if the `Sc` has exactly one strong reference.
35  ///
36  /// Otherwise, an [`Err`] is returned with the same `Sc` that was
37  /// passed in.
38  ///
39  /// This will succeed even if there are outstanding weak references.
40  ///
41  /// # Examples
42  ///
43  /// ```
44  /// use ribir_algo::Sc;
45  ///
46  /// let x = Sc::new(3);
47  /// assert_eq!(Sc::try_unwrap(x), Ok(3));
48  ///
49  /// let x = Sc::new(4);
50  /// let _y = Sc::clone(&x);
51  /// assert_eq!(*Sc::try_unwrap(x).unwrap_err(), 4);
52  /// ```
53  #[inline]
54  pub fn try_unwrap(this: Self) -> Result<T, Self> {
55    if Sc::ref_count(&this) == 1 {
56      unsafe {
57        let val = std::ptr::read(&*this); // copy the contained object
58
59        // avoid to call `drop` but release the memory.
60        let layout = std::alloc::Layout::for_value(this.0.as_ref());
61        let ptr = this.0.as_ptr();
62        std::mem::forget(this);
63        std::alloc::dealloc(ptr as *mut _, layout);
64
65        Ok(val)
66      }
67    } else {
68      Err(this)
69    }
70  }
71}
72
73impl Sc<dyn Any> {
74  ///
75  /// todo: prefer implement `CoerceUnsized` if it stable.
76  #[inline]
77  pub fn new_any<T: Any>(value: T) -> Self {
78    let inner: Box<ScBox<dyn Any>> = Box::new(ScBox { ref_cnt: Cell::new(1), value });
79    Self::from_inner(Box::leak(inner).into())
80  }
81}
82
83impl<T: ?Sized> Sc<T> {
84  // Gets the number of pointers to this allocation.
85  ///
86  /// # Examples
87  ///
88  /// ```
89  /// use ribir_algo::Sc;
90  ///
91  /// let five = Sc::new(5);
92  /// let _also_five = Sc::clone(&five);
93  ///
94  /// assert_eq!(2, Sc::ref_count(&five));
95  /// ```
96  #[inline]
97  pub fn ref_count(&self) -> usize { self.inner().ref_cnt() }
98
99  /// Returns `true` if the two `Sc`s point to the same allocation in a vein
100  /// similar to [`ptr::eq`]. See [that function][`ptr::eq`] for caveats when
101  /// comparing `dyn Trait` pointers.
102  ///
103  /// # Examples
104  ///
105  /// ```
106  /// use ribir_algo::Sc;
107  ///
108  /// let five = Sc::new(5);
109  /// let same_five = Sc::clone(&five);
110  /// let other_five = Sc::new(5);
111  ///
112  /// assert!(Sc::ptr_eq(&five, &same_five));
113  /// assert!(!Sc::ptr_eq(&five, &other_five));
114  /// ```
115  pub fn ptr_eq(this: &Self, other: &Self) -> bool {
116    std::ptr::addr_eq(this.0.as_ptr(), other.0.as_ptr())
117  }
118
119  fn from_inner(ptr: NonNull<ScBox<T>>) -> Self { Self(ptr) }
120
121  fn inner(&self) -> &ScBox<T> {
122    // Safety: we're guaranteed that the inner pointer is valid when the `Sc` is
123    // alive
124    unsafe { self.0.as_ref() }
125  }
126}
127
128impl Sc<dyn Any> {
129  /// Attempt to downcast the `Sc<dyn Any>` to a concrete type.
130  ///
131  /// # Examples
132  ///
133  /// ```
134  /// use std::any::Any;
135  ///
136  /// use ribir_algo::Sc;
137  ///
138  /// fn print_if_string(value: Sc<dyn Any>) {
139  ///   if let Ok(string) = value.downcast::<String>() {
140  ///     println!("String ({}): {}", string.len(), string);
141  ///   }
142  /// }
143  ///
144  /// let my_string = "Hello World".to_string();
145  /// print_if_string(Sc::new_any(my_string));
146  /// print_if_string(Sc::new_any(0i8));
147  /// ```
148  pub fn downcast<T: Any>(self) -> Result<Sc<T>, Sc<dyn Any>> {
149    if (*self).is::<T>() {
150      let ptr = self.0.cast::<ScBox<T>>();
151      std::mem::forget(self);
152      Ok(Sc::from_inner(ptr))
153    } else {
154      Err(self)
155    }
156  }
157}
158
159impl<T: ?Sized> ScBox<T> {
160  fn inc(&self) { self.ref_cnt.set(self.ref_cnt.get() + 1); }
161  fn dec(&self) { self.ref_cnt.set(self.ref_cnt.get() - 1) }
162  fn ref_cnt(&self) -> usize { self.ref_cnt.get() }
163}
164
165impl<T: ?Sized> std::ops::Deref for Sc<T> {
166  type Target = T;
167  #[inline]
168  fn deref(&self) -> &Self::Target { &self.inner().value }
169}
170
171impl<T: ?Sized> Drop for Sc<T> {
172  fn drop(&mut self) {
173    self.inner().dec();
174    if self.inner().ref_cnt() == 0 {
175      unsafe {
176        let layout = std::alloc::Layout::for_value(self.0.as_ref());
177        let ptr = self.0.as_ptr();
178        std::ptr::drop_in_place(ptr);
179        std::alloc::dealloc(ptr as *mut _, layout)
180      }
181    }
182  }
183}
184
185impl<T> Clone for Sc<T> {
186  #[inline]
187  fn clone(&self) -> Self {
188    self.inner().inc();
189    Self(self.0)
190  }
191}
192
193impl<T: ?Sized + Display> Display for Sc<T> {
194  fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { Display::fmt(&**self, f) }
195}
196
197impl<T: ?Sized + Debug> Debug for Sc<T> {
198  fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { Debug::fmt(&**self, f) }
199}
200
201impl<T: ?Sized> Pointer for Sc<T> {
202  fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
203    Pointer::fmt(&(&**self as *const T), f)
204  }
205}
206
207impl<T: Default> Default for Sc<T> {
208  #[inline]
209  fn default() -> Sc<T> { Sc::new(Default::default()) }
210}
211
212impl<T: ?Sized + PartialEq> PartialEq for Sc<T> {
213  #[inline]
214  fn eq(&self, other: &Sc<T>) -> bool { **self == **other }
215}
216
217#[cfg(test)]
218mod tests {
219  use super::*;
220  #[test]
221  fn test_sc() {
222    let a = Sc::new(1);
223    assert_eq!(Sc::ref_count(&a), 1);
224    let b = Sc::clone(&a);
225    assert_eq!(Sc::ref_count(&b), 2);
226    drop(a);
227    assert_eq!(Sc::ref_count(&b), 1);
228    drop(b);
229  }
230}