Skip to main content

clt_database/alloc/
mod.rs

1//! Turso-owned allocation namespace.
2//!
3//! Stable builds use `std` collections where allocator parameters are not
4//! available. Builds compiled with `--cfg nightly` use Rust's unstable
5//! `allocator_api` collection parameters.
6
7use std::{fmt, ptr::NonNull};
8
9mod allocation_site;
10mod api;
11mod arc;
12mod backend;
13mod collections;
14
15pub use allocation_site::{
16    current_allocation_site, enter_allocation_site, AllocationSite, AllocationSiteGuard,
17    MvStoreAllocationSite, MvccCheckpointAllocationSite, SchemaAllocationSite,
18};
19/// The underlying allocator trait: `allocator_api2::alloc::Allocator` on
20/// stable, `std::alloc::Allocator` on `--cfg nightly` builds.
21pub use api::ApiAllocator;
22pub use api::{AllocError, Global, Layout};
23pub use arc::{try_arc_slice_from_slice, try_arc_slice_from_slice_in, ArcSlice};
24pub use backend::{set_allocator, SetAllocatorError, TursoAllocBackend};
25pub(crate) use collections::impl_try_clone_via_clone;
26#[cfg(nightly)]
27pub use collections::TursoFromIteratorIn;
28pub use collections::{
29    TryClone, TursoAllocExt, TursoBinaryHeapExt, TursoBoxExt, TursoFromIterator, TursoHashMapExt,
30    TursoHashSetExt, TursoIteratorExt, TursoNewExt, TursoSliceExt, TursoTryNewExt,
31    TursoTryWithCapacityExt, TursoVecDequeExt, TursoVecExt, TursoVecInExt,
32};
33
34pub const ALLOC_ERR_MSG: &str = "fallible allocations";
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub struct TryReserveError;
38
39impl fmt::Display for TryReserveError {
40    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41        f.write_str("memory allocation failed")
42    }
43}
44
45impl std::error::Error for TryReserveError {}
46
47#[cfg(not(nightly))]
48impl From<api::TryReserveError> for TryReserveError {
49    fn from(_: api::TryReserveError) -> Self {
50        Self
51    }
52}
53
54impl From<std::collections::TryReserveError> for TryReserveError {
55    fn from(_: std::collections::TryReserveError) -> Self {
56        Self
57    }
58}
59
60/// Lets containers whose elements clone infallibly (`TryClone<Error =
61/// Infallible>`) satisfy `TryReserveError: From<T::Error>` bounds.
62impl From<std::convert::Infallible> for TryReserveError {
63    fn from(never: std::convert::Infallible) -> Self {
64        match never {}
65    }
66}
67
68/// Allocator safe to clone into concurrent data structures and deferred drops.
69///
70/// Cloning must be cheap and must not panic. The `'static` bound allows
71/// deferred reclamation to outlive the container that captured the allocator.
72pub trait ConcurrentAllocator: ApiAllocator + Clone + Send + Sync + 'static {}
73
74impl<A: ApiAllocator + Clone + Send + Sync + 'static> ConcurrentAllocator for A {}
75
76#[derive(Clone, Copy, Debug, Default)]
77pub struct TursoAllocator;
78
79pub type Allocator = TursoAllocator;
80
81#[derive(Clone)]
82pub struct DynAllocator {
83    inner: Arc<dyn ApiAllocator + Send + Sync>,
84}
85
86impl DynAllocator {
87    pub fn new<A>(alloc: A) -> Self
88    where
89        A: ApiAllocator + Send + Sync + 'static,
90    {
91        Self {
92            inner: Arc::new(alloc),
93        }
94    }
95}
96
97impl Default for DynAllocator {
98    fn default() -> Self {
99        Self::new(TursoAllocator)
100    }
101}
102
103impl fmt::Debug for DynAllocator {
104    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105        f.debug_struct("DynAllocator").finish_non_exhaustive()
106    }
107}
108
109unsafe impl ApiAllocator for DynAllocator {
110    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
111        self.inner.allocate(layout)
112    }
113
114    unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {
115        unsafe {
116            self.inner.deallocate(ptr, layout);
117        }
118    }
119}
120
121pub type Box<T> = std::boxed::Box<T>;
122
123/// Boxed slice that keeps the allocator parameter on nightly.
124///
125/// `Box<T>` stays allocator-free so `Box::new` keeps working, but
126/// `Vec::into_boxed_slice` on an allocator-aware `Vec` produces
127/// `Box<[T], TursoAllocator>` on nightly — fields holding such slices must
128/// use this alias instead of `Box<[T]>`.
129#[cfg(not(nightly))]
130pub type BoxedSlice<T> = std::boxed::Box<[T]>;
131#[cfg(nightly)]
132pub type BoxedSlice<T> = std::boxed::Box<[T], TursoAllocator>;
133
134#[cfg(not(nightly))]
135pub type Vec<T> = std::vec::Vec<T>;
136#[cfg(nightly)]
137pub type Vec<T, A = TursoAllocator> = std::vec::Vec<T, A>;
138
139pub use crate::{__turso_alloc_try_vec as try_vec, __turso_alloc_vec as vec};
140
141#[doc(hidden)]
142#[macro_export]
143macro_rules! __turso_alloc_vec_count {
144    ($($element:expr),*) => {
145        <[()]>::len(&[$($crate::__turso_alloc_vec_count!(@sub $element)),*])
146    };
147    (@sub $element:expr) => {
148        ()
149    };
150}
151
152#[doc(hidden)]
153#[macro_export]
154macro_rules! __turso_alloc_vec {
155    () => {
156        <$crate::alloc::Vec<_> as $crate::alloc::TursoAllocExt>::new()
157    };
158    ($element:expr; $count:expr) => {{
159        let count = $count;
160        let mut values =
161            <$crate::alloc::Vec<_> as $crate::alloc::TursoVecExt<_>>::with_capacity(count);
162        values.resize(count, $element);
163        values
164    }};
165    ($($element:expr),+ $(,)?) => {{
166        let mut values =
167            <$crate::alloc::Vec<_> as $crate::alloc::TursoVecExt<_>>::with_capacity(
168                $crate::__turso_alloc_vec_count!($($element),+),
169            );
170        $(values.push($element);)+
171        values
172    }};
173}
174
175#[doc(hidden)]
176#[macro_export]
177macro_rules! __turso_alloc_try_vec {
178    () => {
179        Ok::<_, $crate::alloc::TryReserveError>(
180            <$crate::alloc::Vec<_> as $crate::alloc::TursoAllocExt>::new(),
181        )
182    };
183    ($element:expr; $count:expr) => {{
184        (|| {
185            let count = $count;
186            let mut values =
187                <$crate::alloc::Vec<_> as $crate::alloc::TursoTryWithCapacityExt>::try_with_capacity_ext(
188                    count,
189                )?;
190            values.resize(count, $element);
191            Ok::<_, $crate::alloc::TryReserveError>(values)
192        })()
193    }};
194    ($($element:expr),+ $(,)?) => {{
195        (|| {
196            let mut values =
197                <$crate::alloc::Vec<_> as $crate::alloc::TursoTryWithCapacityExt>::try_with_capacity_ext(
198                    $crate::__turso_alloc_vec_count!($($element),+),
199                )?;
200            $(values.push($element);)+
201            Ok::<_, $crate::alloc::TryReserveError>(values)
202        })()
203    }};
204}
205
206pub type String = std::string::String;
207
208pub type HashMap<K, V, S = rustc_hash::FxBuildHasher> = std::collections::HashMap<K, V, S>;
209
210pub type HashSet<T, S = rustc_hash::FxBuildHasher> = std::collections::HashSet<T, S>;
211
212pub type BTreeMap<K, V> = std::collections::BTreeMap<K, V>;
213
214pub type BTreeSet<T> = std::collections::BTreeSet<T>;
215
216pub type VecDeque<T> = std::collections::VecDeque<T>;
217
218pub type BinaryHeap<T> = std::collections::BinaryHeap<T>;
219
220pub type LinkedList<T> = std::collections::LinkedList<T>;
221
222// TODO: design allocator-aware shared-pointer support that still preserves
223// shuttle's deterministic sync behavior.
224pub type Arc<T> = crate::sync::Arc<T>;
225pub type Weak<T> = crate::sync::Weak<T>;
226
227pub type Rc<T> = std::rc::Rc<T>;
228
229pub type RcWeak<T> = std::rc::Weak<T>;
230
231#[cfg(clt_turso_tests)]
232mod tests;