stack_cell_ref/
lib.rs

1//! Share a reference in thread inner.
2//!
3//! # Examples
4//! ```
5//! use std::cell::Cell;
6//!
7//! use stack_cell_ref::CellOptionRef;
8//!
9//! struct Foo {
10//!     x: Cell<i32>,
11//! }
12//!
13//! thread_local! {
14//!     static S: CellOptionRef<Foo> = CellOptionRef::new();
15//! }
16//!
17//! fn set_foo(x: i32) {
18//!     S.with(|c| {
19//!         c.read(|f| {
20//!             f.unwrap().x.set(x);
21//!         });
22//!     });
23//! }
24//!
25//! let foo = Foo { x: Cell::new(0) };
26//!
27//! S.with(|c| {
28//!     c.with(Some(&foo), || {
29//!         set_foo(1);
30//!     });
31//!     assert_eq!(c.get_ptr(), None);
32//! });
33//! assert_eq!(foo.x.get(), 1);
34//! ```
35//!
36
37#![no_std]
38
39use core::cell::Cell;
40use core::fmt::{Debug, Display, Formatter, Octal};
41use core::hash::{Hash, Hasher};
42use core::ptr::NonNull;
43
44/// A [`Cell`] that stores option immutable references.
45///
46/// # Examples
47/// ```
48/// use stack_cell_ref::CellOptionRef;
49///
50/// let cell = CellOptionRef::new();
51/// let foo = 1;
52/// cell.with(Some(&foo), || {
53///     cell.read(|r| {
54///         assert_eq!(*r.unwrap(), 1);
55///     });
56/// });
57/// assert_eq!(cell.get_ptr(), None);
58/// ```
59#[repr(transparent)]
60pub struct CellOptionRef<T: ?Sized> {
61    ptr: Cell<Option<NonNull<T>>>,
62}
63
64impl<T: ?Sized> CellOptionRef<T> {
65    /// Creates a new [`CellOptionRef`] containing None.
66    ///
67    /// # Examples
68    /// ```
69    /// use stack_cell_ref::CellOptionRef;
70    ///
71    /// let c = CellOptionRef::<i32>::new();
72    /// ```
73    pub const fn new() -> Self {
74        Self {
75            ptr: Cell::new(None),
76        }
77    }
78
79    /// Returns the contained pointer.
80    ///
81    /// # Examples
82    /// ```
83    /// use stack_cell_ref::CellOptionRef;
84    ///
85    /// let c = CellOptionRef::<i32>::new();
86    /// let none = c.get_ptr();
87    /// ```
88    pub fn get_ptr(&self) -> Option<NonNull<T>> {
89        self.ptr.get()
90    }
91
92    /// Read the cell ref.
93    ///
94    /// # Examples
95    /// ```
96    /// use stack_cell_ref::CellOptionRef;
97    ///
98    /// let cell = CellOptionRef::new();
99    /// let foo = 1;
100    /// cell.with(Some(&foo), || {
101    ///     cell.read(|r| {
102    ///         assert_eq!(*r.unwrap(), 1);
103    ///         // ...
104    ///     });
105    /// });
106    /// ```
107    pub fn read<F: FnOnce(Option<&T>) -> R, R>(&self, f: F) -> R {
108        // Safety: CellOptionRef not Send/Sync
109        f(unsafe { self.get_ptr().map(|r| r.as_ref()) })
110    }
111
112    /// Set the cell pointer then run fn.
113    ///
114    /// # Examples
115    /// ```
116    /// use std::ptr::NonNull;
117    ///
118    /// use stack_cell_ref::CellOptionRef;
119    ///
120    /// let cell = CellOptionRef::new();
121    /// let foo = 1;
122    /// cell.with(Some(&foo), || {
123    ///     assert_eq!(cell.get_ptr(), Some(NonNull::from(&foo)));
124    ///     // ...
125    /// });
126    /// assert_eq!(cell.get_ptr(), None);
127    /// ```
128    pub fn with<F: FnOnce() -> R, R>(&self, r: Option<&T>, f: F) -> R {
129        struct Guard<'s, T: ?Sized> {
130            this: &'s CellOptionRef<T>,
131            ptr: Option<NonNull<T>>,
132        }
133        impl<'s, T: ?Sized> Drop for Guard<'s, T> {
134            fn drop(&mut self) {
135                self.this.ptr.set(self.ptr);
136            }
137        }
138
139        let _guard = Guard {
140            this: &self,
141            ptr: self.ptr.replace(r.map(NonNull::from)),
142        };
143        f()
144    }
145}
146
147impl<T: ?Sized> Default for CellOptionRef<T> {
148    fn default() -> Self {
149        Self::new()
150    }
151}
152
153impl<T: Debug + ?Sized> Debug for CellOptionRef<T> {
154    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
155        self.read(|s| Debug::fmt(&s, f))
156    }
157}
158
159impl<T: PartialEq + ?Sized> PartialEq for CellOptionRef<T> {
160    fn eq(&self, other: &Self) -> bool {
161        self.read(|s| other.read(|r| PartialEq::eq(&s, &r)))
162    }
163
164    fn ne(&self, other: &Self) -> bool {
165        self.read(|s| other.read(|r| PartialEq::ne(&s, &r)))
166    }
167}
168
169impl<T: Eq + ?Sized> Eq for CellOptionRef<T> {}
170
171impl<T: Hash + ?Sized> Hash for CellOptionRef<T> {
172    fn hash<H: Hasher>(&self, state: &mut H) {
173        self.read(|s| Hash::hash(&s, state));
174    }
175}