1use std::{fs::File, marker::PhantomData};
2use binbuf::{BytesPtr, bytes_ptr};
3use memmap2::MmapMut;
4
5#[derive(Debug)]
6pub enum OpenError {
7 Io(std::io::Error)
8}
9
10#[derive(Debug)]
11pub enum CreateError {
12 Io(std::io::Error)
13}
14
15#[derive(Debug)]
16pub enum SetError {
17 Io(std::io::Error),
18}
19
20pub enum OpenMode<T> {
21 New(T),
22 Existing,
23}
24
25pub struct Value<T> {
26 file: File,
27 mmap: MmapMut,
28 len: usize,
29 _marker: PhantomData<fn() -> T>
30}
31
32impl<T: binbuf::Dynamic> Value<T> {
33 pub unsafe fn open(mode: OpenMode<impl binbuf::dynamic::Readable<T>>, file: File) -> Result<Self, OpenError> {
34 let (len, mmap) = match mode {
35 OpenMode::New(value) => {
36 let len = value.len();
37 file.set_len(len as u64).map_err(OpenError::Io)?;
38 let mut mmap = MmapMut::map_mut(&file).map_err(OpenError::Io)?;
39 let buf = unsafe { T::buf(bytes_ptr::Mut::from_slice(&mut mmap[0 .. ])) };
40 value.write_to(buf);
41 (len, mmap)
42 },
43 OpenMode::Existing => {
44 let mut mmap = MmapMut::map_mut(&file).map_err(OpenError::Io)?;
45 let len = binbuf::dynamic::ptr_len::<T>(bytes_ptr::Const::from_slice(&mmap[0 .. ]));
46 (len, mmap)
47 }
48 };
49 Ok(Self { file, mmap, len, _marker: PhantomData })
50 }
51
52 pub fn set(&mut self, value: impl binbuf::dynamic::Readable<T>) -> Result<usize, SetError> {
53 let len = value.len();
54 if len > self.len {
55 self.file.set_len(len as u64).map_err(SetError::Io)?;
56 self.mmap = unsafe { MmapMut::map_mut(&self.file) }.map_err(SetError::Io)?;
57 self.len = len;
58 }
59 let written_len = value.write_to(self.buf_mut());
60 debug_assert_eq!(len, written_len);
61 Ok(len)
62 }
63
64 pub fn buf(&self) -> binbuf::BufConst<T> {
65 unsafe { T::buf(bytes_ptr::Const::from_slice(&self.mmap[0 .. ])) }
66 }
67
68 pub fn buf_mut(&mut self) -> binbuf::BufMut<T> {
69 unsafe { T::buf(bytes_ptr::Mut::from_slice(&mut self.mmap[0 .. ])) }
70 }
71}
72
73impl<T: binbuf::dynamic::Decode> Value<T> {
74 pub fn get(&self) -> T {
75 T::decode(self.buf()).0
76 }
77}