init_cell/
lib.rs

1//! A cell which can be unsafely initialized or interiorly mutated, but safely accessed.
2//! 
3//! This is mostly intended for use in statics. The cell is safe to access, but must be initialized before any access. There is no synchronization to ensure initialization is observed, so you should initialize at the beginning of the main function or using something like the `ctor` crate.
4//! 
5//! # Example
6//! 
7//! ```
8//! use init_cell::InitCell;
9//! 
10//! // SAFETY: We will initialize the cell before using it.
11//! pub static MY_VAL: InitCell<Vec<i32>> = unsafe { InitCell::new() };
12//! 
13//! fn main() {
14//! 	// SAFETY: Nothing is accessing the cell.
15//! 	unsafe {
16//! 		InitCell::init(&MY_VAL, vec![1, 2, 3]);
17//! 	}
18//! 	assert_eq!(MY_VAL.iter().sum::<i32>(), 6);
19//! 
20//! 	// The cell can be mutated, too, which drops the previous value.
21//! 	unsafe {
22//! 		InitCell::set(&MY_VAL, vec![4, 5, 6]);
23//! 	}
24//! 	assert_eq!(MY_VAL.iter().sum::<i32>(), 15);
25//! }
26//! ```
27
28#![no_std]
29
30use core::fmt;
31use core::ops::{Deref, DerefMut};
32use core::cell::UnsafeCell;
33use core::mem::MaybeUninit;
34use core::cmp::Ordering;
35
36/// A one-time initialization cell.
37/// 
38/// This is mostly intended for use in statics. The cell is safe to access,
39/// but must be initialized before any access. There is no synchronization
40/// to ensure initialization is observed, so you should initialize at the
41/// beginning of the main function or using something like the `ctor` crate.
42#[repr(transparent)]
43pub struct InitCell<T>(UnsafeCell<MaybeUninit<T>>);
44
45unsafe impl<T: Send> Send for InitCell<T> {}
46unsafe impl<T: Sync> Sync for InitCell<T> {}
47
48impl<T> From<T> for InitCell<T> {
49	fn from(x: T) -> Self { Self::initialized(x) }
50}
51
52impl<T: PartialEq> PartialEq for InitCell<T> {
53	fn eq(&self, rhs: &Self) -> bool { **self == **rhs }
54}
55
56impl<T: Eq> Eq for InitCell<T> {}
57
58impl<T: PartialOrd> PartialOrd for InitCell<T> {
59	fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> { (**self).partial_cmp(&**rhs) }
60}
61
62impl<T: Ord> Ord for InitCell<T> {
63	fn cmp(&self, rhs: &Self) -> Ordering { (**self).cmp(&**rhs) }
64}
65
66impl<T: fmt::Debug> fmt::Debug for InitCell<T> {
67	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68		(**self).fmt(f)
69	}
70}
71
72impl<T: fmt::Display> fmt::Display for InitCell<T> {
73	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74		(**self).fmt(f)
75	}
76}
77
78impl<T: core::hash::Hash> core::hash::Hash for InitCell<T> {
79	fn hash<H: core::hash::Hasher>(&self, h: &mut H) {
80		(**self).hash(h);
81	}
82}
83
84impl<T> Deref for InitCell<T> {
85	type Target = T;
86
87	fn deref(&self) -> &T {
88		unsafe { (*self.0.get()).assume_init_ref() }
89	}
90}
91
92impl<T> DerefMut for InitCell<T> {
93	fn deref_mut(&mut self) -> &mut T {
94		unsafe { (*self.0.get()).assume_init_mut() }
95	}
96}
97
98impl<T> InitCell<T> {
99	/// Creates a new uninitialized `InitCell`.
100	/// 
101	/// # Safety
102	/// The cell must be initialized before it is accessed.
103	pub const unsafe fn new() -> Self { Self(UnsafeCell::new(MaybeUninit::uninit())) }
104	
105	/// Creates a new initialized `InitCell`. Unlike `InitCell::new`, this is
106	/// safe because the cell is already initialized and can be used freely.
107	pub fn initialized(x: T) -> Self { Self(UnsafeCell::new(MaybeUninit::new(x))) }
108
109	/// Gets the inner (initialized) value of this cell.
110	pub unsafe fn into_inner(cell: Self) -> T { cell.0.into_inner().assume_init() }
111
112	/// Initializes the cell.
113	/// 
114	/// # Safety
115	/// This must be done when there are no references to the contents of this
116	/// cell, including no other threads accessing it.
117	pub unsafe fn init(cell: &Self, x: T) {
118		(*cell.0.get()).write(x);
119	}
120
121	/// Sets the cell's value.
122	/// 
123	/// # Safety
124	/// This must be done when there are no references to the contents of this
125	/// cell, including no other threads accessing it. Additionally, the cell
126	/// must have been previously initialized, as this will drop the old value.
127	pub unsafe fn set(cell: &Self, x: T) {
128		*(*cell.0.get()).as_mut_ptr() = x;
129	}
130}