1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//! # Style Identifier Notation (SIN)
//!
//! A `no_std`, `unsafe`-free implementation of the
//! [SIN v1.0.0 specification](https://sashite.dev/specs/sin/1.0.0/).
//!
//! SIN is a compact, ASCII-only token that encodes a player's identity — the
//! pair (player side, player style) — at the level of notation. A token has the
//! shape:
//!
//! ```text
//! <abbr>
//! ```
//!
//! matching the anchored regular expression `^[A-Za-z]$`, and maps to exactly
//! two attributes:
//!
//! | Component | Encodes | Values |
//! |-------------|------------|-------------------------------------------|
//! | letter case | [`Side`] | uppercase → `First`, lowercase → `Second` |
//! | letter | [`Letter`] | the player-style abbreviation (`A`–`Z`) |
//!
//! SIN standardizes only the *encoding*; which letter denotes which style is
//! left to the rule system. See the [glossary](https://sashite.dev/glossary/).
//!
//! ## Validity
//!
//! The anchors bind the *whole* string, not a line within it: a token is one
//! ASCII letter and nothing else. Nothing is trimmed, no surrounding
//! whitespace is tolerated, and a trailing `\r` or `\n` is never absorbed — so
//! `"W"` parses while `" W"`, `"W "` and `"W\n"` do not. Validation is strict
//! and never normalizes: parsing a token and encoding it again reproduces the
//! original text byte for byte.
//!
//! That makes the domain closed and small — 26 letters × 2 sides = 52 tokens,
//! and nothing else is valid at any length.
//!
//! ## Example
//!
//! ```
//! # fn main() -> Result<(), sashite_sin::ParseError> {
//! use sashite_sin::{Identifier, Side};
//!
//! let western: Identifier = "W".parse()?;
//! assert_eq!(western.letter().as_char(), 'W');
//! assert_eq!(western.side(), Side::First);
//!
//! // A SIN token is exactly one character.
//! assert_eq!(western.to_char(), 'W');
//! assert_eq!(western.encode().as_str(), "W");
//!
//! // Cheap, infallible transformations (the type is `Copy`).
//! assert_eq!(western.flipped().to_char(), 'w');
//! # Ok(())
//! # }
//! ```
//!
//! ## Guarantees
//!
//! - **`no_std` and allocation-free:** parsing borrows the input bytes and an
//! [`Identifier`] is a 2-byte `Copy` value; nothing is heap-allocated.
//! - **No `unsafe`:** the crate is built under a forbid-`unsafe` lint policy.
//! - **Bounded, panic-free parsing:** inputs longer than one byte are rejected
//! before inspection, and the public parsing API never panics — including
//! [`TryFrom<&[u8]>`](Identifier), which accepts arbitrary bytes and needs no
//! UTF-8 check to reject them safely.
//! - **One notion of validity:** every entry point ([`Identifier::parse`],
//! [`Identifier::is_valid`], [`core::str::FromStr`] and both [`TryFrom`]
//! impls) returns the same answer, down to the [`ParseError`] variant.
//! - **No required dependencies:** SIN is self-contained, so the default build
//! has an empty dependency graph; the optional `serde` feature adds `serde`
//! (kept `no_std`).
pub use crateEncodedSin;
pub use crateParseError;
pub use crateIdentifier;
pub use crateLetter;
pub use crateSide;