impl Buffer for File

This commit is contained in:
Szymon Walter 2018-03-19 09:48:11 +01:00
parent 3d946eb721
commit aee2f2def0

View file

@ -15,16 +15,14 @@ where
[T]: ToOwned, [T]: ToOwned,
{ {
fn len(&self) -> Length; fn len(&self) -> Length;
// TODO: return Result
fn commit(&mut self, slice: Option<BufferCommit<T>>); fn commit(&mut self, slice: Option<BufferCommit<T>>);
unsafe fn slice_unchecked<'a>( unsafe fn slice_unchecked<'a>(
&'a self, &'a self,
range: Range<usize>, range: Range<usize>,
) -> BufferSlice<'a, T>; ) -> BufferSlice<'a, T>;
fn slice<'a>( fn slice<'a>(&'a self, range: Range<usize>) -> Option<BufferSlice<'a, T>> {
&'a mut self,
range: Range<usize>,
) -> Option<BufferSlice<'a, T>> {
if self.len() >= range.end && self.len() > range.start { if self.len() >= range.end && self.len() > range.start {
unsafe { Some(self.slice_unchecked(range)) } unsafe { Some(self.slice_unchecked(range)) }
} else { } else {
@ -51,6 +49,16 @@ where
index: 0, index: 0,
} }
} }
pub fn new_owned(
inner: <[T] as ToOwned>::Owned,
index: usize,
) -> BufferSlice<'static, T> {
BufferSlice {
inner: Cow::Owned(inner),
index,
}
}
} }
impl<'a, T> BufferSlice<'a, T> impl<'a, T> BufferSlice<'a, T>
@ -199,55 +207,114 @@ impl<T> DerefMut for BufferCommit<T> {
} }
} }
default impl<T, B> Buffer<T> for B macro_rules! impl_slice {
where (@inner $buffer:ty $( , $lt:lifetime )* ) => {
T: Clone, impl<$( $lt, )* T> Buffer<T> for $buffer
[T]: ToOwned, where
B: AsRef<[T]> + AsMut<[T]>, T: Clone,
{ [T]: ToOwned,
fn len(&self) -> Length { {
Length::Bounded(self.as_ref().len()) fn len(&self) -> Length {
} Length::Bounded(<Self as AsRef<[T]>>::as_ref(self).len())
}
fn commit(&mut self, slice: Option<BufferCommit<T>>) { fn commit(&mut self, slice: Option<BufferCommit<T>>) {
slice.map(|slice| { slice.map(|slice| {
let index = slice.at_index(); let index = slice.at_index();
let end = index + slice.as_ref().len(); let end = index + slice.as_ref().len();
// XXX: it would be much better to drop the contents of dst and // XXX: it would be much better to drop the contents of dst
// move the contents of slice instead of cloning // and move the contents of slice instead of cloning
let dst = &mut self.as_mut()[index..end]; let dst =
dst.clone_from_slice(slice.as_ref()); &mut <Self as AsMut<[T]>>::as_mut(self)[index..end];
}); dst.clone_from_slice(slice.as_ref());
} });
}
unsafe fn slice_unchecked<'a>( unsafe fn slice_unchecked<'a>(
&'a self, &'a self,
range: Range<usize>, range: Range<usize>,
) -> BufferSlice<'a, T> { ) -> BufferSlice<'a, T> {
let index = range.start; let index = range.start;
BufferSlice::new(self.as_ref().get_unchecked(range), index) BufferSlice::new(
} <Self as AsRef<[T]>>::as_ref(self).get_unchecked(range),
index,
)
}
}
};
($buffer:ty) => {
impl_slice!(@inner $buffer);
};
($buffer:ty $( , $lt:lifetime )* ) => {
impl_slice!(@inner $buffer $( , $lt )* );
};
} }
impl<'a, T> Buffer<T> for &'a mut [T] //impl_slice!('a, &'a mut [T]);
where impl_slice!(Vec<T>);
T: Clone, impl_slice!(Box<[T]>);
[T]: ToOwned,
{
}
impl<T> Buffer<T> for Vec<T> #[cfg(any(test, not(feature = "no_std")))]
where mod file {
T: Clone, use std::ops::Range;
[T]: ToOwned, use std::io::{Read, Seek, SeekFrom, Write};
{ use std::fs::File;
} use std::cell::RefCell;
impl<T> Buffer<T> for Box<[T]> use super::{Buffer, BufferCommit, BufferSlice};
where use super::length::Length;
T: Clone,
[T]: ToOwned, impl Buffer<u8> for RefCell<File> {
{ fn len(&self) -> Length {
Length::Bounded(
self.borrow()
.metadata()
.map(|data| data.len() as usize)
.unwrap_or(0),
)
}
fn commit(&mut self, slice: Option<BufferCommit<u8>>) {
slice.map(|slice| {
let index = slice.at_index();
let end = index + slice.as_ref().len();
let mut refmut = self.borrow_mut();
let _ = refmut
.seek(SeekFrom::Start(index as u64))
.and_then(|_| refmut.write(&slice.as_ref()[index..end]));
});
}
unsafe fn slice_unchecked<'a>(
&'a self,
range: Range<usize>,
) -> BufferSlice<'a, u8> {
let index = range.start;
let mut vec = Vec::with_capacity(range.end - range.start);
let mut refmut = self.borrow_mut();
refmut
.seek(SeekFrom::Start(index as u64))
.and_then(|_| refmut.read_exact(&mut vec[range]))
.unwrap_or_else(|err| {
panic!("could't read from File Buffer: {:?}", err)
});
BufferSlice::new_owned(vec, index)
}
fn slice<'a>(
&'a self,
range: Range<usize>,
) -> Option<BufferSlice<'a, u8>> {
let index = range.start;
let mut vec = Vec::with_capacity(range.end - range.start);
let mut refmut = self.borrow_mut();
refmut
.seek(SeekFrom::Start(index as u64))
.and_then(|_| refmut.read_exact(&mut vec[range]))
.map(move |_| BufferSlice::new_owned(vec, index))
.ok()
}
}
} }
#[cfg(test)] #[cfg(test)]