Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce with_range on Parser #43

Merged
merged 10 commits into from
Nov 16, 2023
110 changes: 109 additions & 1 deletion src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//! ref and allows to parse values from the octets.

use core::fmt;
use core::ops::{Bound, RangeBounds};
use crate::octets::Octets;

//------------ Parser --------------------------------------------------------
Expand Down Expand Up @@ -45,6 +46,83 @@ impl<'a, Octs: ?Sized> Parser<'a, Octs> {
}
}

/// Creates a new parser only using a range of the given octets.
///
/// # Panics
///
/// Panics if `range` is decreasing or out of bounds.
pub fn with_range<R>(octets: &'a Octs, range: R) -> Self
where
Octs: AsRef<[u8]>,
R: RangeBounds<usize>
{
match Self::_try_with_range(octets, range) {
Ok(p) => p,
Err(e) => panic!("{}", e)
}
}

/// Creates a new parser only using a range if possible.
///
/// If `range` is decreasing or out of bounds, returns an Error.
pub fn try_with_range<R>(
octets: &'a Octs, range: R
) -> Option<Self>
where
Octs: AsRef<[u8]>,
R: RangeBounds<usize>
{
Self::_try_with_range(octets, range).ok()
}

/// Creates a new parser only using a range if possible.
///
/// If `range` is decreasing or out of bounds, returns an Error.
fn _try_with_range<R>(
octets: &'a Octs, range: R
) -> Result<Self, &'static str>
where
Octs: AsRef<[u8]>,
R: RangeBounds<usize>
{
let octets_len = octets.as_ref().len();

let pos = match range.start_bound() {
Bound::Unbounded => 0,
Bound::Included(n) => *n,
Bound::Excluded(n) => *n + 1,
};

if pos > octets_len {
return Err("range start is out of range for octets")
}

let len = match range.end_bound() {
Bound::Unbounded => octets_len,
Bound::Excluded(n) => *n,
Bound::Included(n) => *n + 1,
};

if len > octets_len {
return Err("range end is out of range for octets")
}

if len < pos {
return Err("range starts after end")
}

Ok(
Parser {
pos,
len,
octets
}
)

}



/// Returns the wrapped reference to the underlying octets sequence.
pub fn octets_ref(&self) -> &'a Octs {
self.octets
Expand Down Expand Up @@ -738,5 +816,35 @@ mod test {
);
assert!(parser.parse_u128_le().is_err());
}
}

#[test]
fn with_range() {
let range = [0, 1, 2, 3, 4, 5_usize];
let slice = &[1, 2, 3];

for start in range {
for end in range {
for start in [
Bound::Unbounded,
Bound::Included(start),
Bound::Excluded(start)
] {
for end in [
Bound::Unbounded,
Bound::Included(end),
Bound::Excluded(end)
] {
let bounds = (start, end);
assert_eq!(
slice.get(bounds),
Parser::try_with_range(
slice, bounds
).as_ref().map(|p| p.peek_all()),
"{:?}", bounds
);
}
}
}
}
}
}