more edge case handling

This commit is contained in:
Robin Appelman 2023-03-16 21:44:41 +01:00
commit f1213a5664
5 changed files with 15 additions and 9 deletions

View file

@ -138,7 +138,8 @@ 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) = skip_matches(input, b'('); let (input, open_tag) = skip_matches(input, b'(');
let (key, input) = split_once(input, b' ', 2)?; let (key, input) = split_once(input, b' ', 1)?;
let input = skip(input, 1)?;
let (value, input) = split_once(input, b'"', 1)?; let (value, input) = split_once(input, b'"', 1)?;
let input = if open_tag { skip(input, 1)? } else { input }; let input = if open_tag { skip(input, 1)? } else { input };

View file

@ -18,7 +18,7 @@ pub struct ShotHitEvent<'a> {
#[derive(Debug, Event)] #[derive(Debug, Event)]
pub struct DamageEvent<'a> { pub struct DamageEvent<'a> {
#[event(name = "against")] #[event(name = "against")]
pub target: RawSubject<'a>, pub target: Option<RawSubject<'a>>,
pub damage: Option<NonZeroU32>, pub damage: Option<NonZeroU32>,
#[event(name = "realdamage")] #[event(name = "realdamage")]
pub real_damage: Option<NonZeroU32>, pub real_damage: Option<NonZeroU32>,

View file

@ -93,7 +93,7 @@ impl EventHandler for ClassStatsHandler {
} }
GameEvent::Damage(DamageEvent { GameEvent::Damage(DamageEvent {
damage: Some(damage), damage: Some(damage),
target, target: Some(target),
.. ..
}) if self.active => { }) if self.active => {
if let Some(target_class) = self.get_class(target) { if let Some(target_class) = self.get_class(target) {

View file

@ -5,6 +5,7 @@ use once_cell::unsync::Lazy;
pub fn split_once(input: &str, delim: u8, offset: usize) -> Result<(&str, &str)> { pub fn split_once(input: &str, delim: u8, offset: usize) -> Result<(&str, &str)> {
debug_assert!(delim < 128); // only basic ascii debug_assert!(delim < 128); // only basic ascii
debug_assert!(offset <= 1);
let end = memchr(delim, input.as_bytes()).ok_or(Error::Incomplete)?; let end = memchr(delim, input.as_bytes()).ok_or(Error::Incomplete)?;
// safety, memchr returns indices that are inside the input length and we only split on ascii // safety, memchr returns indices that are inside the input length and we only split on ascii
Ok(unsafe { Ok(unsafe {
@ -22,6 +23,7 @@ thread_local! {
pub fn split_subject_end<'a>(input: &'a str, offset: usize) -> Result<(&'a str, &'a str)> { pub fn split_subject_end<'a>(input: &'a str, offset: usize) -> Result<(&'a str, &'a str)> {
let start_offset = 1; let start_offset = 1;
let end_offset = start_offset + offset; let end_offset = start_offset + offset;
debug_assert!(offset <= 2);
let end = SUBJECT_END_FINDER let end = SUBJECT_END_FINDER
.with(|finder| finder.find(input.as_bytes())) .with(|finder| finder.find(input.as_bytes()))
.ok_or(Error::Incomplete)?; .ok_or(Error::Incomplete)?;

View file

@ -1,5 +1,5 @@
use crate::common::Team; use crate::common::Team;
use crate::parsing::{split_once, split_subject_end}; use crate::parsing::{skip, split_once, split_subject_end};
use crate::{Error, Result}; use crate::{Error, Result};
use crate::{SubjectError, SubjectId}; use crate::{SubjectError, SubjectId};
use chrono::{NaiveDate, NaiveDateTime}; use chrono::{NaiveDate, NaiveDateTime};
@ -19,7 +19,6 @@ pub struct RawEvent<'a> {
impl<'a> RawEvent<'a> { impl<'a> RawEvent<'a> {
pub fn parse(line: &'a str) -> Result<Self> { pub fn parse(line: &'a str) -> Result<Self> {
debug_assert!(!line.ends_with("\n"));
event_parser(line) event_parser(line)
} }
} }
@ -29,7 +28,7 @@ fn event_parser(input: &str) -> Result<RawEvent> {
let (input, subject) = subject_parser(&input[23..])?; let (input, subject) = subject_parser(&input[23..])?;
let (input, ty) = event_type_parser(&input[1..])?; let (input, ty) = event_type_parser(input)?;
let params = &input[(!input.is_empty() as usize)..]; let params = &input[(!input.is_empty() as usize)..];
@ -133,6 +132,7 @@ pub fn subject_parser(input: &str) -> Result<(&str, RawSubject)> {
let Ok((player, input)) = split_subject_end(input, 1) else { let Ok((player, input)) = split_subject_end(input, 1) else {
return Ok((full, RawSubject::Console)) return Ok((full, RawSubject::Console))
}; };
let input = skip(input, 1)?;
if player.ends_with("le>") { if player.ends_with("le>") {
Ok((input, RawSubject::Console)) Ok((input, RawSubject::Console))
} else { } else {
@ -141,15 +141,18 @@ pub fn subject_parser(input: &str) -> Result<(&str, RawSubject)> {
} else if input.starts_with("Te") { } else if input.starts_with("Te") {
// Team "red" or Team "blue" // Team "red" or Team "blue"
if &input[6..7] == "r" { if &input[6..7] == "r" {
Ok((&input[10..], RawSubject::Team(Team::Red))) Ok((&input[11..], RawSubject::Team(Team::Red)))
} else if &input[6..7] == "b" { } else if &input[6..7] == "b" {
Ok((&input[11..], RawSubject::Team(Team::Blue))) Ok((&input[12..], RawSubject::Team(Team::Blue)))
} else { } else {
let (_, input) = split_once(&input[7..], b'"', 1)?; let (_, input) = split_once(&input[7..], b'"', 1)?;
let input = skip(input, 1)?;
Ok((input, RawSubject::Team(Team::Spectator))) Ok((input, RawSubject::Team(Team::Spectator)))
} }
} else { } else {
let (system, input) = split_once(input, b' ', 0)?; let Ok((system, input)) = split_once(input, b' ', 1) else {
return Ok(("", RawSubject::System(input)))
};
Ok((input, RawSubject::System(system))) Ok((input, RawSubject::System(system)))
} }
} }