#![allow(missing_docs)] use { alloc::{ borrow::{Cow, ToOwned}, boxed::Box, vec::Vec, }, core::{ mem, ops::{Deref, DerefMut, Range}, slice, }, error::Error, sector::{Address, SectorSize}, }; pub mod size; use self::size::Size; pub trait Volume { type Error: Into; fn size(&self) -> Size; fn commit( &mut self, slice: Option>, ) -> Result<(), Self::Error>; unsafe fn slice_unchecked<'a>( &'a self, range: Range>, ) -> VolumeSlice<'a, T, S>; fn slice<'a>( &'a self, range: Range>, ) -> Result, Self::Error>; } #[derive(Debug, Clone, PartialEq, Hash)] pub struct VolumeSlice<'a, T: 'a + Clone, S: SectorSize> { inner: Cow<'a, [T]>, index: Address, } impl VolumeSlice<'static, T, S> { pub fn with_static(inner: &'static [T]) -> VolumeSlice<'static, T, S> { VolumeSlice { inner: Cow::Borrowed(inner), index: Address::new(0, 0), } } pub fn new_owned( inner: <[T] as ToOwned>::Owned, index: Address, ) -> VolumeSlice<'static, T, S> { VolumeSlice { inner: Cow::Owned(inner), index, } } } impl<'a, T: Clone, S: SectorSize> VolumeSlice<'a, T, S> { pub fn new(inner: &'a [T], index: Address) -> VolumeSlice<'a, T, S> { VolumeSlice { inner: Cow::Borrowed(inner), index, } } pub fn is_mutated(&self) -> bool { match self.inner { Cow::Borrowed(_) => false, Cow::Owned(_) => true, } } pub fn address(&self) -> Address { self.index } } impl<'a, S: SectorSize> VolumeSlice<'a, u8, S> { pub unsafe fn dynamic_cast(&self) -> (T, Address) { assert!(self.inner.len() >= mem::size_of::()); let index = self.index; let cast = self.inner.as_ptr().cast::().read_unaligned(); // mem::transmute_copy(self.inner.as_ptr().as_ref().unwrap()); (cast, index) } pub fn from_cast( cast: &'a T, index: Address, ) -> VolumeSlice<'a, u8, S> { let len = mem::size_of::(); let ptr = cast as *const T as *const u8; let slice = unsafe { slice::from_raw_parts(ptr, len) }; VolumeSlice::new(slice, index) } } impl<'a, T: Clone, S: SectorSize> VolumeSlice<'a, T, S> { pub fn commit(self) -> Option> { if self.is_mutated() { Some(VolumeCommit::new(self.inner.into_owned(), self.index)) } else { None } } } impl<'a, T: Clone, S: SectorSize> AsRef<[T]> for VolumeSlice<'a, T, S> { fn as_ref(&self) -> &[T] { self.inner.as_ref() } } impl<'a, T: Clone, S: SectorSize> AsMut<[T]> for VolumeSlice<'a, T, S> { fn as_mut(&mut self) -> &mut [T] { self.inner.to_mut().as_mut() } } impl<'a, T: Clone, S: SectorSize> Deref for VolumeSlice<'a, T, S> { type Target = [T]; fn deref(&self) -> &Self::Target { self.as_ref() } } impl<'a, T: Clone, S: SectorSize> DerefMut for VolumeSlice<'a, T, S> { fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut() } } pub struct VolumeCommit { inner: Vec, index: Address, } impl VolumeCommit { pub fn with_vec(inner: Vec) -> VolumeCommit { VolumeCommit { inner, index: Address::new(0, 0), } } } impl VolumeCommit { pub fn new(inner: Vec, index: Address) -> VolumeCommit { VolumeCommit { inner, index } } pub fn into_inner(self) -> Vec { self.inner } pub fn address(&self) -> Address { self.index } } impl AsRef<[T]> for VolumeCommit { fn as_ref(&self) -> &[T] { self.inner.as_ref() } } impl AsMut<[T]> for VolumeCommit { fn as_mut(&mut self) -> &mut [T] { self.inner.as_mut() } } impl Deref for VolumeCommit { type Target = [T]; fn deref(&self) -> &Self::Target { self.as_ref() } } impl DerefMut for VolumeCommit { fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut() } } macro_rules! impl_slice { (@inner $volume:ty $( , $lt:lifetime )* ) => { impl<$( $lt, )* T: Clone, S: SectorSize> Volume for $volume { type Error = Error; fn size(&self) -> Size { Size::Bounded( Address::from(>::as_ref(self).len()) ) } fn commit( &mut self, slice: Option>, ) -> Result<(), Self::Error> { slice.map(|slice| { let index = slice.address().into_index() as usize; let end = index + slice.as_ref().len(); // XXX: it would be much better to drop the contents of dst // and move the contents of slice instead of cloning let dst = &mut >::as_mut(self)[index..end]; dst.clone_from_slice(slice.as_ref()); }); Ok(()) } unsafe fn slice_unchecked<'a>( &'a self, range: Range>, ) -> VolumeSlice<'a, T, S> { let index = range.start; let range = range.start.into_index() as usize ..range.end.into_index() as usize; VolumeSlice::new( >::as_ref(self).get_unchecked(range), index, ) } fn slice<'a>( &'a self, range: Range>, ) -> Result, Self::Error> { if self.size() >= range.end { unsafe { Ok(self.slice_unchecked(range)) } } else { Err(Error::AddressOutOfBounds { sector: range.end.sector(), offset: range.end.offset(), size: range.end.sector_size() }) } } } }; ($volume:ty) => { impl_slice!(@inner $volume); }; ($volume:ty $( , $lt:lifetime )* ) => { impl_slice!(@inner $volume $( , $lt )* ); }; } impl_slice!(&'b mut [T], 'b); impl_slice!(Vec); impl_slice!(Box<[T]>); #[cfg(any(test, not(feature = "no_std")))] mod file { use std::cell::RefCell; use std::fs::File; use std::io::{self, Read, Seek, SeekFrom, Write}; use std::ops::Range; use sector::{Address, SectorSize}; use super::size::Size; use super::{Volume, VolumeCommit, VolumeSlice}; impl Volume for RefCell { type Error = io::Error; fn size(&self) -> Size { Size::Bounded( self.borrow() .metadata() .map(|data| Address::from(data.len())) .unwrap_or(Address::new(0, 0)), ) } fn commit( &mut self, slice: Option>, ) -> Result<(), Self::Error> { slice .map(|slice| { let index = slice.address(); let mut refmut = self.borrow_mut(); refmut .seek(SeekFrom::Start(index.into_index())) .and_then(|_| refmut.write(slice.as_ref())) .map(|_| ()) }) .unwrap_or(Ok(())) } unsafe fn slice_unchecked<'a>( &'a self, range: Range>, ) -> VolumeSlice<'a, u8, S> { let index = range.start; let len = range.end - range.start; let mut vec = Vec::with_capacity(len.into_index() as usize); vec.set_len(len.into_index() as usize); let mut refmut = self.borrow_mut(); refmut .seek(SeekFrom::Start(index.into_index())) .and_then(|_| refmut.read_exact(&mut vec[..])) .unwrap_or_else(|err| { panic!("could't read from File Volume: {:?}", err) }); VolumeSlice::new_owned(vec, index) } fn slice<'a>( &'a self, range: Range>, ) -> Result, Self::Error> { let index = range.start; let mut vec = Vec::with_capacity( (range.end - range.start).into_index() as usize, ); unsafe { vec.set_len((range.end - range.start).into_index() as usize); } let mut refmut = self.borrow_mut(); refmut .seek(SeekFrom::Start(index.into_index())) .and_then(|_| refmut.read_exact(&mut vec[..])) .map(move |_| VolumeSlice::new_owned(vec, index)) } } } #[cfg(test)] mod tests { use super::*; use sector::{Address, Size512}; #[test] fn volume() { let mut volume = vec![0; 1024]; let commit = { let mut slice = volume .slice( Address::::from(256_u64) ..Address::::from(512_u64), ) .unwrap(); slice.iter_mut().for_each(|x| *x = 1); slice.commit() }; assert!(volume.commit(commit).is_ok()); for (i, &x) in volume.iter().enumerate() { if i < 256 || i >= 512 { assert_eq!(x, 0); } else { assert_eq!(x, 1); } } } }