Skip to content

Commit 597ff85

Browse files
committed
add Singleton<T>
1 parent aefd432 commit 597ff85

File tree

1 file changed

+60
-0
lines changed

1 file changed

+60
-0
lines changed

src/lib.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
#![warn(missing_docs)]
1414
#![deny(missing_debug_implementations)]
1515

16+
use core::cell::UnsafeCell;
17+
use core::sync::atomic::{AtomicBool, Ordering};
18+
1619
pub use crate::addr::{align_down, align_up, PhysAddr, VirtAddr};
1720

1821
/// Makes a function const only when `feature = "const_fn"` is enabled.
@@ -112,3 +115,60 @@ impl PrivilegeLevel {
112115
}
113116
}
114117
}
118+
119+
/// A wrapper that can be used to safely create one mutable reference `&'static mut T` from a static variable.
120+
///
121+
/// `Singleton` is safe because it ensures that it only ever gives out one reference.
122+
///
123+
/// ``Singleton<T>` is a safe alternative to `static mut` or a static `UnsafeCell<T>`.
124+
#[derive(Debug)]
125+
pub struct Singleton<T> {
126+
used: AtomicBool,
127+
value: UnsafeCell<T>,
128+
}
129+
130+
impl<T> Singleton<T> {
131+
/// Construct a new singleton.
132+
pub const fn new(value: T) -> Self {
133+
Self {
134+
used: AtomicBool::new(false),
135+
value: UnsafeCell::new(value),
136+
}
137+
}
138+
139+
/// Try to acquire a mutable reference to the wrapped value.
140+
/// This will only succeed the first time the function is
141+
/// called and fail on all following calls.
142+
///
143+
/// ```
144+
/// use x86_64::Singleton;
145+
///
146+
/// static FOO: Singleton<i32> = Singleton::new(0);
147+
///
148+
/// // Call `try_get_mut` for the first time and get a reference.
149+
/// let first: &'static mut i32 = FOO.try_get_mut().unwrap();
150+
/// assert_eq!(first, &0);
151+
///
152+
/// // Calling `try_get_mut` again will return `None`.
153+
/// assert_eq!(FOO.try_get_mut(), None);
154+
/// ```
155+
pub fn try_get_mut(&self) -> Option<&mut T> {
156+
match self
157+
.used
158+
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
159+
{
160+
Ok(_) => Some(unsafe {
161+
// SAFETY: no reference has been given out yet and we won't give out another.
162+
&mut *self.value.get()
163+
}),
164+
Err(_) => None,
165+
}
166+
}
167+
}
168+
169+
// SAFETY: Sharing a `Singleton<T>` between threads is safe regardless of whether `T` is `Sync`
170+
// because we only expose the inner value once to one thread.
171+
unsafe impl<T> Sync for Singleton<T> {}
172+
173+
// SAFETY: It's safe to send a `Singleton<T>` to another thread if it's safe to send `T`.
174+
unsafe impl<T: Send> Send for Singleton<T> {}

0 commit comments

Comments
 (0)