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.
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).
- 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).
- 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.
use bounded_str::{StackStr, FlexStr, Bytes, Chars, AsciiOnly};
use serde::Deserialize;
// Matrix spec-compliant types — showcase ALL crate features:
// 1. Bytes (O(1)) — Room IDs, technical strings
type RoomId = StackStr<8, 255, 255, Bytes>;
// 2. Chars (Unicode) — usernames with Cyrillic/emoji
type Username = StackStr<1, 255, 1024, Chars>;
// 3. Bytes + AsciiOnly — device IDs, technical strings
type DeviceId = StackStr<1, 32, 32, Bytes, AsciiOnly>;
// 4. Passwords — short, zeroize-enabled - true
type Password = StackStr<8, 128, 128, Bytes, AsciiOnly, true>;
// 5. JWT tokens — large buffer (2KiB)
type Token = FlexStr<16, 2048, 255, Bytes>;
// 6. HTML content — large, auto heap (up to 64KiB) if > 1024
type HtmlBody = FlexStr<0, 65536, 1024, Bytes>;
// JSON auto-validation! (parse, don't validate)
#[derive(Deserialize)]
struct LoginRequest {
username: Username, // Unicode OK, 1-255 chars (1KiB buffer)
device_id: DeviceId, // ASCII only, 1-32 bytes (32B buffer)
password: Password, // 8-128 bytes, zeroize (128B buffer)
access_token: Option<Token>, // JWT up to 2KiB buffer
room_id: Option<RoomId>, // Matrix room everywhere!
html_body: HtmlBody, // Large HTML → auto heap
}
// 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: Result<LoginRequest, _> = serde_json::from_str(json);
// Short password or oversized HTML → serde fails instantly!
// No manual if-checks needed.[dependencies]
bounded-str = { version = "0.1", features = ["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.
- 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.
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.