1use std::cell::{Cell, UnsafeCell};
2use std::fmt::Debug;
3use std::ptr::null;
4
5pub struct HistoryBox<T> {
6 pointer: Cell<* const T>,
7 history: UnsafeCell<Vec<Box<T>>>,
8}
9
10impl<T> HistoryBox<T> {
11
12 pub fn new() -> Self {
13 Self {
14 pointer: Cell::new(null()),
15 history: UnsafeCell::new(Vec::new()),
16 }
17 }
18
19 pub fn new_with(value: T) -> Self {
20 let retval = Self::new();
21 retval.set(value);
22 retval
23 }
24
25 pub fn set(&self, value: T) {
26 let history = unsafe { &mut *self.history.get() };
27 history.push(Box::new(value));
28 self.pointer.set(history.last().unwrap().as_ref());
29 }
30
31 pub fn get(&self) -> Option<&T> {
32 if self.pointer.get().is_null() {
33 None
34 } else {
35 Some(unsafe { &*self.pointer.get() })
36 }
37 }
38
39 pub unsafe fn get_mut(&self) -> Option<&mut T> {
40 if self.pointer.get().is_null() {
41 None
42 } else {
43 Some(unsafe { &mut *(self.pointer.get() as *mut T) })
44 }
45 }
46}
47
48impl<T> Default for HistoryBox<T> {
49 fn default() -> Self {
50 Self::new()
51 }
52}
53
54unsafe impl<T> Send for HistoryBox<T> where T: Send { }
55unsafe impl<T> Sync for HistoryBox<T> where T: Sync { }
56
57impl<T> Debug for HistoryBox<T> where T: Debug {
58 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59 let history = unsafe { &*self.history.get() };
60 write!(f, "HistoryBox {{ current: {:?}, history: {:?} }}", self.get(), history)
61 }
62}
63
64#[cfg(test)]
65mod test {
66 use std::any::Any;
67 use super::*;
68
69 #[test]
70 fn test_history_box_set_get() {
71 let history_box = HistoryBox::new();
72 assert_eq!(history_box.get(), None);
73 history_box.set(1);
74 assert_eq!(history_box.get(), Some(&1));
75 history_box.set(2);
76 assert_eq!(history_box.get(), Some(&2));
77 history_box.set(3);
78 assert_eq!(history_box.get(), Some(&3));
79 }
80
81 #[test]
82 fn test_history_box_get_mut() {
83 let history_box = HistoryBox::new_with(50);
84 assert_eq!(history_box.get(), Some(&50));
85 unsafe { history_box.get_mut().map(|v| *v = 100) };
86 assert_eq!(history_box.get(), Some(&100));
87 }
88
89 #[test]
90 fn test_history_box_debug_message() {
91 let history_box = HistoryBox::new();
92 assert_eq!(format!("{:?}", history_box), "HistoryBox { current: None, history: [] }");
93 history_box.set(1);
94 assert_eq!(format!("{:?}", history_box), "HistoryBox { current: Some(1), history: [1] }");
95 history_box.set(2);
96 assert_eq!(format!("{:?}", history_box), "HistoryBox { current: Some(2), history: [1, 2] }");
97 history_box.set(3);
98 assert_eq!(format!("{:?}", history_box), "HistoryBox { current: Some(3), history: [1, 2, 3] }");
99 }
100
101 #[test]
102 fn history_box_with_dyn_any() {
103 let history_box = HistoryBox::<Box<dyn Any>>::new();
104 assert!(history_box.get().is_none());
105 history_box.set(Box::new(3));
106 let a = history_box.get();
107 assert_eq!(a.map(|v| v.downcast_ref::<i32>()), Some(Some(&3)));
108 history_box.set(Box::new("abc"));
109 let a = history_box.get();
110 assert_eq!(a.map(|v| v.downcast_ref::<&str>()), Some(Some(&"abc")));
111 }
112}