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