Skip to main content

history_box/
lib.rs

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}