use error::Result; | |
use serde; | |
use std::io; | |
/// An optional Read trait for advanced Bincode usage. | |
/// | |
/// It is highly recommended to use bincode with `io::Read` or `&[u8]` before | |
/// implementing a custom `BincodeRead`. | |
/// | |
/// The forward_read_* methods are necessary because some byte sources want | |
/// to pass a long-lived borrow to the visitor and others want to pass a | |
/// transient slice. | |
pub trait BincodeRead<'storage>: io::Read { | |
/// Check that the next `length` bytes are a valid string and pass | |
/// it on to the serde reader. | |
fn forward_read_str<V>(&mut self, length: usize, visitor: V) -> Result<V::Value> | |
where | |
V: serde::de::Visitor<'storage>; | |
/// Transfer ownership of the next `length` bytes to the caller. | |
fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>>; | |
/// Pass a slice of the next `length` bytes on to the serde reader. | |
fn forward_read_bytes<V>(&mut self, length: usize, visitor: V) -> Result<V::Value> | |
where | |
V: serde::de::Visitor<'storage>; | |
} | |
/// A BincodeRead implementation for byte slices | |
pub struct SliceReader<'storage> { | |
slice: &'storage [u8], | |
} | |
/// A BincodeRead implementation for `io::Read`ers | |
pub struct IoReader<R> { | |
reader: R, | |
temp_buffer: Vec<u8>, | |
} | |
impl<'storage> SliceReader<'storage> { | |
/// Constructs a slice reader | |
pub(crate) fn new(bytes: &'storage [u8]) -> SliceReader<'storage> { | |
SliceReader { slice: bytes } | |
} | |
#[inline(always)] | |
fn get_byte_slice(&mut self, length: usize) -> Result<&'storage [u8]> { | |
if length > self.slice.len() { | |
return Err(SliceReader::unexpected_eof()); | |
} | |
let (read_slice, remaining) = self.slice.split_at(length); | |
self.slice = remaining; | |
Ok(read_slice) | |
} | |
pub(crate) fn is_finished(&self) -> bool { | |
self.slice.is_empty() | |
} | |
} | |
impl<R> IoReader<R> { | |
/// Constructs an IoReadReader | |
pub(crate) fn new(r: R) -> IoReader<R> { | |
IoReader { | |
reader: r, | |
temp_buffer: vec![], | |
} | |
} | |
} | |
impl<'storage> io::Read for SliceReader<'storage> { | |
#[inline(always)] | |
fn read(&mut self, out: &mut [u8]) -> io::Result<usize> { | |
if out.len() > self.slice.len() { | |
return Err(io::ErrorKind::UnexpectedEof.into()); | |
} | |
let (read_slice, remaining) = self.slice.split_at(out.len()); | |
out.copy_from_slice(read_slice); | |
self.slice = remaining; | |
Ok(out.len()) | |
} | |
#[inline(always)] | |
fn read_exact(&mut self, out: &mut [u8]) -> io::Result<()> { | |
self.read(out).map(|_| ()) | |
} | |
} | |
impl<R: io::Read> io::Read for IoReader<R> { | |
#[inline(always)] | |
fn read(&mut self, out: &mut [u8]) -> io::Result<usize> { | |
self.reader.read(out) | |
} | |
#[inline(always)] | |
fn read_exact(&mut self, out: &mut [u8]) -> io::Result<()> { | |
self.reader.read_exact(out) | |
} | |
} | |
impl<'storage> SliceReader<'storage> { | |
#[inline(always)] | |
fn unexpected_eof() -> Box<::ErrorKind> { | |
Box::new(::ErrorKind::Io(io::Error::new( | |
io::ErrorKind::UnexpectedEof, | |
"", | |
))) | |
} | |
} | |
impl<'storage> BincodeRead<'storage> for SliceReader<'storage> { | |
#[inline(always)] | |
fn forward_read_str<V>(&mut self, length: usize, visitor: V) -> Result<V::Value> | |
where | |
V: serde::de::Visitor<'storage>, | |
{ | |
use ErrorKind; | |
let string = match ::std::str::from_utf8(self.get_byte_slice(length)?) { | |
Ok(s) => s, | |
Err(e) => return Err(ErrorKind::InvalidUtf8Encoding(e).into()), | |
}; | |
visitor.visit_borrowed_str(string) | |
} | |
#[inline(always)] | |
fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>> { | |
self.get_byte_slice(length).map(|x| x.to_vec()) | |
} | |
#[inline(always)] | |
fn forward_read_bytes<V>(&mut self, length: usize, visitor: V) -> Result<V::Value> | |
where | |
V: serde::de::Visitor<'storage>, | |
{ | |
visitor.visit_borrowed_bytes(self.get_byte_slice(length)?) | |
} | |
} | |
impl<R> IoReader<R> | |
where | |
R: io::Read, | |
{ | |
fn fill_buffer(&mut self, length: usize) -> Result<()> { | |
self.temp_buffer.resize(length, 0); | |
self.reader.read_exact(&mut self.temp_buffer)?; | |
Ok(()) | |
} | |
} | |
impl<'a, R> BincodeRead<'a> for IoReader<R> | |
where | |
R: io::Read, | |
{ | |
fn forward_read_str<V>(&mut self, length: usize, visitor: V) -> Result<V::Value> | |
where | |
V: serde::de::Visitor<'a>, | |
{ | |
self.fill_buffer(length)?; | |
let string = match ::std::str::from_utf8(&self.temp_buffer[..]) { | |
Ok(s) => s, | |
Err(e) => return Err(::ErrorKind::InvalidUtf8Encoding(e).into()), | |
}; | |
visitor.visit_str(string) | |
} | |
fn get_byte_buffer(&mut self, length: usize) -> Result<Vec<u8>> { | |
self.fill_buffer(length)?; | |
Ok(::std::mem::replace(&mut self.temp_buffer, Vec::new())) | |
} | |
fn forward_read_bytes<V>(&mut self, length: usize, visitor: V) -> Result<V::Value> | |
where | |
V: serde::de::Visitor<'a>, | |
{ | |
self.fill_buffer(length)?; | |
visitor.visit_bytes(&self.temp_buffer[..]) | |
} | |
} | |
#[cfg(test)] | |
mod test { | |
use super::IoReader; | |
#[test] | |
fn test_fill_buffer() { | |
let buffer = vec![0u8; 64]; | |
let mut reader = IoReader::new(buffer.as_slice()); | |
reader.fill_buffer(20).unwrap(); | |
assert_eq!(20, reader.temp_buffer.len()); | |
reader.fill_buffer(30).unwrap(); | |
assert_eq!(30, reader.temp_buffer.len()); | |
reader.fill_buffer(5).unwrap(); | |
assert_eq!(5, reader.temp_buffer.len()); | |
} | |
} |