kul_core/parser/premade/
slice_alloc.rs

1use crate::{
2    datum::premade::{MutRefDatum, DatumMutRef},
3    text::Text,
4    parser::{DatumAllocator, AllocError},
5};
6
7
8/// Mutable slice of generic `MutRefDatum` elements which reference each other
9/// with mutable borrows of the same lifetime.
10type Slice<'a, TT, ET> = &'a mut [MutRefDatum<'a, TT, ET>];
11
12/// A [`DatumAllocator`] for generic `Datum` types which simplistically
13/// allocates `Datum` values from a contiguous mutable slice of them by
14/// supplying mutable borrows of them.  Once a `Datum` element has been
15/// allocated, it is not reused if dropped.
16///
17/// This is useful for either or both of:
18///
19/// - Allocating from stack arrays in constrained environments without heap
20/// allocation.
21///
22/// - Limiting the memory consumed by parsing, e.g. to prevent D.o.S. attacks.
23/// Heap-allocated arrays/slices could be used for this.
24///
25/// Allocated elements are not reused if dropped because that would require
26/// implementing `Drop` for the element type which would prevent being able to
27/// use basic arrays/slices (because the `Datum` elements reference each other
28/// with the same lifetime, and this only works for element types without
29/// `Drop`).  To reuse a slice, a new allocator instance can be constructed with
30/// it again, once the prior parsing and borrows of the elements are finished.
31///
32/// [`DatumAllocator`]: ../trait.DatumAllocator.html
33#[derive(Debug)]
34pub struct SliceDatumAllocator<'a, TT, ET> {
35    free: Option<Slice<'a, TT, ET>>,
36}
37
38impl<'a, TT, ET> SliceDatumAllocator<'a, TT, ET>
39    where TT: Text,
40{
41    /// Given a mutable slice of `Datum`s of our type, make a new allocator from
42    /// it.
43    #[inline]
44    pub fn new(slice: Slice<'a, TT, ET>) -> Self {
45        Self { free: if slice.is_empty() { None } else { Some(slice) } }
46    }
47
48    /// Can be used to regain control of the borrow of the unused rest of the
49    /// slice, so that it can be used for something else if desired.
50    #[inline]
51    pub fn unused(self) -> Option<Slice<'a, TT, ET>> {
52        self.free
53    }
54}
55
56impl<'a, TT, ET> DatumAllocator for SliceDatumAllocator<'a, TT, ET>
57    where TT: Text,
58{
59    type TT = TT;
60    type ET = ET;
61    type DR = DatumMutRef<'a, Self::TT, Self::ET>;
62
63    fn new_datum(&mut self, from: MutRefDatum<'a, Self::TT, Self::ET>)
64                 -> Result<Self::DR, AllocError>
65    {
66        match self.free.take().and_then(|a| a.split_first_mut()) {
67            Some((dr, rest)) => {
68                *dr = from;
69                self.free = Some(rest);
70                Ok(DatumMutRef(dr))
71            }
72            None => Err(AllocError::AllocExhausted)
73        }
74    }
75}
76
77
78// Note: Tested by the mutref_stack_alloc integration test.