stack_db/base/layer/
mapper.rs

1//! The mapper of the layer that can either live on the **heap** or **disk**
2
3use std::{borrow::Cow, io::{Read, Seek, Write}};
4use crate::{base::layer::get_u64, errors::Error};
5use super::{Section, REWIND_IDX};
6
7/// The mapper that holds all the writes to the layer and their location mapping in the database
8#[derive(Debug)]
9pub enum Mapper<'l> {
10    /// A **read-write** version of the mapper on the **heap**
11    Heap {
12        /// The current write cursor to speed up sequential qrites
13        write_cursor: (u64, usize),
14        /// *self explainitory*
15        mapper: Vec<Section<'l>>,
16    },
17    /// A **read-only** version of the mapper on the **disk**
18    Disk,
19}
20
21/// A read-only iterator of the mapper that can live on either the heap or disk 
22pub struct MapperIter<'l, Stream: Write + Read + Seek> {
23    mapper: &'l Mapper<'l>,
24    stream: &'l mut Stream,
25    size: u64,
26    /// the index in the mapper
27    idx: usize,
28    /// the **actual** location in the layer
29    cursor: u64,
30}
31
32impl<'l> Default for Mapper<'l> {
33    #[inline]
34    fn default() -> Self {
35        Self::new()
36    }
37}
38
39impl<'l> Mapper<'l> {
40    /// Creates a new **heap**-based mapper
41    #[inline]
42    pub fn new() -> Self {
43        Self::Heap {
44            write_cursor: (0, 0),
45            mapper: Vec::new(),
46        }
47    }
48
49    /// Grabs the internal heap representation; if on disk, throw the `ReadOnly` error
50    #[inline]
51    pub fn get_writer(&mut self) -> Result<(&mut Vec<Section<'l>>, &mut (u64, usize)), Error> {
52        if let Self::Heap { write_cursor, mapper } = self {
53            Ok((mapper, write_cursor))
54        } else {
55            Err(Error::ReadOnly)
56        }
57    }
58
59    /// Generates an iterator over the interal mapper, from the stream, size and layer read cursor position
60    pub fn iter<'a, Stream: Read + Write + Seek>(&'a self, stream: &'a mut Stream, size: u64, cursor: u64) -> Result<MapperIter<'a, Stream>, Error> {
61        stream.seek(std::io::SeekFrom::Start(cursor))?;
62        Ok(MapperIter {
63            mapper: self,
64            stream,
65            size,
66            idx: 0,
67            cursor: cursor - REWIND_IDX,
68        })
69    }
70}
71
72/// for unwrapping results within a function that returns an optional result concisely
73macro_rules! optres {
74    ($expr:expr) => {
75        match $expr {
76            Ok(x) => x,
77            Err(e) => return Some(Err(e.into())),
78        }
79    }
80}
81
82impl<'l, Stream: Write + Read + Seek> Iterator for MapperIter<'l, Stream> {
83    type Item = Result<Section<'l>, Error>;
84
85    fn next(&mut self) -> Option<Self::Item> { // probably not a issue but, it loads the entire layer section into memory
86        Some(Ok(match self.mapper {
87            Mapper::Heap { mapper, .. } => {
88                if self.idx == mapper.len() { return None };
89                let out = mapper[self.idx].clone();
90                self.idx += 1;
91                out
92            },
93            Mapper::Disk => {
94                // check for end of layer
95                if self.cursor == self.size { return None };
96                
97                // read bounds
98                let mut buffer = [0u8; (u64::BITS as usize/8) * 2]; // buffer for two `u64` values: `bounds.start` & `bounds.end`
99                match self.stream.read_exact(&mut buffer) {
100                    Ok(_) => (),
101                    Err(_) => return Some(Err(Error::DBCorrupt(Box::new(Error::InvalidLayer)))),
102                }
103
104                let bounds = optres!(get_u64(&buffer, 0..8))..optres!(get_u64(&buffer, 8..16));
105
106                // load layer section data into the heap
107                let size = if let Some(x) = bounds.end.checked_sub(bounds.start) { x } else {return Some(Err(Error::DBCorrupt(Box::new(Error::InvalidLayer)))) };
108                let mut data = vec![0u8; size as usize];
109                optres!(self.stream.read_exact(&mut data));
110
111                self.cursor += size;
112                (bounds, Cow::Owned(data))
113            },
114        }))
115    }
116}