takparse/
lib.rs

1//! `takparse` is a library which provides helpful types and functions
2//! for parsing objects related to the abstract strategy board game Tak.
3#![warn(missing_docs)]
4#![warn(clippy::pedantic, clippy::nursery, clippy::style)]
5
6#[cfg(test)]
7mod test_utils;
8
9mod file;
10mod ptn;
11mod tps;
12
13pub use file::*;
14pub use ptn::*;
15pub use tps::*;
16
17use std::{
18    error::Error,
19    fmt::{Display, Formatter, Result as FmtResult},
20    str::FromStr,
21};
22
23// TODO: serde, tests
24
25/// Enum representing the piece type.
26#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
27pub enum Piece {
28    /// Flat stone
29    Flat,
30    /// Wall, also known as standing stone
31    Wall,
32    /// Capstone
33    Cap,
34}
35
36impl Default for Piece {
37    fn default() -> Self {
38        Self::Flat
39    }
40}
41
42impl Display for Piece {
43    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
44        match self {
45            Self::Flat => "",
46            Self::Wall => "S",
47            Self::Cap => "C",
48        }
49        .fmt(f)
50    }
51}
52
53/// Error returned when something goes wrong during the parsing of a [`Piece`].
54#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
55pub enum ParsePieceError {
56    /// Pieces should only be single characters. This variant is returned when a piece is not a single character.
57    TooLong,
58    /// Pieces should be one of 'F', 'S', and 'C'. If they are not, this variant is returned.
59    BadChar,
60}
61
62impl Error for ParsePieceError {}
63
64impl Display for ParsePieceError {
65    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
66        match self {
67            Self::TooLong => "piece consisted of multiple characters",
68            Self::BadChar => "unknown piece character (not 'F', 'S', 'C')",
69        }
70        .fmt(f)
71    }
72}
73
74impl FromStr for Piece {
75    type Err = ParsePieceError;
76
77    fn from_str(s: &str) -> Result<Self, Self::Err> {
78        let mut chars = s.chars();
79
80        let c = chars.next();
81
82        if chars.next().is_some() {
83            Err(ParsePieceError::TooLong)?;
84        }
85
86        Ok(match c.unwrap_or('F') {
87            'F' => Self::Flat,
88            'S' => Self::Wall,
89            'C' => Self::Cap,
90            _ => Err(ParsePieceError::BadChar)?,
91        })
92    }
93}