sashite-sin 1.1.0

Style Identifier Notation (SIN): a compact, ASCII-only, no_std token encoding a player's side and style in abstract strategy board games.
Documentation
//! Errors produced when parsing a SIN token.

/// The reason a string could not be parsed as a SIN token.
///
/// Returned by the parsing entry points ([`crate::Identifier::parse`],
/// [`core::str::FromStr`], [`TryFrom`]) and by [`crate::Letter::try_from_char`].
///
/// This enum is `#[non_exhaustive]`: future revisions may add variants without
/// a breaking change, so downstream `match` expressions should include a
/// wildcard arm.
///
/// # Length is measured in bytes
///
/// A valid token is one ASCII letter, which is always exactly one byte, so the
/// parser can decide on the byte length before looking at any content. The
/// consequence is worth knowing when reading the variant back: an input of one
/// *character* that occupies several *bytes* — any non-ASCII character, such as
/// `é` — is reported as [`TooLong`](Self::TooLong), not as
/// [`InvalidLetter`](Self::InvalidLetter). Both say "this is not a token", and
/// the specification requires only that such input be rejected; only the
/// reported reason differs.
///
/// The rule is exact: [`InvalidLetter`](Self::InvalidLetter) means the input
/// was one byte that was not an ASCII letter, and [`TooLong`](Self::TooLong)
/// means it was two bytes or more.
///
/// # Examples
///
/// ```
/// use sashite_sin::{Identifier, ParseError};
///
/// assert_eq!("".parse::<Identifier>(), Err(ParseError::Empty));
/// assert_eq!("CC".parse::<Identifier>(), Err(ParseError::TooLong));
/// assert_eq!("1".parse::<Identifier>(), Err(ParseError::InvalidLetter));
///
/// // One character, two bytes: rejected as too long.
/// assert_eq!("é".chars().count(), 1);
/// assert_eq!("é".parse::<Identifier>(), Err(ParseError::TooLong));
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ParseError {
    /// The input was empty.
    Empty,
    /// The input was two bytes or more, and a token is exactly one.
    ///
    /// Because the check counts bytes, this also covers an input of a single
    /// non-ASCII character; see the note on the enum itself.
    TooLong,
    /// The input was a single byte that was not an ASCII letter.
    InvalidLetter,
}

impl core::fmt::Display for ParseError {
    /// Writes a short, human-readable reason.
    ///
    /// The message goes out through [`core::fmt::Formatter::pad`], so width,
    /// fill, alignment and precision behave as they do for the equivalent
    /// [`str`]; writing it straight to the buffer would silently discard those
    /// options when a caller lines errors up in a column.
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        let message = match self {
            Self::Empty => "empty SIN token",
            Self::TooLong => "SIN token longer than one byte",
            Self::InvalidLetter => "SIN token must contain exactly one ASCII letter",
        };
        f.pad(message)
    }
}

impl core::error::Error for ParseError {}