mirror of
https://github.com/bspeice/kaitai_rust
synced 2024-11-21 21:38:09 -05:00
Split into read
and stream
lifetimes
Much easier to read, and compiles all the examples we need.
This commit is contained in:
parent
d41f578c83
commit
37ea0f5cc1
108
src/lib.rs
108
src/lib.rs
@ -20,16 +20,16 @@ pub enum KError<'a> {
|
|||||||
}
|
}
|
||||||
pub type KResult<'a, T> = Result<T, KError<'a>>;
|
pub type KResult<'a, T> = Result<T, KError<'a>>;
|
||||||
|
|
||||||
pub trait KStruct<'a>: Default {
|
pub trait KStruct<'r, 's: 'r>: Default {
|
||||||
type Parent: KStruct<'a>;
|
type Root: KStruct<'r, 's>;
|
||||||
type Root: KStruct<'a>;
|
type ParentStack;
|
||||||
|
|
||||||
/// Parse this struct (and any children) from the supplied stream
|
/// Parse this struct (and any children) from the supplied stream
|
||||||
fn read<'s: 'a, S: KStream>(
|
fn read<S: KStream>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_io: &'s S,
|
_io: &'s S,
|
||||||
_root: Option<&Self::Root>,
|
_root: Option<&'r Self::Root>,
|
||||||
_parent: Option<&Self::Parent>,
|
_parent: TypedStack<Self::ParentStack>,
|
||||||
) -> KResult<'s, ()>;
|
) -> KResult<'s, ()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,20 +38,55 @@ pub trait KStruct<'a>: Default {
|
|||||||
/// `KStruct` trait.
|
/// `KStruct` trait.
|
||||||
#[derive(Debug, Default, Copy, Clone, PartialEq)]
|
#[derive(Debug, Default, Copy, Clone, PartialEq)]
|
||||||
pub struct KStructUnit;
|
pub struct KStructUnit;
|
||||||
impl<'a> KStruct<'a> for KStructUnit {
|
impl KStructUnit {
|
||||||
type Parent = KStructUnit;
|
pub fn parent_stack() -> TypedStack<(KStructUnit)> {
|
||||||
|
TypedStack { current: (KStructUnit) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'r, 's: 'r> KStruct<'r, 's> for KStructUnit {
|
||||||
type Root = KStructUnit;
|
type Root = KStructUnit;
|
||||||
|
type ParentStack = (KStructUnit);
|
||||||
|
|
||||||
fn read<'s: 'a, S: KStream>(
|
fn read<S: KStream>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_io: &'s S,
|
_io: &'s S,
|
||||||
_root: Option<&Self::Root>,
|
_root: Option<&'r Self::Root>,
|
||||||
_parent: Option<&Self::Parent>,
|
_parent: TypedStack<Self::ParentStack>,
|
||||||
) -> KResult<'s, ()> {
|
) -> KResult<'s, ()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct TypedStack<C> {
|
||||||
|
current: C,
|
||||||
|
}
|
||||||
|
impl<C> TypedStack<C>
|
||||||
|
where
|
||||||
|
C: Clone,
|
||||||
|
{
|
||||||
|
pub fn push<N>(&self, next: N) -> TypedStack<(N, C)> {
|
||||||
|
TypedStack {
|
||||||
|
current: (next, self.current.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<C, P> TypedStack<(C, P)>
|
||||||
|
where
|
||||||
|
C: Clone,
|
||||||
|
P: Clone,
|
||||||
|
{
|
||||||
|
pub fn peek(&self) -> &C {
|
||||||
|
&self.current.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop(&self) -> TypedStack<(P)> {
|
||||||
|
TypedStack {
|
||||||
|
current: (self.current.clone().1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait KStream {
|
pub trait KStream {
|
||||||
fn is_eof(&self) -> KResult<bool>;
|
fn is_eof(&self) -> KResult<bool>;
|
||||||
fn seek(&self, position: u64) -> KResult<()>;
|
fn seek(&self, position: u64) -> KResult<()>;
|
||||||
@ -276,25 +311,41 @@ impl<'a> KStream for BytesReader<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! kf_max {
|
macro_rules! kf_max {
|
||||||
($i: ident, $t: ty) => (
|
($i: ident, $t: ty) => {
|
||||||
pub fn $i<'a>(first: Option<&'a $t>, second: &'a $t) -> Option<&'a $t> {
|
pub fn $i<'a>(first: Option<&'a $t>, second: &'a $t) -> Option<&'a $t> {
|
||||||
if second.is_nan() { first }
|
if second.is_nan() {
|
||||||
else if first.is_none() { Some(second) }
|
first
|
||||||
else { if first.unwrap() < second { Some(second) } else { first } }
|
} else if first.is_none() {
|
||||||
|
Some(second)
|
||||||
|
} else {
|
||||||
|
if first.unwrap() < second {
|
||||||
|
Some(second)
|
||||||
|
} else {
|
||||||
|
first
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
kf_max!(kf32_max, f32);
|
kf_max!(kf32_max, f32);
|
||||||
kf_max!(kf64_max, f64);
|
kf_max!(kf64_max, f64);
|
||||||
|
|
||||||
macro_rules! kf_min {
|
macro_rules! kf_min {
|
||||||
($i: ident, $t: ty) => (
|
($i: ident, $t: ty) => {
|
||||||
pub fn $i<'a>(first: Option<&'a $t>, second: &'a $t) -> Option<&'a $t> {
|
pub fn $i<'a>(first: Option<&'a $t>, second: &'a $t) -> Option<&'a $t> {
|
||||||
if second.is_nan() { first }
|
if second.is_nan() {
|
||||||
else if first.is_none() { Some(second) }
|
first
|
||||||
else { if first.unwrap() < second { first } else { Some(second) } }
|
} else if first.is_none() {
|
||||||
|
Some(second)
|
||||||
|
} else {
|
||||||
|
if first.unwrap() < second {
|
||||||
|
first
|
||||||
|
} else {
|
||||||
|
Some(second)
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
kf_min!(kf32_min, f32);
|
kf_min!(kf32_min, f32);
|
||||||
kf_min!(kf64_min, f64);
|
kf_min!(kf64_min, f64);
|
||||||
@ -365,6 +416,19 @@ mod tests {
|
|||||||
let b: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
|
let b: Vec<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||||
let reader = BytesReader::new(&b[..]);
|
let reader = BytesReader::new(&b[..]);
|
||||||
|
|
||||||
assert_eq!(reader.read_bits_int(65).unwrap_err(), KError::ReadBitsTooLarge { requested: 65 })
|
assert_eq!(
|
||||||
|
reader.read_bits_int(65).unwrap_err(),
|
||||||
|
KError::ReadBitsTooLarge { requested: 65 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn stack_clone() {
|
||||||
|
let t = TypedStack { current: () };
|
||||||
|
let t2: TypedStack<(u8, ())> = t.push(12);
|
||||||
|
let t3: TypedStack<(u16, (u8, ()))> = t2.push(14);
|
||||||
|
|
||||||
|
assert_eq!(*t3.peek(), 14);
|
||||||
|
assert_eq!(*t3.pop().peek(), *t2.peek());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
79
tests/grandparent_validation.rs
Normal file
79
tests/grandparent_validation.rs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
use kaitai::*;
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
struct Grandparent<'s> {
|
||||||
|
value: &'s [u8],
|
||||||
|
parent: Option<Parent<'s>>,
|
||||||
|
}
|
||||||
|
impl<'r, 's: 'r> KStruct<'r, 's> for Grandparent<'s> {
|
||||||
|
type Root = Self;
|
||||||
|
type ParentStack = (KStructUnit);
|
||||||
|
|
||||||
|
fn read<S: KStream>(
|
||||||
|
&mut self,
|
||||||
|
_io: &'s S,
|
||||||
|
_root: Option<&'r Self::Root>,
|
||||||
|
_parent: TypedStack<Self::ParentStack>,
|
||||||
|
) -> KResult<'s, ()> {
|
||||||
|
self.value = _io.read_bytes(1)?;
|
||||||
|
|
||||||
|
let mut tmp = Parent::default();
|
||||||
|
tmp.read(_io, Some(self), _parent.push(self));
|
||||||
|
self.parent = Some(tmp);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
struct Parent<'s> {
|
||||||
|
value: &'s [u8],
|
||||||
|
child: Option<Child>,
|
||||||
|
}
|
||||||
|
impl<'r, 's: 'r> KStruct<'r, 's> for Parent<'s> {
|
||||||
|
type Root = Grandparent<'s>;
|
||||||
|
type ParentStack = (&'r Grandparent<'s>, <Grandparent<'s> as KStruct<'r, 's>>::ParentStack);
|
||||||
|
|
||||||
|
fn read<S: KStream>(
|
||||||
|
&mut self,
|
||||||
|
_io: &'s S,
|
||||||
|
_root: Option<&'r Self::Root>,
|
||||||
|
_parent: TypedStack<Self::ParentStack>,
|
||||||
|
) -> KResult<'s, ()> {
|
||||||
|
self.value = _io.read_bytes(1)?;
|
||||||
|
|
||||||
|
let mut tmp = Child::default();
|
||||||
|
tmp.read(_io, _root, _parent.push(self));
|
||||||
|
self.child = Some(tmp);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
struct Child {
|
||||||
|
gp_value: u8,
|
||||||
|
}
|
||||||
|
impl<'r, 's: 'r> KStruct<'r, 's> for Child {
|
||||||
|
type Root = Grandparent<'s>;
|
||||||
|
type ParentStack = (&'r Parent<'s>, <Parent<'s> as KStruct<'r, 's>>::ParentStack);
|
||||||
|
|
||||||
|
fn read<S: KStream>(
|
||||||
|
&mut self,
|
||||||
|
_io: &'s S,
|
||||||
|
_root: Option<&'r Self::Root>,
|
||||||
|
_parent: TypedStack<Self::ParentStack>,
|
||||||
|
) -> KResult<'s, ()> {
|
||||||
|
self.gp_value = _parent.pop().peek().value[0];
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn basic_parse() {
|
||||||
|
let bytes = [0u8, 1];
|
||||||
|
let r = BytesReader::new(&bytes);
|
||||||
|
|
||||||
|
let mut gp = Grandparent::default();
|
||||||
|
gp.read(&r, None, KStructUnit::parent_stack());
|
||||||
|
}
|
@ -1,52 +1,48 @@
|
|||||||
//! Example using hand-coded structs to validate that the borrow checker
|
//! Example using hand-coded structs to validate that the borrow checker
|
||||||
//! will allow our code to actually run
|
//! will allow our code to actually run
|
||||||
|
|
||||||
use kaitai::{BytesReader, KError, KResult, KStream, KStruct, KStructUnit};
|
use kaitai::{BytesReader, KError, KResult, KStream, KStruct, KStructUnit, TypedStack};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Default)]
|
#[derive(Debug, PartialEq, Clone, Default)]
|
||||||
struct TestRootStruct<'a> {
|
struct TestRootStruct<'s> {
|
||||||
pub bytes: &'a [u8],
|
pub bytes: &'s [u8],
|
||||||
pub child: Option<TestChildStruct<'a>>,
|
pub child: Option<TestChildStruct<'s>>,
|
||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq, Clone, Default)]
|
#[derive(Debug, PartialEq, Clone, Default)]
|
||||||
struct TestChildStruct<'a> {
|
struct TestChildStruct<'s> {
|
||||||
pub bytes: &'a [u8],
|
pub bytes: &'s [u8],
|
||||||
pub root_bytes: &'a [u8],
|
pub root_bytes: &'s [u8],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> KStruct<'a> for TestRootStruct<'a> {
|
impl<'r, 's: 'r> KStruct<'r, 's> for TestRootStruct<'s> {
|
||||||
type Parent = KStructUnit;
|
type Root = Self;
|
||||||
type Root = TestRootStruct<'a>;
|
type ParentStack = (KStructUnit);
|
||||||
|
|
||||||
fn read<'s: 'a, S: KStream>(
|
fn read<S: KStream>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_io: &'s S,
|
_io: &'s S,
|
||||||
_root: Option<&Self::Root>,
|
_root: Option<&'r Self::Root>,
|
||||||
_parent: Option<&Self::Parent>,
|
_parent: TypedStack<Self::ParentStack>,
|
||||||
) -> KResult<'s, ()> {
|
) -> KResult<'s, ()> {
|
||||||
self.bytes = _io.read_bytes(1)?;
|
self.bytes = _io.read_bytes(1)?;
|
||||||
|
|
||||||
// TODO: `new` method in KStruct?
|
|
||||||
let mut child = TestChildStruct::default();
|
let mut child = TestChildStruct::default();
|
||||||
// Implementation note: because callers of `read` can't call us as
|
child.read(_io, Some(self), _parent.push(self))?;
|
||||||
// `struct.read(_io, Some(struct), None)`, we have to use the `or`
|
|
||||||
// call below to give an immutable copy of ourselves to the child
|
|
||||||
child.read(_io, _root.or(Some(self)), Some(self))?;
|
|
||||||
self.child = Some(child);
|
self.child = Some(child);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> KStruct<'a> for TestChildStruct<'a> {
|
impl<'r, 's: 'r> KStruct<'r, 's> for TestChildStruct<'s> {
|
||||||
type Parent = TestRootStruct<'a>;
|
type Root = <TestRootStruct<'s> as KStruct<'r, 's>>::Root;
|
||||||
type Root = TestRootStruct<'a>;
|
type ParentStack = (&'r TestRootStruct<'s>, <TestRootStruct<'s> as KStruct<'r, 's>>::ParentStack);
|
||||||
|
|
||||||
fn read<'s: 'a, S: KStream>(
|
fn read<S: KStream>(
|
||||||
&mut self,
|
&mut self,
|
||||||
_io: &'s S,
|
_io: &'s S,
|
||||||
_root: Option<&Self::Root>,
|
_root: Option<&'r Self::Root>,
|
||||||
_parent: Option<&Self::Parent>,
|
_parent: TypedStack<Self::ParentStack>,
|
||||||
) -> KResult<'s, ()> {
|
) -> KResult<'s, ()> {
|
||||||
self.bytes = _io.read_bytes(1).unwrap();
|
self.bytes = _io.read_bytes(1).unwrap();
|
||||||
_root.map(|r| self.root_bytes = r.bytes).ok_or(KError::MissingRoot)?;
|
_root.map(|r| self.root_bytes = r.bytes).ok_or(KError::MissingRoot)?;
|
||||||
@ -61,7 +57,7 @@ fn basic_parse() {
|
|||||||
let mut reader = BytesReader::new(&bytes);
|
let mut reader = BytesReader::new(&bytes);
|
||||||
|
|
||||||
let mut root = TestRootStruct::default();
|
let mut root = TestRootStruct::default();
|
||||||
let res = root.read(&mut reader, None, None);
|
let res = root.read(&mut reader, None, KStructUnit::parent_stack());
|
||||||
assert!(res.is_ok());
|
assert!(res.is_ok());
|
||||||
|
|
||||||
assert_eq!([1], root.bytes);
|
assert_eq!([1], root.bytes);
|
||||||
|
Loading…
Reference in New Issue
Block a user