1use std::any::{type_name, Any};
2use std::ffi::c_void;
3use std::mem::size_of;
4use std::ptr::NonNull;
5
6use crate::{BoxerError, Result, ReturnBoxerResult};
7
8
9#[repr(transparent)]
10pub struct ValueBox<T: Any> {
11 value: T,
12}
13
14impl<T: Any> ValueBox<T> {
15 pub fn new(object: T) -> Self {
16 Self { value: object }
17 }
18
19 pub fn has_value(&self) -> bool {
20 true
21 }
22
23 pub fn replace_value(&mut self, object: T) -> T {
24 std::mem::replace(&mut self.value, object)
25 }
26
27 pub fn set_value(&mut self, object: T) {
28 self.value = object;
29 }
30
31 pub fn clone_value(&self) -> T
32 where
33 T: Clone,
34 {
35 self.value.clone()
36 }
37
38 pub fn into_value(self) -> T {
39 self.value
40 }
41
42 pub fn into_raw(self) -> *mut Self {
43 let ptr: *mut T = into_raw(Box::new(self.value));
44 ptr.cast()
45 }
46
47 pub fn into_erased_raw(self) -> *mut ErasedValueBox {
48 self.into_raw().cast()
49 }
50}
51
52impl<T: Any> AsRef<T> for ValueBox<T> {
53 fn as_ref(&self) -> &T {
54 &self.value
55 }
56}
57
58impl<T: Any> AsMut<T> for ValueBox<T> {
59 fn as_mut(&mut self) -> &mut T {
60 &mut self.value
61 }
62}
63
64#[repr(C)]
65pub struct ErasedValueBox {
66 _private: [u8; 0],
67}
68
69pub trait ErasedValueBoxPointer {
70 fn with_ptr<R: Any, F>(&self, op: F) -> Result<R>
73 where
74 F: FnOnce(NonNull<c_void>) -> Result<R>;
75
76 fn with_ptr_ok<R: Any, F>(&self, op: F) -> Result<R>
79 where
80 F: FnOnce(NonNull<c_void>) -> R,
81 {
82 self.with_ptr(|pointer| Ok(op(pointer)))
83 }
84}
85
86pub trait ValueBoxPointer<T: Any> {
87 fn take_value(&self) -> Result<T>;
89
90 fn erase(self) -> *mut ErasedValueBox;
92
93 fn with_ref<R: Any, F>(&self, op: F) -> Result<R>
96 where
97 F: FnOnce(&T) -> Result<R>;
98
99 fn with_option_ref<R: Any, F>(&self, op: F) -> Result<R>
104 where
105 F: FnOnce(Option<&T>) -> Result<R>,
106 {
107 if self.has_value() {
108 self.with_ref(|value| op(Some(value)))
109 } else {
110 op(None)
111 }
112 }
113
114 fn with_ref_ok<R: Any, F>(&self, op: F) -> Result<R>
117 where
118 F: FnOnce(&T) -> R,
119 {
120 self.with_ref(|value| Ok(op(value)))
121 }
122
123 fn with_mut<R: Any, F>(&self, op: F) -> Result<R>
126 where
127 F: FnOnce(&mut T) -> Result<R>;
128
129 fn with_mut_ok<R: Any, F>(&self, op: F) -> Result<R>
132 where
133 F: FnOnce(&mut T) -> R,
134 {
135 self.with_mut(|value| Ok(op(value)))
136 }
137
138 fn with_clone<R: Any, F>(&self, op: F) -> Result<R>
141 where
142 F: FnOnce(T) -> Result<R>,
143 T: Clone,
144 {
145 self.with_ref(|value| op(value.clone()))
146 }
147
148 fn with_clone_ok<R: Any, F>(&self, op: F) -> Result<R>
151 where
152 F: FnOnce(T) -> R,
153 T: Clone,
154 {
155 self.with_clone(|value| Ok(op(value)))
156 }
157
158 fn with_ref_ref<R: Any, F, P: Any>(&self, ptr: *mut ValueBox<P>, op: F) -> Result<R>
161 where
162 F: FnOnce(&T, &P) -> Result<R>,
163 {
164 self.with_ref(|t| ptr.with_ref(|p| op(t, p)))
165 }
166
167 fn with_ref_ref_ref<R: Any, F, P1: Any, P2: Any>(
170 &self,
171 ptr1: *mut ValueBox<P1>,
172 ptr2: *mut ValueBox<P2>,
173 op: F,
174 ) -> Result<R>
175 where
176 F: FnOnce(&T, &P1, &P2) -> Result<R>,
177 {
178 self.with_ref(|t| ptr1.with_ref(|p1| ptr2.with_ref(|p2| op(t, p1, p2))))
179 }
180
181 fn with_ref_ref_ref_ref<R: Any, F, P1: Any, P2: Any, P3: Any>(
184 &self,
185 ptr1: *mut ValueBox<P1>,
186 ptr2: *mut ValueBox<P2>,
187 ptr3: *mut ValueBox<P3>,
188 op: F,
189 ) -> Result<R>
190 where
191 F: FnOnce(&T, &P1, &P2, &P3) -> Result<R>,
192 {
193 self.with_ref(|t| {
194 ptr1.with_ref(|p1| ptr2.with_ref(|p2| ptr3.with_ref(|p3| op(t, p1, p2, p3))))
195 })
196 }
197
198 fn replace_value<F>(&self, op: F) -> Result<()>
202 where
203 F: FnOnce(T) -> T;
204
205 fn release(self);
206
207 fn has_value(&self) -> bool {
208 self.with_ref_ok(|_| ()).is_ok()
209 }
210
211 #[deprecated(since = "0.1.0", note = "please use `has_value` instead")]
212 fn is_valid(&self) -> bool {
213 self.has_value()
214 }
215
216 #[deprecated(since = "0.1.0", note = "please use `with_ref` or `with_mut` instead")]
217 fn with_not_null<Block>(&self, block: Block)
218 where
219 Block: FnOnce(&mut T),
220 {
221 self.with_mut_ok(|value| block(value)).log();
222 }
223
224 #[deprecated(since = "0.1.0", note = "please use `with_ref` or `with_mut` instead")]
225 fn with_not_null_return<Block, Return: Any>(&self, default: Return, block: Block) -> Return
226 where
227 Block: FnOnce(&mut T) -> Return,
228 {
229 self.with_mut_ok(|value| block(value)).or_log(default)
230 }
231
232 #[deprecated(since = "0.1.0", note = "please use `with_ref` or `with_mut` instead")]
233 fn with_value<DefaultBlock, Block, Return: Any>(
234 &self,
235 default: DefaultBlock,
236 block: Block,
237 ) -> Return
238 where
239 DefaultBlock: FnOnce() -> Return,
240 Block: FnOnce(T) -> Return,
241 T: Clone,
242 {
243 self.with_clone_ok(block).unwrap_or_else(|_| default())
244 }
245
246 #[deprecated(since = "0.1.0", note = "please use `with_ref` or `with_mut` instead")]
247 fn with_not_null_value<Block>(&self, block: Block)
248 where
249 Block: FnOnce(T),
250 T: Clone,
251 {
252 self.with_ref_ok(|value| block(value.clone())).log();
253 }
254
255 #[deprecated(since = "0.1.0", note = "please use `with_ref` or `with_mut` instead")]
256 fn with_not_null_value_return<Block, Return: Any>(
257 &self,
258 default: Return,
259 block: Block,
260 ) -> Return
261 where
262 Block: FnOnce(T) -> Return,
263 T: Clone,
264 {
265 self.with_ref_ok(|reference| block(reference.clone()))
266 .unwrap_or(default)
267 }
268}
269
270impl<T: Any> ValueBoxPointer<T> for *mut ValueBox<T> {
271 fn take_value(&self) -> Result<T> {
272 if self.is_null() {
273 return BoxerError::NullPointer(type_name::<T>().to_string()).into();
274 }
275
276 let value_box = unsafe { *from_raw(*self) };
277 Ok(value_box.into_value())
278 }
279
280 fn erase(self) -> *mut ErasedValueBox {
281 self.cast()
282 }
283
284 fn with_ref<R: Any, F>(&self, op: F) -> Result<R>
285 where
286 F: FnOnce(&T) -> Result<R>,
287 {
288 if self.is_null() {
289 return BoxerError::NullPointer(type_name::<T>().to_string()).into();
290 }
291
292 unsafe { op(&(**self).value) }
293 }
294
295 fn with_mut<R: Any, F>(&self, op: F) -> Result<R>
296 where
297 F: FnOnce(&mut T) -> Result<R>,
298 {
299 if self.is_null() {
300 return BoxerError::NullPointer(type_name::<T>().to_string()).into();
301 }
302
303 unsafe { op(&mut (**self).value) }
304 }
305
306 fn replace_value<F>(&self, op: F) -> Result<()>
307 where
308 F: FnOnce(T) -> T,
309 {
310 if self.is_null() {
311 return BoxerError::NullPointer(type_name::<T>().to_string()).into();
312 }
313
314 let value = unsafe { &mut (**self).value };
315 let guard = AbortOnPanic;
316 let previous_value = unsafe { std::ptr::read(value) };
317 let new_value = op(previous_value);
318 unsafe { std::ptr::write(value, new_value) };
319 std::mem::forget(guard);
320 Ok(())
321 }
322
323 #[allow(clippy::not_unsafe_ptr_arg_deref)]
324 fn release(self) {
325 let result = if self.is_null() {
326 BoxerError::NullPointer(type_name::<T>().to_string()).into()
327 } else {
328 unsafe { Ok(from_raw(self)) }
329 };
330 result.log();
331 }
332
333 fn has_value(&self) -> bool {
334 !self.is_null()
335 }
336}
337
338impl<T: Any> ErasedValueBoxPointer for *mut ValueBox<T> {
339 fn with_ptr<R: Any, F>(&self, op: F) -> Result<R>
340 where
341 F: FnOnce(NonNull<c_void>) -> Result<R>,
342 {
343 if self.is_null() {
344 return BoxerError::NullPointer(type_name::<T>().to_string()).into();
345 }
346
347 let pointer = NonNull::new((*self).cast::<c_void>())
348 .expect("nonnull pointer must be available after null check");
349 op(pointer)
350 }
351}
352
353impl ErasedValueBoxPointer for *mut ErasedValueBox {
354 fn with_ptr<R: Any, F>(&self, op: F) -> Result<R>
355 where
356 F: FnOnce(NonNull<c_void>) -> Result<R>,
357 {
358 if self.is_null() {
359 return BoxerError::NullPointer("erased value box".to_string()).into();
360 }
361
362 let pointer = NonNull::new((*self).cast::<c_void>())
363 .expect("nonnull pointer must be available after null check");
364 op(pointer)
365 }
366}
367
368impl ErasedValueBoxPointer for *const ErasedValueBox {
369 fn with_ptr<R: Any, F>(&self, op: F) -> Result<R>
370 where
371 F: FnOnce(NonNull<c_void>) -> Result<R>,
372 {
373 if self.is_null() {
374 return BoxerError::NullPointer("erased value box".to_string()).into();
375 }
376
377 let pointer = NonNull::new((*self).cast_mut().cast::<c_void>())
378 .expect("nonnull pointer must be available after null check");
379 op(pointer)
380 }
381}
382
383pub unsafe fn from_raw<T>(pointer: *mut T) -> Box<T> {
391 assert!(!pointer.is_null(), "from_raw(): Pointer must not be null!");
392 assert_eq!(
393 size_of::<*mut T>(),
394 size_of::<*mut std::ffi::c_void>(),
395 "The pointer must be compatible with void*"
396 );
397 unsafe { Box::from_raw(pointer) }
398}
399
400pub fn into_raw<T>(_box: Box<T>) -> *mut T {
401 assert_eq!(
402 size_of::<*mut T>(),
403 size_of::<*mut std::ffi::c_void>(),
404 "The pointer must be compatible with void*"
405 );
406 Box::into_raw(_box)
407}
408
409struct AbortOnPanic;
410
411impl Drop for AbortOnPanic {
412 fn drop(&mut self) {
413 if std::thread::panicking() {
414 std::process::abort();
415 }
416 }
417}
418
419#[cfg(test)]
420mod test {
421 #![allow(deprecated)]
422 #![allow(dead_code)]
423
424 use std::error::Error;
425 use std::ffi::c_void;
426 use std::fmt::{Display, Formatter};
427 use std::mem::size_of;
428 use std::rc::Rc;
429
430 use crate::value_box::{ErasedValueBox, ErasedValueBoxPointer, ValueBox, ValueBoxPointer};
431
432 use super::*;
433
434 #[derive(Debug)]
435 pub struct CustomError {}
436
437 impl Display for CustomError {
438 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
439 f.write_str("CustomError")
440 }
441 }
442
443 impl Error for CustomError {}
444
445 #[test]
446 pub fn value_box_size_in_memory() -> Result<()> {
447 assert_eq!(size_of::<ValueBox<c_void>>(), size_of::<c_void>());
448 assert_eq!(size_of::<ValueBox<(u64, u64)>>(), size_of::<(u64, u64)>());
449 assert_eq!(size_of::<ValueBox<()>>(), size_of::<()>());
450 assert_eq!(
451 size_of::<ValueBox<Box<dyn Error>>>(),
452 size_of::<Box<dyn Error>>()
453 );
454
455 Ok(())
456 }
457
458 #[test]
459 pub fn value_box_as_ref_mut() -> Result<()> {
460 let value_box = ValueBox::new(5);
461 let value_box_ptr = value_box.into_raw();
462 let value = value_box_ptr.with_ref_ok(|value| *value)?;
463 assert_eq!(value, 5);
464 value_box_ptr.release();
465
466 Ok(())
467 }
468
469 #[test]
470 pub fn value_box_as_non_null() -> Result<()> {
471 let value_box = ValueBox::new(5_i32);
472 let value_box_ptr = value_box.into_raw();
473 let value = value_box_ptr.with_ptr_ok(|pointer| unsafe {
474 *(pointer.as_ptr().cast::<i32>())
475 })?;
476 assert_eq!(value, 5);
477 value_box_ptr.release();
478
479 Ok(())
480 }
481
482 #[test]
483 pub fn erased_value_box_as_non_null() -> Result<()> {
484 let value_box = ValueBox::new(7_i32);
485 let value_box_ptr = value_box.into_raw();
486 let erased_value_box_ptr = value_box_ptr.erase();
487 let value = erased_value_box_ptr.with_ptr_ok(|pointer| unsafe {
488 *(pointer.as_ptr().cast::<i32>())
489 })?;
490 assert_eq!(value, 7);
491 value_box_ptr.release();
492
493 Ok(())
494 }
495
496 #[test]
497 pub fn value_box_into_erased_raw() -> Result<()> {
498 let erased_value_box_ptr = ValueBox::new(9_i32).into_erased_raw();
499 let value = erased_value_box_ptr.with_ptr_ok(|pointer| unsafe {
500 *(pointer.as_ptr().cast::<i32>())
501 })?;
502 assert_eq!(value, 9);
503 unsafe { from_raw::<i32>(erased_value_box_ptr.cast()) };
504
505 Ok(())
506 }
507
508 #[test]
509 pub fn const_erased_value_box_as_non_null() -> Result<()> {
510 let value_box_ptr = ValueBox::new(11_i32).into_raw();
511 let erased_value_box_ptr = value_box_ptr.erase() as *const ErasedValueBox;
512 let value = erased_value_box_ptr.with_ptr_ok(|pointer| unsafe {
513 *(pointer.as_ptr().cast::<i32>())
514 })?;
515 assert_eq!(value, 11);
516 value_box_ptr.release();
517
518 Ok(())
519 }
520
521 #[test]
522 fn value_box_with_not_null_value() {
523 let value_box = ValueBox::new(5);
524
525 let value_box_ptr = value_box.into_raw();
526 assert!(!value_box_ptr.is_null());
527
528 let mut result = 0;
529 value_box_ptr.with_not_null_value(|value| result = value * 2);
530 assert!(!value_box_ptr.is_null());
531 assert_eq!(result, 10);
532
533 value_box_ptr.release();
534 }
535
536 #[test]
537 fn value_box_with_not_null_value_return() {
538 let value_box = ValueBox::new(5);
539
540 let value_box_ptr = value_box.into_raw();
541 assert!(!value_box_ptr.is_null());
542
543 let result = value_box_ptr.with_not_null_value_return(0, |value| value * 2);
544 assert!(!value_box_ptr.is_null());
545 assert_eq!(result, 10);
546
547 value_box_ptr.release();
548 }
549
550 #[test]
551 fn value_box_drop() {
552 let value = Rc::new(42);
553
554 let ptr = ValueBox::new(value.clone()).into_raw();
555 assert_eq!(Rc::strong_count(&value), 2);
556 ptr.release();
557
558 assert_eq!(Rc::strong_count(&value), 1);
559 }
560}