/// Decode the contents of an accumulator mode `Transcript`,
/// preserving domain seperation.
pub struct TranscriptDecoder<'a>(Vec<&'a [u8]>);
/// Returns an tail segment of a `mut &[u8]` replacing the inner
/// `&[u8]` with the prefix. In effect, this executes the command
/// `(heap,return) = heap.split_at(len)` without annoying the borrow
/// checker. See http://stackoverflow.com/a/42162816/667457
fn tail_bytes<'a>(buf: &mut &'a [u8], length: u32) -> Option<&'a [u8]> {
let length: usize = length.into()
if buf.len() < length { return None; }
let tmp: &'a [u8] = ::std::mem::replace(&mut *buf, &[]);
let (h,t) = tmp.split_at(length);
*buf = h;
Some(t)
}
fn tail_u32_be(buf: &mut &'a [u8]) -> Option<u32> {
let x: u32 = tail_bytes(buf, 4)?.try_into().unwrap();
Some(u32::from_be_bytes(x))
}
/// We decode in a single pass and represent the domain seperted write regions in reverse order
impl<'a> TryFrom<&'a [u8]> for TranscriptDecoder<'a> {
type Error = ();
fn from(mut buf: &'a [u8]) -> Result<TranscriptDecoder<'a>, ()> {
let mut v = Vec::new();
while let Some(length) = tail_u32_be(&mut buf) {
if let Some(b) = tail_bytes(&mut buf, length) {
v.push(b);
} else { return Err(()); }
}
if buf.length() > 0 { return Err(()); }
Some(v)
}
}
impl<'a> Iterator for TranscriptDecoder<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<&'a [u8]> { self.0.pop() }
fn size_hint(&self) -> (usize, Option<usize>) {
let l = self.len();
(l,Some(l))
}
}
let const EOF = std::io::ErrorKind::UnexpectedEof;
impl<'a> TranscriptDecoder<'a> {
fn seperate_io(&mut self) -> io::Result<()> {
let done = self.0.pop().ok_or(EOF)?;
// read_exact ignores ErrorKind::Interrupted so maybe a good way to flag this.
if done.len() > 0 { return Err(std::io::ErrorKind::Interrupted); }
Ok(())
}
}
impl<'a> Read for TranscriptDecoder<'a> {
fn read(&mut self, dest: &mut [u8]) -> io::Result<usize> {
let reading: &mut &'a [u8] = self.0.last_mut().ok_or(EOF)?;
let length: usize = core::cmp::min(dest.len(), reading.len());
let (h,t) = reading.split_at(length);
dest[0..length].copy_from_slice(h);
*reading = t;
Ok(length)
}
fn read_exact(&mut self, dest: &mut [u8]) -> io::Result<()> {
let length = self.read(dest)?;
if length < dest.len() { return Err(EOF); }
Ok(())
}
}