Still working with the borrow checker

This commit is contained in:
Bradlee Speice 2019-04-24 17:13:34 -04:00
parent 442b5c4006
commit 0835e4bc26
2 changed files with 137 additions and 45 deletions

View File

@ -1,52 +1,66 @@
use std::io; use std::io;
use std::marker::PhantomData; use std::marker::PhantomData;
#[derive(Debug)] #[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Needed {
Size(usize),
Unknown,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum KError<'a> { pub enum KError<'a> {
InvalidContents { actual: &'a [u8] }, Incomplete(Needed),
IoError(io::Error), UnexpectedContents { actual: &'a [u8] },
UnknownEnum(u64), UnknownVariant(u64),
} }
impl<'a> From<io::Error> for KError<'a> {
fn from(e: io::Error) -> Self {
KError::IoError(e)
}
}
pub type KResult<'a, T> = Result<T, KError<'a>>; pub type KResult<'a, T> = Result<T, KError<'a>>;
// TODO: Do we need extra lifetimes for parents/roots?
// Likely not necessary since everyone effectively lives
// as long as the stream, but worth looking into
pub trait KStruct<'a> { pub trait KStruct<'a> {
type Parent: KStruct<'a>; type Parent: KStruct<'a>;
type Root: KStruct<'a>; type Root: KStruct<'a>;
/// Create a new instance of this struct; if we are the root node, /// Create a new instance of this struct; if we are the root node,
/// then both `_parent` and `_root` will be `None`. /// then both `_parent` and `_root` will be `None`.
// `_root` is an Option because we need to create a root in the first place fn new(_parent: Option<&'a Self::Parent>, _root: Option<&'a Self::Root>) -> Self
fn new(_parent: Option<&'a Self::Parent>, _root: Option<&'a Self::Root>) -> KResult<'a, Self>
where where
Self: Sized; Self: Sized;
/// Parse this struct (and any children) from the supplied stream /// Parse this struct (and any children) from the supplied stream
fn read<S: KStream>(&'a mut self, stream: &mut S) -> KResult<'a, ()>; fn read<'s: 'a, S: KStream>(&mut self, stream: &'s mut S) -> KResult<'s, ()>;
/// Get the root of this parse structure
fn root(&self) -> &'a Self::Root;
} }
#[derive(Debug, Default, Copy, Clone)] /// Dummy struct used to indicate an absence of value; needed for
/// root structs to satisfy the associate type bounds in the
/// `KStruct` trait.
#[derive(Debug, Default, Copy, Clone, PartialEq)]
pub struct KStructUnit<'a> { pub struct KStructUnit<'a> {
phantom: PhantomData<&'a ()> phantom: PhantomData<&'a ()>,
} }
impl<'a> KStruct<'a> for KStructUnit<'a> { impl<'a> KStruct<'a> for KStructUnit<'a> {
type Parent = KStructUnit<'a>; type Parent = KStructUnit<'a>;
type Root = KStructUnit<'a>; type Root = KStructUnit<'a>;
fn new(_parent: Option<&'a Self::Parent>, _root: Option<&'a Self::Root>) -> Result<Self, KError<'a>> where fn new(_parent: Option<&'a Self::Parent>, _root: Option<&'a Self::Root>) -> Self
Self: Sized { where
Ok(KStructUnit { phantom: PhantomData }) Self: Sized,
{
KStructUnit {
phantom: PhantomData,
}
} }
fn read<S: KStream>(&mut self, _stream: &mut S) -> Result<(), KError<'a>> { fn read<'s: 'a, S: KStream>(&mut self, _stream: &'s mut S) -> KResult<'s, ()> {
Ok(()) Ok(())
} }
fn root(&self) -> &'a Self::Root {
panic!("Attempted to get root of unit structure.")
}
} }
pub trait KStream { pub trait KStream {
@ -79,15 +93,15 @@ pub trait KStream {
fn align_to_byte(&mut self) -> io::Result<()>; fn align_to_byte(&mut self) -> io::Result<()>;
fn read_bits_int(&mut self, n: u32) -> io::Result<u64>; fn read_bits_int(&mut self, n: u32) -> io::Result<u64>;
fn read_bytes(&mut self, len: usize) -> io::Result<&[u8]>; fn read_bytes(&mut self, len: usize) -> KResult<&[u8]>;
fn read_bytes_full(&mut self) -> io::Result<&[u8]>; fn read_bytes_full(&mut self) -> KResult<&[u8]>;
fn read_bytes_term( fn read_bytes_term(
&mut self, &mut self,
term: char, term: char,
include: bool, include: bool,
consume: bool, consume: bool,
eos_error: bool, eos_error: bool,
) -> io::Result<&[u8]>; ) -> KResult<&[u8]>;
fn ensure_fixed_contents(&mut self, expected: &[u8]) -> KResult<&[u8]> { fn ensure_fixed_contents(&mut self, expected: &[u8]) -> KResult<&[u8]> {
let actual = self.read_bytes(expected.len())?; let actual = self.read_bytes(expected.len())?;
@ -97,7 +111,7 @@ pub trait KStream {
// Return what the actual contents were; our caller provided us // Return what the actual contents were; our caller provided us
// what was expected so we don't need to return it, and it makes // what was expected so we don't need to return it, and it makes
// the lifetimes way easier // the lifetimes way easier
Err(KError::InvalidContents { actual }) Err(KError::UnexpectedContents { actual })
} }
} }
@ -128,7 +142,7 @@ pub trait KStream {
} }
#[allow(dead_code)] #[allow(dead_code)]
struct BytesReader<'a> { pub struct BytesReader<'a> {
bytes: &'a [u8], bytes: &'a [u8],
pos: usize, pos: usize,
bits: u8, bits: u8,
@ -250,9 +264,9 @@ impl<'a> KStream for BytesReader<'a> {
unimplemented!() unimplemented!()
} }
fn read_bytes(&mut self, len: usize) -> io::Result<&[u8]> { fn read_bytes(&mut self, len: usize) -> KResult<&[u8]> {
if len > self.remaining() { if len > self.remaining() {
return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()) return Err(KError::Incomplete(Needed::Size(len - self.remaining())));
} }
let slice = &self.bytes[self.pos..self.pos + len]; let slice = &self.bytes[self.pos..self.pos + len];
self.pos += len; self.pos += len;
@ -260,12 +274,12 @@ impl<'a> KStream for BytesReader<'a> {
Ok(slice) Ok(slice)
} }
fn read_bytes_full(&mut self) -> io::Result<&[u8]> { fn read_bytes_full(&mut self) -> KResult<&[u8]> {
if self.remaining() > 0 { if self.remaining() > 0 {
self.pos = self.bytes.len(); self.pos = self.bytes.len();
Ok(&self.bytes[self.pos..]) Ok(&self.bytes[self.pos..])
} else { } else {
Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()) Err(KError::Incomplete(Needed::Unknown))
} }
} }
@ -275,7 +289,7 @@ impl<'a> KStream for BytesReader<'a> {
_include: bool, _include: bool,
_consume: bool, _consume: bool,
_eos_error: bool, _eos_error: bool,
) -> io::Result<&[u8]> { ) -> KResult<&[u8]> {
unimplemented!() unimplemented!()
} }
} }
@ -297,21 +311,12 @@ mod tests {
let b = vec![1, 2, 3, 4, 5, 6, 7, 8]; let b = vec![1, 2, 3, 4, 5, 6, 7, 8];
let mut reader = BytesReader::from(b.as_slice()); let mut reader = BytesReader::from(b.as_slice());
assert_eq!(reader.read_bytes(4).unwrap(), &[1, 2, 3, 4]);
assert_eq!(reader.read_bytes(3).unwrap(), &[5, 6, 7]);
assert_eq!( assert_eq!(
reader.read_bytes(4).unwrap(), reader.read_bytes(4).unwrap_err(),
&[1, 2, 3, 4] KError::Incomplete(Needed::Size(3))
);
assert_eq!(
reader.read_bytes(3).unwrap(),
&[5, 6, 7]
);
assert_eq!(
reader.read_bytes(4).unwrap_err().kind(),
io::ErrorKind::UnexpectedEof
);
assert_eq!(
reader.read_bytes(1).unwrap(),
&[8]
); );
assert_eq!(reader.read_bytes(1).unwrap(), &[8]);
} }
} }

View File

@ -0,0 +1,87 @@
//! Example using hand-coded structs to validate that the borrow checker
//! will allow our code to actually run
/*
use kaitai::{BytesReader, KError, KStream, KStructUnit, KStruct};
#[derive(Debug, PartialEq, Clone, Default)]
struct TestRootStruct<'a> {
pub bytes: &'a [u8],
pub child: Option<&'a TestChildStruct<'a>>,
parent: Option<&'a KStructUnit<'a>>,
root: Option<&'a TestRootStruct<'a>>,
}
#[derive(Debug, PartialEq, Clone, Default)]
struct TestChildStruct<'a> {
pub bytes: &'a [u8],
parent: Option<&'a TestRootStruct<'a>>,
root: Option<&'a TestRootStruct<'a>>,
}
impl<'a> KStruct<'a> for TestRootStruct<'a> {
type Parent = KStructUnit<'a>;
type Root = TestRootStruct<'a>;
fn new(_parent: Option<&'a Self::Parent>, _root: Option<&'a Self::Root>) -> Self
where
Self: Sized {
TestRootStruct {
parent: _parent,
root: _root,
..Default::default()
}
}
fn read<'s: 'a, S: KStream>(&mut self, stream: &'s mut S) -> Result<(), KError<'s>> {
self.bytes = stream.read_bytes(1)?;
let mut child = TestChildStruct::new(Some(self), Some(self.root()));
child.read(stream)?;
self.child = Some(&child);
Ok(())
}
fn root(&self) -> &'a Self::Root {
self.root.or(Some(self)).unwrap()
}
}
impl<'a> KStruct<'a> for TestChildStruct<'a> {
type Parent = TestRootStruct<'a>;
type Root = TestRootStruct<'a>;
fn new(_parent: Option<&'a Self::Parent>, _root: Option<&'a Self::Root>) -> Self where
Self: Sized {
TestChildStruct {
parent: _parent,
root: _root,
..Default::default()
}
}
fn read<'s: 'a, S: KStream>(&mut self, stream: &'s mut S) -> Result<(), KError<'s>> {
self.bytes = stream.read_bytes(1)?;
Ok(())
}
fn root(&self) -> &'a Self::Root {
self.root.unwrap()
}
}
#[test]
fn basic_parse() {
let bytes = [1, 2];
let mut reader = BytesReader::from(&bytes[..]);
let mut root = TestRootStruct::new(None, None);
let res = root.read(&mut reader);
assert!(res.is_ok());
assert_eq!([1], root.bytes);
assert!(root.child.is_some());
assert_eq!([2], root.child.unwrap().bytes);
}
*/