bindb/storage/
fixed.rs

1use binbuf::{BytesPtr, bytes_ptr, Fixed as _, Entry as _};
2use crate::utils::{slice_to_array, slice_to_array_mut};
3use std::{fs::File, marker::PhantomData, path::Path};
4use memmap2::{MmapAsRawDesc, MmapMut, MmapOptions};
5pub use header::Value as Header;
6use super::OpenMode;
7
8pub mod header;
9
10#[derive(Debug)]
11pub enum GetError {
12    InvalidId,
13}
14
15#[derive(Debug)]
16pub enum AddError {
17    Io(std::io::Error),
18}
19
20#[derive(Debug)]
21pub enum RemoveLastError {
22    Io(std::io::Error),
23}
24
25#[derive(Debug)]
26pub enum SwapRemoveError {
27    RemoveLastError(RemoveLastError),
28    //Fmmap(fmmap::error::Error),
29}
30
31#[derive(Debug)]
32pub enum CreateError {
33    Io(std::io::Error),
34}
35
36#[derive(Debug)]
37pub enum OpenError {
38    Io(std::io::Error),
39}
40
41pub struct OpenConfig {
42    pub mode: OpenMode,
43    pub file: File,
44    pub max_margin: u64,
45}
46
47pub struct Value<E> {
48    next_entry_id: u64,
49    file: File,
50    file_map: MmapMut,
51    margin: u64,
52    max_margin: u64,
53    _marker: PhantomData<fn() -> E>
54}
55
56impl<E: binbuf::Fixed> Value<E> {
57    pub unsafe fn open(mode: OpenMode, file: File, max_margin: u64) -> Result<Self, OpenError> {
58        let header_len = Header::LEN;
59        if let OpenMode::New = &mode {
60            file.set_len(header_len as u64).map_err(OpenError::Io)?;
61        }
62        let mut file_map = MmapMut::map_mut(&file).map_err(OpenError::Io)?;
63        let ptr = bytes_ptr::Const::new(file_map[0 .. header_len].as_ptr(), header_len);
64        let next_entry_id = match mode {
65            OpenMode::Existing => binbuf::fixed::decode(Header::buf(ptr).next_entry_id()),
66            OpenMode::New => unsafe {
67                binbuf::fixed::encode_ptr(
68                    bytes_ptr::Mut::from_slice(&mut file_map[0 .. header_len]),
69                    &Header { next_entry_id: 0 }
70                );
71                0
72            }
73        };
74        Ok(Self {
75            next_entry_id,
76            margin: 0,
77            max_margin,
78            file,
79            file_map,
80            _marker: PhantomData
81        })
82    }
83
84    pub fn len(&self) -> u64 {
85        self.next_entry_id
86    }
87
88    pub fn last_id(&self) -> u64 {
89        self.len() - 1
90    }
91
92    pub fn is_empty(&self) -> bool {
93        self.len() == 0
94    }
95
96    // pub fn next_entry_id(&self) -> u64 {
97    //     self.next_entry_id
98    // }
99
100    fn entry_offset(&self, id: u64) -> usize {
101        Header::LEN + E::LEN * (id as usize)
102    }
103
104    // pub fn meta_buf(&self) -> binbuf::BufConst<E> {
105    //     self.header_buf().meta()
106    // }
107
108    // pub fn meta_buf_mut(&mut self) -> binbuf::BufMut<E> {
109    //     self.header_buf_mut().meta()
110    // }
111
112    pub fn last_entry_id(&self) -> Option<u64> {
113        match self.next_entry_id {
114            0 => None,
115            _ => Some(self.next_entry_id - 1),
116        }
117    }
118
119    fn header_buf(&self) -> binbuf::BufConst<Header> {
120        let len = Header::LEN;
121        let ptr = unsafe { bytes_ptr::Const::from_slice(self.file_map.get_unchecked(0 .. len)) };
122        unsafe { Header::buf(ptr) }
123    }
124
125    fn header_buf_mut(&mut self) -> binbuf::BufMut<Header> {
126        let len = Header::LEN;
127        let ptr = unsafe { bytes_ptr::Mut::from_slice(self.file_map.get_unchecked_mut(0 .. len)) };
128        unsafe { Header::buf(ptr) }
129    }
130
131    fn set_next_entry_id(&mut self, value: u64) {
132        self.next_entry_id = value;
133        let v = self.next_entry_id;
134        v.encode(self.header_buf_mut().next_entry_id());
135    }
136
137    // region: Core functions.
138    // Doesn't check if ID is valid.
139    pub unsafe fn buf_unchecked(&self, id: u64) -> binbuf::BufConst<E> {
140        let offset = self.entry_offset(id);
141        let ptr = bytes_ptr::Const::new(self.file_map.get_unchecked(offset .. offset + E::LEN).as_ptr(), E::LEN);
142        E::buf(ptr)
143    }
144
145    pub unsafe fn buf_mut_unchecked(&mut self, id: u64) -> binbuf::BufMut<E> {
146        let offset = self.entry_offset(id);
147        let ptr = bytes_ptr::Mut::new(self.file_map.get_unchecked_mut(offset .. offset + E::LEN).as_mut_ptr(), E::LEN);
148        E::buf(ptr)
149    }
150
151    pub fn last_buf(&self) -> Option<binbuf::BufConst<E>> {
152        if self.is_empty() {
153            None
154        } else {
155            Some(unsafe { self.buf_unchecked(self.len() - 1) })
156        }
157    }
158
159    pub fn is_id_valid(&self, id: u64) -> bool {
160        self.next_entry_id > id
161    }
162
163    pub fn buf(&self, id: u64) -> binbuf::BufConst<E> {
164        if self.is_id_valid(id) {
165            unsafe { self.buf_unchecked(id) }
166        } else {
167            panic!("Id is invalid: {id}")
168        }
169    }
170
171    pub fn buf_mut(&mut self, id: u64) -> binbuf::BufMut<E> {
172        if self.is_id_valid(id) {
173            unsafe { self.buf_mut_unchecked(id) }
174        } else {
175            panic!("Id is invalid: {id}")
176        }
177    }
178    // endregion: Core functions.
179
180    pub fn add(&mut self, entry: impl binbuf::fixed::Readable<E>) -> Result<u64, AddError> {
181        let id = self.next_entry_id;
182        if self.margin == 0 {
183            let new_len = self.entry_offset(id + self.max_margin + 2);
184            self.file.set_len(new_len as u64).map_err(AddError::Io)?;
185            self.file_map = unsafe { MmapOptions::new().len(new_len).map_mut(&self.file).map_err(AddError::Io)? };
186            self.margin = self.max_margin + 1;
187        }
188        self.margin -= 1;
189        entry.write_to(unsafe { self.buf_mut_unchecked(id) });
190        self.set_next_entry_id(self.next_entry_id + 1);
191        Ok(id)
192    }
193
194    pub fn remove_last(&mut self) -> Result<(), RemoveLastError> {
195        let id = self.next_entry_id;
196        if self.margin >= self.max_margin {
197            let new_len = self.entry_offset(id);
198            self.file.set_len(new_len as u64).map_err(RemoveLastError::Io)?;
199            self.file_map = unsafe { MmapOptions::new().len(new_len).map_mut(&self.file).map_err(RemoveLastError::Io)? };
200            self.margin = 0;
201        }
202        self.margin += 1;
203        self.set_next_entry_id(id - 1);
204        Ok(())
205    }
206
207    // Removes if ID is last.
208    // Returns Ok(true) if ID is NOT last, and Ok(false) if ID is last and is successfully removed.
209    pub fn remove_if_last(&mut self, id: u64) -> Result<bool, RemoveLastError> {
210        if id == self.last_id() {
211            self.remove_last()?;
212            Ok(false)
213        } else {
214            Ok(true)
215        }
216    }
217
218    pub fn all_ids(&self) -> impl Iterator<Item = u64> {
219        0 .. self.next_entry_id
220    }
221
222    // Convenience functions.
223    // pub fn find<Out: Entry>(
224    //     &self,
225    //     lens: impl Lens<E, Out> + Clone,
226    //     // ids: impl Iterator<Item = entry::Id<Entry>>,
227    //     f: impl Fn(entry::BufConst<Out>) -> bool,
228    // ) -> Result<Option<(u64, entry::BufConst<Out>)>, GetError> {
229    //     for id in self.all_ids() {
230    //         let buf = lens.clone().apply(unsafe { self.buf_unchecked(id) });
231    //         if f(buf) {
232    //             return Ok(Some((id, buf)));
233    //         }
234    //     }
235    //     Ok(None)
236    // }
237
238    // Doesn't check if src_id or dst_id are valid.
239    pub unsafe fn copy(
240        &mut self,
241        src_id: u64,
242        dst_id: u64,
243    ) {
244        let mut dst = self.buf_mut_unchecked(dst_id);
245        let src = self.buf_unchecked(src_id);
246        binbuf::fixed::buf_copy_to::<E>(src, dst);
247    }
248
249    // Doesn't check if a_id or b_id are valid.
250    // It's OK if a_id == b_id.
251    pub unsafe fn swap(
252        &mut self,
253        a_id: u64,
254        b_id: u64,
255    ) {
256        if a_id != b_id {
257            let mut a = self.buf_mut_unchecked(a_id);
258            let mut b = self.buf_mut_unchecked(b_id);
259            binbuf::fixed::buf_swap::<E>(a, b);
260        }
261    }
262
263    /// Swaps given entry with the last entry and removes it.
264    /// WARNING: This method changes ID of the last entry in this collection.
265    /// You probably should only use this if this collection is used as a stack/set and not as a map.
266    /// Doesn't check if id is valid.
267    pub unsafe fn swap_remove(&mut self, id: u64) -> Result<(), SwapRemoveError> {
268        if let Some(last_entry_id) = self.last_entry_id() {
269            self.swap(id, last_entry_id);
270        }
271        self.remove_last().map_err(SwapRemoveError::RemoveLastError)?;
272        Ok(())
273    }
274
275    pub fn set(&mut self, id: u64, value: impl binbuf::fixed::Readable<E>) {
276        if self.is_id_valid(id) {
277            unsafe { value.write_to(self.buf_mut_unchecked(id)) }
278        } else {
279            panic!("Invalid id: {id}");
280        }
281    }
282}
283
284impl<E: binbuf::fixed::Decode> Value<E> {
285    pub fn get(&self, id: u64) -> E {
286        E::decode(self.buf(id))
287    }
288}