1use std::ops::{Deref, DerefMut};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum Augmented<T, A: Clone> {
15 Primary(T),
17 WithAux(T, A),
19}
20
21impl<T, A: Clone> Augmented<T, A> {
22 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Augmented<U, A> {
25 match self {
26 Self::Primary(t) => Augmented::Primary(f(t)),
27 Self::WithAux(t, aux) => Augmented::WithAux(f(t), aux),
28 }
29 }
30
31 pub fn extract(self) -> T {
34 match self {
35 Self::Primary(t) => t,
36 Self::WithAux(t, _) => t,
37 }
38 }
39
40 pub fn as_ref(&self) -> Augmented<&T, A> {
42 match self {
43 Self::Primary(t) => Augmented::Primary(t),
44 Self::WithAux(t, aux) => Augmented::WithAux(t, aux.clone()),
45 }
46 }
47
48 pub fn as_mut(&mut self) -> Augmented<&mut T, A> {
50 match self {
51 Self::Primary(t) => Augmented::Primary(t),
52 Self::WithAux(t, aux) => Augmented::WithAux(t, aux.clone()),
53 }
54 }
55}
56
57impl<T, A: Clone> Augmented<&mut T, A> {
58 pub fn as_unmut(&self) -> Augmented<&T, A> {
60 match self {
61 Self::Primary(t) => Augmented::Primary(t),
62 Self::WithAux(t, aux) => Augmented::WithAux(t, aux.clone()),
63 }
64 }
65}
66
67impl<T, A: Clone> Augmented<Option<T>, A> {
68 pub fn transpose(self) -> Option<Augmented<T, A>> {
70 match self {
71 Self::Primary(t) => Some(Augmented::Primary(t?)),
72 Self::WithAux(t, aux) => Some(Augmented::WithAux(t?, aux)),
73 }
74 }
75}
76
77impl<T, A: Clone, E> Augmented<Result<T, E>, A> {
78 pub fn transpose(self) -> Result<Augmented<T, A>, E> {
80 match self {
81 Self::Primary(t) => Ok(Augmented::Primary(t?)),
82 Self::WithAux(t, aux) => Ok(Augmented::WithAux(t?, aux)),
83 }
84 }
85}
86
87impl<T, A: Clone> From<T> for Augmented<T, A> {
88 fn from(t: T) -> Self {
90 Self::Primary(t)
91 }
92}
93
94impl<T, A: Clone> Deref for Augmented<T, A> {
95 type Target = T;
96
97 fn deref(&self) -> &Self::Target {
99 match self {
100 Self::Primary(t) => &t,
101 Self::WithAux(t, _) => &t,
102 }
103 }
104}
105
106impl<T, A: Clone> DerefMut for Augmented<T, A> {
107 fn deref_mut(&mut self) -> &mut Self::Target {
109 match self {
110 Self::Primary(t) => t,
111 Self::WithAux(t, _) => t,
112 }
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 #[test]
121 fn test_map() {
122 let primary = Augmented::<_, ()>::Primary(5);
123 let mapped_primary = primary.map(|x| x * 2);
124 assert!(matches!(mapped_primary, Augmented::<_, ()>::Primary(10)));
125
126 let with_aux = Augmented::WithAux(5, "hello");
127 let mapped_with_aux = with_aux.map(|x| x * 2);
128 assert!(matches!(mapped_with_aux, Augmented::WithAux(10, "hello")));
129 }
130
131 #[test]
132 fn test_extract() {
133 assert_eq!(Augmented::<_, ()>::Primary(5).extract(), 5);
134 assert_eq!(Augmented::WithAux(5, "hello").extract(), 5);
135 }
136
137 #[test]
138 fn test_as_ref() {
139 let primary = Augmented::<_, ()>::Primary(5);
140 let ref_primary = primary.as_ref();
141 assert!(matches!(ref_primary, Augmented::<_, ()>::Primary(&5)));
142
143 let with_aux = Augmented::WithAux(5, "hello");
144 let ref_with_aux = with_aux.as_ref();
145 assert!(matches!(ref_with_aux, Augmented::WithAux(&5, "hello")));
146 }
147
148 #[test]
149 fn test_as_mut() {
150 let mut primary = Augmented::<_, ()>::Primary(5);
151 if let Augmented::<_, ()>::Primary(val) = primary.as_mut() {
152 *val = 10;
153 }
154 assert_eq!(*primary, 10);
155
156 let mut with_aux = Augmented::WithAux(5, "hello");
157 if let Augmented::WithAux(val, aux) = with_aux.as_mut() {
158 assert_eq!(aux, "hello");
159 *val = 10;
160 }
161 assert_eq!(*with_aux, 10);
162 }
163
164 #[test]
165 fn test_as_unmut() {
166 let mut primary = Augmented::<_, ()>::Primary(5);
167 let mut_ref = primary.as_mut();
168 let unmut_ref = mut_ref.as_unmut();
169 assert!(matches!(unmut_ref, Augmented::<_, ()>::Primary(&5)));
170
171 let mut with_aux = Augmented::WithAux(5, "hello");
172 let mut_ref_aux = with_aux.as_mut();
173 let unmut_ref_aux = mut_ref_aux.as_unmut();
174 assert!(matches!(unmut_ref_aux, Augmented::WithAux(&5, "hello")));
175 }
176
177 #[test]
178 fn test_transpose_option() {
179 let primary_some = Augmented::<_, ()>::Primary(Some(5));
180 let transposed_primary_some = primary_some.transpose();
181 assert!(matches!(transposed_primary_some, Some(Augmented::<_, ()>::Primary(5))));
182
183 let primary_none: Augmented<Option<i32>, &str> = Augmented::Primary(None);
184 assert!(primary_none.transpose().is_none());
185
186 let with_aux_some = Augmented::WithAux(Some(5), "hello");
187 let transposed_with_aux_some = with_aux_some.transpose();
188 assert!(matches!(transposed_with_aux_some, Some(Augmented::WithAux(5, "hello"))));
189
190 let with_aux_none: Augmented<Option<i32>, &str> = Augmented::WithAux(None, "hello");
191 assert!(with_aux_none.transpose().is_none());
192 }
193
194 #[test]
195 fn test_transpose_result() {
196 let primary_ok: Augmented<Result<i32, &str>, &str> = Augmented::Primary(Ok(5));
197 let transposed_primary_ok = primary_ok.transpose();
198 assert!(matches!(transposed_primary_ok, Ok(Augmented::Primary(5))));
199
200 let primary_err: Augmented<Result<i32, &str>, &str> = Augmented::Primary(Err("error"));
201 assert_eq!(primary_err.transpose(), Err("error"));
202
203 let with_aux_ok: Augmented<Result<i32, &str>, &str> = Augmented::WithAux(Ok(5), "hello");
204 let transposed_with_aux_ok = with_aux_ok.transpose();
205 assert!(matches!(transposed_with_aux_ok, Ok(Augmented::WithAux(5, "hello"))));
206
207 let with_aux_err: Augmented<Result<i32, &str>, &str> =
208 Augmented::WithAux(Err("error"), "hello");
209 assert_eq!(with_aux_err.transpose(), Err("error"));
210 }
211
212 #[test]
213 fn test_from() {
214 let augmented: Augmented<i32, &str> = 5.into();
215 assert!(matches!(augmented, Augmented::Primary(5)));
216 }
217
218 #[test]
219 fn test_deref() {
220 assert_eq!(*Augmented::<_, ()>::Primary(5), 5);
221 assert_eq!(*Augmented::WithAux(5, "hello"), 5);
222 }
223
224 #[test]
225 fn test_deref_mut() {
226 let mut primary = Augmented::<_, ()>::Primary(5);
227 *primary = 10;
228 assert_eq!(*primary, 10);
229
230 let mut with_aux = Augmented::WithAux(5, "hello");
231 *with_aux = 10;
232 assert_eq!(*with_aux, 10);
233 }
234
235 #[derive(Clone, Copy, Debug, PartialEq)]
236 struct Data {
237 a: i32,
238 b: i32,
239 }
240
241 #[derive(Clone, Copy, Debug, PartialEq)]
242 struct DataOverride {
243 b: Option<i32>,
244 }
245
246 fn get_b(augmented: &Augmented<Data, DataOverride>) -> i32 {
247 match augmented {
248 Augmented::Primary(data) => data.b,
249 Augmented::WithAux(data, aux) => aux.b.unwrap_or(data.b),
250 }
251 }
252
253 #[test]
254 fn test_override_example() {
255 let primary = Augmented::Primary(Data { a: 1, b: 2 });
256 assert_eq!(get_b(&primary), 2);
257
258 let with_aux_override =
259 Augmented::WithAux(Data { a: 1, b: 2 }, DataOverride { b: Some(3) });
260 assert_eq!(get_b(&with_aux_override), 3);
261
262 let with_aux_no_override =
263 Augmented::WithAux(Data { a: 1, b: 2 }, DataOverride { b: None });
264 assert_eq!(get_b(&with_aux_no_override), 2);
265 }
266}