sashite-sin
SIN (Style Identifier Notation) implementation for Rust.
Overview
This crate implements the SIN Specification v1.0.0.
SIN is a compact, ASCII-only token format that encodes a player identity at the level of notation: the tuple (player side, player style). A single letter carries both — its case encodes the side, and the letter itself is the player-style abbreviation.
<abbr> e.g. W c J s
Because a player's side and style are both fixed for the duration of a match, a SIN token is a stable player identifier. SIN standardizes only the encoding: which letter denotes which style is left to the rule system — see the Game Protocol and Glossary.
Implementation constraints
| Property | Value | Rationale |
|---|---|---|
| Token length | 1 byte | ^[A-Za-z]$ per the specification |
| Closed domain | 52 tokens | 26 letters × 2 sides |
Identifier size |
2 bytes, Copy |
stored inline; parsing and encoding never allocate |
| Dependencies | none required | zero by default; serde is an optional, no_std add-on |
unsafe |
forbidden | the crate is built under a forbid-unsafe lint policy |
| MSRV | 1.81 | for core::error::Error without a std feature |
Installation
Or add it manually to Cargo.toml:
[]
= "1"
Cargo features
serde(off by default) — implementsSerialize/DeserializeforIdentifier, (de)serializing it as its canonical token string (e.g."W"). Enabling it keeps the crateno_std.
[]
= { = "1", = ["serde"] }
Usage
Parsing
use ;
let western: Identifier = "W".parse?; // via FromStr
let chinese = parse?; // via the inherent method
assert_eq!;
assert_eq!;
assert_eq!;
Building from typed components
Construction is infallible: because each component type is valid by construction, every combination denotes a valid token.
use ;
let japanese = new;
assert_eq!;
Encoding and formatting
encode returns an allocation-free, fixed-buffer string view that dereferences
to str; to_char returns the single character; Display writes the same
canonical form.
use Identifier;
let id = parse?;
assert_eq!;
assert_eq!;
assert_eq!; // requires `alloc`/`std`
Validation
use Identifier;
assert!;
assert!; // a token is exactly one letter
Transformations and queries
Every transformation returns a new value (the type is Copy, so this is cheap):
use ;
let western = parse?;
assert_eq!;
assert_eq!;
assert!;
Token format
The grammar (EBNF) is:
sin ::= abbr ;
abbr ::= "A"…"Z" | "a"…"z" ;
A token maps to exactly two attributes:
| Component | Encodes | Values |
|---|---|---|
| letter case | side | uppercase → First, lowercase → Second |
| letter | player style | a single-letter abbreviation (A–Z) |
Letters are not reserved: the mapping from abbreviation to full style name is defined entirely by the rule system. See the examples page for the conventional mappings (Western, Chinese, Japanese, Siamese).
Design and guarantees
no_stdand allocation-free. Parsing borrows the input bytes; anIdentifieris a 2-byteCopyvalue andEncodedSinkeeps the single output byte in a fixed inline buffer. Nothing touches the heap.- No
unsafe, no regex engine. The parser matches raw bytes directly, eliminating ReDoS as an attack vector. - Bounded, panic-free parsing. Inputs longer than one byte are rejected on a
structural length check before any byte is inspected, and the public parsing
API returns a
Resultrather than panicking. const-friendly. Construction, parsing, validation, the accessors, and the transformations are allconst fn, so identifiers can be built and checked at compile time.- Total component construction. With valid-by-construction component types, building an identifier from its parts cannot fail.
Performance
The hot paths are tiny: parsing is a length check followed by a single byte
classification, and encoding writes one byte — expect single-digit nanoseconds
per call. Run cargo bench (see benches/parse.rs) for figures on your own
hardware.
Related specifications
- Game Protocol — the conceptual foundation
- SIN Specification v1.0.0 — the normative document
- SIN Examples — sample style mappings
Reference implementations in other languages are maintained by Sashité: Elixir, Ruby.
If a library's behavior appears to conflict with the specification, the specification is normative.
License
Available as open source under the terms of the Apache License 2.0.