bindb/storage/
indexed_dynamic.rs

1use std::{fs::File, path::Path};
2use super::OpenMode;
3
4pub use super::dynamic::EntryId as DynamicEntryId;
5
6type IndexData = DynamicEntryId;
7
8#[derive(Debug)]
9pub enum AddError {
10    RawAdd(super::dynamic::AddError),
11    AddIndex(super::fixed::AddError),
12    RemoveFreeId(super::fixed::RemoveLastError)
13}
14
15#[derive(Debug)]
16pub enum RemoveError {
17    RawRemove(super::dynamic::RemoveError),
18    AddIndex(super::fixed::AddError),
19    RemoveLastIndex(super::fixed::RemoveLastError),
20    AddFreeId(super::fixed::AddError),
21}
22
23#[derive(Debug)]
24pub enum OpenError {
25    DynamicOpen(super::dynamic::OpenError),
26    FixedOpen(super::fixed::OpenError),
27}
28
29pub struct OpenFiles {
30    pub raw_entries: File,
31    pub raw_free_locations: File,
32    pub indices: File,
33    pub free_ids: File,
34}
35
36pub struct OpenMaxMargins {
37    pub raw_entries: u64,
38    pub raw_free_locations: u64,
39    pub indices: u64,
40    pub free_ids: u64,
41}
42
43pub struct OpenConfig {
44    pub mode: OpenMode,
45    pub files: OpenFiles,
46    pub max_margins: OpenMaxMargins,
47}
48
49pub struct Value<E> {
50    raw: super::Dynamic<E>,
51    indices: super::Fixed<IndexData>,
52    free_ids: super::Fixed<u64>,
53}
54
55impl<E: binbuf::Dynamic> Value<E> {
56    pub unsafe fn open(OpenConfig { mode, files, max_margins }: OpenConfig) -> Result<Self, OpenError> {
57        Ok(Self {
58            raw: super::Dynamic::open(super::dynamic::OpenConfig {
59                mode,
60                files: super::dynamic::OpenFiles { entries: files.raw_entries, free_locations: files.raw_free_locations },
61                max_margins: super::dynamic::OpenMaxMargins { entries: max_margins.raw_entries, free_locations: max_margins.raw_free_locations },
62            }).map_err(OpenError::DynamicOpen)?,
63            indices: super::Fixed::open(mode, files.indices, max_margins.indices).map_err(OpenError::FixedOpen)?,
64            free_ids: super::Fixed::open(mode, files.free_ids, max_margins.free_ids).map_err(OpenError::FixedOpen)?,
65        })
66    }
67
68    pub fn is_id_valid(&self, id: u64) -> bool {
69        id < self.indices.len()
70    }
71
72    // pub unsafe fn create(raw: super::Dynamic<E>, indices_file: File, free_ids_file: File) -> Result<Self, CreateError> {
73    //     Ok(Self {
74    //         raw,
75    //         indices: super::Fixed::create(indices_file).map_err(CreateError::FixedCreate)?,
76    //         free_ids: super::Fixed::create(free_ids_file).map_err(CreateError::FixedCreate)?,
77    //     })
78    // }
79
80    pub unsafe fn buf_unchecked(&self, id: u64) -> binbuf::BufConst<E> {
81        let raw_id = binbuf::fixed::decode::<IndexData, _>(self.indices.buf_unchecked(id));
82        self.raw.buf_unchecked(raw_id)
83    }
84
85    pub unsafe fn buf_mut_unchecked(&mut self, id: u64) -> binbuf::BufMut<E> {
86        let raw_id = binbuf::fixed::decode::<IndexData, _>(self.indices.buf_unchecked(id));
87        self.raw.buf_mut_unchecked(raw_id)
88    }
89
90    pub fn buf(&self, id: u64) -> binbuf::BufConst<E> {
91        if self.is_id_valid(id) {
92            unsafe { self.buf_unchecked(id) }
93        } else {
94            panic!("Id is invalid: {id}");
95        }
96    }
97
98    pub fn buf_mut(&mut self, id: u64) -> binbuf::BufMut<E> {
99        if self.is_id_valid(id) {
100            unsafe { self.buf_mut_unchecked(id) }
101        } else {
102            panic!("Id is invalid: {id}");
103        }
104    }
105
106    pub fn add(&mut self, value: impl binbuf::dynamic::Readable<E>) -> Result<u64, AddError> {
107        let raw_id = self.raw.add(value).map_err(AddError::RawAdd)?;
108        let id = if let Some(id_buf) = self.free_ids.last_buf() {
109            let id = binbuf::fixed::decode::<u64, _>(id_buf);
110            self.free_ids.remove_last().map_err(AddError::RemoveFreeId)?;
111            self.indices.set(id, &raw_id);
112            id
113        } else {
114            self.indices.add(&raw_id).map_err(AddError::AddIndex)?
115        };
116        Ok(id)
117    }
118
119    pub fn free_locations_len(&self) -> u64 {
120        self.raw.free_locations_len()
121    }
122
123    pub unsafe fn remove(&mut self, id: u64) -> Result<(), RemoveError> {
124        let raw_id = binbuf::fixed::decode::<IndexData, _>(self.indices.buf_unchecked(id));
125        self.raw.remove(raw_id).map_err(RemoveError::RawRemove)?;
126
127        if self.indices.remove_if_last(id).map_err(RemoveError::RemoveLastIndex)? {
128            self.free_ids.add(&id).map_err(RemoveError::AddFreeId)?;
129        }
130        Ok(())
131    }
132}
133
134impl<E: binbuf::dynamic::Decode> Value<E> {
135    pub fn get(&self, id: u64) -> E {
136        binbuf::dynamic::decode(self.buf(id)).0
137    }
138}