diff --git a/examples/decode_torrent.rs b/examples/decode_torrent.rs index 3960a89..d0712ff 100644 --- a/examples/decode_torrent.rs +++ b/examples/decode_torrent.rs @@ -15,7 +15,7 @@ //! ``` use bendy::{ - decoding::{Error, FromBencode, Object, ResultExt}, + decoding::{Error, FromBencode, ResultExt, StrictObject}, encoding::AsString, }; @@ -80,7 +80,7 @@ impl FromBencode for MetaInfo { /// non-optional and optional fields. Missing optional fields are ignored /// but any other missing fields result in stopping the decoding and in /// spawning [`DecodingError::MissingField`]. - fn decode_bencode_object(object: Object) -> Result + fn decode_bencode_object(object: StrictObject) -> Result where Self: Sized, { @@ -146,7 +146,7 @@ impl FromBencode for Info { /// On success the dictionary is parsed for the fields of info which are /// necessary for torrent. Any missing field will result in a missing field /// error which will stop the decoding. - fn decode_bencode_object(object: Object) -> Result + fn decode_bencode_object(object: StrictObject) -> Result where Self: Sized, { diff --git a/rustfmt.toml b/rustfmt.toml index 6b97a3a..9a7a31e 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,6 +1,6 @@ unstable_features = true -required_version = "1.4.11" +required_version = "1.4.21" edition = "2018" format_code_in_doc_comments = true diff --git a/src/decoding.rs b/src/decoding.rs index d2f151a..b8e12d2 100644 --- a/src/decoding.rs +++ b/src/decoding.rs @@ -4,7 +4,7 @@ //! For any decoding process, first we need to create a decoder: //! //! ``` -//! # use bendy::decoding::{Decoder}; +//! # use bendy::decoding::StrictDecoder as Decoder; //! # //! # let buf: &[u8] = b"d3:fooi1ee"; //! let _decoder = Decoder::new(buf); @@ -16,7 +16,7 @@ //! attacker can cause your program to use, so we recommend setting the bounds tightly: //! //! ``` -//! # use bendy::decoding::{Decoder}; +//! # use bendy::decoding::StrictDecoder as Decoder; //! # //! # let buf: &[u8] = b"d3:fooi1ee"; //! let _decoder = Decoder::new(buf).with_max_depth(3); @@ -28,10 +28,10 @@ //! Now, you can start reading objects: //! //! ``` -//! # use bendy::decoding::{Decoder,Object}; +//! # use bendy::decoding::{StrictDecoder as Decoder, StrictObject as Object}; //! # -//! # fn decode_list(_: bendy::decoding::ListDecoder) {} -//! # fn decode_dict(_: bendy::decoding::DictDecoder) {} +//! # fn decode_list(_: bendy::decoding::StrictListDecoder) {} +//! # fn decode_dict(_: bendy::decoding::StrictDictDecoder) {} //! # //! # let buf: &[u8] = b"d3:fooi1ee"; //! # let mut decoder = Decoder::new(buf); @@ -52,7 +52,7 @@ //! of an input object without fully decoding it: //! //! ``` -//! # use bendy::decoding::Decoder; +//! # use bendy::decoding::StrictDecoder as Decoder; //! # //! fn syntax_check(buf: &[u8]) -> bool { //! let mut decoder = Decoder::new(buf); @@ -69,8 +69,11 @@ mod from_bencode; mod object; pub use self::{ - decoder::{Decoder, DictDecoder, ListDecoder, Tokens}, + decoder::{ + Decoder, DictDecoder, ListDecoder, StrictDecoder, StrictDictDecoder, StrictListDecoder, + Tokens, + }, error::{Error, ErrorKind, ResultExt}, from_bencode::FromBencode, - object::Object, + object::{Object, StrictObject}, }; diff --git a/src/decoding/decoder.rs b/src/decoding/decoder.rs index db4230d..2f8d388 100644 --- a/src/decoding/decoder.rs +++ b/src/decoding/decoder.rs @@ -3,27 +3,38 @@ use core::str; use crate::{ decoding::{Error, Object}, - state_tracker::{StateTracker, StructureError, Token}, + state_tracker::{StateTracker, StrictTracker, StructureError, Token}, + StrictByteTracker, }; +pub type StrictDecoder<'ser> = Decoder<'ser, StrictByteTracker<'ser>>; +pub type StrictListDecoder<'obj, 'ser> = ListDecoder<'obj, 'ser, StrictByteTracker<'ser>>; +pub type StrictDictDecoder<'obj, 'ser> = DictDecoder<'obj, 'ser, StrictByteTracker<'ser>>; + /// A bencode decoder /// /// This can be used to either get a stream of tokens (using the [`Decoder::tokens()`] method) or to /// read a complete object at a time (using the [`Decoder::next_object()`]) method. #[derive(Debug)] -pub struct Decoder<'a> { - source: &'a [u8], +pub struct Decoder<'ser, StateTrackerT = StrictTracker<&'ser [u8], Error>> +where + StateTrackerT: StateTracker<&'ser [u8], Error>, +{ + source: &'ser [u8], offset: usize, - state: StateTracker<&'a [u8], Error>, + state: StateTrackerT, } -impl<'ser> Decoder<'ser> { +impl<'ser, StateTrackerT> Decoder<'ser, StateTrackerT> +where + StateTrackerT: StateTracker<&'ser [u8], Error>, +{ /// Create a new decoder from the given byte array pub fn new(buffer: &'ser [u8]) -> Self { Decoder { source: buffer, offset: 0, - state: StateTracker::new(), + state: StateTrackerT::new(), } } @@ -181,16 +192,21 @@ impl<'ser> Decoder<'ser> { /// Iterate over the tokens in the input stream. This guarantees that the resulting stream /// of tokens constitutes a valid bencoded structure. - pub fn tokens(self) -> Tokens<'ser> { + pub fn tokens(self) -> Tokens<'ser, StateTrackerT> { Tokens(self) } } /// Iterator over the tokens in the input stream. This guarantees that the resulting stream /// of tokens constitutes a valid bencoded structure. -pub struct Tokens<'a>(Decoder<'a>); - -impl<'a> Iterator for Tokens<'a> { +pub struct Tokens<'a, StateTrackerT>(Decoder<'a, StateTrackerT>) +where + StateTrackerT: StateTracker<&'a [u8], Error>; + +impl<'a, StateTrackerT> Iterator for Tokens<'a, StateTrackerT> +where + StateTrackerT: StateTracker<&'a [u8], Error>, +{ type Item = Result, Error>; fn next(&mut self) -> Option { @@ -208,7 +224,10 @@ impl<'a> Iterator for Tokens<'a> { // High level interface -impl<'ser> Decoder<'ser> { +impl<'ser, StateTrackerT> Decoder<'ser, StateTrackerT> +where + StateTrackerT: StateTracker<&'ser [u8], Error>, +{ /// Read the next object from the encoded stream /// /// If the beginning of an object was successfully read, returns `Ok(Some(object))`. @@ -218,7 +237,9 @@ impl<'ser> Decoder<'ser> { /// Note that complex objects (lists and dicts) are not fully validated before being /// returned from this method, so you may still get an error while decoding the contents /// of the object - pub fn next_object<'obj>(&'obj mut self) -> Result>, Error> { + pub fn next_object<'obj>( + &'obj mut self, + ) -> Result>, Error> { use self::Token::*; Ok(match self.next_token()? { None | Some(End) => None, @@ -232,22 +253,31 @@ impl<'ser> Decoder<'ser> { /// A dictionary read from the input stream #[derive(Debug)] -pub struct DictDecoder<'obj, 'ser: 'obj> { - decoder: &'obj mut Decoder<'ser>, +pub struct DictDecoder<'obj, 'ser: 'obj, StateTrackerT> +where + StateTrackerT: StateTracker<&'ser [u8], Error>, +{ + decoder: &'obj mut Decoder<'ser, StateTrackerT>, finished: bool, start_point: usize, } /// A list read from the input stream #[derive(Debug)] -pub struct ListDecoder<'obj, 'ser: 'obj> { - decoder: &'obj mut Decoder<'ser>, +pub struct ListDecoder<'obj, 'ser: 'obj, StateTrackerT> +where + StateTrackerT: StateTracker<&'ser [u8], Error>, +{ + decoder: &'obj mut Decoder<'ser, StateTrackerT>, finished: bool, start_point: usize, } -impl<'obj, 'ser: 'obj> DictDecoder<'obj, 'ser> { - fn new(decoder: &'obj mut Decoder<'ser>) -> Self { +impl<'obj, 'ser: 'obj, StateTrackerT> DictDecoder<'obj, 'ser, StateTrackerT> +where + StateTrackerT: StateTracker<&'ser [u8], Error>, +{ + fn new(decoder: &'obj mut Decoder<'ser, StateTrackerT>) -> Self { let offset = decoder.offset - 1; DictDecoder { decoder, @@ -260,7 +290,7 @@ impl<'obj, 'ser: 'obj> DictDecoder<'obj, 'ser> { /// at the end of the dictionary pub fn next_pair<'item>( &'item mut self, - ) -> Result)>, Error> { + ) -> Result)>, Error> { if self.finished { return Ok(None); } @@ -297,15 +327,21 @@ impl<'obj, 'ser: 'obj> DictDecoder<'obj, 'ser> { } } -impl<'obj, 'ser: 'obj> Drop for DictDecoder<'obj, 'ser> { +impl<'obj, 'ser: 'obj, StateTrackerT> Drop for DictDecoder<'obj, 'ser, StateTrackerT> +where + StateTrackerT: StateTracker<&'ser [u8], Error>, +{ fn drop(&mut self) { // we don't care about errors in drop; they'll be reported again in the parent self.consume_all().ok(); } } -impl<'obj, 'ser: 'obj> ListDecoder<'obj, 'ser> { - fn new(decoder: &'obj mut Decoder<'ser>) -> Self { +impl<'obj, 'ser: 'obj, StateTrackerT> ListDecoder<'obj, 'ser, StateTrackerT> +where + StateTrackerT: StateTracker<&'ser [u8], Error>, +{ + fn new(decoder: &'obj mut Decoder<'ser, StateTrackerT>) -> Self { let offset = decoder.offset - 1; ListDecoder { decoder, @@ -315,7 +351,9 @@ impl<'obj, 'ser: 'obj> ListDecoder<'obj, 'ser> { } /// Get the next item from the list. Returns `Ok(None)` at the end of the list - pub fn next_object<'item>(&'item mut self) -> Result>, Error> { + pub fn next_object<'item>( + &'item mut self, + ) -> Result>, Error> { if self.finished { return Ok(None); } @@ -347,7 +385,10 @@ impl<'obj, 'ser: 'obj> ListDecoder<'obj, 'ser> { } } -impl<'obj, 'ser: 'obj> Drop for ListDecoder<'obj, 'ser> { +impl<'obj, 'ser: 'obj, StateTrackerT> Drop for ListDecoder<'obj, 'ser, StateTrackerT> +where + StateTrackerT: StateTracker<&'ser [u8], Error>, +{ fn drop(&mut self) { // we don't care about errors in drop; they'll be reported again in the parent self.consume_all().ok(); @@ -361,14 +402,15 @@ mod test { use alloc::{vec, vec::Vec}; use core::iter; - use regex; - use super::*; + use crate::decoding::object::StrictObject as Object; + + use regex; static SIMPLE_MSG: &'static [u8] = b"d3:bari1e3:fooli2ei3eee"; fn decode_tokens(msg: &[u8]) -> Vec { - let tokens: Vec> = Decoder::new(msg).tokens().collect(); + let tokens: Vec> = StrictDecoder::new(msg).tokens().collect(); if tokens.iter().all(Result::is_ok) { tokens.into_iter().map(Result::unwrap).collect() } else { @@ -380,7 +422,7 @@ mod test { } fn decode_err(msg: &[u8], err_regex: &str) { - let mut tokens: Vec> = Decoder::new(msg).tokens().collect(); + let mut tokens: Vec> = StrictDecoder::new(msg).tokens().collect(); if tokens.iter().all(Result::is_ok) { panic!("Unexpected parse success: {:?}", tokens); } else { @@ -486,13 +528,13 @@ mod test { #[test] fn recursion_bounds_should_be_tight() { let test_msg = b"lllleeee"; - assert!(Decoder::new(test_msg) + assert!(StrictDecoder::new(test_msg) .with_max_depth(4) .tokens() .last() .unwrap() .is_ok()); - assert!(Decoder::new(test_msg) + assert!(StrictDecoder::new(test_msg) .with_max_depth(3) .tokens() .last() @@ -502,7 +544,7 @@ mod test { #[test] fn dict_drop_should_consume_struct() { - let mut decoder = Decoder::new(b"d3:fooi1e3:quxi2eei1000e"); + let mut decoder = StrictDecoder::new(b"d3:fooi1e3:quxi2eei1000e"); drop(decoder.next_object()); let token = decoder.tokens().next().unwrap().unwrap(); @@ -511,7 +553,7 @@ mod test { #[test] fn list_drop_should_consume_struct() { - let mut decoder = Decoder::new(b"li1ei2ei3eei1000e"); + let mut decoder = StrictDecoder::new(b"li1ei2ei3eei1000e"); drop(decoder.next_object()); let token = decoder.tokens().next().unwrap().unwrap(); @@ -533,7 +575,7 @@ mod test { Object::Integer("123").bytes_or(Err("failure")) ); - let mut list_decoder = Decoder::new(b"le"); + let mut list_decoder = StrictDecoder::new(b"le"); assert_eq!( Err("failure"), list_decoder @@ -542,7 +584,7 @@ mod test { .unwrap() .bytes_or(Err("failure")) ); - let mut dict_decoder = Decoder::new(b"de"); + let mut dict_decoder = StrictDecoder::new(b"de"); assert_eq!( Err("failure"), dict_decoder @@ -567,7 +609,7 @@ mod test { Err("failure"), Object::Integer("123").bytes_or_else(|_| Err("failure")) ); - let mut list_decoder = Decoder::new(b"le"); + let mut list_decoder = StrictDecoder::new(b"le"); assert_eq!( Err("failure"), list_decoder @@ -576,7 +618,7 @@ mod test { .unwrap() .bytes_or_else(|_| Err("failure")) ); - let mut dict_decoder = Decoder::new(b"de"); + let mut dict_decoder = StrictDecoder::new(b"de"); assert_eq!( Err("failure"), dict_decoder @@ -601,7 +643,7 @@ mod test { Err("failure"), Object::Bytes(b"foo").integer_or(Err("failure")) ); - let mut list_decoder = Decoder::new(b"le"); + let mut list_decoder = StrictDecoder::new(b"le"); assert_eq!( Err("failure"), list_decoder @@ -610,7 +652,7 @@ mod test { .unwrap() .integer_or(Err("failure")) ); - let mut dict_decoder = Decoder::new(b"de"); + let mut dict_decoder = StrictDecoder::new(b"de"); assert_eq!( Err("failure"), dict_decoder @@ -635,7 +677,7 @@ mod test { Err("failure"), Object::Bytes(b"foo").integer_or_else(|_| Err("failure")) ); - let mut list_decoder = Decoder::new(b"le"); + let mut list_decoder = StrictDecoder::new(b"le"); assert_eq!( Err("failure"), list_decoder @@ -644,7 +686,7 @@ mod test { .unwrap() .integer_or_else(|_| Err("failure")) ); - let mut dict_decoder = Decoder::new(b"de"); + let mut dict_decoder = StrictDecoder::new(b"de"); assert_eq!( Err("failure"), dict_decoder @@ -657,7 +699,7 @@ mod test { #[test] fn list_or_should_work_on_list() { - let mut list_decoder = Decoder::new(b"le"); + let mut list_decoder = StrictDecoder::new(b"le"); assert!(list_decoder .next_object() .unwrap() @@ -676,7 +718,7 @@ mod test { Object::Integer("foo").list_or(Err("failure")).unwrap_err() ); - let mut dict_decoder = Decoder::new(b"de"); + let mut dict_decoder = StrictDecoder::new(b"de"); assert_eq!( "failure", dict_decoder @@ -690,7 +732,7 @@ mod test { #[test] fn list_or_else_should_work_on_list() { - let mut list_decoder = Decoder::new(b"le"); + let mut list_decoder = StrictDecoder::new(b"le"); assert!(list_decoder .next_object() .unwrap() @@ -713,7 +755,7 @@ mod test { .unwrap_err() ); - let mut dict_decoder = Decoder::new(b"de"); + let mut dict_decoder = StrictDecoder::new(b"de"); assert_eq!( "failure", dict_decoder @@ -727,7 +769,7 @@ mod test { #[test] fn dictionary_or_should_work_on_dict() { - let mut dict_decoder = Decoder::new(b"de"); + let mut dict_decoder = StrictDecoder::new(b"de"); assert!(dict_decoder .next_object() .unwrap() @@ -751,7 +793,7 @@ mod test { .unwrap_err() ); - let mut list_decoder = Decoder::new(b"le"); + let mut list_decoder = StrictDecoder::new(b"le"); assert_eq!( "failure", list_decoder @@ -765,7 +807,7 @@ mod test { #[test] fn dictionary_or_else_should_work_on_dict() { - let mut dict_decoder = Decoder::new(b"de"); + let mut dict_decoder = StrictDecoder::new(b"de"); assert!(dict_decoder .next_object() .unwrap() @@ -789,7 +831,7 @@ mod test { .unwrap_err() ); - let mut list_decoder = Decoder::new(b"le"); + let mut list_decoder = StrictDecoder::new(b"le"); assert_eq!( "failure", list_decoder diff --git a/src/decoding/from_bencode.rs b/src/decoding/from_bencode.rs index 4a803a3..f3e2f77 100644 --- a/src/decoding/from_bencode.rs +++ b/src/decoding/from_bencode.rs @@ -9,13 +9,14 @@ use std::{ }; use crate::{ - decoding::{Decoder, Error, Object}, + decoding::{Decoder, Error, Object, StrictObject}, encoding::AsString, state_tracker::StructureError, + StrictByteTracker, }; ///Basic trait for bencode based value deserialization. -pub trait FromBencode { +pub trait FromBencode> { /// Maximum allowed depth of nested structures before the decoding should be aborted. const EXPECTED_RECURSION_DEPTH: usize = 2048; @@ -34,7 +35,7 @@ pub trait FromBencode { } /// Deserialize an object from its intermediate bencode representation. - fn decode_bencode_object(object: Object) -> Result + fn decode_bencode_object(object: StrictObject) -> Result where Self: Sized; } @@ -44,7 +45,7 @@ macro_rules! impl_from_bencode_for_integer { impl FromBencode for $type { const EXPECTED_RECURSION_DEPTH: usize = 0; - fn decode_bencode_object(object: Object) -> Result + fn decode_bencode_object(object: StrictObject) -> Result where Self: Sized, { @@ -59,10 +60,13 @@ macro_rules! impl_from_bencode_for_integer { impl_from_bencode_for_integer!(u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize); -impl FromBencode for Vec { +impl FromBencode for Vec +where + ContentT: FromBencode, +{ const EXPECTED_RECURSION_DEPTH: usize = ContentT::EXPECTED_RECURSION_DEPTH + 1; - fn decode_bencode_object(object: Object) -> Result + fn decode_bencode_object(object: StrictObject) -> Result where Self: Sized, { @@ -81,7 +85,7 @@ impl FromBencode for Vec { impl FromBencode for String { const EXPECTED_RECURSION_DEPTH: usize = 0; - fn decode_bencode_object(object: Object) -> Result + fn decode_bencode_object(object: StrictObject) -> Result where Self: Sized, { @@ -99,7 +103,7 @@ where { const EXPECTED_RECURSION_DEPTH: usize = V::EXPECTED_RECURSION_DEPTH + 1; - fn decode_bencode_object(object: Object) -> Result + fn decode_bencode_object(object: StrictObject) -> Result where Self: Sized, { @@ -126,7 +130,7 @@ where { const EXPECTED_RECURSION_DEPTH: usize = V::EXPECTED_RECURSION_DEPTH + 1; - fn decode_bencode_object(object: Object) -> Result + fn decode_bencode_object(object: StrictObject) -> Result where Self: Sized, { @@ -147,7 +151,7 @@ where impl FromBencode for Rc { const EXPECTED_RECURSION_DEPTH: usize = T::EXPECTED_RECURSION_DEPTH; - fn decode_bencode_object(object: Object) -> Result + fn decode_bencode_object(object: StrictObject) -> Result where Self: Sized, { @@ -158,7 +162,7 @@ impl FromBencode for Rc { impl FromBencode for AsString> { const EXPECTED_RECURSION_DEPTH: usize = 0; - fn decode_bencode_object(object: Object) -> Result + fn decode_bencode_object(object: StrictObject) -> Result where Self: Sized, { diff --git a/src/decoding/object.rs b/src/decoding/object.rs index c2a43a9..45ae3f1 100644 --- a/src/decoding/object.rs +++ b/src/decoding/object.rs @@ -1,21 +1,29 @@ use crate::{ decoding::{DictDecoder, Error, ListDecoder}, - state_tracker::Token, + state_tracker::{StateTracker, StrictTracker, Token}, }; +pub type StrictObject<'obj, 'ser> = Object<'obj, 'ser, StrictTracker<&'ser [u8], Error>>; + /// An object read from a decoder -pub enum Object<'obj, 'ser: 'obj> { +pub enum Object<'obj, 'ser: 'obj, StateTrackerT> +where + StateTrackerT: StateTracker<&'ser [u8], Error>, +{ /// A list of arbitrary objects - List(ListDecoder<'obj, 'ser>), + List(ListDecoder<'obj, 'ser, StateTrackerT>), /// A map of string-valued keys to arbitrary objects - Dict(DictDecoder<'obj, 'ser>), + Dict(DictDecoder<'obj, 'ser, StateTrackerT>), /// An unparsed integer Integer(&'ser str), /// A byte string Bytes(&'ser [u8]), } -impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { +impl<'obj, 'ser: 'obj, StateTrackerT> Object<'obj, 'ser, StateTrackerT> +where + StateTrackerT: StateTracker<&'ser [u8], Error>, +{ pub fn into_token(self) -> Token<'ser> { match self { Object::List(_) => Token::List, @@ -39,7 +47,7 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// # Examples /// /// ``` - /// use bendy::decoding::Object; + /// use bendy::decoding::StrictObject as Object; /// /// let x = Object::Bytes(b"foo"); /// assert_eq!(Ok(&b"foo"[..]), x.bytes_or(Err("failure"))); @@ -66,7 +74,7 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// # Examples /// /// ``` - /// use bendy::decoding::Object; + /// use bendy::decoding::StrictObject as Object; /// /// let x = Object::Bytes(b"foo"); /// assert_eq!( @@ -100,7 +108,7 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// # Examples /// /// ``` - /// use bendy::decoding::Object; + /// use bendy::decoding::StrictObject as Object; /// /// let x = Object::Bytes(b"foo"); /// assert_eq!(b"foo", x.try_into_bytes().unwrap()); @@ -127,7 +135,7 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// # Examples /// /// ``` - /// use bendy::decoding::Object; + /// use bendy::decoding::StrictObject as Object; /// /// let x = Object::Integer("123"); /// assert_eq!(Ok(&"123"[..]), x.integer_or(Err("failure"))); @@ -155,7 +163,7 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// # Examples /// /// ``` - /// use bendy::decoding::Object; + /// use bendy::decoding::StrictObject as Object; /// /// let x = Object::Integer("123"); /// assert_eq!( @@ -190,7 +198,7 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// # Examples /// /// ``` - /// use bendy::decoding::Object; + /// use bendy::decoding::StrictObject as Object; /// /// let x = Object::Integer("123"); /// assert_eq!("123", x.try_into_integer().unwrap()); @@ -217,7 +225,7 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// # Examples /// /// ``` - /// use bendy::decoding::{Decoder, Object}; + /// use bendy::decoding::{StrictDecoder as Decoder, StrictObject as Object}; /// /// let mut list_decoder = Decoder::new(b"le"); /// let x = list_decoder.next_object().unwrap().unwrap(); @@ -229,8 +237,8 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// ``` pub fn list_or( self, - default: Result, ErrorT>, - ) -> Result, ErrorT> { + default: Result, ErrorT>, + ) -> Result, ErrorT> { match self { Object::List(content) => Ok(content), _ => default, @@ -247,7 +255,7 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// # Examples /// /// ``` - /// use bendy::decoding::{Decoder, Object}; + /// use bendy::decoding::{StrictDecoder as Decoder, StrictObject as Object}; /// /// let mut list_decoder = Decoder::new(b"le"); /// let x = list_decoder.next_object().unwrap().unwrap(); @@ -263,8 +271,8 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// ``` pub fn list_or_else( self, - op: impl FnOnce(Self) -> Result, ErrorT>, - ) -> Result, ErrorT> { + op: impl FnOnce(Self) -> Result, ErrorT>, + ) -> Result, ErrorT> { match self { Object::List(content) => Ok(content), _ => op(self), @@ -282,7 +290,7 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// # Examples /// /// ``` - /// use bendy::decoding::{Decoder, Object}; + /// use bendy::decoding::{StrictDecoder as Decoder, StrictObject as Object}; /// /// let mut list_decoder = Decoder::new(b"le"); /// let x = list_decoder.next_object().unwrap().unwrap(); @@ -292,7 +300,7 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// let x = Object::Bytes(b"foo"); /// assert!(x.try_into_list().is_err()); /// ``` - pub fn try_into_list(self) -> Result, Error> { + pub fn try_into_list(self) -> Result, Error> { self.list_or_else(|obj| Err(Error::unexpected_token("List", obj.into_token().name()))) } @@ -311,7 +319,7 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// # Examples /// /// ``` - /// use bendy::decoding::{Decoder, Object}; + /// use bendy::decoding::{StrictDecoder as Decoder, StrictObject as Object}; /// /// let mut dict_decoder = Decoder::new(b"de"); /// let x = dict_decoder.next_object().unwrap().unwrap(); @@ -323,8 +331,8 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// ``` pub fn dictionary_or( self, - default: Result, ErrorT>, - ) -> Result, ErrorT> { + default: Result, ErrorT>, + ) -> Result, ErrorT> { match self { Object::Dict(content) => Ok(content), _ => default, @@ -341,7 +349,7 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// # Examples /// /// ``` - /// use bendy::decoding::{Decoder, Object}; + /// use bendy::decoding::{StrictDecoder as Decoder, StrictObject as Object}; /// /// let mut dict_decoder = Decoder::new(b"de"); /// let x = dict_decoder.next_object().unwrap().unwrap(); @@ -359,8 +367,8 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// ``` pub fn dictionary_or_else( self, - op: impl FnOnce(Self) -> Result, ErrorT>, - ) -> Result, ErrorT> { + op: impl FnOnce(Self) -> Result, ErrorT>, + ) -> Result, ErrorT> { match self { Object::Dict(content) => Ok(content), _ => op(self), @@ -378,7 +386,7 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// # Examples /// /// ``` - /// use bendy::decoding::{Decoder, Object}; + /// use bendy::decoding::{StrictDecoder as Decoder, StrictObject as Object}; /// /// let mut dict_decoder = Decoder::new(b"de"); /// let x = dict_decoder.next_object().unwrap().unwrap(); @@ -388,7 +396,7 @@ impl<'obj, 'ser: 'obj> Object<'obj, 'ser> { /// let x = Object::Bytes(b"foo"); /// assert!(x.try_into_dictionary().is_err()); /// ``` - pub fn try_into_dictionary(self) -> Result, Error> { + pub fn try_into_dictionary(self) -> Result, Error> { self.dictionary_or_else(|obj| Err(Error::unexpected_token("Dict", obj.into_token().name()))) } } diff --git a/src/encoding/encoder.rs b/src/encoding/encoder.rs index ba4a164..2dd83e5 100644 --- a/src/encoding/encoder.rs +++ b/src/encoding/encoder.rs @@ -11,14 +11,14 @@ use std::{collections::BTreeMap, vec::Vec}; use crate::{ encoding::{Error, PrintableInteger, ToBencode}, - state_tracker::{StateTracker, StructureError, Token}, + state_tracker::{StateTracker, StrictTracker, StructureError, Token}, }; /// The actual encoder. Unlike the decoder, this is not zero-copy, as that would /// result in a horrible interface #[derive(Default, Debug)] pub struct Encoder { - state: StateTracker, Error>, + state: StrictTracker, Error>, output: Vec, } diff --git a/src/lib.rs b/src/lib.rs index 58b35e5..2f4fe9c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,3 +21,11 @@ pub mod state_tracker; pub mod serde; pub mod value; + +//------------------------------------------------------------------------------ +// Helper +//------------------------------------------------------------------------------ + +use self::{decoding::Error, state_tracker::StrictTracker}; + +type StrictByteTracker<'ser> = StrictTracker<&'ser [u8], Error>; diff --git a/src/serde.rs b/src/serde.rs index ad34b00..1cf6be4 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -5,9 +5,9 @@ //! deserialized from bencode with `bendy::serde::from_bytes`: //! //! ``` -//! use bendy::serde::{to_bytes, from_bytes}; +//! use bendy::serde::{from_bytes, to_bytes}; //! use serde_ as serde; -//! use serde_derive::{Serialize, Deserialize}; +//! use serde_derive::{Deserialize, Serialize}; //! //! assert_eq!(to_bytes(&10).unwrap(), b"i10e"); //! assert_eq!(from_bytes::(b"i10e").unwrap(), 10); @@ -531,8 +531,8 @@ mod tests { #[test] fn borrowed_value() { - use std::borrow::Cow; use crate::value::Value; + use std::borrow::Cow; #[derive(Debug, Deserialize, PartialEq, Eq)] #[serde(crate = "serde_")] @@ -542,8 +542,12 @@ mod tests { } assert_eq!( - Deserializer::from_bytes(b"d1:v3:\x01\x02\x03e").deserialize::>().unwrap(), - Dict { v: Value::Bytes(Cow::Owned(vec![1, 2, 3]))}, + Deserializer::from_bytes(b"d1:v3:\x01\x02\x03e") + .deserialize::>() + .unwrap(), + Dict { + v: Value::Bytes(Cow::Owned(vec![1, 2, 3])) + }, ); } } diff --git a/src/state_tracker.rs b/src/state_tracker.rs index b56ee2d..904448d 100644 --- a/src/state_tracker.rs +++ b/src/state_tracker.rs @@ -3,5 +3,6 @@ mod state; mod structure_error; mod token; -pub use self::token::Token; -pub(crate) use self::{stack::Stack, state::StateTracker, structure_error::StructureError}; +pub use self::{state::StateTracker, token::Token}; + +pub(crate) use self::{stack::Stack, state::StrictTracker, structure_error::StructureError}; diff --git a/src/state_tracker/state.rs b/src/state_tracker/state.rs index 783fa1a..adc7e58 100644 --- a/src/state_tracker/state.rs +++ b/src/state_tracker/state.rs @@ -3,6 +3,34 @@ use alloc::vec::Vec; use crate::state_tracker::{Stack, StructureError, Token}; +//------------------------------------------------------------------------------ +// StateTracker +//------------------------------------------------------------------------------ + +/// Used to validate that a structure is valid +pub trait StateTracker { + fn new() -> Self; + + fn set_max_depth(&mut self, new_max_depth: usize); + + fn remaining_depth(&self) -> usize; + + /// Observe that an EOF was seen. This function is idempotent. + fn observe_eof(&mut self) -> Result<(), E>; + + fn observe_token<'a>(&mut self, token: &Token<'a>) -> Result<(), E> + where + S: From<&'a [u8]>; + + fn latch_err(&mut self, result: Result) -> Result; + + fn check_error(&self) -> Result<(), E>; +} + +//------------------------------------------------------------------------------ +// State +//------------------------------------------------------------------------------ + /// The state of current level of the decoder #[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Debug)] enum State, E> { @@ -16,41 +44,45 @@ enum State, E> { Failed(E), } +//------------------------------------------------------------------------------ +// StrictTracker +//------------------------------------------------------------------------------ + /// Used to validate that a structure is valid #[derive(Debug)] -pub struct StateTracker, E = StructureError> { +pub struct StrictTracker, E = StructureError> { state: Vec>, max_depth: usize, } -impl, E> Default for StateTracker { +impl, E> Default for StrictTracker { fn default() -> Self { - StateTracker { + StrictTracker { state: Vec::new(), max_depth: 2048, } } } -impl, E> StateTracker +impl StateTracker for StrictTracker where S: AsRef<[u8]>, E: From + Clone, { - pub fn new() -> Self { + fn new() -> Self { ::default() } - pub fn set_max_depth(&mut self, new_max_depth: usize) { + fn set_max_depth(&mut self, new_max_depth: usize) { self.max_depth = new_max_depth } - pub fn remaining_depth(&self) -> usize { + fn remaining_depth(&self) -> usize { self.max_depth - self.state.len() } /// Observe that an EOF was seen. This function is idempotent. - pub fn observe_eof(&mut self) -> Result<(), E> { + fn observe_eof(&mut self) -> Result<(), E> { self.check_error()?; if self.state.is_empty() { @@ -61,7 +93,7 @@ where } #[allow(clippy::match_same_arms)] - pub fn observe_token<'a>(&mut self, token: &Token<'a>) -> Result<(), E> + fn observe_token<'a>(&mut self, token: &Token<'a>) -> Result<(), E> where S: From<&'a [u8]>, { @@ -141,7 +173,7 @@ where Ok(()) } - pub fn latch_err(&mut self, result: Result) -> Result { + fn latch_err(&mut self, result: Result) -> Result { self.check_error()?; if let Err(ref err) = result { self.state.push(State::Failed(err.clone())) @@ -149,7 +181,7 @@ where result } - pub fn check_error(&self) -> Result<(), E> { + fn check_error(&self) -> Result<(), E> { if let Some(&State::Failed(ref error)) = self.state.peek() { Err(error.clone()) } else { diff --git a/src/value.rs b/src/value.rs index 1a7f86a..fdd5a5d 100644 --- a/src/value.rs +++ b/src/value.rs @@ -27,7 +27,7 @@ use serde::{ }; use crate::{ - decoding::{FromBencode, Object}, + decoding::{FromBencode, Object, StrictObject}, encoding::{SingleItemEncoder, ToBencode}, }; @@ -77,8 +77,8 @@ impl<'a> ToBencode for Value<'a> { impl<'a> FromBencode for Value<'a> { const EXPECTED_RECURSION_DEPTH: usize = ::MAX_DEPTH; - - fn decode_bencode_object(object: Object) -> Result { + + fn decode_bencode_object(object: StrictObject) -> Result { match object { Object::Bytes(bytes) => Ok(Value::Bytes(Cow::Owned(bytes.to_owned()))), Object::Dict(mut decoder) => { diff --git a/tests/core_test.rs b/tests/core_test.rs index 66fa9e5..2bd5c88 100644 --- a/tests/core_test.rs +++ b/tests/core_test.rs @@ -7,7 +7,7 @@ extern crate alloc; use alloc::collections::BTreeMap; use bendy::{ - decoding::{Error as DecodingError, FromBencode, Object}, + decoding::{Error as DecodingError, FromBencode, Object, StrictObject}, encoding::{Error as EncodingError, SingleItemEncoder, ToBencode}, }; @@ -371,7 +371,7 @@ where } impl FromBencode for Something { - fn decode_bencode_object(object: Object) -> Result + fn decode_bencode_object(object: StrictObject) -> Result where Self: Sized, { diff --git a/tests/readme.rs b/tests/readme.rs index 35b342f..d701330 100644 --- a/tests/readme.rs +++ b/tests/readme.rs @@ -174,7 +174,7 @@ mod decoding_1 { } mod decoding_2 { - use bendy::decoding::{Error, FromBencode, Object}; + use bendy::decoding::{Error, FromBencode, StrictObject}; #[derive(Debug, Eq, PartialEq)] struct IntegerWrapper(i64); @@ -182,7 +182,7 @@ mod decoding_2 { impl FromBencode for IntegerWrapper { const EXPECTED_RECURSION_DEPTH: usize = 0; - fn decode_bencode_object(object: Object) -> Result { + fn decode_bencode_object(object: StrictObject) -> Result { // This is an example for content handling. It would also be possible // to call `i64::decode_bencode_object(object)` directly. let content = object.try_into_integer()?; @@ -207,7 +207,7 @@ mod decoding_2 { } mod decoding_3 { - use bendy::decoding::{Error, FromBencode, Object}; + use bendy::decoding::{Error, FromBencode, StrictObject}; #[derive(Debug, Eq, PartialEq)] struct StringWrapper(String); @@ -215,7 +215,7 @@ mod decoding_3 { impl FromBencode for StringWrapper { const EXPECTED_RECURSION_DEPTH: usize = 0; - fn decode_bencode_object(object: Object) -> Result { + fn decode_bencode_object(object: StrictObject) -> Result { // This is an example for content handling. It would also be possible // to call `String::decode_bencode_object(object)` directly. let content = object.try_into_bytes()?; @@ -241,7 +241,7 @@ mod decoding_3 { mod decoding_4 { use bendy::{ - decoding::{Error, FromBencode, Object}, + decoding::{Error, FromBencode, StrictObject}, encoding::AsString, }; @@ -251,7 +251,7 @@ mod decoding_4 { impl FromBencode for ByteStringWrapper { const EXPECTED_RECURSION_DEPTH: usize = 0; - fn decode_bencode_object(object: Object) -> Result { + fn decode_bencode_object(object: StrictObject) -> Result { let content = AsString::decode_bencode_object(object)?; Ok(ByteStringWrapper(content.0)) } @@ -272,7 +272,7 @@ mod decoding_4 { } mod decoding_5 { - use bendy::decoding::{Error, FromBencode, Object, ResultExt}; + use bendy::decoding::{Error, FromBencode, ResultExt, StrictObject}; #[derive(Debug, Eq, PartialEq)] struct Example { @@ -283,7 +283,7 @@ mod decoding_5 { impl FromBencode for Example { const EXPECTED_RECURSION_DEPTH: usize = 1; - fn decode_bencode_object(object: Object) -> Result { + fn decode_bencode_object(object: StrictObject) -> Result { let mut counter = None; let mut label = None; @@ -331,7 +331,7 @@ mod decoding_5 { } mod decoding_6 { - use bendy::decoding::{Error, FromBencode, Object}; + use bendy::decoding::{Error, FromBencode, StrictObject}; #[derive(Debug, PartialEq, Eq)] struct Location(i64, i64); @@ -339,7 +339,7 @@ mod decoding_6 { impl FromBencode for Location { const EXPECTED_RECURSION_DEPTH: usize = 1; - fn decode_bencode_object(object: Object) -> Result { + fn decode_bencode_object(object: StrictObject) -> Result { let mut list = object.try_into_list()?; let x = list.next_object()?.ok_or(Error::missing_field("x"))?; diff --git a/tests/struct_codec.rs b/tests/struct_codec.rs index 2769545..e36fc45 100644 --- a/tests/struct_codec.rs +++ b/tests/struct_codec.rs @@ -1,5 +1,5 @@ use bendy::{ - decoding::{Error as DecodingError, FromBencode, Object}, + decoding::{Error as DecodingError, FromBencode, StrictObject}, encoding::{Error as EncodingError, SingleItemEncoder, ToBencode}, }; @@ -23,7 +23,7 @@ impl ToBencode for Example { impl FromBencode for Example { const EXPECTED_RECURSION_DEPTH: usize = 2; - fn decode_bencode_object(object: Object) -> Result + fn decode_bencode_object(object: StrictObject) -> Result where Self: Sized, {