diff --git a/src/run/parser/flitter.rs b/src/run/parser/flitter.rs new file mode 100644 index 00000000..d9af8f10 --- /dev/null +++ b/src/run/parser/flitter.rs @@ -0,0 +1,134 @@ +//! Provides the parser for Flitter splits files. + +use crate::{ + platform::prelude::*, + timing::{parse_custom, CustomParser}, + Run, Segment, Time, +}; +use alloc::borrow::Cow; +use core::result::Result as StdResult; +use serde_derive::Deserialize; +use serde_json::Error as JsonError; +use snafu::ensure; + +/// The Error type for splits files that couldn't be parsed by the Flitter +/// Parser. +#[derive(Debug, snafu::Snafu)] +#[snafu(context(suffix(false)))] +pub enum Error { + /// Failed to parse JSON. + Json { + /// The underlying error. + #[cfg_attr(not(feature = "std"), snafu(source(false)))] + source: JsonError, + }, + /// The split names can't be empty. + SplitNamesEmpty, + /// The personal best can't be empty. + PersonalBestEmpty, + /// The golds can't be empty. + GoldsEmpty, + /// The split name count does not match the gold count. + GoldCountMismatch, + /// The split name count does not match the personal best split count. + PersonalBestCountMismatch, + /// The last split of the personal best can't be null. + LastSplitNull, +} + +/// The Result type for the Flitter Parser. +pub type Result = StdResult; + +#[derive(Deserialize)] +struct Splits<'a> { + #[serde(borrow)] + title: Cow<'a, str>, + #[serde(borrow)] + category: Cow<'a, str>, + attempts: u32, + // completed: u32, + #[serde(borrow)] + split_names: Vec>, + #[serde(borrow)] + golds: Vec>>, + #[serde(borrow)] + personal_best: PersonalBest<'a>, +} + +#[derive(Deserialize)] +struct Gold<'a> { + #[serde(borrow)] + duration: Cow<'a, str>, +} + +#[derive(Deserialize)] +struct PersonalBest<'a> { + // attempt: u32, + #[serde(borrow)] + splits: Vec>>, +} + +#[derive(Deserialize)] +struct Split<'a> { + #[serde(borrow)] + time: Cow<'a, str>, +} + +struct FlitterParser; + +impl CustomParser for FlitterParser { + const ASCII_ONLY: bool = true; + const ALLOW_NEGATIVE: bool = false; + const WITH_DAYS: bool = true; +} + +fn parse_time(real_time: &str) -> Option