1use std::ptr::{NonNull, null_mut, write};
2
3use crate::MangledBoxArbitrary;
4
5
6pub enum MangledOption<T> {
13 Some(MangledBoxArbitrary<T>),
14 None,
15}
16
17impl<T> MangledOption<T> {
18 pub fn new() -> Self {
20 Self::None
21 }
22
23 pub fn filled_with_unmasked_value(value: T) -> Self {
28 let mut this = Self::new();
29 this.insert_unmasked_value(value);
30 this
31 }
32
33 pub fn is_some(&self) -> bool {
35 matches!(self, Self::Some(_))
36 }
37
38 pub fn is_none(&self) -> bool {
40 !self.is_some()
41 }
42
43 pub fn take(&mut self) -> MangledOption<T> {
45 std::mem::take(self)
46 }
47
48 pub fn clear(&mut self) {
50 *self = Self::None;
52 }
53
54 pub fn insert_unmasked_value(&mut self, value: T) {
60 self.insert_by_ptr(|p| unsafe { p.write(value); });
61 }
62
63 pub fn insert_by_ptr(&mut self, f: impl FnOnce(NonNull<T>)) {
69 let mut new_content_box = MangledBoxArbitrary::new();
70 new_content_box.with_unmangled(f);
71 *self = Self::Some(new_content_box);
72 }
73
74 pub fn map_mut_or_else<F, G, R>(&mut self, default: G, f: F) -> R
83 where
84 F: FnOnce(&mut T) -> R,
85 G: FnOnce() -> R,
86 {
87 match self {
88 MangledOption::Some(mangled_box) => {
89 mangled_box.with_unmangled(|mut ptr| f(unsafe { ptr.as_mut() }))
90 }
91 MangledOption::None => default(),
92 }
93 }
94
95 pub fn map_mut<F, R>(&mut self, f: F) -> Option<R>
103 where
104 F: FnOnce(&mut T) -> R,
105 {
106 self.map_mut_or_else(|| None, |m| Some(f(m)))
107 }
108
109 pub fn rekey(&mut self) {
111 match self {
112 MangledOption::Some(mangled_box) => {
113 mangled_box.rekey();
114 }
115 MangledOption::None => {}
116 }
117 }
118
119 pub fn as_ptr(&mut self) -> *mut T {
121 match self {
122 MangledOption::Some(mangled_box) => mangled_box.with_mangled(|p| p.as_ptr()),
123 MangledOption::None => null_mut(),
124 }
125 }
126}
127
128impl<T> Drop for MangledOption<T> {
129 fn drop(&mut self) {
130 match self {
131 MangledOption::Some(mangled_box) => {
132 unsafe { mangled_box.drop_in_place(); }
133 }
134 MangledOption::None => {}
135 }
136 unsafe { write(self as *mut Self, Self::None); }
137 }
138}
139
140impl<T> Default for MangledOption<T> {
141 fn default() -> Self {
142 Self::None
143 }
144}
145
146
147#[cfg(all(test, not(miri)))]
148mod tests {
149 use std::sync::atomic::{AtomicUsize, Ordering};
150 use std::mem::size_of;
151
152 use super::*;
153
154
155 #[test]
156 fn test_map_mut() {
157 let mut option = MangledOption::filled_with_unmasked_value(42);
158 assert_eq!(option.map_mut(|x| { *x += 1; *x }), Some(43));
159 }
160
161 #[test]
162 fn test_map_mut_or_else() {
163 let mut option = MangledOption::filled_with_unmasked_value(42);
164 assert_eq!(option.map_mut_or_else(|| 5, |x| { *x += 1; *x }), 43);
165
166 option = MangledOption::None;
167 assert_eq!(option.map_mut_or_else(|| 5, |x| { *x += 1; *x }), 5);
168 }
169
170 #[test]
171 fn test_new_is_none() {
172 let option: MangledOption<i32> = MangledOption::new();
173 assert!(option.is_none());
174 }
175
176 #[test]
177 fn test_filled_with_unmasked_value() {
178 let mut option = MangledOption::filled_with_unmasked_value(10);
179 assert!(option.is_some());
180 assert_eq!(option.map_mut(|x| *x), Some(10));
181 }
182
183 #[test]
184 fn test_take() {
185 let mut option = MangledOption::filled_with_unmasked_value(20);
186 let mut taken = option.take();
187
188 assert!(option.is_none());
189 assert_eq!(taken.map_mut(|x| *x), Some(20));
190 }
191
192 #[test]
193 fn test_clear() {
194 let mut option = MangledOption::filled_with_unmasked_value(30);
195 option.clear();
196 assert!(option.is_none());
197 }
198
199 #[test]
200 fn test_insert_unmasked_value() {
201 let mut option = MangledOption::new();
202 option.insert_unmasked_value(40);
203 assert_eq!(option.map_mut(|x| *x), Some(40));
204
205 option.insert_unmasked_value(50); assert_eq!(option.map_mut(|x| *x), Some(50));
207 }
208
209 #[test]
210 fn test_insert_by_ptr() {
211 let mut option = MangledOption::<usize>::new();
212 option.insert_by_ptr(|ptr| unsafe { ptr.as_ptr().write(60) });
213 assert_eq!(option.map_mut(|x| *x), Some(60));
214
215 option.insert_by_ptr(|ptr| unsafe { ptr.as_ptr().write(70) });
217 assert_eq!(option.map_mut(|x| *x), Some(70));
218 }
219
220 #[test]
221 fn test_rekey() {
222 let mut option = MangledOption::filled_with_unmasked_value(80);
223 let original_value = option.map_mut(|x| *x).unwrap();
224
225 option.rekey(); assert_eq!(option.map_mut(|x| *x), Some(original_value));
227 }
228
229 #[test]
230 fn test_drop_behavior() {
231 static DROP_COUNT: AtomicUsize = AtomicUsize::new(0);
232
233 struct DropCounter;
234 impl Drop for DropCounter {
235 fn drop(&mut self) {
236 DROP_COUNT.fetch_add(1, Ordering::SeqCst);
237 }
238 }
239
240 {
241 let _option = MangledOption::filled_with_unmasked_value(DropCounter);
242 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 0);
243 }
244 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 1);
245
246 {
247 let _option = MangledOption::<DropCounter>::new();
248 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 1);
249 }
250 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 1);
251
252 {
253 let mut option = MangledOption::filled_with_unmasked_value(DropCounter);
254 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 1);
255 option.clear();
256 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 2);
257 }
258 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 2);
259
260 {
261 let mut option = MangledOption::new();
262 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 2);
263 option.insert_unmasked_value(DropCounter);
264 }
265 assert_eq!(DROP_COUNT.load(Ordering::SeqCst), 3);
266 }
267
268 #[test]
269 fn test_string_content() {
270 let s = String::from("test_value");
271 let mut option = MangledOption::filled_with_unmasked_value(s);
272
273 option.map_mut(|inner| assert_eq!(inner, "test_value"));
274
275 option.map_mut(|inner| inner.push_str("_modified"));
276 option.map_mut(|inner| assert_eq!(inner, "test_value_modified"));
277
278 option.rekey();
280 option.map_mut(|inner| assert_eq!(inner, "test_value_modified"));
281 }
282
283 #[test]
284 fn test_padded_struct() {
285 #[repr(C)]
286 #[derive(Debug, PartialEq)]
287 struct Padded {
288 a: u8,
289 b: u16,
290 c: u32,
291 }
292
293 let val = Padded { a: 0xAA, b: 0xBBBB, c: 0xCCCCCCCC };
294 let mut option = MangledOption::filled_with_unmasked_value(val);
295
296 option.map_mut(|inner| assert_eq!(*inner, Padded { a: 0xAA, b: 0xBBBB, c: 0xCCCCCCCC }));
297
298 option.map_mut(|inner| inner.a = 0x11);
299 option.map_mut(|inner| {
300 assert_eq!(inner.a, 0x11);
301 assert_eq!(inner.b, 0xBBBB);
302 assert_eq!(inner.c, 0xCCCCCCCC);
303 });
304
305 option.rekey();
307 option.map_mut(|inner| {
308 inner.b = 0x2222;
309 assert_eq!(inner.a, 0x11);
310 });
311 option.map_mut(|inner| assert_eq!(*inner, Padded { a: 0x11, b: 0x2222, c: 0xCCCCCCCC }));
312 }
313
314 #[test]
315 fn test_large_inline_struct() {
316 #[derive(PartialEq, Eq, Debug)]
317 struct LargeStruct([u64; 8]);
318
319 let val = LargeStruct([0xDEADBEEF; 8]);
320 let mut option = MangledOption::filled_with_unmasked_value(val);
321
322 option.map_mut(|inner| assert_eq!(inner.0, [0xDEADBEEF; 8]));
323
324 option.map_mut(|inner| inner.0[4] = 0xCAFEBABE);
326 option.map_mut(|inner| {
327 assert_eq!(inner.0[0], 0xDEADBEEF);
328 assert_eq!(inner.0[4], 0xCAFEBABE);
329 });
330 }
331
332 #[test]
333 fn test_rekey_integrity() {
334 struct Nested {
335 a: u32,
336 b: MangledOption<u64>,
337 }
338
339 let mut option = MangledOption::filled_with_unmasked_value(Nested {
340 a: 0x12345678,
341 b: MangledOption::filled_with_unmasked_value(0xABCDEF),
342 });
343
344 option.map_mut(|inner| {
345 assert_eq!(inner.a, 0x12345678);
346 assert_eq!(inner.b.map_mut(|x| *x), Some(0xABCDEF));
347 });
348
349 option.rekey();
351 option.map_mut(|inner| {
352 inner.b.rekey();
353 inner.a = 0x87654321;
354 });
355
356 option.map_mut(|inner| {
357 assert_eq!(inner.a, 0x87654321);
358 assert_eq!(inner.b.map_mut(|x| *x), Some(0xABCDEF));
359 });
360 option.map_mut(|inner| {
361 inner.b.map_mut(|x| *x = 0x123456789);
362 });
363
364 option.map_mut(|inner| {
366 assert_eq!(inner.b.map_mut(|x| *x), Some(0x123456789));
367 });
368 }
369
370 #[test]
371 fn xor_behavior() {
372 #[repr(C)]
373 #[derive(Debug, PartialEq)]
374 struct Padded {
375 a: u8,
376 b: u16,
377 c: u32,
378 }
379
380 let mut option = MangledOption::new();
381 option.insert_by_ptr(|ptr: NonNull<Padded>| {
382 let a = ptr.addr().trailing_zeros() as u8;
383 let c = size_of::<Padded>() as u32;
384
385 unsafe {
387 let place: *mut u8 = ptr.as_ptr().cast();
388 place.write(a);
389 place.add(2).write(0xAA);
390 place.add(3).write(0xBB);
391 place.add(4).cast::<u32>().write(c);
392 }
393 });
394
395 let had = option.map_mut(|inner| {
396 assert!(inner.a < 64);
397 assert_eq!(inner.b, u16::from_ne_bytes([0xAA, 0xBB]));
398 assert_eq!(inner.c as usize, size_of::<Padded>());
399 });
400 assert!(had.is_some());
401
402 let p: *mut u8 = option.as_ptr().cast();
403 unsafe {
404 p.write(p.read() ^ 128);
405 }
406 let had = option.map_mut(|inner| {
407 assert!(inner.a > 128);
408 assert_eq!(inner.b, u16::from_ne_bytes([0xAA, 0xBB]));
409 assert_eq!(inner.c as usize, size_of::<Padded>());
410 });
411 assert!(had.is_some());
412 }
413}
414