Skip to main content

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}