mirror of
https://codeberg.org/icewind/tf-log-parser.git
synced 2026-06-03 18:24:09 +02:00
even less nom
This commit is contained in:
parent
41d558ecb0
commit
19f9c9f973
4 changed files with 74 additions and 56 deletions
|
|
@ -337,6 +337,16 @@ pub fn split_once(input: &str, delim: u8, offset: usize) -> Result<(&str, &str)>
|
|||
})
|
||||
}
|
||||
|
||||
pub fn take_until(input: &str, delim: u8) -> (&str, &str) {
|
||||
debug_assert!(delim < 128); // only basic ascii
|
||||
if let Some(end) = memchr(delim, input.as_bytes()) {
|
||||
// safety, memchr returns indices that are inside the input length and we only split on ascii
|
||||
unsafe { (input.get_unchecked(end..), input.get_unchecked(..end)) }
|
||||
} else {
|
||||
("", input)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn skip(input: &str, count: usize) -> Result<&str> {
|
||||
input.get(count..).ok_or(Error::Incomplete)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
use crate::event::{param_parse, param_parse_with, parse_field, ParamIter};
|
||||
use crate::event::{param_parse_with, parse_field, ParamIter};
|
||||
use crate::raw_event::RawSubject;
|
||||
use crate::{Event, IResult};
|
||||
use crate::{Error, Event, IResult};
|
||||
|
||||
use nom::bytes::complete::{tag, take_while};
|
||||
use nom::combinator::opt;
|
||||
use crate::common::{skip, take_until};
|
||||
|
||||
#[derive(Debug, Event)]
|
||||
pub struct RoundWinEvent<'a> {
|
||||
|
|
@ -32,10 +31,10 @@ pub struct TournamentModeStartedEvent<'a> {
|
|||
|
||||
impl<'a> Event<'a> for TournamentModeStartedEvent<'a> {
|
||||
fn parse(input: &'a str) -> IResult<Self> {
|
||||
let (input, _) = tag("\nBlue Team: ")(input)?;
|
||||
let (input, blue) = take_while(|c| c != '\n')(input)?;
|
||||
let (input, _) = tag("\nRed Team: ")(input)?;
|
||||
let (input, red) = take_while(|c| c != '\n')(input)?;
|
||||
let input = skip(input, "\nBlue Team: ".len())?;
|
||||
let (input, blue) = take_until(input, b'\n');
|
||||
let input = skip(input, "\nRed Team: ".len())?;
|
||||
let (input, red) = take_until(input, b'\n');
|
||||
Ok((input, TournamentModeStartedEvent { blue, red }))
|
||||
}
|
||||
}
|
||||
|
|
@ -58,20 +57,41 @@ pub struct PointCapturedEvent<'a> {
|
|||
|
||||
impl<'a> Event<'a> for PointCapturedEvent<'a> {
|
||||
fn parse(input: &'a str) -> IResult<Self> {
|
||||
let (input, cp) = opt(param_parse("cp"))(input)?;
|
||||
let (input, cp_name) = opt(param_parse("cpname"))(input)?;
|
||||
let (input, num_cappers) = opt(param_parse("numcappers"))(input)?;
|
||||
|
||||
let mut cp = Default::default();
|
||||
let mut cp_name = Default::default();
|
||||
let mut num_cappers = Default::default();
|
||||
let mut players = Vec::new();
|
||||
|
||||
let mut params = ParamIter::new(input);
|
||||
let mut params = ParamIter::new(input).peekable();
|
||||
while let Some((name, value)) = params.peek() {
|
||||
match *name {
|
||||
"cp" => {
|
||||
cp = Some(value.parse().map_err(Error::from)?);
|
||||
let _ = params.next();
|
||||
}
|
||||
"cpname" => {
|
||||
cp_name = Some(*value);
|
||||
let _ = params.next();
|
||||
}
|
||||
"numcappers" => {
|
||||
num_cappers = Some(value.parse().map_err(Error::from)?);
|
||||
let _ = params.next();
|
||||
}
|
||||
_ => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
loop {
|
||||
match (params.next(), params.next()) {
|
||||
(Some((subject_key, subject)), Some((position_key, position_str)))
|
||||
if subject_key.starts_with("player") && position_key.starts_with("position") =>
|
||||
if subject_key.starts_with("player")
|
||||
&& position_key.starts_with("position") =>
|
||||
{
|
||||
players.push((parse_field(subject)?.1, parse_field(position_str)?.1));
|
||||
}
|
||||
_ => {}
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
|
||||
Ok((
|
||||
|
|
|
|||
|
|
@ -2,15 +2,12 @@ mod game;
|
|||
mod medic;
|
||||
mod player;
|
||||
|
||||
use crate::common::{skip, skip_matches, split_once};
|
||||
use crate::common::{skip, skip_matches, split_once, take_until};
|
||||
use crate::event::game::{RoundLengthEvent, RoundWinEvent};
|
||||
use crate::raw_event::{against_subject_parser, RawSubject};
|
||||
use crate::{err_incomplete, IResult, RawEvent, RawEventType, SubjectId};
|
||||
pub use game::*;
|
||||
pub use medic::*;
|
||||
use nom::bytes::complete::{tag, take_while};
|
||||
use nom::character::complete::digit1;
|
||||
use nom::combinator::opt;
|
||||
use nom::error::{ErrorKind, ParseError};
|
||||
use nom::number::complete::float;
|
||||
use nom::Err;
|
||||
|
|
@ -253,9 +250,9 @@ fn quoted<'a, T, P: Fn(&'a str) -> IResult<'a, T>>(
|
|||
parser: P,
|
||||
) -> impl Fn(&'a str) -> IResult<'a, T> {
|
||||
move |input| {
|
||||
let (input, _) = tag(r#"""#)(input)?;
|
||||
let (input, res) = parser(input)?;
|
||||
let (input, _) = tag(r#"""#)(input)?;
|
||||
let input = skip(input, 1)?;
|
||||
let (inner, input) = split_once(input, b'"', 1)?;
|
||||
let (_, res) = parser(inner)?;
|
||||
Ok((input, res))
|
||||
}
|
||||
}
|
||||
|
|
@ -297,45 +294,29 @@ fn parse_from_str<'a, T: FromStr + 'a>(input: &'a str) -> IResult<T> {
|
|||
}
|
||||
|
||||
fn int(input: &str) -> IResult<i32> {
|
||||
let (input, sign) = opt(tag("-"))(input)?;
|
||||
let (input, raw) = digit1(input)?;
|
||||
let val: i32 = raw
|
||||
.parse()
|
||||
.map_err(|_| Err::Error(nom::error::Error::new(raw, ErrorKind::Digit)))?;
|
||||
Ok((input, if sign.is_some() { -val } else { val }))
|
||||
let (input, sign) = skip_matches(input, b'-');
|
||||
let (input, unsigned) = u_int(input)?;
|
||||
let signed = unsigned as i32;
|
||||
Ok((input, if sign { -signed } else { signed }))
|
||||
}
|
||||
|
||||
fn u_int(input: &str) -> IResult<u32> {
|
||||
let (input, quote) = opt(tag("\""))(input)?;
|
||||
|
||||
let (input, raw) = digit1(input)?;
|
||||
let (input, raw) = take_until(input, b' ');
|
||||
let val = raw.parse().map_err(|_| err_incomplete())?;
|
||||
|
||||
let input = if quote.is_some() {
|
||||
tag("\"")(input)?.0
|
||||
} else {
|
||||
input
|
||||
};
|
||||
Ok((input, val))
|
||||
}
|
||||
|
||||
pub fn position(input: &str) -> IResult<(i32, i32, i32)> {
|
||||
let (input, x) = int(input)?;
|
||||
let (input, _) = tag(" ")(input)?;
|
||||
let (input, y) = int(input)?;
|
||||
let (input, _) = tag(" ")(input)?;
|
||||
let (input, z) = int(input)?;
|
||||
Ok((input, (x, y, z)))
|
||||
}
|
||||
|
||||
pub trait EventField<'a>: Sized + 'a {
|
||||
fn parse_field(input: &'a str) -> IResult<Self>;
|
||||
}
|
||||
|
||||
impl<'a> EventField<'a> for &'a str {
|
||||
fn parse_field(input: &'a str) -> IResult<Self> {
|
||||
if input.starts_with('"') {
|
||||
quoted(take_while(|c| c != '"'))(input)
|
||||
let (input, quoted) = skip_matches(input, b'"');
|
||||
if quoted {
|
||||
let (value, input) = split_once(input, b'"', 1)?;
|
||||
Ok((input, value))
|
||||
} else {
|
||||
Ok(("", input))
|
||||
}
|
||||
|
|
@ -384,11 +365,11 @@ impl EventFieldFromStr for SocketAddr {}
|
|||
|
||||
impl<'a, T: EventField<'a>> EventField<'a> for (T, T, T) {
|
||||
fn parse_field(input: &'a str) -> IResult<Self> {
|
||||
let (input, x) = T::parse_field(input)?;
|
||||
let (input, _) = tag(" ")(input)?;
|
||||
let (input, y) = T::parse_field(input)?;
|
||||
let (input, _) = tag(" ")(input)?;
|
||||
let (input, z) = T::parse_field(input)?;
|
||||
let (input, x) = parse_field(input)?;
|
||||
let input = skip(input, 1)?;
|
||||
let (input, y) = parse_field(input)?;
|
||||
let input = skip(input, 1)?;
|
||||
let (input, z) = parse_field(input)?;
|
||||
Ok((input, (x, y, z)))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ pub use raw_event::{RawEvent, RawEventType};
|
|||
use std::collections::BTreeMap;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt::Debug;
|
||||
use std::num::ParseIntError;
|
||||
pub use tf_log_parser_derive::Event;
|
||||
use thiserror::Error;
|
||||
|
||||
|
|
@ -64,6 +65,12 @@ impl From<nom::error::Error<&'_ str>> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<ParseIntError> for Error {
|
||||
fn from(_: ParseIntError) -> Self {
|
||||
Error::Malformed
|
||||
}
|
||||
}
|
||||
|
||||
type Result<O, E = Error> = std::result::Result<O, E>;
|
||||
|
||||
#[doc(hidden)]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue