mirror of
https://codeberg.org/icewind/tf-log-parser.git
synced 2026-06-03 18:24:09 +02:00
remove some more nom
This commit is contained in:
parent
d326e1bb6a
commit
311345cf4e
15 changed files with 103 additions and 91 deletions
|
|
@ -4,7 +4,7 @@ use tf_log_parser::{parse, RawEvent};
|
||||||
static LOG: &str = include_str!("../test_data/log_2892242.log");
|
static LOG: &str = include_str!("../test_data/log_2892242.log");
|
||||||
|
|
||||||
pub fn parse_benchmark() {
|
pub fn parse_benchmark() {
|
||||||
black_box(parse(black_box(&LOG))).ok();
|
black_box(parse(black_box(LOG))).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_raw() {
|
pub fn parse_raw() {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ handler!(Handler {
|
||||||
});
|
});
|
||||||
|
|
||||||
fn main() -> Result<(), MainError> {
|
fn main() -> Result<(), MainError> {
|
||||||
let path = args().skip(1).next().expect("No path provided");
|
let path = args().nth(1).expect("No path provided");
|
||||||
let content = fs::read_to_string(path)?;
|
let content = fs::read_to_string(path)?;
|
||||||
|
|
||||||
let (
|
let (
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ impl GlobalData for HighestDamageHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), MainError> {
|
fn main() -> Result<(), MainError> {
|
||||||
let path = args().skip(1).next().expect("No path provided");
|
let path = args().nth(1).expect("No path provided");
|
||||||
let content = fs::read_to_string(path)?;
|
let content = fs::read_to_string(path)?;
|
||||||
|
|
||||||
let HighestDamage { user, damage } = parse_with_handler::<HighestDamageHandler>(&content)?
|
let HighestDamage { user, damage } = parse_with_handler::<HighestDamageHandler>(&content)?
|
||||||
|
|
|
||||||
|
|
@ -263,7 +263,7 @@ impl TryFrom<&RawSubject<'_>> for SubjectData {
|
||||||
fn try_from(raw: &RawSubject<'_>) -> Result<Self, Self::Error> {
|
fn try_from(raw: &RawSubject<'_>) -> Result<Self, Self::Error> {
|
||||||
Ok(match raw {
|
Ok(match raw {
|
||||||
RawSubject::Player(raw) => {
|
RawSubject::Player(raw) => {
|
||||||
let (_, (name, user_id, steam_id, team)) =
|
let (name, user_id, steam_id, team) =
|
||||||
split_player_subject(raw).map_err(|_| SubjectError::InvalidUserId)?;
|
split_player_subject(raw).map_err(|_| SubjectError::InvalidUserId)?;
|
||||||
SubjectData::Player {
|
SubjectData::Player {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::event::{param_parse, param_parse_with, position, u_int, ParamIter};
|
use crate::event::{param_parse, param_parse_with, position, u_int, ParamIter};
|
||||||
use crate::raw_event::{subject_parser, RawSubject};
|
use crate::raw_event::{against_subject_parser, RawSubject};
|
||||||
|
|
||||||
use nom::bytes::complete::{tag, take_while};
|
use nom::bytes::complete::{tag, take_while};
|
||||||
use nom::combinator::opt;
|
use nom::combinator::opt;
|
||||||
use nom::number::complete::float;
|
use nom::number::complete::float;
|
||||||
|
|
@ -103,7 +104,7 @@ pub fn point_captures_event_parser(input: &str) -> IResult<&str, PointCapturedEv
|
||||||
(Some((subject_key, subject)), Some((position_key, position_str)))
|
(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") =>
|
||||||
{
|
{
|
||||||
let (_, subject) = subject_parser(subject)?;
|
let (_, subject) = against_subject_parser(subject)?;
|
||||||
let (_, position) = position(position_str)?;
|
let (_, position) = position(position_str)?;
|
||||||
players.push((subject, position));
|
players.push((subject, position));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::event::{param_parse, param_parse_with, quoted, u_int, ParamIter};
|
use crate::event::{param_parse, param_parse_with, quoted, u_int, ParamIter};
|
||||||
use crate::raw_event::{subject_parser, RawSubject};
|
use crate::raw_event::{against_subject_parser, RawSubject};
|
||||||
use nom::combinator::opt;
|
use nom::combinator::opt;
|
||||||
use nom::number::complete::float;
|
use nom::number::complete::float;
|
||||||
use nom::IResult;
|
use nom::IResult;
|
||||||
|
|
@ -11,7 +11,7 @@ pub struct HealedEvent<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn healed_event_parser(input: &str) -> IResult<&str, HealedEvent> {
|
pub fn healed_event_parser(input: &str) -> IResult<&str, HealedEvent> {
|
||||||
let (input, subject) = param_parse_with("against", subject_parser)(input)?;
|
let (input, subject) = param_parse_with("against", against_subject_parser)(input)?;
|
||||||
let (input, amount) = param_parse_with("healing", quoted(u_int))(input)?;
|
let (input, amount) = param_parse_with("healing", quoted(u_int))(input)?;
|
||||||
Ok((
|
Ok((
|
||||||
input,
|
input,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::common::{Class, Team};
|
use crate::common::{Class, Team};
|
||||||
use crate::event::{param_parse, param_parse_with, parse_from_str, position, u_int, ParamIter};
|
use crate::event::{param_parse, param_parse_with, parse_from_str, position, u_int, ParamIter};
|
||||||
use crate::raw_event::{subject_parser, RawSubject};
|
use crate::raw_event::{against_subject_parser, RawSubject};
|
||||||
use nom::combinator::opt;
|
use nom::combinator::opt;
|
||||||
use nom::IResult;
|
use nom::IResult;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
@ -35,7 +35,7 @@ pub struct DamageEvent<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn damage_event_parser(input: &str) -> IResult<&str, DamageEvent> {
|
pub fn damage_event_parser(input: &str) -> IResult<&str, DamageEvent> {
|
||||||
let (input, target) = param_parse_with("against", subject_parser)(input)?;
|
let (input, target) = param_parse_with("against", against_subject_parser)(input)?;
|
||||||
let mut event = DamageEvent {
|
let mut event = DamageEvent {
|
||||||
target,
|
target,
|
||||||
damage: None,
|
damage: None,
|
||||||
|
|
@ -62,7 +62,7 @@ pub struct KillEvent<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kill_event_parser(input: &str) -> IResult<&str, KillEvent> {
|
pub fn kill_event_parser(input: &str) -> IResult<&str, KillEvent> {
|
||||||
let (input, target) = subject_parser(input)?;
|
let (input, target) = against_subject_parser(input)?;
|
||||||
let (input, weapon) = param_parse("with")(input)?;
|
let (input, weapon) = param_parse("with")(input)?;
|
||||||
let mut event = KillEvent {
|
let mut event = KillEvent {
|
||||||
target,
|
target,
|
||||||
|
|
@ -88,7 +88,7 @@ pub struct KillAssistEvent<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn kill_assist_event_parser(input: &str) -> IResult<&str, KillAssistEvent> {
|
pub fn kill_assist_event_parser(input: &str) -> IResult<&str, KillAssistEvent> {
|
||||||
let (input, target) = param_parse_with("against", subject_parser)(input)?;
|
let (input, target) = param_parse_with("against", against_subject_parser)(input)?;
|
||||||
let mut event = KillAssistEvent {
|
let mut event = KillAssistEvent {
|
||||||
target,
|
target,
|
||||||
attacker_position: None,
|
attacker_position: None,
|
||||||
|
|
@ -188,7 +188,7 @@ pub struct DominationEvent<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn domination_event_parser(input: &str) -> IResult<&str, DominationEvent> {
|
pub fn domination_event_parser(input: &str) -> IResult<&str, DominationEvent> {
|
||||||
let (input, against) = param_parse_with("against", subject_parser)(input)?;
|
let (input, against) = param_parse_with("against", against_subject_parser)(input)?;
|
||||||
Ok((input, DominationEvent { against }))
|
Ok((input, DominationEvent { against }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -198,7 +198,7 @@ pub struct RevengeEvent<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn revenge_event_parser(input: &str) -> IResult<&str, RevengeEvent> {
|
pub fn revenge_event_parser(input: &str) -> IResult<&str, RevengeEvent> {
|
||||||
let (input, against) = param_parse_with("against", subject_parser)(input)?;
|
let (input, against) = param_parse_with("against", against_subject_parser)(input)?;
|
||||||
Ok((input, RevengeEvent { against }))
|
Ok((input, RevengeEvent { against }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -235,7 +235,8 @@ pub struct KilledObjectEvent<'a> {
|
||||||
pub fn killed_object_event_parser(input: &str) -> IResult<&str, KilledObjectEvent> {
|
pub fn killed_object_event_parser(input: &str) -> IResult<&str, KilledObjectEvent> {
|
||||||
let (input, object) = opt(param_parse("object"))(input)?;
|
let (input, object) = opt(param_parse("object"))(input)?;
|
||||||
let (input, weapon) = opt(param_parse("weapon"))(input)?;
|
let (input, weapon) = opt(param_parse("weapon"))(input)?;
|
||||||
let (input, object_owner) = opt(param_parse_with("objectowner", subject_parser))(input)?;
|
let (input, object_owner) =
|
||||||
|
opt(param_parse_with("objectowner", against_subject_parser))(input)?;
|
||||||
let (input, attacker_position) = opt(param_parse_with("attacker_position", position))(input)?;
|
let (input, attacker_position) = opt(param_parse_with("attacker_position", position))(input)?;
|
||||||
Ok((
|
Ok((
|
||||||
input,
|
input,
|
||||||
|
|
@ -257,7 +258,7 @@ pub struct ExtinguishedEvent<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extinguished_event_parser(input: &str) -> IResult<&str, ExtinguishedEvent> {
|
pub fn extinguished_event_parser(input: &str) -> IResult<&str, ExtinguishedEvent> {
|
||||||
let (input, against) = param_parse_with("against", subject_parser)(input)?;
|
let (input, against) = param_parse_with("against", against_subject_parser)(input)?;
|
||||||
let (input, with) = param_parse("with")(input)?;
|
let (input, with) = param_parse("with")(input)?;
|
||||||
let (input, attacker_position) = opt(param_parse_with("attacker_position", position))(input)?;
|
let (input, attacker_position) = opt(param_parse_with("attacker_position", position))(input)?;
|
||||||
let (input, victim_position) = opt(param_parse_with("victim_position", position))(input)?;
|
let (input, victim_position) = opt(param_parse_with("victim_position", position))(input)?;
|
||||||
|
|
|
||||||
33
src/lib.rs
33
src/lib.rs
|
|
@ -1,10 +1,13 @@
|
||||||
pub use crate::common::{SteamId3, SubjectData, SubjectError, SubjectId};
|
pub use crate::common::{SteamId3, SubjectData, SubjectError, SubjectId};
|
||||||
use crate::event::GameEventError;
|
use crate::event::GameEventError;
|
||||||
pub use crate::module::EventHandler;
|
pub use crate::module::EventHandler;
|
||||||
use crate::module::{ChatMessages, ClassStatsHandler, HealSpread, PlayerHandler};
|
use crate::module::{
|
||||||
|
ChatMessages, ClassStatsHandler, HealSpread, MedicStatsBuilder, PlayerHandler,
|
||||||
|
};
|
||||||
pub use crate::subjectmap::SubjectMap;
|
pub use crate::subjectmap::SubjectMap;
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
pub use event::{EventMeta, GameEvent};
|
pub use event::{EventMeta, GameEvent};
|
||||||
|
use nom::Err;
|
||||||
pub use raw_event::{RawEvent, RawEventType};
|
pub use raw_event::{RawEvent, RawEventType};
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
@ -20,8 +23,8 @@ mod subjectmap;
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Malformed logfile: {0}")]
|
#[error("Malformed logfile")]
|
||||||
Malformed(nom::error::Error<String>),
|
Malformed,
|
||||||
#[error("Incomplete logfile")]
|
#[error("Incomplete logfile")]
|
||||||
Incomplete,
|
Incomplete,
|
||||||
#[error("Malformed subject: {0}")]
|
#[error("Malformed subject: {0}")]
|
||||||
|
|
@ -29,16 +32,24 @@ pub enum Error {
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
MalformedEvent(#[from] GameEventError),
|
MalformedEvent(#[from] GameEventError),
|
||||||
}
|
}
|
||||||
|
impl From<nom::Err<nom::error::Error<&'_ str>>> for Error {
|
||||||
impl From<nom::error::Error<&'_ str>> for Error {
|
fn from(e: nom::Err<nom::error::Error<&'_ str>>) -> Self {
|
||||||
fn from(e: nom::error::Error<&str>) -> Self {
|
match e {
|
||||||
Error::Malformed(nom::error::Error {
|
Err::Incomplete(_) => Error::Incomplete,
|
||||||
input: e.input.to_string(),
|
Err::Error(_) => Error::Malformed,
|
||||||
code: e.code,
|
Err::Failure(_) => Error::Malformed,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<nom::error::Error<&'_ str>> for Error {
|
||||||
|
fn from(_: nom::error::Error<&str>) -> Self {
|
||||||
|
Error::Malformed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result<O, E = Error> = std::result::Result<O, E>;
|
||||||
|
|
||||||
pub fn parse(
|
pub fn parse(
|
||||||
log: &str,
|
log: &str,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
|
|
@ -113,6 +124,6 @@ pub fn parse_with_handler<Handler: EventHandler>(
|
||||||
handler!(LogHandler {
|
handler!(LogHandler {
|
||||||
chat: ChatMessages,
|
chat: ChatMessages,
|
||||||
heal_spread: PlayerHandler::<HealSpread>,
|
heal_spread: PlayerHandler::<HealSpread>,
|
||||||
// medic_stats: MedicStatsHandler,
|
medic_stats: PlayerHandler::<MedicStatsBuilder>,
|
||||||
class_stats: ClassStatsHandler,
|
class_stats: ClassStatsHandler,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use std::io::stdout;
|
||||||
use tf_log_parser::parse;
|
use tf_log_parser::parse;
|
||||||
|
|
||||||
fn main() -> Result<(), MainError> {
|
fn main() -> Result<(), MainError> {
|
||||||
let path = args().skip(1).next().expect("No path provided");
|
let path = args().nth(1).expect("No path provided");
|
||||||
let content = fs::read_to_string(path)?;
|
let content = fs::read_to_string(path)?;
|
||||||
|
|
||||||
let log = parse(&content)?;
|
let log = parse(&content)?;
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ pub struct ChatMessage {
|
||||||
impl ChatMessage {
|
impl ChatMessage {
|
||||||
fn from_bare(bare: BareChatMessage, subjects: &SubjectMap) -> Self {
|
fn from_bare(bare: BareChatMessage, subjects: &SubjectMap) -> Self {
|
||||||
let (name, steam_id) = match &subjects[bare.subject] {
|
let (name, steam_id) = match &subjects[bare.subject] {
|
||||||
(SubjectData::Player { name, steam_id, .. }, _) => (name.clone(), steam_id.clone()),
|
(SubjectData::Player { name, steam_id, .. }, _) => (name.clone(), *steam_id),
|
||||||
_ => {
|
_ => {
|
||||||
unreachable!("only player messages are added");
|
unreachable!("only player messages are added");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ impl EventHandler for ClassStatsHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_global(self, _subjects: &SubjectMap) -> Self::GlobalOutput {
|
fn finish_global(self, _subjects: &SubjectMap) -> Self::GlobalOutput {
|
||||||
()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_per_subject(
|
fn finish_per_subject(
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ impl FromStr for LobbyLeader {
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
if let Some((name, steam_id)) = s.rsplit_once(" (") {
|
if let Some((name, steam_id)) = s.rsplit_once(" (") {
|
||||||
if let Ok(steam_id) = steam_id.trim_end_matches(")").parse::<u64>() {
|
if let Ok(steam_id) = steam_id.trim_end_matches(')').parse::<u64>() {
|
||||||
Ok(LobbyLeader {
|
Ok(LobbyLeader {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
steam_id: steam_id.into(),
|
steam_id: steam_id.into(),
|
||||||
|
|
@ -90,8 +90,14 @@ pub struct Settings {
|
||||||
|
|
||||||
impl Default for Settings {
|
impl Default for Settings {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
Self::with_id(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Settings {
|
||||||
|
pub fn with_id(id: u32) -> Self {
|
||||||
Settings {
|
Settings {
|
||||||
id: 0,
|
id,
|
||||||
leader: LobbyLeader::default(),
|
leader: LobbyLeader::default(),
|
||||||
map: "".to_string(),
|
map: "".to_string(),
|
||||||
game_type: GameType::Sixes,
|
game_type: GameType::Sixes,
|
||||||
|
|
@ -157,8 +163,7 @@ impl LobbySettingsHandler {
|
||||||
.strip_prefix("TF2Center Lobby #")
|
.strip_prefix("TF2Center Lobby #")
|
||||||
.and_then(|s| str::split_once(s, " |"))
|
.and_then(|s| str::split_once(s, " |"))
|
||||||
{
|
{
|
||||||
let mut settings = Settings::default();
|
let settings = Settings::with_id(id.parse()?);
|
||||||
settings.id = id.parse()?;
|
|
||||||
*self = LobbySettingsHandler::Active(settings);
|
*self = LobbySettingsHandler::Active(settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ impl PlayerSpecificData for MedicStatsBuilder {
|
||||||
}
|
}
|
||||||
GameEvent::MedicDeath(death) => {
|
GameEvent::MedicDeath(death) => {
|
||||||
let charge = death.charge.unwrap_or_default();
|
let charge = death.charge.unwrap_or_default();
|
||||||
if charge >= 95 && charge < 100 {
|
if (95..100).contains(&charge) {
|
||||||
self.near_full_charge_death += 1;
|
self.near_full_charge_death += 1;
|
||||||
} else if charge >= 100 {
|
} else if charge >= 100 {
|
||||||
self.drops += 1;
|
self.drops += 1;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ pub use healspread::HealSpread;
|
||||||
pub use lobbysettings::{
|
pub use lobbysettings::{
|
||||||
LobbySettingsError, LobbySettingsHandler, Location, Settings as LobbySettings,
|
LobbySettingsError, LobbySettingsHandler, Location, Settings as LobbySettings,
|
||||||
};
|
};
|
||||||
pub use medicstats::MedicStats;
|
pub use medicstats::{MedicStats, MedicStatsBuilder};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
|
@ -108,11 +108,11 @@ macro_rules! handler {
|
||||||
paste::paste! {
|
paste::paste! {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct $name {
|
pub struct $name {
|
||||||
$($child: $ty),*
|
pub $($child: $ty),*
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct [<$name GlobalOutput>] {
|
pub struct [<$name GlobalOutput>] {
|
||||||
$($child: <$ty as $crate::EventHandler>::GlobalOutput),*
|
pub $($child: <$ty as $crate::EventHandler>::GlobalOutput),*
|
||||||
}
|
}
|
||||||
|
|
||||||
impl serde::Serialize for [<$name GlobalOutput>] {
|
impl serde::Serialize for [<$name GlobalOutput>] {
|
||||||
|
|
@ -144,7 +144,7 @@ macro_rules! handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct [<$name PerSubjectOutput>] {
|
pub struct [<$name PerSubjectOutput>] {
|
||||||
$($child: <$ty as $crate::EventHandler>::PerSubjectOutput),*
|
pub $($child: <$ty as $crate::EventHandler>::PerSubjectOutput),*
|
||||||
}
|
}
|
||||||
|
|
||||||
impl serde::Serialize for [<$name PerSubjectOutput>] {
|
impl serde::Serialize for [<$name PerSubjectOutput>] {
|
||||||
|
|
@ -235,7 +235,7 @@ impl<T: GlobalData> EventHandler for T {
|
||||||
_subject: &SubjectData,
|
_subject: &SubjectData,
|
||||||
_data: Self::PerSubjectData,
|
_data: Self::PerSubjectData,
|
||||||
) -> Self::PerSubjectOutput {
|
) -> Self::PerSubjectOutput {
|
||||||
()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -270,7 +270,7 @@ impl<T: PlayerSpecificData + Default> EventHandler for PlayerHandler<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_global(self, _subjects: &SubjectMap) -> Self::GlobalOutput {
|
fn finish_global(self, _subjects: &SubjectMap) -> Self::GlobalOutput {
|
||||||
()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_per_subject(
|
fn finish_per_subject(
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
use crate::common::Team;
|
use crate::common::Team;
|
||||||
|
use crate::{Error, Result};
|
||||||
use crate::{SubjectError, SubjectId};
|
use crate::{SubjectError, SubjectId};
|
||||||
use chrono::{NaiveDate, NaiveDateTime};
|
use chrono::{NaiveDate, NaiveDateTime};
|
||||||
use logos::{Lexer, Logos};
|
use logos::{Lexer, Logos};
|
||||||
use nom::bytes::complete::{tag, take, take_while};
|
use nom::{IResult, Needed};
|
||||||
use nom::character::complete::{digit1, one_of};
|
|
||||||
use nom::combinator::opt;
|
|
||||||
use nom::{Finish, IResult, Needed};
|
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
use std::num::ParseIntError;
|
use std::num::ParseIntError;
|
||||||
|
|
||||||
|
|
@ -20,30 +18,24 @@ pub struct RawEvent<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RawEvent<'a> {
|
impl<'a> RawEvent<'a> {
|
||||||
pub fn parse(line: &'a str) -> Result<Self, nom::error::Error<&'a str>> {
|
pub fn parse(line: &'a str) -> Result<Self> {
|
||||||
let (_, event) = event_parser(line).finish()?;
|
event_parser(line)
|
||||||
Ok(event)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn event_parser(input: &str) -> IResult<&str, RawEvent> {
|
fn event_parser(input: &str) -> Result<RawEvent> {
|
||||||
let (input, date) = date_parser(input)?;
|
let date = RawDate(&input[0..21]);
|
||||||
|
|
||||||
let (input, _) = tag(": ")(input)?;
|
let (input, subject) = subject_parser(&input[23..])?;
|
||||||
let (input, subject) = subject_parser(input)?;
|
|
||||||
|
|
||||||
let (input, _) = opt(tag(" "))(input)?;
|
let (input, ty) = event_type_parser(input.trim_start())?;
|
||||||
let (input, ty) = event_type_parser(input)?;
|
|
||||||
|
|
||||||
Ok((
|
Ok(RawEvent {
|
||||||
input,
|
|
||||||
RawEvent {
|
|
||||||
date,
|
date,
|
||||||
subject,
|
subject,
|
||||||
ty,
|
ty,
|
||||||
params: input.trim(),
|
params: input.trim(),
|
||||||
},
|
})
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
|
|
@ -64,11 +56,6 @@ impl<'a> TryFrom<RawDate<'a>> for NaiveDateTime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn date_parser(input: &str) -> IResult<&str, RawDate> {
|
|
||||||
let (input, raw) = take(21usize)(input)?;
|
|
||||||
Ok((input, RawDate(raw)))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_date() {
|
fn test_parse_date() {
|
||||||
let raw = RawDate("08/06/2018 - 21:13:57");
|
let raw = RawDate("08/06/2018 - 21:13:57");
|
||||||
|
|
@ -93,29 +80,40 @@ impl<'a> RawSubject<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn split_player_subject(input: &str) -> IResult<&str, (&str, &str, &str, &str)> {
|
pub fn split_player_subject(input: &str) -> Result<(&str, &str, &str, &str)> {
|
||||||
let (input, name) = take_while(|c| c != '<')(input)?;
|
let mut parts = input.splitn(4, '<');
|
||||||
|
let (name, user_id, steam_id, team) =
|
||||||
|
if let (Some(name), Some(user_id), Some(steam_id), Some(team)) =
|
||||||
|
(parts.next(), parts.next(), parts.next(), parts.next())
|
||||||
|
{
|
||||||
|
(
|
||||||
|
name,
|
||||||
|
&user_id[0..user_id.len() - 1],
|
||||||
|
&steam_id[0..steam_id.len() - 1],
|
||||||
|
&team[0..team.len() - 1],
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return Err(Error::Incomplete);
|
||||||
|
};
|
||||||
|
|
||||||
let (input, _) = one_of("<")(input)?;
|
Ok((name, user_id, steam_id, team))
|
||||||
let (input, user_id) = digit1(input)?;
|
|
||||||
let (input, _) = one_of(">")(input)?;
|
|
||||||
|
|
||||||
let (input, _) = one_of("<")(input)?;
|
|
||||||
let (input, steam_id) = take_while(|c| c != '>')(input)?;
|
|
||||||
let (input, _) = one_of(">")(input)?;
|
|
||||||
|
|
||||||
let (input, _) = one_of("<")(input)?;
|
|
||||||
let (input, team) = take_while(|c| c != '>')(input)?;
|
|
||||||
let (input, _) = one_of(">")(input)?;
|
|
||||||
|
|
||||||
Ok((input, (name, user_id, steam_id, team)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn subject_parser(input: &str) -> IResult<&str, RawSubject> {
|
#[test]
|
||||||
if input.starts_with('"') {
|
fn test_split_player_subject() {
|
||||||
let (player, input) = input[1..]
|
assert_eq!(
|
||||||
.split_once('"')
|
("Fin", "4", "[U:1:129852188]", "Blue"),
|
||||||
.ok_or_else(|| nom::Err::Incomplete(Needed::Unknown))?;
|
split_player_subject("Fin<4><[U:1:129852188]><Blue>").unwrap()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn against_subject_parser(input: &str) -> IResult<&str, RawSubject> {
|
||||||
|
subject_parser(input).map_err(|_| nom::Err::Incomplete(Needed::Unknown))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subject_parser(input: &str) -> Result<(&str, RawSubject)> {
|
||||||
|
if let Some(input) = input.strip_prefix('"') {
|
||||||
|
let (player, input) = input.split_once('"').ok_or(Error::Incomplete)?;
|
||||||
if player.ends_with("e>") {
|
if player.ends_with("e>") {
|
||||||
Ok((input, RawSubject::Console))
|
Ok((input, RawSubject::Console))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -128,15 +126,11 @@ pub fn subject_parser(input: &str) -> IResult<&str, RawSubject> {
|
||||||
} else if &input[6..7] == "b" {
|
} else if &input[6..7] == "b" {
|
||||||
Ok((&input[11..], RawSubject::Team(Team::Blue)))
|
Ok((&input[11..], RawSubject::Team(Team::Blue)))
|
||||||
} else {
|
} else {
|
||||||
let (_, input) = input[7..]
|
let (_, input) = input[7..].split_once('"').ok_or(Error::Incomplete)?;
|
||||||
.split_once('"')
|
|
||||||
.ok_or_else(|| nom::Err::Incomplete(Needed::Unknown))?;
|
|
||||||
Ok((input, RawSubject::Team(Team::Spectator)))
|
Ok((input, RawSubject::Team(Team::Spectator)))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let (system, input) = input
|
let (system, input) = input.split_once(' ').ok_or(Error::Incomplete)?;
|
||||||
.split_once(' ')
|
|
||||||
.ok_or_else(|| nom::Err::Incomplete(Needed::Unknown))?;
|
|
||||||
Ok((input, RawSubject::System(system)))
|
Ok((input, RawSubject::System(system)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -263,7 +257,7 @@ pub enum RawEventType {
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn event_type_parser(input: &str) -> IResult<&str, RawEventType> {
|
fn event_type_parser(input: &str) -> Result<(&str, RawEventType)> {
|
||||||
let mut lexer = Lexer::new(input);
|
let mut lexer = Lexer::new(input);
|
||||||
let ty = lexer.next().unwrap_or(RawEventType::Unknown);
|
let ty = lexer.next().unwrap_or(RawEventType::Unknown);
|
||||||
Ok((lexer.remainder(), ty))
|
Ok((lexer.remainder(), ty))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue