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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//! Some default `stack-db` allocator implementations

use std::{fs::{self, File}, io::Cursor, path::{Path, PathBuf}};
use crate::{base::{database::allocator::Allocator, layer::Layer}, errors::Error};

/// # In-Memory Allocator
/// ---
/// For a redis-like database for caching, testing the database, etc. Lives only on the heap and gets wiped on program exit.
pub struct SkdbMemAlloc;
impl<'a> Allocator<'a> for SkdbMemAlloc {
    type LayerStream = Cursor<Vec<u8>>;
    #[inline]
    fn load_layers(&self) -> Result<Vec<Layer<'a, Self::LayerStream>>, Error> {
        Ok(Vec::new())
    }
    #[inline]
    fn add_layer(&mut self) -> Result<Layer<'a, Self::LayerStream>, Error> {
        Ok(Layer::new(Cursor::new(Vec::new())))
    }
    #[inline]
    fn drop_top_layer(&mut self) -> Result<(), Error> {
        Ok(())
    }
    #[inline]
    fn rebase(&mut self, _: usize) -> Result<(), Error> {
        Ok(())
    }
}

/// # Directory Allocator
/// ---
/// Allocates within a directory that lives on the file-system with the layer order determined by the layer file names
pub struct SkdbDirAlloc {
    /// the path of the directory database
    pub path: PathBuf,
    /// the (sorted) paths of the layers in the database
    pub layers: Vec<PathBuf>,
    pub cursor: u32,
}
impl SkdbDirAlloc {
    /// Creates a new SkDB
    pub fn new(path: impl AsRef<Path>) -> Result<Self, Error> {
        let path = path.as_ref();

        fs::create_dir_all(path)?;
        Ok(Self {
            path: path.to_path_buf(),
            layers: Vec::new(),
            cursor: 0,
        })
    }
    
    /// Loads a Skdb from a directory
    pub fn load(path: PathBuf) -> Result<Self, Error> {
        // grab file paths
        let mut file_paths = Vec::new();
        for entry in fs::read_dir(&path)? {
            let entry = entry?;
            if entry.file_type()?.is_file() {
                file_paths.push(entry.path());
            }
        }

        // index files and sort them
        let mut layers = file_paths.iter()
            .enumerate()
            .filter_map(|(i, file)| file.file_name().map(|x| (x.to_string_lossy(), i)))
            .filter_map(|(name, i)| name.parse::<u32>().ok().map(|x| (x, i)))
            .collect::<Vec<(u32, usize)>>();
        layers.sort_by(|x, y| x.0.cmp(&y.0));

        let cursor = layers.last().map(|x| x.0 + 1).unwrap_or(0);
        let layers = layers.into_iter()
            .map(|(_, i)| std::mem::take(&mut file_paths[i]))
            .collect::<Vec<_>>();

        // return self
        Ok(Self {
            path,
            layers,
            cursor,
        })
    }
}
impl<'a> Allocator<'a> for SkdbDirAlloc {
    type LayerStream = File;

    /// Loads the layer files from the directory
    fn load_layers(&self) -> Result<Vec<Layer<'a, Self::LayerStream>>, Error> {
        let mut layers = Vec::with_capacity(self.layers.len());
        for path in self.layers.iter() {
            let file = File::options()
                .read(true)
                .write(true)
                .append(false)
                .truncate(false)
                .open(path)?;
            layers.push(Layer::new(file));
        } Ok(layers)
    }

    fn add_layer(&mut self) -> Result<Layer<'a, Self::LayerStream>, Error> {
        let path = self.path.join(self.cursor.to_string());
        let file = File::options()
            .read(true)
            .write(true)
            .append(false)
            .truncate(false)
            .create_new(true) .open(&path)?;
        self.cursor += 1;
        self.layers.push(path);
        Ok(Layer::new(file))
    }

    fn drop_top_layer(&mut self) -> Result<(), Error> {
        let path = if let Some(x) = self.layers.pop() { x } else { return Ok(()) };
        self.cursor -= 1;
        fs::remove_file(path)?;

        Ok(())
    }

    fn rebase(&mut self, top_layer: usize) -> Result<(), Error> {
        let mut top = Vec::with_capacity(self.layers.len()-top_layer);
        top.extend(self.layers.drain(top_layer..));

        // delete the other layer files
        for path in self.layers.iter() {
            fs::remove_file(path)?;
        }

        // move the base layer
        self.layers.clear();
        for (i, path) in top.into_iter().enumerate() {
            let new_path = self.path.join(i.to_string());
            fs::rename(path, &new_path)?;
            self.layers.push(new_path);
        } Ok(())
    }
}