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
//! # Extended Piece Identifier Notation (EPIN)
//!
//! A `no_std`, `unsafe`-free implementation of the
//! [EPIN v1.0.0 specification](https://sashite.dev/specs/epin/1.0.0/).
//!
//! EPIN is a strict superset of [PIN](https://sashite.dev/specs/pin/1.0.0/): it
//! inherits the four PIN attributes (piece name, side, state, terminal status)
//! and adds a single optional trailing marker, the **derivation marker** `'`,
//! which flags whether a piece's style is *native* or *derived*. A token has
//! the shape:
//!
//! ```text
//! <pin>[']        e.g.  K   r'   +K^   -k^'
//! ```
//!
//! matching the anchored regular expression `\A[-+]?[A-Za-z]\^?'?\z`. What
//! "native" and "derived" *mean*, and how a concrete style is resolved, is
//! defined by the surrounding context — EPIN encodes only the flag.
//!
//! This crate is a thin layer over [`sashite_pin`]: an [`Identifier`] is a PIN
//! [`sashite_pin::Identifier`] paired with the native/derived flag. The PIN
//! layer is re-exported (see below) so callers can reach the full PIN API —
//! including the type returned by [`Identifier::pin`] — without declaring
//! `sashite-pin` themselves.
//!
//! ## Example
//!
//! ```
//! # fn main() -> Result<(), sashite_epin::ParseError> {
//! use sashite_epin::{Identifier, Side};
//!
//! let king: Identifier = "+K^'".parse()?;
//! assert_eq!(king.letter().as_char(), 'K');
//! assert_eq!(king.side(), Side::First);
//! assert!(king.is_terminal());
//! assert!(king.is_derived());
//!
//! // The underlying PIN token is one method away.
//! assert_eq!(king.pin().encode().as_str(), "+K^");
//!
//! // Native/derived is a single, idempotent flag.
//! assert_eq!(king.native().encode().as_str(), "+K^");
//! assert_eq!(king.encode().as_str(), "+K^'");
//! # Ok(())
//! # }
//! ```
//!
//! ## Guarantees
//!
//! - **`no_std` and allocation-free:** parsing borrows the input bytes and an
//!   [`Identifier`] is a small `Copy` value; nothing is heap-allocated.
//! - **No `unsafe`:** the crate is built under a forbid-`unsafe` lint policy.
//! - **Single source of truth:** all PIN-level parsing, validation, and
//!   encoding is delegated to [`sashite_pin`]; EPIN only adds the `'` marker.
//! - **No required dependencies beyond PIN:** the optional `serde` feature adds
//!   `serde` (and turns on `sashite-pin/serde`), and keeps the crate `no_std`.

#![no_std]

mod encode;
mod error;
mod identifier;
mod parse;
#[cfg(feature = "serde")]
mod serde_impl;

pub use encode::EncodedEpin;
pub use error::ParseError;
pub use identifier::Identifier;

// The PIN layer EPIN builds upon is re-exported so downstream users can rely on
// the exact same version without declaring `sashite-pin` themselves. The PIN
// identifier (returned by [`Identifier::pin`]) is reachable as
// `sashite_epin::sashite_pin::Identifier`.
pub use sashite_pin;
pub use sashite_pin::{Letter, Side, State};