use nom::{
AsBytes, AsChar, Compare, Input, Offset, ParseTo, Parser,
character::complete::{anychar, char},
combinator::opt,
error::ParseError,
multi::many0,
sequence::preceded,
};
use crate::{Error, IResult};
pub trait NmeaParse<I, E = nom::error::Error<I>>
where
I: Input,
E: ParseError<I>,
Self: Sized,
{
fn parse(i: I) -> IResult<I, Self, E>;
fn parse_preceded<S>(separator: S) -> impl Parser<I, Output = Self, Error = Error<I, E>>
where
S: Parser<I, Error = Error<I, E>>,
{
preceded(separator, Self::parse)
}
}
macro_rules! impl_uints_type {
($($t:tt),*) => ($(
impl<I, E> NmeaParse<I, E> for $t
where
I: Input,
<I as Input>::Item: AsChar,
E: ParseError<I>,
{
fn parse(i: I) -> IResult<I, Self, E> {
nom::character::complete::$t.parse(i)
}
}
)*)
}
macro_rules! impl_ints_type {
($($t:tt),*) => ($(
impl<I, E> NmeaParse<I, E> for $t
where
I: Input + for<'a> Compare<&'a [u8]>,
<I as Input>::Item: AsChar,
E: ParseError<I>,
{
fn parse(i: I) -> IResult<I, Self, E> {
nom::character::complete::$t.parse(i)
}
}
)*)
}
impl_uints_type!(u8, u16, u32, u64, u128, usize);
impl_ints_type!(i8, i16, i32, i64, i128, isize);
macro_rules! impl_float_type {
($($t:ty, $p:ident),*) => ($(
impl<I, E> NmeaParse<I, E> for $t
where
I: Input + Offset + ParseTo<$t> + AsBytes,
I: Compare<&'static str> + for<'a> Compare<&'a [u8]>,
<I as Input>::Item: AsChar,
<I as Input>::Iter: Clone,
E: ParseError<I>,
{
fn parse(i: I) -> IResult<I, Self, E> {
nom::number::complete::$p.parse(i)
}
}
)*)
}
impl_float_type!(f32, float, f64, double);
impl<I, E> NmeaParse<I, E> for char
where
I: Input,
<I as Input>::Item: AsChar,
E: ParseError<I>,
{
fn parse(i: I) -> IResult<I, Self, E> {
anychar.parse(i)
}
}
impl<T, I, E> NmeaParse<I, E> for Option<T>
where
T: NmeaParse<I, E>,
I: Input,
E: ParseError<I>,
{
fn parse(i: I) -> IResult<I, Self, E> {
opt(T::parse).parse(i)
}
fn parse_preceded<S>(separator: S) -> impl Parser<I, Output = Self, Error = Error<I, E>>
where
S: Parser<I, Error = Error<I, E>>,
{
let mut separator = separator;
move |i: I| {
let input = i.clone();
let (i, _) = separator.parse(i)?;
match T::parse.parse(i.clone()) {
Ok((i, value)) => Ok((i, Some(value))),
Err(_) => {
if let Ok((_, _)) = separator.parse(i.clone()) {
Ok((i, None))
} else if i.input_len() == 0 {
Ok((i, None))
} else {
Err(nom::Err::Error(nom::error::make_error(
input,
nom::error::ErrorKind::Verify,
)))
}
}
}
}
}
}
impl<T, I, E, const N: usize> NmeaParse<I, E> for [T; N]
where
T: NmeaParse<I, E> + Default + Copy,
I: Input,
<I as Input>::Item: AsChar,
E: ParseError<I>,
{
fn parse(i: I) -> IResult<I, Self, E> {
let mut elems = [T::default(); N];
let mut i = i;
match T::parse(i.clone()) {
Ok((i1, first)) => {
elems[0] = first;
i = i1;
}
Err(nom::Err::Error(_)) => {
return Err(nom::Err::Error(nom::error::make_error(
i,
nom::error::ErrorKind::Count,
)));
}
Err(nom::Err::Failure(e)) => return Err(nom::Err::Failure(e)),
Err(nom::Err::Incomplete(e)) => return Err(nom::Err::Incomplete(e)),
}
for elem in &mut elems[1..] {
match preceded(char(','), T::parse).parse(i.clone()) {
Ok((i1, next)) => {
*elem = next;
i = i1;
}
Err(nom::Err::Error(_)) => {
return Err(nom::Err::Error(nom::error::make_error(
i,
nom::error::ErrorKind::Count,
)));
}
Err(e) => return Err(e),
};
}
Ok((i, elems))
}
fn parse_preceded<S>(separator: S) -> impl Parser<I, Output = Self, Error = Error<I, E>>
where
S: Parser<I, Error = Error<I, E>>,
{
let mut parser = T::parse_preceded(separator);
move |i: I| {
let mut i = i;
let mut elems = [T::default(); N];
for elem in &mut elems {
match parser.parse(i.clone()) {
Ok((i1, next)) => {
*elem = next;
i = i1;
}
Err(nom::Err::Error(_)) => {
return Err(nom::Err::Error(nom::error::make_error(
i,
nom::error::ErrorKind::Count,
)));
}
Err(e) => return Err(e),
};
}
Ok((i, elems))
}
}
}
impl<T, I, E> NmeaParse<I, E> for Vec<T>
where
T: NmeaParse<I, E>,
I: Clone + Input,
<I as Input>::Item: AsChar,
E: ParseError<I>,
{
fn parse(i: I) -> IResult<I, Self, E> {
let mut elems = Vec::with_capacity(4);
let mut i = i;
match T::parse(i.clone()) {
Ok((i1, first)) => {
if i1.input_len() == i.input_len() {
return Err(nom::Err::Error(nom::error::make_error(
i,
nom::error::ErrorKind::Many0,
)));
}
elems.push(first);
i = i1;
}
Err(nom::Err::Error(_)) => {
return Ok((i, elems));
}
Err(e) => return Err(e),
}
loop {
let len = i.input_len();
match T::parse_preceded(char(',')).parse(i.clone()) {
Ok((i1, next)) => {
if i1.input_len() == len {
return Err(nom::Err::Error(nom::error::make_error(
i,
nom::error::ErrorKind::Many0,
)));
}
elems.push(next);
i = i1;
}
Err(nom::Err::Error(_)) => return Ok((i, elems)),
Err(e) => return Err(e),
};
}
}
fn parse_preceded<S>(separator: S) -> impl Parser<I, Output = Self, Error = Error<I, E>>
where
S: Parser<I, Error = Error<I, E>>,
{
many0(<T>::parse_preceded(separator))
}
}
#[cfg(test)]
mod tests {
use crate::{IResult, NmeaParse};
use nom::{Parser, character::complete::char};
#[test]
fn test_parse_vec() {
let input = "1,2,,4";
let expected: Vec<Option<u8>> = vec![Some(1), Some(2), None, Some(4)];
let result: IResult<_, _> = Vec::<Option<u8>>::parse(input);
assert_eq!(result, Ok(("", expected)));
let input = ",1,2,,4";
let expected: Vec<Option<u8>> = vec![Some(1), Some(2), None, Some(4)];
let result: IResult<_, _> = Vec::<Option<u8>>::parse_preceded(char(',')).parse(input);
assert_eq!(result, Ok(("", expected)));
}
}