Skip to content

Commit

Permalink
More work, fix todoes, realise I have to refactor everything
Browse files Browse the repository at this point in the history
  • Loading branch information
Virinas-code committed Oct 22, 2024
1 parent c9628ba commit 2e4568b
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 58 deletions.
2 changes: 1 addition & 1 deletion examples/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ fn main() {
let contents = fs::read_to_string(FILE_NAME);

match contents {
Ok(c) => println!("{:#?}", Situation::try_from(c)),
Ok(c) => println!("{:?}", Situation::try_from(c)),
Err(_) => eprintln!("Failed to open file"),
}
}
12 changes: 10 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@
clippy::all,
clippy::pedantic,
clippy::nursery,
clippy::cargo
clippy::cargo,
clippy::indexing_slicing
)]
#![feature(iter_next_chunk)]

use std::{error::Error, str::Split};

Expand Down Expand Up @@ -65,7 +67,13 @@ impl TryFrom<String> for Situation {
type Error = Box<dyn Error>;

fn try_from(value: String) -> Result<Self, Self::Error> {
let lines: Split<'_, char> = value.split('\n'); // TODO: Use FIDE's \r (ew)
let split_char: char = if value.contains('\r') {
'\r'
} else {
eprintln!("Using non-FIDE \\n line separator");
'\n'
};
let lines: Split<'_, char> = value.split(split_char);

let mut players: Vec<Section> = vec![];

Expand Down
17 changes: 16 additions & 1 deletion src/trf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub mod player;
///
/// Most of the time those don't stop the parser, but they are stored inside of
/// [`Result`] in the struct instead.
#[derive(Error, Debug)]
#[derive(Error, Debug, Clone)]
pub enum TRFError {
/// Error when the gender is invalid (neither "m" nor "w" nor empty).
#[error("Expected a valid gender, found string {0}")]
Expand All @@ -41,6 +41,21 @@ pub enum TRFError {
#[error("Expected a valid date, found string {0}")]
InvalidDateError(String),

/// Error when the player round color is invalid (neither "w" nor "b" nor "-" nor
/// empty).
#[error("Expected a valid color, found string {0}")]
InvalidColorError(String),

/// Error when a round result is invalid.
///
/// See [`crate::trf::player::round::Result`].
#[error("Expected a valid round result, found string {0}")]
InvalidRoundResultError(String),

/// Error when a player's round section isn't the right length.
#[error("A player round section must be 7 characters long, found string {0}")]
PlayerRoundSectionTooShort(String),

/// Error when the parser can't parse an integer.
#[error("Expected a valid integer: {0}")]
ParseIntError(#[from] ParseIntError),
Expand Down
55 changes: 35 additions & 20 deletions src/trf/player/fields.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,16 @@ pub enum Sex {
///
/// > Note: In most TRF files a different format seems to be used ("m", "g"???).
#[derive(Debug)]
#[allow(clippy::upper_case_acronyms, missing_docs)] // F it
#[allow(missing_docs)] // F it
pub enum Title {
GM,
IM,
WGM,
FM,
WIM,
CM,
WFM,
WCM,
Grandmaster,
InternationalMaster,
WomanGrandmaster,
FIDEMaster,
WomanInternationalMaster,
CandidateMaster,
WomanFIDEMaster,
WomanCandidateMaster,
}

impl TryFrom<&str> for Title {
Expand All @@ -43,14 +43,14 @@ impl TryFrom<&str> for Title {
// TODO: Parse weird format ('m', 'g')??

Ok(match value {
"GM" => Self::GM,
"IM" => Self::IM,
"WGM" => Self::WGM,
"FM" => Self::FM,
"WIM" => Self::WIM,
"CM" => Self::CM,
"WFM" => Self::WFM,
"WCM" => Self::WCM,
"GM" => Self::Grandmaster,
"IM" => Self::InternationalMaster,
"WGM" => Self::WomanGrandmaster,
"FM" => Self::FIDEMaster,
"WIM" => Self::WomanInternationalMaster,
"CM" => Self::CandidateMaster,
"WFM" => Self::WomanFIDEMaster,
"WCM" => Self::WomanCandidateMaster,
other => return Err(TRFError::InvalidTitleError(other.to_string())),
})
}
Expand Down Expand Up @@ -157,13 +157,28 @@ impl TryFrom<&str> for Date {
};

Ok(Self {
year: parse_number(parts[0]).and_then(|option| {
year: parse_number(
parts
.first()
.ok_or_else(|| TRFError::InvalidDateError(value.to_string()))?,
)
.and_then(|option| {
option.ok_or_else(|| TRFError::InvalidDateError(value.to_string()))
})?,
month: parse_number(parts[1]).and_then(|option| {
month: parse_number(
parts
.get(1)
.ok_or_else(|| TRFError::InvalidDateError(value.to_string()))?,
)
.and_then(|option| {
option.ok_or_else(|| TRFError::InvalidDateError(value.to_string()))
})?,
day: parse_number(parts[2]).and_then(|option| {
day: parse_number(
parts
.get(2)
.ok_or_else(|| TRFError::InvalidDateError(value.to_string()))?,
)
.and_then(|option| {
option.ok_or_else(|| TRFError::InvalidDateError(value.to_string()))
})?,
})
Expand Down
6 changes: 2 additions & 4 deletions src/trf/player/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,7 @@ pub struct Section {
/// Exact definition, especially for Team.
///
/// > I don't know what any of this means...
///
/// TODO: Use [`Result<Option>`]
rank: Option<u16>,
rank: Result<Option<u16>, TRFError>,

/// Information about each round played by the player in the tournament.
///
Expand Down Expand Up @@ -147,7 +145,7 @@ impl TryFrom<String> for Section {
other => Date::try_from(other).map(Some),
}, // [65..75]
points: parse_number(&value[76..80]),
rank: value[81..85].trim().parse::<u16>().ok(),
rank: parse_number(&value[81..85]),
rounds,
})
}
Expand Down
67 changes: 38 additions & 29 deletions src/trf/player/round.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
//!
//! Getter methods are available to retrieve information. Currently no setter methods are
//! available.
use std::error::Error;
use crate::trf::TRFError;

use super::utils::{parse_into, parse_number};

/// Scheduled color or forfeit in round.
#[derive(Debug, Copy, Clone)]
Expand All @@ -26,15 +28,15 @@ pub enum Color {
}

impl TryFrom<&str> for Color {
type Error = Box<dyn Error>;
type Error = TRFError;

fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
Ok(match value {
"w" => Self::White,
"b" => Self::Black,
"-" | " " => Self::None,

other => return Err(Box::from(format!("Invalid round color: {other}"))),
other => return Err(TRFError::InvalidColorError(other.to_string())),
})
}
}
Expand All @@ -56,7 +58,7 @@ pub enum Result {
}

impl TryFrom<&str> for Result {
type Error = Box<dyn Error>;
type Error = TRFError;

fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
Ok(match value.to_uppercase().as_str() {
Expand All @@ -76,7 +78,7 @@ impl TryFrom<&str> for Result {
"U" => Self::Bye(ByeRoundResult::PairingAllocatedBye),
"Z" | " " => Self::Bye(ByeRoundResult::ZeroPointBye),

other => return Err(Box::from(format!("Invalid round result: {other}"))),
other => return Err(TRFError::InvalidRoundResultError(other.to_string())),
})
}
}
Expand Down Expand Up @@ -211,55 +213,62 @@ impl From<ByeRoundResult> for String {
/// A player's single round result.
///
/// > **TODO:** Use Result
#[derive(Debug, Copy, Clone)]
#[derive(Debug)]
pub struct PlayerRoundSection {
/// Player or forfeit id.
id: Option<u16>,
id: std::result::Result<Option<u16>, TRFError>,

/// Scheduled color or forfeit.
color: Option<Color>,
color: std::result::Result<Option<Color>, TRFError>,

/// Result.
result: Option<Result>,
result: std::result::Result<Option<Result>, TRFError>,
}

impl PlayerRoundSection {
/// Get the player id or forfeit
#[must_use]
pub const fn id(&self) -> Option<u16> {
self.id
/// Get the player or forfeit id.
///
/// # Errors
///
/// This field is [`Err`] if the parsed value isn't a valid number.
pub const fn id(&self) -> std::result::Result<&Option<u16>, &TRFError> {
self.id.as_ref()
}

/// Get the scheduled color or forfeit
#[must_use]
pub const fn color(&self) -> Option<Color> {
self.color
/// Get the scheduled color or forfeit.
///
/// # Errors
///
/// This field is [`Err`] if the parsed value isn't a valid color. See [`Color`].
pub const fn color(&self) -> std::result::Result<&Option<Color>, &TRFError> {
self.color.as_ref()
}

/// Get the round result
#[must_use]
pub const fn result(&self) -> Option<Result> {
self.result
/// Get the round result.
///
/// # Errors
///
/// This field is [`Err`] if the parsed value isn't a valid result. See [`Result`].
pub const fn result(&self) -> std::result::Result<&Option<Result>, &TRFError> {
self.result.as_ref()
}
}

impl TryFrom<&str> for PlayerRoundSection {
type Error = Box<dyn Error>;
type Error = TRFError;

fn try_from(value: &str) -> std::result::Result<Self, Self::Error> {
if value.len() < 7 {
return Err(Box::from(
"At least 7 characters are required to parse a player round section",
));
return Err(TRFError::PlayerRoundSectionTooShort(value.to_string()));
};

Ok(Self {
id: match value[0..4].trim() {
"0000" | "" => None,
other => other.parse::<u16>().ok(),
"0000" | "" => Ok(None),
other => parse_number(other),
},
color: Color::try_from(&value[5..6]).ok(),
result: Result::try_from(&value[7..8]).ok(),
color: parse_into(&value[5..6]),
result: parse_into(&value[7..8]),
})
}
}
2 changes: 1 addition & 1 deletion test_file.trf
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ DAT 7 EMAIL [email protected]

001 8 m Bailleul, Geert 0 BEL 225185 1956/00/00 3 b 0 9 w 1 1 b 1
001 9 w Prokopova, Jirina 0 CZE 337994 1992/00/00 4 w 0 8 b 0 2 w 1
001 10 w Tzegka, Ismini 0 GRE 4273613 1989/00/00 5 b = 1 w = 7 b 1
001 10 w Tzegka, Ismini 0 GRE 4273613 1989/00/00 5 b = 1 w ù 7 b 1


001 -1 a ff Test01, Testin u GRE 4273613 1989/00/00 5 b = 1 w = 7 b 1
Expand Down

0 comments on commit 2e4568b

Please sign in to comment.