1use std::mem::MaybeUninit;
2use std::{fmt, io};
3
4use crate::mdb::ffi;
5
6pub struct ReservedSpace<'a> {
10 bytes: &'a mut [MaybeUninit<u8>],
11 written: usize,
13 write_head: usize,
20}
21
22impl ReservedSpace<'_> {
23 pub(crate) unsafe fn from_val<'a>(val: ffi::MDB_val) -> ReservedSpace<'a> {
24 let len = val.mv_size;
25 let ptr = val.mv_data;
26
27 ReservedSpace {
28 bytes: std::slice::from_raw_parts_mut(ptr.cast(), len),
29 written: 0,
30 write_head: 0,
31 }
32 }
33
34 #[inline]
36 pub fn size(&self) -> usize {
37 self.bytes.len()
38 }
39
40 #[inline]
42 pub fn remaining(&self) -> usize {
43 self.bytes.len() - self.write_head
44 }
45
46 #[inline]
53 pub fn written_mut(&mut self) -> &mut [u8] {
54 let ptr = self.bytes.as_mut_ptr();
55 let len = self.written;
56 unsafe { std::slice::from_raw_parts_mut(ptr.cast(), len) }
57 }
58
59 #[inline]
69 pub fn fill_zeroes(&mut self) {
70 self.bytes[self.write_head..].fill(MaybeUninit::new(0));
71 self.written = self.bytes.len();
72 self.write_head = self.bytes.len();
73 }
74
75 #[inline]
87 pub fn as_uninit_mut(&mut self) -> &mut [MaybeUninit<u8>] {
88 self.bytes
89 }
90
91 #[inline]
98 pub unsafe fn assume_written(&mut self, len: usize) {
99 debug_assert!(len <= self.bytes.len());
100 self.written = len;
101 self.write_head = len;
102 }
103}
104
105impl io::Write for ReservedSpace<'_> {
106 #[inline]
107 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
108 self.write_all(buf)?;
109 Ok(buf.len())
110 }
111
112 #[inline]
113 fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
114 let remaining = unsafe { self.bytes.get_unchecked_mut(self.write_head..) };
115
116 if buf.len() > remaining.len() {
117 return Err(io::Error::from(io::ErrorKind::WriteZero));
118 }
119
120 unsafe {
121 let buf_uninit = std::slice::from_raw_parts(buf.as_ptr().cast(), buf.len());
123 remaining.as_mut_ptr().copy_from_nonoverlapping(buf_uninit.as_ptr(), buf.len());
124 }
125
126 self.write_head += buf.len();
127 self.written = usize::max(self.written, self.write_head);
128
129 Ok(())
130 }
131
132 #[inline(always)]
133 fn flush(&mut self) -> io::Result<()> {
134 Ok(())
135 }
136}
137
138impl io::Seek for ReservedSpace<'_> {
143 #[inline]
144 fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
145 let (base, offset) = match pos {
146 io::SeekFrom::Start(start) => (start, 0),
147 io::SeekFrom::End(offset) => (self.written as u64, offset),
148 io::SeekFrom::Current(offset) => (self.write_head as u64, offset),
149 };
150
151 let Some(new_pos) = base.checked_add_signed(offset) else {
152 return Err(std::io::Error::new(
153 std::io::ErrorKind::InvalidInput,
154 "cannot seek before start of reserved space",
155 ));
156 };
157
158 if new_pos > self.written as u64 {
159 return Err(std::io::Error::new(
160 std::io::ErrorKind::InvalidInput,
161 "cannot seek past end of reserved space",
162 ));
163 }
164
165 self.write_head = new_pos as usize;
166
167 Ok(new_pos)
168 }
169
170 #[inline]
171 fn rewind(&mut self) -> io::Result<()> {
172 self.write_head = 0;
173 Ok(())
174 }
175
176 #[inline]
177 fn stream_position(&mut self) -> io::Result<u64> {
178 Ok(self.write_head as u64)
179 }
180}
181
182impl fmt::Debug for ReservedSpace<'_> {
183 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
184 f.debug_struct("ReservedSpace").finish()
185 }
186}