This commit is contained in:
Robin Appelman 2023-03-08 23:11:10 +01:00
commit b9b4ad619b
3 changed files with 54 additions and 33 deletions

View file

@ -330,6 +330,18 @@ pub fn split_once(input: &str, delim: u8, offset: usize) -> Result<(&str, &str)>
Ok((&input[..end], &input[(end + offset)..])) Ok((&input[..end], &input[(end + offset)..]))
} }
pub fn skip(input: &str, count: usize) -> Result<&str> {
input.get(count..).ok_or(Error::Incomplete)
}
pub fn skip_matches(input: &str, char: u8) -> (&str, bool) {
if input.as_bytes().get(0) == Some(&char) {
(&input[1..], true)
} else {
(input, false)
}
}
pub fn find_between_end(input: &str, start: u8, end: u8) -> Option<&str> { pub fn find_between_end(input: &str, start: u8, end: u8) -> Option<&str> {
let end = memrchr(end, input.as_bytes())?; let end = memrchr(end, input.as_bytes())?;
let start = memrchr(start, &input.as_bytes()[0..end])?; let start = memrchr(start, &input.as_bytes()[0..end])?;

View file

@ -2,13 +2,14 @@ mod game;
mod medic; mod medic;
mod player; mod player;
use crate::common::{skip, skip_matches, split_once};
use crate::event::game::{RoundLengthEvent, RoundWinEvent}; use crate::event::game::{RoundLengthEvent, RoundWinEvent};
use crate::raw_event::{against_subject_parser, RawSubject}; use crate::raw_event::{against_subject_parser, RawSubject};
use crate::{IResult, RawEvent, RawEventType, SubjectId}; use crate::{err_incomplete, IResult, RawEvent, RawEventType, SubjectId};
pub use game::*; pub use game::*;
pub use medic::*; pub use medic::*;
use nom::bytes::complete::{tag, take_while}; use nom::bytes::complete::{tag, take_while};
use nom::character::complete::{alpha1, digit1}; use nom::character::complete::digit1;
use nom::combinator::opt; use nom::combinator::opt;
use nom::error::{ErrorKind, ParseError}; use nom::error::{ErrorKind, ParseError};
use nom::number::complete::float; use nom::number::complete::float;
@ -37,7 +38,7 @@ trait GameEventErrTrait<T> {
impl<'a, T> GameEventErrTrait<T> for IResult<'a, T> { impl<'a, T> GameEventErrTrait<T> for IResult<'a, T> {
fn with_type(self, ty: RawEventType) -> Result<T, GameEventError> { fn with_type(self, ty: RawEventType) -> Result<T, GameEventError> {
self.map_err(|err| match err { self.map_err(|err| match err {
nom::Err::Error(e) | nom::Err::Failure(e) => GameEventError::Error { Err::Error(e) | Err::Failure(e) => GameEventError::Error {
err: nom::error::Error { err: nom::error::Error {
input: e.input.to_string(), input: e.input.to_string(),
code: e.code, code: e.code,
@ -238,16 +239,13 @@ impl<'a> Iterator for ParamIter<'a> {
} }
fn param_pair_parse(input: &str) -> IResult<'_, (&str, &str)> { fn param_pair_parse(input: &str) -> IResult<'_, (&str, &str)> {
let (input, open_tag) = opt(tag("("))(input)?; let (input, open_tag) = skip_matches(input, b'(');
let (input, key) = alpha1(input)?; let (key, input) = split_once(input, b' ', 0)?;
let (input, _) = tag(r#" ""#)(input)?; let input = skip(input, 2)?;
let (input, value) = take_while(|c| c != '"')(input)?; let (value, input) = split_once(input, b'"', 1)?;
let (input, _) = tag(r#"""#)(input)?;
if open_tag.is_some() { let input = if open_tag { skip(input, 1)? } else { input };
let (_input, _) = tag(")")(input)?;
}
Ok((input, (key, value))) Ok((input, (key, value)))
} }
@ -273,14 +271,13 @@ pub fn param_parse_with<'a, T, P: Fn(&'a str) -> IResult<'a, T>>(
move |input: &str| { move |input: &str| {
debug_assert!(input.as_bytes()[0] != b' '); debug_assert!(input.as_bytes()[0] != b' ');
let has_open = input.as_bytes()[0] == b'('; let (input, has_open) = skip_matches(input, b'(');
let input = &input[has_open as usize..];
let input = &input[key.len() + 1..]; // skip space + key let input = skip(input, key.len() + 1)?; // skip space + key
let (input, value) = parser(input)?; let (input, value) = parser(input)?;
let input = &input[has_open as usize..]; let input = skip(input, has_open as usize)?;
debug_assert!( debug_assert!(
input.is_empty() || input.as_bytes()[0] == b' ', input.is_empty() || input.as_bytes()[0] == b' ',
@ -288,7 +285,7 @@ pub fn param_parse_with<'a, T, P: Fn(&'a str) -> IResult<'a, T>>(
input input
); );
let input = &input[(!input.is_empty() as usize)..]; let input = skip(input, 1).unwrap_or(input);
Ok((input, value)) Ok((input, value))
} }
} }
@ -296,7 +293,7 @@ pub fn param_parse_with<'a, T, P: Fn(&'a str) -> IResult<'a, T>>(
fn parse_from_str<'a, T: FromStr + 'a>(input: &'a str) -> IResult<T> { fn parse_from_str<'a, T: FromStr + 'a>(input: &'a str) -> IResult<T> {
T::from_str(input) T::from_str(input)
.map(|res| ("", res)) .map(|res| ("", res))
.map_err(|_| nom::Err::Error(nom::error::Error::from_error_kind(input, ErrorKind::IsNot))) .map_err(|_| Err::Error(nom::error::Error::from_error_kind(input, ErrorKind::IsNot)))
} }
fn int(input: &str) -> IResult<i32> { fn int(input: &str) -> IResult<i32> {
@ -304,7 +301,7 @@ fn int(input: &str) -> IResult<i32> {
let (input, raw) = digit1(input)?; let (input, raw) = digit1(input)?;
let val: i32 = raw let val: i32 = raw
.parse() .parse()
.map_err(|_| nom::Err::Error(nom::error::Error::new(raw, ErrorKind::Digit)))?; .map_err(|_| Err::Error(nom::error::Error::new(raw, ErrorKind::Digit)))?;
Ok((input, if sign.is_some() { -val } else { val })) Ok((input, if sign.is_some() { -val } else { val }))
} }
@ -312,9 +309,7 @@ fn u_int(input: &str) -> IResult<u32> {
let (input, quote) = opt(tag("\""))(input)?; let (input, quote) = opt(tag("\""))(input)?;
let (input, raw) = digit1(input)?; let (input, raw) = digit1(input)?;
let val = raw let val = raw.parse().map_err(|_| err_incomplete())?;
.parse()
.map_err(|_| nom::Err::Error(nom::error::Error::new(raw, ErrorKind::Digit)))?;
let input = if quote.is_some() { let input = if quote.is_some() {
tag("\"")(input)?.0 tag("\"")(input)?.0
@ -334,11 +329,11 @@ pub fn position(input: &str) -> IResult<(i32, i32, i32)> {
} }
pub trait EventField<'a>: Sized + 'a { pub trait EventField<'a>: Sized + 'a {
fn parse_field(input: &'a str) -> crate::IResult<Self>; fn parse_field(input: &'a str) -> IResult<Self>;
} }
impl<'a> EventField<'a> for &'a str { impl<'a> EventField<'a> for &'a str {
fn parse_field(input: &'a str) -> crate::IResult<Self> { fn parse_field(input: &'a str) -> IResult<Self> {
if input.starts_with('"') { if input.starts_with('"') {
quoted(take_while(|c| c != '"'))(input) quoted(take_while(|c| c != '"'))(input)
} else { } else {
@ -348,31 +343,31 @@ impl<'a> EventField<'a> for &'a str {
} }
impl<'a> EventField<'a> for i32 { impl<'a> EventField<'a> for i32 {
fn parse_field(input: &'a str) -> crate::IResult<Self> { fn parse_field(input: &'a str) -> IResult<Self> {
int(input) int(input)
} }
} }
impl<'a> EventField<'a> for u32 { impl<'a> EventField<'a> for u32 {
fn parse_field(input: &'a str) -> crate::IResult<Self> { fn parse_field(input: &'a str) -> IResult<Self> {
u_int(input) u_int(input)
} }
} }
impl<'a> EventField<'a> for f32 { impl<'a> EventField<'a> for f32 {
fn parse_field(input: &'a str) -> crate::IResult<Self> { fn parse_field(input: &'a str) -> IResult<Self> {
float(input) float(input)
} }
} }
impl<'a> EventField<'a> for u8 { impl<'a> EventField<'a> for u8 {
fn parse_field(input: &'a str) -> crate::IResult<Self> { fn parse_field(input: &'a str) -> IResult<Self> {
u_int(input).map(|(rest, num)| (rest, num as u8)) u_int(input).map(|(rest, num)| (rest, num as u8))
} }
} }
impl<'a, T: EventField<'a>> EventField<'a> for Option<T> { impl<'a, T: EventField<'a>> EventField<'a> for Option<T> {
fn parse_field(input: &'a str) -> crate::IResult<Self> { fn parse_field(input: &'a str) -> IResult<Self> {
T::parse_field(input).map(|(rest, int)| (rest, Some(int))) T::parse_field(input).map(|(rest, int)| (rest, Some(int)))
} }
} }
@ -380,7 +375,7 @@ impl<'a, T: EventField<'a>> EventField<'a> for Option<T> {
pub trait EventFieldFromStr: FromStr {} pub trait EventFieldFromStr: FromStr {}
impl<'a, T: EventFieldFromStr + 'a> EventField<'a> for T { impl<'a, T: EventFieldFromStr + 'a> EventField<'a> for T {
fn parse_field(input: &'a str) -> crate::IResult<Self> { fn parse_field(input: &'a str) -> IResult<Self> {
parse_from_str(input) parse_from_str(input)
} }
} }
@ -388,7 +383,7 @@ impl<'a, T: EventFieldFromStr + 'a> EventField<'a> for T {
impl EventFieldFromStr for SocketAddr {} impl EventFieldFromStr for SocketAddr {}
impl<'a, T: EventField<'a>> EventField<'a> for (T, T, T) { impl<'a, T: EventField<'a>> EventField<'a> for (T, T, T) {
fn parse_field(input: &'a str) -> crate::IResult<Self> { fn parse_field(input: &'a str) -> IResult<Self> {
let (input, x) = T::parse_field(input)?; let (input, x) = T::parse_field(input)?;
let (input, _) = tag(" ")(input)?; let (input, _) = tag(" ")(input)?;
let (input, y) = T::parse_field(input)?; let (input, y) = T::parse_field(input)?;
@ -399,17 +394,17 @@ impl<'a, T: EventField<'a>> EventField<'a> for (T, T, T) {
} }
impl<'a> EventField<'a> for Option<NonZeroU32> { impl<'a> EventField<'a> for Option<NonZeroU32> {
fn parse_field(input: &'a str) -> crate::IResult<Self> { fn parse_field(input: &'a str) -> IResult<Self> {
u32::parse_field(input).map(|(rest, int)| (rest, NonZeroU32::new(int))) u32::parse_field(input).map(|(rest, int)| (rest, NonZeroU32::new(int)))
} }
} }
impl<'a> EventField<'a> for RawSubject<'a> { impl<'a> EventField<'a> for RawSubject<'a> {
fn parse_field(input: &'a str) -> crate::IResult<Self> { fn parse_field(input: &'a str) -> IResult<Self> {
against_subject_parser(input) against_subject_parser(input)
} }
} }
pub fn parse_field<'a, T: EventField<'a>>(input: &'a str) -> crate::IResult<T> { pub fn parse_field<'a, T: EventField<'a>>(input: &'a str) -> IResult<T> {
T::parse_field(input) T::parse_field(input)
} }

View file

@ -8,6 +8,7 @@ pub use crate::subjectmap::SubjectMap;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
pub use event::{Event, EventMeta, GameEvent}; pub use event::{Event, EventMeta, GameEvent};
use memchr::memmem::{find_iter, FindIter}; use memchr::memmem::{find_iter, FindIter};
use nom::error::ErrorKind;
use nom::Err; use nom::Err;
pub use raw_event::{RawEvent, RawEventType}; pub use raw_event::{RawEvent, RawEventType};
use std::collections::BTreeMap; use std::collections::BTreeMap;
@ -23,6 +24,10 @@ pub mod module;
pub mod raw_event; pub mod raw_event;
mod subjectmap; mod subjectmap;
pub(crate) fn err_incomplete() -> Err<nom::error::Error<&'static str>> {
Err::Error(nom::error::Error::new("", ErrorKind::Digit))
}
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum Error { pub enum Error {
#[error("Malformed logfile")] #[error("Malformed logfile")]
@ -44,6 +49,15 @@ impl From<nom::Err<nom::error::Error<&'_ str>>> for Error {
} }
} }
impl From<Error> for nom::Err<nom::error::Error<&'static str>> {
fn from(e: Error) -> Self {
match e {
Error::Incomplete => err_incomplete(),
_ => Err::Error(nom::error::Error::new("", ErrorKind::Verify)),
}
}
}
impl From<nom::error::Error<&'_ str>> for Error { impl From<nom::error::Error<&'_ str>> for Error {
fn from(_: nom::error::Error<&str>) -> Self { fn from(_: nom::error::Error<&str>) -> Self {
Error::Malformed Error::Malformed