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::arena::{Alloc, ArenaBox};
10
11/// An owned value of a serialization, like a `Box`.
12///
13/// The value is either in the arena of the state (which is how
14/// [`Emit::seq`](crate::ser::Emit::seq), [`Emit::map`](crate::ser::Emit::map),
15/// [`Emit::structure`](crate::ser::Emit::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    alloc: Alloc,
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            alloc: Alloc::Arena,
41            _marker: PhantomData,
42        }
43    }
44
45    /// Takes the pointer out of the box together with where the value is
46    /// allocated.
47    #[inline(always)]
48    pub(crate) fn into_raw(this: Boxed<T>) -> (NonNull<T>, Alloc) {
49        let rv = (this.ptr, this.alloc);
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 allocation 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>, alloc: Alloc) -> Boxed<T> {
62        Boxed {
63            ptr,
64            alloc,
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, alloc) = Boxed::into_raw(this);
74        // SAFETY: the pointer comes from a box of the allocation
75        unsafe {
76            match alloc {
77                Alloc::Arena => {
78                    ArenaBox::release_in(ArenaBox::from_raw(ptr.as_ptr()), &mut state.arena)
79                }
80                Alloc::Heap => drop(Box::from_raw(ptr.as_ptr())),
81            }
82        }
83    }
84}
85
86impl<T> Boxed<T> {
87    /// Moves a value into the arena of the state.
88    #[inline(always)]
89    pub(crate) fn arena(value: T, state: &mut State) -> Boxed<T> {
90        Boxed::from_arena(ArenaBox::new(value, &mut state.arena))
91    }
92}
93
94impl<T: ?Sized> From<Box<T>> for Boxed<T> {
95    /// Moves a value on the heap into the box.
96    fn from(value: Box<T>) -> Boxed<T> {
97        Boxed {
98            // SAFETY: the pointer of a box is not null
99            ptr: unsafe { NonNull::new_unchecked(Box::into_raw(value)) },
100            alloc: Alloc::Heap,
101            _marker: PhantomData,
102        }
103    }
104}
105
106impl<T: ?Sized> Deref for Boxed<T> {
107    type Target = T;
108
109    #[inline(always)]
110    fn deref(&self) -> &T {
111        // SAFETY: the value is valid while the box exists
112        unsafe { self.ptr.as_ref() }
113    }
114}
115
116impl<T: ?Sized> DerefMut for Boxed<T> {
117    #[inline(always)]
118    fn deref_mut(&mut self) -> &mut T {
119        // SAFETY: the value is valid while the box exists
120        unsafe { self.ptr.as_mut() }
121    }
122}
123
124impl<T: ?Sized> Drop for Boxed<T> {
125    fn drop(&mut self) {
126        // SAFETY: the pointer comes from a box of the allocation
127        unsafe {
128            match self.alloc {
129                Alloc::Arena => drop(ArenaBox::from_raw(self.ptr.as_ptr())),
130                Alloc::Heap => 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, alloc) = 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())), alloc) }
150}