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}