spreadsheet_ods/ds/
detach.rs

1use get_size2::GetSize;
2/// Allows to detach data and reattach it later.
3use std::ops::{Deref, DerefMut};
4
5#[derive(Debug, GetSize)]
6pub(crate) struct Detach<T> {
7    val: Option<Box<T>>,
8}
9
10impl<T> Default for Detach<T> {
11    fn default() -> Self {
12        Self { val: None }
13    }
14}
15
16impl<T> Clone for Detach<T>
17where
18    T: Clone,
19{
20    fn clone(&self) -> Self {
21        if let Some(t) = &self.val {
22            Detach {
23                val: Some(t.clone()),
24            }
25        } else {
26            Detach { val: None }
27        }
28    }
29}
30
31impl<T> Deref for Detach<T> {
32    type Target = T;
33
34    fn deref(&self) -> &Self::Target {
35        self.val.as_ref().expect("already detached")
36    }
37}
38
39impl<T> DerefMut for Detach<T> {
40    fn deref_mut(&mut self) -> &mut Self::Target {
41        self.val.as_mut().expect("already detached")
42    }
43}
44
45impl<T> Detach<T> {
46    #[allow(dead_code)]
47    pub(crate) fn new(val: T) -> Self {
48        Self {
49            val: Some(Box::new(val)),
50        }
51    }
52
53    /// No data contained.
54    #[allow(dead_code)]
55    pub(crate) fn is_detached(&self) -> bool {
56        self.val.is_none()
57    }
58
59    /// Detaches the data and links it with a key for reattaching.
60    /// The key is not used here, but contains information for reattaching
61    /// where ever this is used.
62    ///
63    /// Panics
64    ///
65    /// Panics if the data was already detached.
66    pub(crate) fn detach<K: Copy>(&mut self, key: K) -> Detached<K, T> {
67        let val = self.val.take().expect("already detached");
68        Detached::new(key, val)
69    }
70
71    /// Reattaches the data.
72    pub(crate) fn attach<K: Copy>(&mut self, detached: Detached<K, T>) {
73        let Detached { key: _, val } = detached;
74        self.val.replace(val);
75    }
76
77    /// Returns a reference to the data.
78    ///
79    /// Panics
80    ///
81    /// Panics if the data was detached.
82    pub(crate) fn as_ref(&self) -> &T {
83        self.val.as_ref().expect("already detached")
84    }
85
86    /// Returns a reference to the data.
87    ///
88    /// Panics
89    ///
90    /// Panics if the data was detached.
91    pub(crate) fn as_mut(&mut self) -> &mut T {
92        self.val.as_mut().expect("already detached")
93    }
94
95    /// Dissolves this container.
96    ///
97    /// Panics
98    ///
99    /// Panics if the data was detached.
100    pub(crate) fn take(mut self) -> T {
101        *self.val.take().expect("already detached")
102    }
103}
104
105impl<T> From<T> for Detach<T> {
106    fn from(val: T) -> Self {
107        Self {
108            val: Some(Box::new(val)),
109        }
110    }
111}
112
113/// Detached data. Implements Deref and DerefMut for transparent access
114/// to the data. The attached key can be accessed with the key function.
115#[derive(Debug)]
116pub struct Detached<K, T> {
117    key: K,
118    val: Box<T>,
119}
120
121impl<K, T> Detached<K, T>
122where
123    K: Copy,
124{
125    fn new(key: K, val: Box<T>) -> Self {
126        Self { key, val }
127    }
128
129    /// Extracts the key.
130    pub fn key(det: &Detached<K, T>) -> K {
131        det.key
132    }
133}
134
135impl<K, T> Deref for Detached<K, T> {
136    type Target = T;
137
138    fn deref(&self) -> &Self::Target {
139        self.val.as_ref()
140    }
141}
142
143impl<K, T> DerefMut for Detached<K, T> {
144    fn deref_mut(&mut self) -> &mut Self::Target {
145        self.val.as_mut()
146    }
147}
148
149#[cfg(test)]
150mod tests {
151    use crate::ds::detach::Detach;
152
153    #[test]
154    fn test_detach() {
155        let mut dd = Detach::new("fop");
156
157        assert!(!dd.is_detached());
158
159        assert_eq!(*dd.as_ref(), "fop");
160        assert_eq!(*dd.as_mut(), "fop");
161
162        let d = dd.detach(0u32);
163
164        assert_eq!(*d, "fop");
165        assert_eq!(d.trim(), "fop");
166
167        assert!(dd.is_detached());
168
169        dd.attach(d);
170
171        assert!(!dd.is_detached());
172
173        let tt = dd.take();
174
175        assert_eq!(tt, "fop");
176    }
177}