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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! # Field Expression Encoding Notation (FEEN)
//!
//! A `no_std`, `unsafe`-free, allocation-free implementation of the
//! [FEEN v1.0.0 specification](https://sashite.dev/specs/feen/1.0.0/), built on
//! [EPIN](https://sashite.dev/specs/epin/1.0.0/) (piece tokens) and
//! [SIN](https://sashite.dev/specs/sin/1.0.0/) (style tokens).
//!
//! FEEN encodes a complete board-game **position** as three space-separated
//! fields:
//!
//! ```text
//! <piece-placement> <hands> <style-turn>
//! ```
//!
//! for example the chess starting position
//! `-rnbqk^bn-r/+p+p+p+p+p+p+p+p/8/8/8/8/+P+P+P+P+P+P+P+P/-RNBQK^BN-R / C/c`.
//!
//! ## Allocation-free by design
//!
//! Unlike a fixed-size token, a position is variable-sized, so this crate is
//! built as a **borrowing, streaming validator** rather than a parser that
//! returns an owned value:
//!
//! - [`Feen::parse`] validates an input string in a single pass and returns a
//! [`Feen`] *view* that borrows it — nothing is materialized, nothing is
//! allocated.
//! - The view exposes the geometry ([`Feen::shape`]), the square and piece
//! counts, the active player, and **lazy iterators** over board squares and
//! hand items.
//! - An owned position is available behind the `alloc` feature as a
//! [`sashite_qi::Qi`], produced by [`Feen::to_qi`]; [`encode`] turns one back
//! into a canonical FEEN string. That conversion is the only part of the crate
//! that allocates.
//!
//! The default build does not even link the `alloc` crate.
//!
//! ## Bounds (assumed for safety)
//!
//! Inputs are bounded before and during parsing, which keeps memory and time
//! bounded even on untrusted input:
//!
//! - at most [`MAX_STRING_LENGTH`] bytes (checked before any parsing),
//! - at most [`MAX_DIMENSIONS`] board dimensions,
//! - at most [`MAX_DIMENSION_SIZE`] cells along any dimension,
//! - **regular shapes only**: every rank within a dimension has the same length.
//!
//! The last point makes this crate intentionally *stricter* than the FEEN
//! specification, which also permits irregular boards: such inputs are rejected
//! with [`ParseError::BoardNotRegular`].
//!
//! ## Example
//!
//! ```
//! # fn main() -> Result<(), sashite_feen::ParseError> {
//! use sashite_feen::{Feen, Side};
//!
//! let feen = Feen::parse("8/8/8/8/8/8/8/8 / C/c")?;
//! assert_eq!(feen.square_count(), 64);
//! assert_eq!(feen.piece_count(), 0);
//! assert_eq!(feen.active_side(), Side::First);
//!
//! assert!(Feen::is_valid("k^+p4+PK^ / C/c")); // a 1D, 8-square board
//! # Ok(())
//! # }
//! ```
//!
//! ## Guarantees
//!
//! - **`no_std` and allocation-free core.** Validation and iteration borrow the
//! input; nothing touches the heap unless the `alloc` feature is used.
//! - **No `unsafe`, no regex engine.** Parsing is a single left-to-right pass
//! over raw bytes, with bounded integer arithmetic.
//! - **Built on EPIN and SIN.** Piece and style tokens are validated by those
//! crates; FEEN adds only the field, dimensional, canonicality, and
//! cardinality rules.
// `no_std` for every normal build; under `cargo test` the crate links `std` so
// the unit-test harness (and the in-module unit tests) can run. Consumers and
// the `no_std` CI job (which builds `--lib`, not tests) still get `no_std`.
extern crate alloc;
/// Re-export of the [`sashite_epin`] crate, which provides the piece-token type
/// surfaced by this crate's board and hand iterators.
pub use sashite_epin;
/// Re-export of the [`sashite_sin`] crate, which provides the style-token type
/// surfaced by the style–turn accessors.
pub use sashite_sin;
/// Re-export of the [`sashite_qi`] crate, whose [`Qi`](sashite_qi::Qi) is the
/// owned position type produced by [`Feen::to_qi`]. Available with the `alloc`
/// feature.
pub use sashite_qi;
/// The two-side model (`First` / `second`) shared across the ecosystem,
/// re-exported from [`sashite_sin`]. Used here for the active player and the
/// hand attribution.
pub use Side;
pub use crateParseError;
pub use crate;
pub use crate;
pub use crate;
pub use crateShape;
/// Canonical FEEN serialization of an owned [`Qi`](sashite_qi::Qi) position.
/// Available with the `alloc` feature.
pub use crate;
/// A `#[serde(with = "…")]` adapter that (de)serializes a
/// [`Qi`](sashite_qi::Qi) position as its canonical FEEN string. Available with
/// the `serde` feature.
pub use cratefeen_string;