Skip to main content

Crate sashite_epin

Crate sashite_epin 

Source
Expand description

§Extended Piece Identifier Notation (EPIN)

A no_std, unsafe-free implementation of the EPIN v1.0.0 specification.

EPIN is a strict superset of PIN: 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:

<pin>[']        e.g.  K   r'   +K^   -k^'

matching the anchored regular expression \A[-+]?[A-Za-z]\^?'?\z. The anchors apply to the whole input, never to a line within it, so anything carrying a \r or \n is rejected. The domain is closed and small: 624 tokens, the 312 PIN identifiers taken native and derived. 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 Re-exports) so callers can reach the full PIN API — including the type returned by Identifier::pin — without declaring sashite-pin themselves.

§Example

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^'");

§Guarantees

  • no_std and allocation-free: the parser reads a borrowed slice without copying it, an Identifier is a 5-byte Copy value that borrows nothing, and EncodedEpin holds its at-most-four output bytes in an inline buffer. Nothing touches the heap, and the crate needs no alloc.
  • No unsafe: the crate is built under a forbid-unsafe lint policy.
  • Panic-free parsing: every entry point returns a ParseError rather than panicking, for any input — including bytes that are not valid UTF-8. The parser performs no indexing and no arithmetic at all, and tests/conformance.rs exercises it over every byte string up to three bytes, every byte value at every position of a four-byte string, and every Unicode scalar.
  • 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.

§What is, and is not, const

sashite_pin is const end to end — a PIN token can be parsed, checked and spelled out at compile time. EPIN inherits only part of that: Identifier::new, every accessor (including Identifier::pin) and the native / derive / with_pin transforms are const fn, so a const PIN core lifts into a const EPIN identifier:

use sashite_epin::{sashite_pin::Identifier as Pin, Identifier};

const CORE: Pin = match Pin::parse("+K^") {
    Ok(pin) => pin,
    Err(_) => panic!("\"+K^\" is a valid PIN token"),
};
const KING: Identifier = Identifier::new(CORE, true);
const IS_DERIVED: bool = KING.is_derived();

Identifier::parse, Identifier::is_valid and Identifier::encode are not const, so const TOKEN: Identifier = Identifier::parse("+K^'") does not compile. The obstacles are in the standard library, not in the design: at this crate’s 1.81 MSRV, parsing may call neither <[u8]>::contains (the misplaced-marker check) nor a TryFrom implementation (how the core reaches PIN) from a const fn, and encoding may neither iterate PIN’s encoded bytes with a for loop nor index the output buffer. Parse at run time, or build from a const PIN core as above.

Re-exports§

pub use sashite_pin;

Structs§

EncodedEpin
The canonical string form of an Identifier, stored inline.
Identifier
A parsed EPIN token: a PIN identity plus a native/derived style flag.
Letter
The PIN attribute types, re-exported because they appear throughout EPIN’s own API: Identifier::letter, Identifier::side and Identifier::state return them. The single-letter abbreviation of a piece name.

Enums§

ParseError
The reason a string could not be parsed as an EPIN token.
Side
The PIN attribute types, re-exported because they appear throughout EPIN’s own API: Identifier::letter, Identifier::side and Identifier::state return them. The camp a piece belongs to.
State
The PIN attribute types, re-exported because they appear throughout EPIN’s own API: Identifier::letter, Identifier::side and Identifier::state return them. The state of a piece, encoded by the optional + / - prefix.