sashite-epin 1.0.0

Extended Piece Identifier Notation (EPIN): a compact, ASCII-only, no_std token format that extends PIN with a native/derived style marker for abstract strategy board games.
Documentation
//! Errors produced when parsing an EPIN token.

/// The reason a string could not be parsed as an EPIN token.
///
/// An EPIN token is a PIN token followed by an optional derivation marker
/// (`'`). Parsing can fail either because the PIN core is invalid — in which
/// case the underlying [`sashite_pin::ParseError`] is carried in [`Pin`] — or
/// because the derivation marker is misplaced ([`DerivationMarker`]).
///
/// This enum is `#[non_exhaustive]`: future revisions may add variants without
/// a breaking change, so downstream `match` expressions should include a
/// wildcard arm.
///
/// [`Pin`]: ParseError::Pin
/// [`DerivationMarker`]: ParseError::DerivationMarker
///
/// # Examples
///
/// ```
/// use sashite_epin::{Identifier, ParseError};
/// use sashite_pin::ParseError as PinError;
///
/// // A misplaced or duplicated derivation marker.
/// assert_eq!("K'^".parse::<Identifier>(), Err(ParseError::DerivationMarker));
///
/// // A failure in the PIN core is wrapped, preserving the original reason.
/// assert_eq!(
///     "".parse::<Identifier>(),
///     Err(ParseError::Pin(PinError::Empty)),
/// );
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum ParseError {
    /// The core PIN token (with any trailing derivation marker removed) was
    /// itself invalid; the wrapped error gives the precise reason.
    Pin(sashite_pin::ParseError),
    /// A derivation marker (`'`) appeared somewhere other than as the final
    /// character. It must be last, and may appear at most once.
    DerivationMarker,
}

impl core::fmt::Display for ParseError {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            Self::Pin(source) => write!(f, "invalid EPIN core: {source}"),
            Self::DerivationMarker => {
                f.write_str("EPIN derivation marker (') must be the final character")
            }
        }
    }
}

impl core::error::Error for ParseError {
    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
        match self {
            Self::Pin(source) => Some(source),
            Self::DerivationMarker => None,
        }
    }
}

impl From<sashite_pin::ParseError> for ParseError {
    fn from(source: sashite_pin::ParseError) -> Self {
        Self::Pin(source)
    }
}