deser_core/ser/boxed.rs
1//! Owned values of serializations (emitters and forwarded values).
2use alloc::boxed::Box;
3use core::fmt;
4use core::marker::PhantomData;
5use core::ops::{Deref, DerefMut};
6use core::ptr::NonNull;
7
8use crate::State;
9use crate::de::arena::ArenaBox;
10
11/// An owned value of a serialization, like a `Box`.
12///
13/// The value is either in the arena of the serialization (which is how
14/// [`Chunk::seq`](crate::ser::Chunk::seq), [`Chunk::map`](crate::ser::Chunk::map),
15/// [`Chunk::structure`](crate::ser::Chunk::structure) and
16/// [`SerializeHandle::arena`](crate::ser::SerializeHandle::arena) allocate
17/// it) or on the heap (`Box::new(value).into()`). The arena belongs to the
18/// state, the emitters of the open containers are on top of each other in
19/// it, allocating one bumps a pointer and the space is reused once it's
20/// dropped. A value in the arena can be kept after the serialization, the
21/// chunk of the arena it's in is then freed when it's dropped (the rest of
22/// the arena right away). A value that is meant to be kept should rather
23/// be on the heap.
24pub struct Boxed<T: ?Sized> {
25 ptr: NonNull<T>,
26 in_arena: bool,
27 _marker: PhantomData<T>,
28}
29
30// SAFETY: the box owns the value like a `Box`
31unsafe impl<T: ?Sized + Send> Send for Boxed<T> {}
32unsafe impl<T: ?Sized + Sync> Sync for Boxed<T> {}
33
34impl<T: ?Sized> Boxed<T> {
35 /// Creates a box from a value in the arena.
36 #[inline(always)]
37 pub(crate) fn from_arena(value: ArenaBox<T>) -> Boxed<T> {
38 Boxed {
39 ptr: ArenaBox::into_raw(value),
40 in_arena: true,
41 _marker: PhantomData,
42 }
43 }
44
45 /// Takes the pointer out of the box, the flag is `true` if the value is
46 /// in an arena.
47 #[inline(always)]
48 pub(crate) fn into_raw(this: Boxed<T>) -> (NonNull<T>, bool) {
49 let rv = (this.ptr, this.in_arena);
50 core::mem::forget(this);
51 rv
52 }
53
54 /// Creates a box from a pointer of [`into_raw`](Self::into_raw).
55 ///
56 /// # Safety
57 ///
58 /// The pointer and flag must come from `into_raw` and the box must
59 /// only be created once.
60 #[inline(always)]
61 pub(crate) unsafe fn from_raw(ptr: NonNull<T>, in_arena: bool) -> Boxed<T> {
62 Boxed {
63 ptr,
64 in_arena,
65 _marker: PhantomData,
66 }
67 }
68
69 /// Drops the value, a value in the arena of the state is popped right
70 /// away if it's on the top (see [`SinkHandle::arena`](crate::de::SinkHandle::arena)).
71 #[inline(always)]
72 pub(crate) fn release(this: Boxed<T>, state: &mut State) {
73 let (ptr, in_arena) = Boxed::into_raw(this);
74 // SAFETY: the pointer comes from a box of the kind of the flag
75 unsafe {
76 if in_arena {
77 ArenaBox::release_in(ArenaBox::from_raw(ptr.as_ptr()), &mut state.arena)
78 } else {
79 drop(Box::from_raw(ptr.as_ptr()))
80 }
81 }
82 }
83}
84
85impl<T> Boxed<T> {
86 /// Moves a value into the arena of the state.
87 #[inline(always)]
88 pub(crate) fn arena(value: T, state: &mut State) -> Boxed<T> {
89 Boxed::from_arena(ArenaBox::new(value, &mut state.arena))
90 }
91}
92
93impl<T: ?Sized> From<Box<T>> for Boxed<T> {
94 /// Moves a value on the heap into the box.
95 fn from(value: Box<T>) -> Boxed<T> {
96 Boxed {
97 // SAFETY: the pointer of a box is not null
98 ptr: unsafe { NonNull::new_unchecked(Box::into_raw(value)) },
99 in_arena: false,
100 _marker: PhantomData,
101 }
102 }
103}
104
105impl<T: ?Sized> Deref for Boxed<T> {
106 type Target = T;
107
108 #[inline(always)]
109 fn deref(&self) -> &T {
110 // SAFETY: the value is valid while the box exists
111 unsafe { self.ptr.as_ref() }
112 }
113}
114
115impl<T: ?Sized> DerefMut for Boxed<T> {
116 #[inline(always)]
117 fn deref_mut(&mut self) -> &mut T {
118 // SAFETY: the value is valid while the box exists
119 unsafe { self.ptr.as_mut() }
120 }
121}
122
123impl<T: ?Sized> Drop for Boxed<T> {
124 fn drop(&mut self) {
125 // SAFETY: the pointer comes from a box of the kind of the flag
126 unsafe {
127 if self.in_arena {
128 drop(ArenaBox::from_raw(self.ptr.as_ptr()))
129 } else {
130 drop(Box::from_raw(self.ptr.as_ptr()))
131 }
132 }
133 }
134}
135
136impl<T: ?Sized + fmt::Debug> fmt::Debug for Boxed<T> {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 fmt::Debug::fmt(&**self, f)
139 }
140}
141
142/// Converts a box of a sized value into a box of a trait object.
143///
144/// The trait object is created by `cast`, which is `|x| x as *mut dyn Trait`.
145#[inline(always)]
146pub(crate) fn unsize<T, U: ?Sized>(value: Boxed<T>, cast: fn(*mut T) -> *mut U) -> Boxed<U> {
147 let (ptr, in_arena) = Boxed::into_raw(value);
148 // SAFETY: the cast only changes the type of the pointer
149 unsafe { Boxed::from_raw(NonNull::new_unchecked(cast(ptr.as_ptr())), in_arena) }
150}