bindb/storage/
indexed_dynamic.rs1use 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 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}