Skip to content

ArkTranscript reader mode #1

@burdges

Description

@burdges
/// 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(())
    }
}

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions