mirror of
				https://github.com/bspeice/kaitai_rust
				synced 2025-10-31 17:40:32 -04:00 
			
		
		
		
	Split into read and stream lifetimes
				
					
				
			Much easier to read, and compiles all the examples we need.
This commit is contained in:
		
							
								
								
									
										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 trait KStruct<'a>: Default { | ||||
|     type Parent: KStruct<'a>; | ||||
|     type Root: KStruct<'a>; | ||||
| pub trait KStruct<'r, 's: 'r>: Default { | ||||
|     type Root: KStruct<'r, 's>; | ||||
|     type ParentStack; | ||||
|  | ||||
|     /// Parse this struct (and any children) from the supplied stream | ||||
|     fn read<'s: 'a, S: KStream>( | ||||
|     fn read<S: KStream>( | ||||
|         &mut self, | ||||
|         _io: &'s S, | ||||
|         _root: Option<&Self::Root>, | ||||
|         _parent: Option<&Self::Parent>, | ||||
|         _root: Option<&'r Self::Root>, | ||||
|         _parent: TypedStack<Self::ParentStack>, | ||||
|     ) -> KResult<'s, ()>; | ||||
| } | ||||
|  | ||||
| @ -38,20 +38,55 @@ pub trait KStruct<'a>: Default { | ||||
| /// `KStruct` trait. | ||||
| #[derive(Debug, Default, Copy, Clone, PartialEq)] | ||||
| pub struct KStructUnit; | ||||
| impl<'a> KStruct<'a> for KStructUnit { | ||||
|     type Parent = KStructUnit; | ||||
| impl KStructUnit { | ||||
|     pub fn parent_stack() -> TypedStack<(KStructUnit)> { | ||||
|         TypedStack { current: (KStructUnit) } | ||||
|     } | ||||
| } | ||||
| impl<'r, 's: 'r> KStruct<'r, 's> for KStructUnit { | ||||
|     type Root = KStructUnit; | ||||
|     type ParentStack = (KStructUnit); | ||||
|  | ||||
|     fn read<'s: 'a, S: KStream>( | ||||
|     fn read<S: KStream>( | ||||
|         &mut self, | ||||
|         _io: &'s S, | ||||
|         _root: Option<&Self::Root>, | ||||
|         _parent: Option<&Self::Parent>, | ||||
|         _root: Option<&'r Self::Root>, | ||||
|         _parent: TypedStack<Self::ParentStack>, | ||||
|     ) -> KResult<'s, ()> { | ||||
|         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 { | ||||
|     fn is_eof(&self) -> KResult<bool>; | ||||
|     fn seek(&self, position: u64) -> KResult<()>; | ||||
| @ -276,25 +311,41 @@ impl<'a> KStream for BytesReader<'a> { | ||||
| } | ||||
|  | ||||
| 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> { | ||||
|             if second.is_nan() { first } | ||||
|             else if first.is_none() { Some(second) } | ||||
|             else { if first.unwrap() < second { Some(second) } else { first } } | ||||
|             if second.is_nan() { | ||||
|                 first | ||||
|             } else if first.is_none() { | ||||
|                 Some(second) | ||||
|             } else { | ||||
|                 if first.unwrap() < second { | ||||
|                     Some(second) | ||||
|                 } else { | ||||
|                     first | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     ) | ||||
|     }; | ||||
| } | ||||
| kf_max!(kf32_max, f32); | ||||
| kf_max!(kf64_max, f64); | ||||
|  | ||||
| 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> { | ||||
|             if second.is_nan() { first } | ||||
|             else if first.is_none() { Some(second) } | ||||
|             else { if first.unwrap() < second { first } else { Some(second) } } | ||||
|             if second.is_nan() { | ||||
|                 first | ||||
|             } else if first.is_none() { | ||||
|                 Some(second) | ||||
|             } else { | ||||
|                 if first.unwrap() < second { | ||||
|                     first | ||||
|                 } else { | ||||
|                     Some(second) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     ) | ||||
|     }; | ||||
| } | ||||
| kf_min!(kf32_min, f32); | ||||
| 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 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 | ||||
| //! 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)] | ||||
| struct TestRootStruct<'a> { | ||||
|     pub bytes: &'a [u8], | ||||
|     pub child: Option<TestChildStruct<'a>>, | ||||
| struct TestRootStruct<'s> { | ||||
|     pub bytes: &'s [u8], | ||||
|     pub child: Option<TestChildStruct<'s>>, | ||||
| } | ||||
| #[derive(Debug, PartialEq, Clone, Default)] | ||||
| struct TestChildStruct<'a> { | ||||
|     pub bytes: &'a [u8], | ||||
|     pub root_bytes: &'a [u8], | ||||
| struct TestChildStruct<'s> { | ||||
|     pub bytes: &'s [u8], | ||||
|     pub root_bytes: &'s [u8], | ||||
| } | ||||
|  | ||||
| impl<'a> KStruct<'a> for TestRootStruct<'a> { | ||||
|     type Parent = KStructUnit; | ||||
|     type Root = TestRootStruct<'a>; | ||||
| impl<'r, 's: 'r> KStruct<'r, 's> for TestRootStruct<'s> { | ||||
|     type Root = Self; | ||||
|     type ParentStack = (KStructUnit); | ||||
|  | ||||
|     fn read<'s: 'a, S: KStream>( | ||||
|     fn read<S: KStream>( | ||||
|         &mut self, | ||||
|         _io: &'s S, | ||||
|         _root: Option<&Self::Root>, | ||||
|         _parent: Option<&Self::Parent>, | ||||
|         _root: Option<&'r Self::Root>, | ||||
|         _parent: TypedStack<Self::ParentStack>, | ||||
|     ) -> KResult<'s, ()> { | ||||
|         self.bytes = _io.read_bytes(1)?; | ||||
|  | ||||
|         // TODO: `new` method in KStruct? | ||||
|         let mut child = TestChildStruct::default(); | ||||
|         // Implementation note: because callers of `read` can't call us as | ||||
|         // `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))?; | ||||
|         child.read(_io, Some(self), _parent.push(self))?; | ||||
|         self.child = Some(child); | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl<'a> KStruct<'a> for TestChildStruct<'a> { | ||||
|     type Parent = TestRootStruct<'a>; | ||||
|     type Root = TestRootStruct<'a>; | ||||
| impl<'r, 's: 'r> KStruct<'r, 's> for TestChildStruct<'s> { | ||||
|     type Root = <TestRootStruct<'s> as KStruct<'r, 's>>::Root; | ||||
|     type ParentStack = (&'r TestRootStruct<'s>, <TestRootStruct<'s> as KStruct<'r, 's>>::ParentStack); | ||||
|  | ||||
|     fn read<'s: 'a, S: KStream>( | ||||
|     fn read<S: KStream>( | ||||
|         &mut self, | ||||
|         _io: &'s S, | ||||
|         _root: Option<&Self::Root>, | ||||
|         _parent: Option<&Self::Parent>, | ||||
|         _root: Option<&'r Self::Root>, | ||||
|         _parent: TypedStack<Self::ParentStack>, | ||||
|     ) -> KResult<'s, ()> { | ||||
|         self.bytes = _io.read_bytes(1).unwrap(); | ||||
|         _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 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_eq!([1], root.bytes); | ||||
|  | ||||
		Reference in New Issue
	
	Block a user