use base::VolatileSlice;
use remain::sorted;
use thiserror::Error as ThisError;
#[sorted]
#[derive(ThisError, Debug)]
pub enum Error {
#[error("Invalid offset/len for getting a slice from {0} with len {1}.")]
InvalidOffset(u64, usize),
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct MemRegion {
pub offset: u64,
pub len: usize,
}
#[derive(Clone)]
pub struct MemRegionIter<'a> {
regions: &'a [MemRegion],
skip_bytes: usize,
remaining_bytes: usize,
}
impl<'a> MemRegionIter<'a> {
pub fn new(regions: &'a [MemRegion]) -> Self {
MemRegionIter {
regions,
skip_bytes: 0,
remaining_bytes: usize::MAX,
}
}
pub fn skip_bytes(self, offset: usize) -> Self {
MemRegionIter {
regions: self.regions,
skip_bytes: self.skip_bytes.saturating_add(offset),
remaining_bytes: self.remaining_bytes.saturating_sub(offset),
}
}
pub fn take_bytes(self, max: usize) -> Self {
MemRegionIter {
regions: self.regions,
skip_bytes: self.skip_bytes,
remaining_bytes: self.remaining_bytes.min(max),
}
}
}
impl Iterator for MemRegionIter<'_> {
type Item = MemRegion;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining_bytes == 0 {
return None;
}
while let Some((first, remaining)) = self.regions.split_first() {
self.regions = remaining;
if self.skip_bytes >= first.len {
self.skip_bytes -= first.len;
continue;
}
let mut region = MemRegion {
offset: first.offset + self.skip_bytes as u64,
len: first.len - self.skip_bytes,
};
self.skip_bytes = 0;
if region.len >= self.remaining_bytes {
region.len = self.remaining_bytes;
self.remaining_bytes = 0;
self.regions = &[];
} else {
self.remaining_bytes -= region.len;
}
debug_assert_ne!(region.len, 0);
return Some(region);
}
None
}
}
pub unsafe trait BackingMemory {
fn get_volatile_slice(&self, mem_range: MemRegion) -> Result<VolatileSlice>;
}
pub struct VecIoWrapper {
inner: Box<[u8]>,
}
impl From<Vec<u8>> for VecIoWrapper {
fn from(vec: Vec<u8>) -> Self {
VecIoWrapper { inner: vec.into() }
}
}
impl From<VecIoWrapper> for Vec<u8> {
fn from(v: VecIoWrapper) -> Vec<u8> {
v.inner.into()
}
}
impl VecIoWrapper {
#[cfg_attr(windows, allow(dead_code))]
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
fn check_addrs(&self, mem_range: &MemRegion) -> Result<()> {
let end = mem_range
.offset
.checked_add(mem_range.len as u64)
.ok_or(Error::InvalidOffset(mem_range.offset, mem_range.len))?;
if end > self.inner.len() as u64 {
return Err(Error::InvalidOffset(mem_range.offset, mem_range.len));
}
Ok(())
}
}
unsafe impl BackingMemory for VecIoWrapper {
fn get_volatile_slice(&self, mem_range: MemRegion) -> Result<VolatileSlice<'_>> {
self.check_addrs(&mem_range)?;
unsafe {
Ok(VolatileSlice::from_raw_parts(
self.inner.as_ptr().add(mem_range.offset as usize) as *mut _,
mem_range.len,
))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mem_region_iter_empty() {
let mut iter = MemRegionIter::new(&[]);
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_one() {
let mut iter = MemRegionIter::new(&[MemRegion { offset: 0, len: 4 }]);
assert_eq!(iter.next(), Some(MemRegion { offset: 0, len: 4 }));
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_one_len_usize_max() {
let mut iter = MemRegionIter::new(&[MemRegion {
offset: 0,
len: usize::MAX,
}]);
assert_eq!(
iter.next(),
Some(MemRegion {
offset: 0,
len: usize::MAX
})
);
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_one_len_zero() {
let mut iter = MemRegionIter::new(&[MemRegion { offset: 0, len: 0 }]);
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_one_skip_partial() {
let mut iter = MemRegionIter::new(&[MemRegion { offset: 0, len: 4 }]).skip_bytes(1);
assert_eq!(iter.next(), Some(MemRegion { offset: 1, len: 3 }));
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_one_skip_full() {
let mut iter = MemRegionIter::new(&[MemRegion { offset: 0, len: 4 }]).skip_bytes(4);
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_one_skip_excess() {
let mut iter = MemRegionIter::new(&[MemRegion { offset: 0, len: 4 }]).skip_bytes(5);
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_one_take_zero() {
let mut iter = MemRegionIter::new(&[MemRegion { offset: 0, len: 4 }]).take_bytes(0);
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_one_take_partial() {
let mut iter = MemRegionIter::new(&[MemRegion { offset: 0, len: 4 }]).take_bytes(1);
assert_eq!(iter.next(), Some(MemRegion { offset: 0, len: 1 }));
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_one_take_full() {
let mut iter = MemRegionIter::new(&[MemRegion { offset: 0, len: 4 }]).take_bytes(4);
assert_eq!(iter.next(), Some(MemRegion { offset: 0, len: 4 }));
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_one_take_excess() {
let mut iter = MemRegionIter::new(&[MemRegion { offset: 0, len: 4 }]).take_bytes(5);
assert_eq!(iter.next(), Some(MemRegion { offset: 0, len: 4 }));
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_one_take_skip() {
let mut iter = MemRegionIter::new(&[MemRegion { offset: 0, len: 4 }])
.take_bytes(2)
.skip_bytes(1);
assert_eq!(iter.next(), Some(MemRegion { offset: 1, len: 1 }));
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_one_skip_take() {
let mut iter = MemRegionIter::new(&[MemRegion { offset: 0, len: 4 }])
.skip_bytes(1)
.take_bytes(2);
assert_eq!(iter.next(), Some(MemRegion { offset: 1, len: 2 }));
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_two() {
let mut iter = MemRegionIter::new(&[
MemRegion { offset: 0, len: 4 },
MemRegion { offset: 8, len: 2 },
]);
assert_eq!(iter.next(), Some(MemRegion { offset: 0, len: 4 }));
assert_eq!(iter.next(), Some(MemRegion { offset: 8, len: 2 }));
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_two_skip_partial() {
let mut iter = MemRegionIter::new(&[
MemRegion { offset: 0, len: 4 },
MemRegion { offset: 8, len: 2 },
])
.skip_bytes(1);
assert_eq!(iter.next(), Some(MemRegion { offset: 1, len: 3 }));
assert_eq!(iter.next(), Some(MemRegion { offset: 8, len: 2 }));
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_two_skip_full() {
let mut iter = MemRegionIter::new(&[
MemRegion { offset: 0, len: 4 },
MemRegion { offset: 8, len: 2 },
])
.skip_bytes(4);
assert_eq!(iter.next(), Some(MemRegion { offset: 8, len: 2 }));
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_two_skip_excess() {
let mut iter = MemRegionIter::new(&[
MemRegion { offset: 0, len: 4 },
MemRegion { offset: 8, len: 2 },
])
.skip_bytes(5);
assert_eq!(iter.next(), Some(MemRegion { offset: 9, len: 1 }));
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_two_skip_multi() {
let mut iter = MemRegionIter::new(&[
MemRegion { offset: 0, len: 4 },
MemRegion { offset: 8, len: 2 },
])
.skip_bytes(6);
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_two_take_partial() {
let mut iter = MemRegionIter::new(&[
MemRegion { offset: 0, len: 4 },
MemRegion { offset: 8, len: 2 },
])
.take_bytes(1);
assert_eq!(iter.next(), Some(MemRegion { offset: 0, len: 1 }));
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_two_take_partial2() {
let mut iter = MemRegionIter::new(&[
MemRegion { offset: 0, len: 4 },
MemRegion { offset: 8, len: 2 },
])
.take_bytes(5);
assert_eq!(iter.next(), Some(MemRegion { offset: 0, len: 4 }));
assert_eq!(iter.next(), Some(MemRegion { offset: 8, len: 1 }));
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_two_take_full() {
let mut iter = MemRegionIter::new(&[
MemRegion { offset: 0, len: 4 },
MemRegion { offset: 8, len: 2 },
])
.take_bytes(6);
assert_eq!(iter.next(), Some(MemRegion { offset: 0, len: 4 }));
assert_eq!(iter.next(), Some(MemRegion { offset: 8, len: 2 }));
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_two_take_excess() {
let mut iter = MemRegionIter::new(&[
MemRegion { offset: 0, len: 4 },
MemRegion { offset: 8, len: 2 },
])
.take_bytes(7);
assert_eq!(iter.next(), Some(MemRegion { offset: 0, len: 4 }));
assert_eq!(iter.next(), Some(MemRegion { offset: 8, len: 2 }));
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_embedded_zero_len() {
let mut iter = MemRegionIter::new(&[
MemRegion { offset: 0, len: 4 },
MemRegion { offset: 8, len: 2 },
MemRegion { offset: 9, len: 0 },
MemRegion { offset: 16, len: 5 },
MemRegion { offset: 6, len: 0 },
MemRegion { offset: 24, len: 9 },
])
.skip_bytes(2)
.take_bytes(12);
assert_eq!(iter.next(), Some(MemRegion { offset: 2, len: 2 }));
assert_eq!(iter.next(), Some(MemRegion { offset: 8, len: 2 }));
assert_eq!(iter.next(), Some(MemRegion { offset: 16, len: 5 }));
assert_eq!(iter.next(), Some(MemRegion { offset: 24, len: 3 }));
assert_eq!(iter.next(), None);
}
#[test]
fn mem_region_iter_skip_multi() {
let mut iter = MemRegionIter::new(&[
MemRegion { offset: 0, len: 4 },
MemRegion { offset: 8, len: 2 },
MemRegion { offset: 16, len: 5 },
MemRegion { offset: 24, len: 9 },
])
.skip_bytes(7);
assert_eq!(iter.next(), Some(MemRegion { offset: 17, len: 4 }));
assert_eq!(iter.next(), Some(MemRegion { offset: 24, len: 9 }));
assert_eq!(iter.next(), None);
}
}