nexus_ascii/lib.rs
1//! Fixed-capacity ASCII strings for high-performance systems.
2//!
3//! This crate provides stack-allocated, fixed-capacity ASCII string types
4//! optimized for trading systems and other latency-sensitive applications.
5//!
6//! # `no_std` Support
7//!
8//! This crate is `no_std` compatible by default. Enable the `std` feature
9//! for `Error` trait implementations.
10//!
11//! # Design Principles
12//!
13//! - **Immutable**: Strings are immutable after creation. Hash is computed once.
14//! - **Copy**: All string types are `Copy`. Use newtypes for move semantics.
15//! - **Performance**: Single 64-bit comparison for equality fast path.
16//! - **Full ASCII**: Supports 0x01-0x7F (null is structural, not content). Use `AsciiText` for printable-only.
17//!
18//! # Example
19//!
20//! ```
21//! use nexus_ascii::{AsciiString, AsciiError};
22//!
23//! // Construction
24//! let s: AsciiString<32> = AsciiString::try_from("BTC-USD")?;
25//!
26//! // Equality is fast (header comparison first)
27//! let s2: AsciiString<32> = AsciiString::try_from("BTC-USD")?;
28//! assert_eq!(s, s2);
29//!
30//! // Access underlying data
31//! assert_eq!(s.as_str(), "BTC-USD");
32//! assert_eq!(s.len(), 7);
33//! # Ok::<(), AsciiError>(())
34//! ```
35
36#![cfg_attr(not(any(feature = "std", test)), no_std)]
37
38mod builder;
39mod char;
40mod flat_string;
41mod flat_text;
42mod format;
43mod parse;
44mod str_ref;
45mod string;
46mod text;
47mod text_ref;
48
49pub mod hash;
50pub mod simd;
51
52pub use builder::AsciiStringBuilder;
53pub use char::{AsciiChar, InvalidAsciiChar};
54pub use flat_string::FlatAsciiString;
55pub use flat_text::FlatAsciiText;
56pub use format::IntegerTooLarge;
57pub use str_ref::AsciiStr;
58pub use string::AsciiString;
59pub use text::AsciiText;
60pub use text_ref::AsciiTextStr;
61
62// =============================================================================
63// Type Aliases
64// =============================================================================
65
66/// 8-byte capacity ASCII string.
67pub type AsciiString8 = AsciiString<8>;
68/// 16-byte capacity ASCII string.
69pub type AsciiString16 = AsciiString<16>;
70/// 32-byte capacity ASCII string.
71pub type AsciiString32 = AsciiString<32>;
72/// 64-byte capacity ASCII string.
73pub type AsciiString64 = AsciiString<64>;
74/// 128-byte capacity ASCII string.
75pub type AsciiString128 = AsciiString<128>;
76/// 256-byte capacity ASCII string.
77pub type AsciiString256 = AsciiString<256>;
78
79/// 8-byte capacity printable ASCII text.
80pub type AsciiText8 = AsciiText<8>;
81/// 16-byte capacity printable ASCII text.
82pub type AsciiText16 = AsciiText<16>;
83/// 32-byte capacity printable ASCII text.
84pub type AsciiText32 = AsciiText<32>;
85/// 64-byte capacity printable ASCII text.
86pub type AsciiText64 = AsciiText<64>;
87/// 128-byte capacity printable ASCII text.
88pub type AsciiText128 = AsciiText<128>;
89
90/// 8-byte capacity flat ASCII string.
91pub type FlatAsciiString8 = FlatAsciiString<8>;
92/// 16-byte capacity flat ASCII string.
93pub type FlatAsciiString16 = FlatAsciiString<16>;
94/// 32-byte capacity flat ASCII string.
95pub type FlatAsciiString32 = FlatAsciiString<32>;
96/// 64-byte capacity flat ASCII string.
97pub type FlatAsciiString64 = FlatAsciiString<64>;
98/// 128-byte capacity flat ASCII string.
99pub type FlatAsciiString128 = FlatAsciiString<128>;
100/// 256-byte capacity flat ASCII string.
101pub type FlatAsciiString256 = FlatAsciiString<256>;
102
103/// 8-byte capacity flat printable ASCII text.
104pub type FlatAsciiText8 = FlatAsciiText<8>;
105/// 16-byte capacity flat printable ASCII text.
106pub type FlatAsciiText16 = FlatAsciiText<16>;
107/// 32-byte capacity flat printable ASCII text.
108pub type FlatAsciiText32 = FlatAsciiText<32>;
109/// 64-byte capacity flat printable ASCII text.
110pub type FlatAsciiText64 = FlatAsciiText<64>;
111/// 128-byte capacity flat printable ASCII text.
112pub type FlatAsciiText128 = FlatAsciiText<128>;
113
114/// 8-byte capacity ASCII string builder.
115pub type AsciiStringBuilder8 = AsciiStringBuilder<8>;
116/// 16-byte capacity ASCII string builder.
117pub type AsciiStringBuilder16 = AsciiStringBuilder<16>;
118/// 32-byte capacity ASCII string builder.
119pub type AsciiStringBuilder32 = AsciiStringBuilder<32>;
120/// 64-byte capacity ASCII string builder.
121pub type AsciiStringBuilder64 = AsciiStringBuilder<64>;
122/// 128-byte capacity ASCII string builder.
123pub type AsciiStringBuilder128 = AsciiStringBuilder<128>;
124
125// =============================================================================
126// NoHash Support (feature-gated)
127// =============================================================================
128
129// AsciiString and AsciiText store a precomputed 48-bit XXH3 hash in their header.
130// This makes them ideal candidates for identity hashing with nohash-hasher,
131// avoiding redundant hash computation in HashMap/HashSet lookups.
132
133#[cfg(feature = "nohash")]
134impl<const CAP: usize> nohash_hasher::IsEnabled for AsciiString<CAP> {}
135#[cfg(feature = "nohash")]
136impl<const CAP: usize> nohash_hasher::IsEnabled for AsciiText<CAP> {}
137
138/// A `HashMap` using `AsciiString` keys with identity hashing.
139///
140/// Since `AsciiString` stores a precomputed hash in its header, this avoids
141/// the overhead of SipHash or other hash functions during lookup.
142///
143/// # Example
144///
145/// ```
146/// use nexus_ascii::{AsciiString, AsciiHashMap};
147///
148/// let mut map: AsciiHashMap<32, u64> = AsciiHashMap::default();
149/// let key: AsciiString<32> = AsciiString::try_from("BTC-USD").unwrap();
150/// map.insert(key, 42);
151/// assert_eq!(map.get(&key), Some(&42));
152/// ```
153#[cfg(feature = "nohash")]
154pub type AsciiHashMap<const CAP: usize, V> =
155 std::collections::HashMap<AsciiString<CAP>, V, nohash_hasher::BuildNoHashHasher<u64>>;
156
157/// A `HashSet` using `AsciiString` values with identity hashing.
158///
159/// Since `AsciiString` stores a precomputed hash in its header, this avoids
160/// the overhead of SipHash or other hash functions during lookup.
161///
162/// # Example
163///
164/// ```
165/// use nexus_ascii::{AsciiString, AsciiHashSet};
166///
167/// let mut set: AsciiHashSet<32> = AsciiHashSet::default();
168/// let key: AsciiString<32> = AsciiString::try_from("BTC-USD").unwrap();
169/// set.insert(key);
170/// assert!(set.contains(&key));
171/// ```
172#[cfg(feature = "nohash")]
173pub type AsciiHashSet<const CAP: usize> =
174 std::collections::HashSet<AsciiString<CAP>, nohash_hasher::BuildNoHashHasher<u64>>;
175
176/// A `HashMap` using `AsciiText` keys with identity hashing.
177#[cfg(feature = "nohash")]
178pub type AsciiTextHashMap<const CAP: usize, V> =
179 std::collections::HashMap<AsciiText<CAP>, V, nohash_hasher::BuildNoHashHasher<u64>>;
180
181/// A `HashSet` using `AsciiText` values with identity hashing.
182#[cfg(feature = "nohash")]
183pub type AsciiTextHashSet<const CAP: usize> =
184 std::collections::HashSet<AsciiText<CAP>, nohash_hasher::BuildNoHashHasher<u64>>;
185
186// =============================================================================
187// Error Types
188// =============================================================================
189
190/// Errors that can occur when constructing ASCII types.
191#[derive(Debug, Clone, Copy, PartialEq, Eq)]
192pub enum AsciiError {
193 /// Input exceeds the string's capacity.
194 TooLong {
195 /// Actual length of the input.
196 len: usize,
197 /// Maximum capacity of the target string.
198 cap: usize,
199 },
200 /// Byte is not valid ASCII (null byte or value > 127).
201 InvalidByte {
202 /// The invalid byte value.
203 byte: u8,
204 /// Position in the input where the invalid byte was found.
205 pos: usize,
206 },
207 /// Byte is not printable ASCII (< 32 or > 126). Used by `AsciiText`.
208 NonPrintable {
209 /// The non-printable byte value.
210 byte: u8,
211 /// Position in the input where the non-printable byte was found.
212 pos: usize,
213 },
214}
215
216impl core::fmt::Display for AsciiError {
217 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
218 match self {
219 AsciiError::TooLong { len, cap } => {
220 write!(f, "input length {} exceeds capacity {}", len, cap)
221 }
222 AsciiError::InvalidByte { byte, pos } => {
223 write!(f, "invalid ASCII byte 0x{:02X} at position {}", byte, pos)
224 }
225 AsciiError::NonPrintable { byte, pos } => {
226 write!(
227 f,
228 "non-printable ASCII byte 0x{:02X} at position {}",
229 byte, pos
230 )
231 }
232 }
233 }
234}
235
236#[cfg(feature = "std")]
237impl std::error::Error for AsciiError {}