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}