Skip to main content

musli_core/alloc/
allocator.rs

1use core::ptr::NonNull;
2
3use super::{Alloc, AllocError, Vec};
4
5/// The trait governing a global allocator.
6///
7/// # Safety
8///
9/// Implementing this trait promises that the implementing allocator ultimately
10/// is backed by the global allocator [`Global`] and subsequently is what will
11/// be used to allocate and free data.
12///
13/// [`Global`]: super::Global
14pub unsafe trait GlobalAllocator
15where
16    Self: Allocator,
17{
18    /// Do not implement this trait. It is internal to Musli and will change.
19    fn __do_not_implement();
20
21    /// Construct a new instance of the global allocator.
22    #[doc(hidden)]
23    fn new() -> Self;
24
25    /// Clone an allocation.
26    fn clone_alloc<T>(alloc: &Self::Alloc<T>) -> Self::Alloc<T>;
27
28    /// Construct an allocation from the given raw parts assuming they are
29    /// allocated using the [`Global`] allocator.
30    ///
31    /// # Safety
32    ///
33    /// - `ptr` must have been allocated by the [`Global`] allocator with the
34    ///   layout of an array of `len` elements of `T`, or be dangling and
35    ///   suitably aligned if that layout has a size of zero.
36    /// - The returned allocation takes ownership of that memory, so it must not
37    ///   be freed or used through any other means afterwards.
38    ///
39    /// Since the pointer is trusted, calling this requires `unsafe`:
40    ///
41    /// ```compile_fail,E0133
42    /// use core::ptr::NonNull;
43    ///
44    /// use musli::alloc::{Global, GlobalAllocator};
45    ///
46    /// let alloc = Global::slice_from_raw_parts(NonNull::<u32>::dangling(), 4);
47    /// ```
48    ///
49    /// [`Global`]: super::Global
50    #[doc(hidden)]
51    unsafe fn slice_from_raw_parts<T>(ptr: NonNull<T>, len: usize) -> Self::Alloc<T>;
52}
53
54/// An allocator which can be obtained from the allocator `A`.
55///
56/// Every [`Allocator`] can be obtained from itself, and the [`Global`]
57/// allocator can be obtained from any allocator since it carries no state.
58///
59/// This is used when decoding a container which is tied to a particular
60/// allocator. A decoder hands out its own allocator `A`, which the container
61/// converts into the allocator it stores its data in. This is what allows a
62/// field of type `String<Global>`, `Vec<T, Global>` or `Value<Global>` to be
63/// decoded by a decoder using any allocator.
64///
65/// This is implemented for every allocator provided by Müsli, and only Müsli
66/// can implement [`Allocator`], so it does not need to be implemented
67/// manually.
68///
69/// # Examples
70///
71/// ```
72/// use musli::alloc::{Allocator, FromAllocator, Global, Vec};
73///
74/// fn copy_to<A, B>(alloc: A, bytes: &[u8]) -> Vec<u8, B>
75/// where
76///     A: Allocator,
77///     B: Allocator + FromAllocator<A>,
78/// {
79///     let mut out = Vec::new_in(B::from_allocator(alloc));
80///     out.extend_from_slice(bytes).unwrap();
81///     out
82/// }
83///
84/// musli::alloc::default(|alloc| {
85///     let bytes: Vec<u8, Global> = copy_to(alloc, b"hello");
86///     assert_eq!(bytes.as_slice(), b"hello");
87/// });
88/// ```
89///
90/// [`Global`]: super::Global
91pub trait FromAllocator<A> {
92    /// Obtain this allocator from the allocator `alloc`.
93    fn from_allocator(alloc: A) -> Self;
94
95    /// Take over a vector allocated in `A` without copying it, if its
96    /// allocation is compatible with this allocator.
97    ///
98    /// This lets a decoder hand an owned buffer to a container stored in a
99    /// different but compatible allocator, such as an allocation backed by the
100    /// global allocator to a container using [`Global`]. If the allocation
101    /// cannot be taken over, the vector is returned as-is and the caller has to
102    /// copy it.
103    ///
104    /// [`Global`]: super::Global
105    #[doc(hidden)]
106    #[inline]
107    fn __from_vec<T>(vec: Vec<T, A>) -> Result<Vec<T, Self>, Vec<T, A>>
108    where
109        A: Allocator,
110        Self: Allocator,
111    {
112        Err(vec)
113    }
114}
115
116/// An allocator that can be used in combination with a context.
117///
118/// # Safety
119///
120/// Setting `IS_GLOBAL` to `true` has safety implications, since it determines
121/// whether the allocation can be safely converted into a standard container or
122/// not.
123pub unsafe trait Allocator
124where
125    Self: Copy + FromAllocator<Self>,
126{
127    /// Do not implement this trait. It is internal to Musli and will change.
128    fn __do_not_implement();
129
130    /// Whether the allocations returned by this allocatore is backed by the
131    /// global allocator or not.
132    ///
133    /// # Safety
134    ///
135    /// Setting this to `true` has safety implications, since it determines
136    /// whether the allocation can be safely converted into a standard container
137    /// or not.
138    #[doc(hidden)]
139    const IS_GLOBAL: bool;
140
141    /// A raw allocation from the allocator.
142    #[doc(hidden)]
143    type Alloc<T>: Alloc<T>;
144
145    /// Construct an empty uninitialized raw vector with an alignment matching
146    /// that of `T` that is associated with this allocator.
147    ///
148    /// ## Examples
149    ///
150    /// ```
151    /// use core::slice;
152    /// use musli::alloc::{Alloc, AllocError, Allocator};
153    ///
154    /// let values: [u32; 4] = [1, 2, 3, 4];
155    ///
156    /// musli::alloc::default(|alloc| {
157    ///     let mut buf = alloc.alloc_empty::<u32>();
158    ///     let mut len = 0;
159    ///
160    ///     for value in values {
161    ///         buf.resize(len, 1)?;
162    ///
163    ///         // SAFETY: We've just resized the above buffer.
164    ///         unsafe {
165    ///             buf.as_mut_ptr().add(len).write(value);
166    ///         }
167    ///
168    ///         len += 1;
169    ///     }
170    ///
171    ///     // SAFETY: Slice does not outlive the buffer it references.
172    ///     let bytes = unsafe { slice::from_raw_parts(buf.as_ptr(), len) };
173    ///     assert_eq!(bytes, values);
174    ///     Ok::<_, AllocError>(())
175    /// });
176    /// # Ok::<_, AllocError>(())
177    /// ```
178    #[doc(hidden)]
179    fn alloc_empty<T>(self) -> Self::Alloc<T>;
180
181    /// Construct an empty uninitialized raw allocation with an alignment
182    /// matching that of `T` that is associated with this allocator.
183    ///
184    /// ## Examples
185    ///
186    /// ```
187    /// use musli::alloc::{AllocError, Allocator, Alloc};
188    ///
189    /// musli::alloc::default(|alloc| {
190    ///     let mut buf = alloc.alloc(10u32)?;
191    ///
192    ///     unsafe {
193    ///         buf.as_mut_ptr().write(20u32);
194    ///         assert_eq!(buf.as_ptr().read(), 20u32);
195    ///     }
196    ///
197    ///     Ok::<_, AllocError>(())
198    /// });
199    /// # Ok::<_, AllocError>(())
200    /// ```
201    #[doc(hidden)]
202    fn alloc<T>(self, value: T) -> Result<Self::Alloc<T>, AllocError>;
203}