Skip to content

Commit

Permalink
implement std::io::Seek for ReservedSpace
Browse files Browse the repository at this point in the history
  • Loading branch information
nolanderc committed Apr 29, 2024
1 parent a36a40d commit 6057c4e
Showing 1 changed file with 61 additions and 4 deletions.
65 changes: 61 additions & 4 deletions heed/src/reserved_space.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,27 @@ use crate::mdb::ffi;
///
/// You must write the exact amount of bytes, no less, no more.
pub struct ReservedSpace {
/// Total size of the space.
size: usize,

/// Pointer to the start of the reserved space.
start_ptr: *mut u8,

/// Number of bytes which have been written: all bytes in `0..written`.
written: usize,

/// Index of the byte which should be written next.
write_head: usize,
}

impl ReservedSpace {
pub(crate) unsafe fn from_val(val: ffi::MDB_val) -> ReservedSpace {
ReservedSpace { size: val.mv_size, start_ptr: val.mv_data as *mut u8, written: 0 }
ReservedSpace {
size: val.mv_size,
start_ptr: val.mv_data as *mut u8,
written: 0,
write_head: 0,
}
}

/// The total number of bytes that this memory buffer has.
Expand All @@ -24,7 +37,7 @@ impl ReservedSpace {

/// The remaining number of bytes that this memory buffer has.
pub fn remaining(&self) -> usize {
self.size - self.written
self.size - self.write_head
}

/// Get a slice of all the bytes that have previously been written.
Expand All @@ -51,6 +64,7 @@ impl ReservedSpace {
unsafe { self.start_ptr.add(i).write(0) };
}
self.written = self.size;
self.write_head = self.size;
}

/// Get a slice of bytes corresponding to the *entire* reserved space.
Expand All @@ -77,15 +91,17 @@ impl ReservedSpace {
pub unsafe fn assume_written(&mut self, len: usize) {
debug_assert!(len <= self.size);
self.written = len;
self.write_head = len;
}
}

impl io::Write for ReservedSpace {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if self.remaining() >= buf.len() {
let dest = unsafe { self.start_ptr.add(self.written) };
let dest = unsafe { self.start_ptr.add(self.write_head) };
unsafe { buf.as_ptr().copy_to_nonoverlapping(dest, buf.len()) };
self.written += buf.len();
self.write_head += buf.len();
self.written = usize::max(self.written, self.write_head);
Ok(buf.len())
} else {
Err(io::Error::from(io::ErrorKind::WriteZero))
Expand All @@ -97,6 +113,47 @@ impl io::Write for ReservedSpace {
}
}

/// ## Note
///
/// May only seek within the already within the previously written space.
/// Attempts to do otherwise will result in an error.
impl io::Seek for ReservedSpace {
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
let (base, offset) = match pos {
io::SeekFrom::Start(start) => (start, 0),
io::SeekFrom::End(offset) => (self.written as u64, offset),
io::SeekFrom::Current(offset) => (self.write_head as u64, offset),
};

let Some(new_pos) = base.checked_add_signed(offset) else {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"cannot seek before start of reserved space",
));
};

if new_pos > self.written as u64 {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"cannot seek past end of reserved space",
));
}

self.write_head = new_pos as usize;

Ok(new_pos)
}

fn rewind(&mut self) -> io::Result<()> {
self.write_head = 0;
Ok(())
}

fn stream_position(&mut self) -> io::Result<u64> {
Ok(self.write_head as u64)
}
}

impl fmt::Debug for ReservedSpace {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ReservedSpace").finish()
Expand Down

0 comments on commit 6057c4e

Please sign in to comment.