BoundedStr: Type-Safe Strings with Static Limits and Hybrid Storage
BoundedStr is a library for creating string types with guaranteed invariants.
It follows the "Parse, don't validate" principle: once an object is created, you can trust its length, format, and encoding.
- Hybrid Storage: Automatic selection between stack (
StackStr) and dynamic memory (FlexStr) when the byte limit is exceeded. - Policy-Based Design: You choose how to measure length (bytes or characters) and how to validate content (ASCII, AlphaNumeric, etc.) via traits.
- No-Std First: Full support for embedded systems,
allocis required only forFlexStr.
Core Concepts
1. Policies
Instead of hard-coded logic, BoundedStr uses:
- LengthPolicy:
Bytes(fast, O(1)) orChars(Unicode-correct, O(n)). - FormatPolicy:
AllowAll,AsciiOnly, or your own rules (e.g.,EmailValidator).
2. Storage Types
- StackStr: Always on the stack. If the string does not fit in
MAX_BYTES— error. - FlexStr: Tries to fit on the stack, but if
allocis enabled and the data is large — transparently moves to the heap. Optimized Memory: Starting from v0.1.4, FlexStr uses an internal enum. If data moves to the heap, the stack buffer is freed, significantly reducing stack pressure (SSO).
Key Features
- Compile-time checks: Checks
MIN <= MAXat compile time via const assertions. - Transactional Mutation:
mutate()allows modifying both content&mut [u8]and length&mut usize. It automatically rolls back if the new string violates length, UTF-8, or format rules. - Zero-cost Deref: Implements
Deref<Target=str>, works like a regular string with no overhead. - Security: Supports
zeroizefor automatic memory clearing (passwords, keys) and constant-time comparison.
Usage
use ;
use Deserialize;
// Matrix spec-compliant types — showcase ALL crate features:
// 1. Bytes (O(1)) — Room IDs, technical strings
type RoomId = ;
// 2. Chars (Unicode) — usernames with Cyrillic/emoji
type Username = ;
// 3. Bytes + AsciiOnly — device IDs, technical strings
type DeviceId = ;
// 4. Passwords — short, zeroize-enabled - true
type Password = ;
// 5. JWT tokens — large buffer (2KiB)
type Token = ;
// 6. HTML content — large, auto heap (up to 64KiB) if > 1024
type HtmlBody = ;
// JSON auto-validation! (parse, don't validate)
// Real usage — invalid JSON fails automatically!
let json = r#"{
"username": "alexey",
"device_id": "DEV123",
"password": "MySecurePass123",
"html_body": "<p>Matrix <b>rich content</b> up to 64KiB</p>"
}"#;
let req: = from_str;
// Short password or oversized HTML → serde fails instantly!
// No manual if-checks needed.
Cargo Features
[]
= { = "0.1", = ["serde", "alloc", "zeroize", "constant-time"] }
- serde: Automatic validation during deserialization.
- alloc: Enables
FlexStrand dynamic memory support. - zeroize: Clears the buffer when it goes out of scope (
Drop). - constant-time: Protects all equality checks (==) against timing attacks by comparing every byte regardless of content.
Limitations
- By default, the stack limit is set to a reasonable size (recommended up to 4KiB).
- The
Charspolicy requires a full scan of the string during creation and mutation.
Important Architectural Note
Although FormatPolicy allows checking data format (e.g., Email or Regex), remember the "Parse, don't validate" philosophy:
- Complexity: Attempting perfect Email validation via policies may produce fragile code.
- Recommendation: Use policies for structural constraints (length, ASCII encoding, absence of control characters).
- Business Logic: Deep validation (e.g., domain existence, RFC 5322 compliance) is better handled by specialized parsers that convert BoundedStr into stricter data types.