1use std::cell::UnsafeCell;
2use std::fmt::{Debug, Formatter};
3
4pub struct DeferredBox<T> {
5 unsafe_cell: UnsafeCell<Option<T>>,
6}
7
8impl <T> DeferredBox<T> {
9 pub fn new() -> Self {
10 Self {
11 unsafe_cell: UnsafeCell::new(None),
12 }
13 }
14
15 pub fn get(&self) -> Option<&T> {
16 (unsafe { &*self.unsafe_cell.get() }).as_ref()
17 }
18
19 pub fn get_or_init<F>(&self, init: F) -> &T where F: FnOnce() -> T {
20 if self.get().is_none() {
21 unsafe {
22 *self.unsafe_cell.get() = Some(init());
23 }
24 }
25 self.get().unwrap()
26 }
27
28 pub unsafe fn get_mut(&self) -> Option<&mut T> {
29 { &mut *self.unsafe_cell.get() }.as_mut()
30 }
31
32 pub unsafe fn alter(&self, value: T) {
33 *self.unsafe_cell.get() = Some(value);
34 }
35
36 pub fn set(&self, value: T) -> Result<(), DeferredBoxSetError> {
37 if self.get().is_some() {
38 return Err(DeferredBoxSetError());
39 }
40 unsafe {
41 *self.unsafe_cell.get() = Some(value);
42 }
43 Ok(())
44 }
45}
46
47impl<T> Default for DeferredBox<T> {
48 fn default() -> Self {
49 Self::new()
50 }
51}
52
53unsafe impl<T> Send for DeferredBox<T> where T: Send { }
54unsafe impl<T> Sync for DeferredBox<T> where T: Sync { }
55
56impl<T> Debug for DeferredBox<T> where T: Debug {
57 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
58 write!(f, "DeferredBox {{ {:?} }})", self.get())
59 }
60}
61
62#[derive(Eq, PartialEq, Copy, Clone)]
63pub struct DeferredBoxSetError();
64
65impl Debug for DeferredBoxSetError {
66 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
67 write!(f, "value has been set, trying to set it twice")
68 }
69}
70
71#[cfg(test)]
72mod test {
73 #[test]
74 fn test_deferred_box_for_number() {
75 let deferred_box = super::DeferredBox::new();
76 assert_eq!(deferred_box.get(), None);
77 assert_eq!(deferred_box.set(1), Ok(()));
78 assert_eq!(deferred_box.get(), Some(&1));
79 assert_eq!(deferred_box.set(2), Err(super::DeferredBoxSetError()));
80 assert_eq!(deferred_box.get(), Some(&1));
81 }
82
83 #[test]
84 fn test_deferred_box_for_string() {
85 let deferred_box = super::DeferredBox::new();
86 assert_eq!(deferred_box.get(), None);
87 assert_eq!(deferred_box.set("hello".to_string()), Ok(()));
88 assert_eq!(deferred_box.get(), Some(&"hello".to_string()));
89 assert_eq!(deferred_box.set("world".to_string()), Err(super::DeferredBoxSetError()));
90 assert_eq!(deferred_box.get(), Some(&"hello".to_string()));
91 }
92
93 #[test]
94 fn test_get_or_init() {
95 let deferred_box = super::DeferredBox::new();
96 assert_eq!(deferred_box.get(), None);
97 assert_eq!(deferred_box.get_or_init(|| 1), &1);
98 assert_eq!(deferred_box.get(), Some(&1));
99 assert_eq!(deferred_box.get_or_init(|| 2), &1);
100 assert_eq!(deferred_box.get(), Some(&1));
101 }
102
103 #[test]
104 fn test_debug_message() {
105 let deferred_box: super::DeferredBox<i32> = super::DeferredBox::new();
106 deferred_box.set(50).unwrap();
107 assert_eq!(&format!("{:?}", deferred_box), "DeferredBox { Some(50) })");
108 }
109}