use crate::errors::DataParseError;
use crate::parser::core::DataParser;
use crate::utils::ParseResult;
pub fn delim_extract(
expected: &'static [u8],
) -> impl for<'a> Fn(&'a mut DataParser<'a>) -> ParseResult<&'a [u8]> {
move |parser: &mut DataParser| {
let actual = parser.take(expected.len())?;
if actual == expected {
Ok(actual)
} else {
Err(DataParseError::Custom {
e: format!("Tag mismatch: expected {:?}, got {:?}", expected, actual),
})
}
}
}
pub fn map<A, B, F, G>(parser: F, f: G) -> impl Fn(&mut DataParser) -> ParseResult<B>
where
F: Fn(&mut DataParser) -> ParseResult<A>,
G: Fn(A) -> B,
{
move |p: &mut DataParser| parser(p).map(&f)
}
pub fn parse_between<P, T>(
parser: P,
delim_start: u8,
delim_end: u8,
) -> impl Fn(&mut DataParser) -> ParseResult<T>
where
P: Fn(&mut DataParser) -> ParseResult<T>,
{
move |input: &mut DataParser| {
let start = input.get_byte()?;
if start != delim_start {
return Err(DataParseError::Custom {
e: format!(
"Expected start delimiter {:?}, found {:?}",
delim_start, start
),
});
}
let value = parser(input)?;
let end = input.get_byte()?;
if end != delim_end {
return Err(DataParseError::Custom {
e: format!("Expected end delimiter {:?}, found {:?}", delim_end, end),
});
}
Ok(value)
}
}
impl DataParser<'_> {
pub(crate) fn parse_with_length_prefix<T, F>(&mut self, f: F) -> ParseResult<T>
where
F: FnOnce(&mut DataParser) -> ParseResult<T>,
{
let options = self.options.clone();
let len = self.__get_u32()?;
let mut sub_buffer = self.take(len as usize)?.to_vec();
let mut sub_parser = DataParser::with_options(&mut sub_buffer, options);
f(&mut sub_parser)
}
pub fn parse_with<T, P>(&mut self, parser: P) -> ParseResult<T>
where
P: FnOnce(&mut DataParser) -> ParseResult<T>,
{
parser(self)
}
pub fn parse_until<F>(&mut self, terminator: F, max_len: Option<usize>) -> ParseResult<Vec<u8>>
where
F: Fn(u8) -> bool,
{
let mut collected = Vec::new();
while self.remaining() > 0 {
if let Some(limit) = max_len {
if collected.len() >= limit {
return Err(DataParseError::Custom {
e: "parse_until exceeded max_len".into(),
});
}
}
let byte = self.get_byte()?;
if terminator(byte) {
break;
}
collected.push(byte);
}
Ok(collected)
}
}