devela/sys/mem/guard.rs
1#!/usr/bin/env -S rust-script -c --debug
2//! ```cargo
3//! [dependencies]
4//! devela = { path = "../../../../devela", features = ["std"]}
5//! ```
6//!
7//! Defines the [`Current`] and [`CurrentGuard`] structs.
8//
9
10use ::devela::{
11 any_type_name, define_static_map, transmute, Any, Deref, DerefMut, Hash, Hasher, HasherFx, Mem,
12 PhantomData, PtrNonNull, RefCell,
13};
14
15// Stores the current pointers for concrete types.
16define_static_map![typeid KeyCurrentMap];
17thread_local! {
18 static CURRENT_PTR_MAP: RefCell<KeyCurrentMap<u64, PtrNonNull<u8>, 64>>
19 = RefCell::new(KeyCurrentMap::new_cloned(PtrNonNull::<u8>::dangling()));
20}
21
22/// A guard that temporarily sets a global current pointer for `T`, restoring the old one on drop.
23///
24/// When dropped, it restores the previous pointer or sets a placeholder if none existed."
25///
26/// This is useful for tracking the current instance of a type within a thread.
27#[cfg_attr(doc, doc = ::devela::doc_!(vendor: "current"))]
28pub struct CurrentGuard<'a, T: Any> {
29 /// The active instance of `T` for the duration of this guard.
30 _current: &'a mut T,
31 /// The previous pointer, restored when this guard is dropped.
32 prev_ptr: Option<PtrNonNull<T>>,
33}
34impl<T: Any> CurrentGuard<'_, T> {
35 /// Creates a new *current guard* for the given value.
36 ///
37 /// When this guard is dropped, the previous pointer (if any) will be restored.
38 ///
39 /// # Safety
40 /// - This function modifies global state within a thread-local map.
41 /// - It ensures that only one mutable reference to a given `T` exists at a time.
42 /// - Improper use may lead to stale pointers if lifetimes are not respected.
43 ///
44 /// # Example
45 /// ```
46 /// # use devela::{CurrentGuard};
47 /// # struct MyType { data: u64} impl MyType { fn new() -> Self { Self { data:0 } }}
48 /// let mut my_value = MyType::new();
49 /// let guard = CurrentGuard::new(&mut my_value);
50 /// ```
51 pub fn new(current: &mut T) -> CurrentGuard<T> {
52 let ptr = PtrNonNull::from(&mut *current).cast::<u8>();
53 let prev_ptr = CURRENT_PTR_MAP.with(|current| {
54 let mut map = current.borrow_mut();
55 if let Some(entry) = map.get_mut_type::<T>() {
56 Some(Mem::replace(entry, ptr).cast::<T>())
57 } else {
58 map.insert_type::<T>(ptr.cast()).ok();
59 None
60 }
61 });
62 CurrentGuard { prev_ptr, _current: current }
63 }
64}
65impl<T: Any> Drop for CurrentGuard<'_, T> {
66 fn drop(&mut self) {
67 CURRENT_PTR_MAP.with(|current| {
68 let mut map = current.borrow_mut();
69 match self.prev_ptr {
70 None => map.insert_type::<T>(PtrNonNull::<u8>::dangling().cast()).ok(),
71 Some(prev_ptr) => map.insert_type::<T>(prev_ptr.cast()).ok(),
72 }
73 });
74 }
75}
76
77/// A marker object representing the current instance of a type `T`.
78///
79/// This struct does not hold any actual value but instead allows access to
80/// a globally tracked instance of `T`, typically managed through `CurrentGuard`.
81///
82/// The primary purpose of `Current<T>` is to:
83/// - Provide safe, structured access to a global instance of `T`.
84/// - Prevent direct global mutable access in safe code.
85///
86/// Not a smart pointer; instead, it acts as a reference handle for thread-local state.
87#[cfg_attr(doc, doc = ::devela::doc_!(vendor: "current"))]
88pub struct Current<T>(PhantomData<T>);
89
90impl<T: Any> Current<T> {
91 /// Creates a new `Current<T>` marker object.
92 ///
93 /// # Safety
94 /// - This function does not initialize an actual value.
95 /// - Dereferencing without an active `CurrentGuard` leads to undefined behavior.
96 /// - Ensure that `CurrentGuard` is properly managed before using this.
97 ///
98 /// # Example
99 /// ```ignore
100 /// let current = unsafe { Current::<MyType>::new() };
101 /// ```
102 pub unsafe fn new() -> Current<T> {
103 Current(PhantomData)
104 }
105
106 /// Retrieves an exclusive reference to the current instance of `T`, if set.
107 ///
108 /// # Safety
109 /// - May return a dangling reference if the associated `CurrentGuard<T>` has been dropped.
110 /// - The caller must ensure the reference is only used while the `CurrentGuard<T>` is alive.
111 /// - If the same `T` is set multiple times, the reference may be stale.
112 ///
113 /// # Example
114 /// ```ignore
115 /// let mut my_value = MyType::new();
116 /// let guard = CurrentGuard::new(&mut my_value);
117 /// let current = unsafe { Current::<MyType>::new().current() };
118 /// assert!(current.is_some());
119 /// ```
120 #[rustfmt::skip]
121 pub unsafe fn current(&mut self) -> Option<&mut T> {
122 let ptr: PtrNonNull<u8> = CURRENT_PTR_MAP.with(|current| current.borrow().get_type::<T>())?;
123 // SAFETY: The pointer is non-null but may not be valid; ensure `CurrentGuard<T>` is active.
124 Some(unsafe { &mut *ptr.cast::<T>().as_ptr() })
125 }
126
127 /// Retrieves an exclusive reference to the current instance of `T`, or panics.
128 ///
129 /// # Safety
130 /// Same as [`current`][Self::current]: the caller must ensure the reference remains valid.
131 ///
132 /// # Panics
133 /// Panics if no instance of `T` is currently set.
134 ///
135 /// # Example
136 /// ```ignore
137 /// let mut my_value = MyType::new();
138 /// let guard = CurrentGuard::new(&mut my_value);
139 /// let current = unsafe { Current::<MyType>::new().current_unwrap() };
140 /// ```
141 pub unsafe fn current_unwrap(&mut self) -> &mut T {
142 // SAFETY: Panics if no `CurrentGuard<T>` exists, preventing invalid access.
143 match unsafe { self.current() } {
144 None => panic!("No current `{}` is set", any_type_name::<T>()),
145 Some(x) => x,
146 }
147 }
148}
149impl<T: Any> Deref for Current<T> {
150 type Target = T;
151
152 #[inline(always)] #[rustfmt::skip]
153 fn deref<'a>(&'a self) -> &'a T {
154 // SAFETY:
155 // - `Current<T>` is only an access point, not an actual value.
156 // - Transmuting `&Current<T>` to `&mut Current<T>` is safe since it's never directly used.
157 // - Caller must ensure `CurrentGuard<T>` is active; otherwise, `current_unwrap` panics.
158 #[allow(mutable_transmutes, reason = "`Current` only acts as a reference handle")]
159 unsafe { transmute::<&Current<T>, &'a mut Current<T>>(self).current_unwrap() }
160 }
161}
162impl<T: Any> DerefMut for Current<T> {
163 #[inline(always)]
164 fn deref_mut(&mut self) -> &mut T {
165 // SAFETY:
166 // - Requires an active `CurrentGuard<T>`, ensuring a valid instance.
167 // - If no guard exists, `current_unwrap` panics instead of returning an invalid reference.
168 unsafe { self.current_unwrap() }
169 }
170}
171
172#[allow(unused, reason = "example script")]
173fn main() {
174 struct State {
175 text: String,
176 }
177 impl State {
178 // prints the current text, and changes it to "world!"
179 fn print() {
180 let mut ctx = unsafe { Current::<State>::new() };
181 println!("{}", ctx.text);
182 ctx.text = "world!".to_string();
183 }
184 // changes the text to "good bye" and calls print() two times.
185 fn bar() {
186 let mut bar = State { text: "good bye".to_string() };
187 let guard = CurrentGuard::new(&mut bar);
188 State::print(); // good bye
189 State::print(); // world!
190 }
191 }
192 let mut ctx = State { text: "hello".to_string() };
193 let guard = CurrentGuard::new(&mut ctx);
194 State::print(); // hello
195 State::print(); // world!
196 State::bar(); // good bye world!
197}