mirror of
https://codeberg.org/icewind/tf-log-parser.git
synced 2026-06-03 18:24:09 +02:00
split parsing utils
This commit is contained in:
parent
b138798b53
commit
446cbbe433
6 changed files with 60 additions and 56 deletions
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::event::EventFieldFromStr;
|
use crate::event::EventFieldFromStr;
|
||||||
|
use crate::parsing::find_between_end;
|
||||||
use crate::raw_event::{split_player_subject, RawSubject};
|
use crate::raw_event::{split_player_subject, RawSubject};
|
||||||
use crate::{Error, Result};
|
use crate::Result;
|
||||||
use enum_iterator::{all, Sequence};
|
use enum_iterator::{all, Sequence};
|
||||||
use memchr::{memchr, memrchr};
|
|
||||||
use serde::ser::SerializeMap;
|
use serde::ser::SerializeMap;
|
||||||
use serde::{Serialize, Serializer};
|
use serde::{Serialize, Serializer};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
@ -324,54 +324,3 @@ impl Serialize for SteamId3 {
|
||||||
self.0.steam3().serialize(serializer)
|
self.0.steam3().serialize(serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn split_once(input: &str, delim: u8, offset: usize) -> Result<(&str, &str)> {
|
|
||||||
debug_assert!(delim < 128); // only basic ascii
|
|
||||||
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
|
|
||||||
Ok(unsafe {
|
|
||||||
(
|
|
||||||
input.get_unchecked(..end),
|
|
||||||
input.get_unchecked(end + offset..),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn skip_matches(input: &str, char: u8) -> (&str, bool) {
|
|
||||||
if input.as_bytes().get(0) == Some(&char) {
|
|
||||||
// safety, we verified that the input has a length of at least 1
|
|
||||||
(unsafe { input.get_unchecked(1..) }, true)
|
|
||||||
} else {
|
|
||||||
(input, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_between_end(input: &str, start: u8, end: u8) -> Option<&str> {
|
|
||||||
debug_assert!(start < 128 && end < 128); // only basic ascii
|
|
||||||
let bytes = input.as_bytes();
|
|
||||||
let end = memrchr(end, bytes)?;
|
|
||||||
// safety, memchr returns indices that are inside the input
|
|
||||||
let start = memrchr(start, unsafe { &bytes.get_unchecked(0..end) })?;
|
|
||||||
// safety, memchr returns indices that are inside the input length and we only split on ascii
|
|
||||||
Some(unsafe { input.get_unchecked((start + 1)..end) })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_find_between_end() {
|
|
||||||
assert_eq!(Some("foo"), find_between_end("asd[foo]bar", b'[', b']'));
|
|
||||||
assert_eq!(None, find_between_end("asd]foo[bar", b'[', b']'));
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use crate::event::{param_parse_with, parse_field, ParamIter};
|
||||||
use crate::raw_event::RawSubject;
|
use crate::raw_event::RawSubject;
|
||||||
use crate::{Error, Event, IResult};
|
use crate::{Error, Event, IResult};
|
||||||
|
|
||||||
use crate::common::{skip, take_until};
|
use crate::parsing::{skip, take_until};
|
||||||
|
|
||||||
#[derive(Debug, Event)]
|
#[derive(Debug, Event)]
|
||||||
pub struct RoundWinEvent<'a> {
|
pub struct RoundWinEvent<'a> {
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ 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::parsing::{skip, skip_matches, split_once};
|
||||||
use crate::raw_event::{against_subject_parser, RawSubject};
|
use crate::raw_event::{against_subject_parser, RawSubject};
|
||||||
use crate::{Error, IResult, RawEvent, RawEventType, Result, SubjectId};
|
use crate::{Error, IResult, RawEvent, RawEventType, Result, SubjectId};
|
||||||
pub use game::*;
|
pub use game::*;
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ mod common;
|
||||||
pub mod event;
|
pub mod event;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod module;
|
pub mod module;
|
||||||
|
pub(crate) mod parsing;
|
||||||
pub mod raw_event;
|
pub mod raw_event;
|
||||||
mod subjectmap;
|
mod subjectmap;
|
||||||
|
|
||||||
|
|
|
||||||
53
src/parsing.rs
Normal file
53
src/parsing.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
use crate::{Error, Result};
|
||||||
|
use memchr::{memchr, memrchr};
|
||||||
|
|
||||||
|
pub fn split_once(input: &str, delim: u8, offset: usize) -> Result<(&str, &str)> {
|
||||||
|
debug_assert!(delim < 128); // only basic ascii
|
||||||
|
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
|
||||||
|
Ok(unsafe {
|
||||||
|
(
|
||||||
|
input.get_unchecked(..end),
|
||||||
|
input.get_unchecked(end + offset..),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn skip_matches(input: &str, char: u8) -> (&str, bool) {
|
||||||
|
if input.as_bytes().get(0) == Some(&char) {
|
||||||
|
// safety, we verified that the input has a length of at least 1
|
||||||
|
(unsafe { input.get_unchecked(1..) }, true)
|
||||||
|
} else {
|
||||||
|
(input, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_between_end(input: &str, start: u8, end: u8) -> Option<&str> {
|
||||||
|
debug_assert!(start < 128 && end < 128); // only basic ascii
|
||||||
|
let bytes = input.as_bytes();
|
||||||
|
let end = memrchr(end, bytes)?;
|
||||||
|
// safety, memchr returns indices that are inside the input
|
||||||
|
let start = memrchr(start, unsafe { &bytes.get_unchecked(0..end) })?;
|
||||||
|
// safety, memchr returns indices that are inside the input length and we only split on ascii
|
||||||
|
Some(unsafe { input.get_unchecked((start + 1)..end) })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_find_between_end() {
|
||||||
|
assert_eq!(Some("foo"), find_between_end("asd[foo]bar", b'[', b']'));
|
||||||
|
assert_eq!(None, find_between_end("asd]foo[bar", b'[', b']'));
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::common::{split_once, Team};
|
use crate::common::Team;
|
||||||
|
use crate::parsing::split_once;
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use crate::{SubjectError, SubjectId};
|
use crate::{SubjectError, SubjectId};
|
||||||
use chrono::{NaiveDate, NaiveDateTime};
|
use chrono::{NaiveDate, NaiveDateTime};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue