CheetahString is an immutable, clone-cheap UTF-8 value for latency-sensitive
systems. It stores short text inline, keeps static text allocation-free, and
shares long dynamic text through Arc<str>. The same value contract works with
std and no_std + alloc.
Version 3.0.0-alpha.1 is the opt-in preview of the immutable architecture.
| Storage | Condition | Construction allocation | Clone allocation |
|---|---|---|---|
| Inline | UTF-8 length β€ 23 bytes | 0 | 0 |
| Static | &'static str |
0 | 0 |
| Shared | Other long text | 1 live backing allocation | 0 |
The representation has no mutable Owned(String) state. Construction history
therefore cannot change clone complexity. Use:
CheetahStringfor protocol text, immutable fields, and collection keys;CheetahBuilderfor append-heavy construction followed byfinish();- standard
Stringwhen mutation or spare capacity must continue; CheetahBytesfor byte semantics when the optionalbytesfeature is active.
Opt into the alpha explicitly:
[dependencies]
cheetah-string = "=3.0.0-alpha.1"With optional integrations:
[dependencies]
cheetah-string = {
version = "=3.0.0-alpha.1",
features = ["serde", "bytes"]
}The minimum supported Rust version is 1.75.
use cheetah_string::{CheetahBuilder, CheetahString};
let inline = CheetahString::from("orders");
let static_value = CheetahString::from_static_str("system-topic");
let shared = CheetahString::from_string("long-dynamic-value-".repeat(8));
let cloned = shared.clone();
assert_eq!(inline, "orders");
assert_eq!(static_value, "system-topic");
assert_eq!(shared, cloned);
assert_eq!(shared.as_bytes().as_ptr(), cloned.as_bytes().as_ptr());
let mut builder = CheetahBuilder::with_capacity(64);
builder.push_str("orders");
builder.push('@');
builder.push_str("group-a");
let route_key = builder.finish();
assert_eq!(route_key, "orders@group-a");When mutation continues, keep the builder's String:
use cheetah_string::CheetahBuilder;
let mut builder = CheetahBuilder::with_capacity(128);
builder.push_str("orders");
let mut value = builder.into_string();
value.push_str("@group-a");Equality, prefix, and suffix checks use Rust's portable slice/str paths.
Substring search uses memchr/memmem.
Iterator capabilities are explicit:
use cheetah_string::CheetahString;
let value = CheetahString::from("a::b::c");
let forward: Vec<_> = value.split_str("::").collect();
assert_eq!(forward, ["a", "b", "c"]);
let csv = CheetahString::from("a,b,c");
let reverse: Vec<_> = csv.split_char(',').rev().collect();
assert_eq!(reverse, ["c", "b", "a"]);split_str is intentionally forward-only. Unsupported reverse iteration fails
at compile time instead of panicking at runtime.
The ownership boundary is explicit:
| Conversion | UTF-8 validation | Payload copy |
|---|---|---|
bytes::Bytes -> CheetahBytes |
No | No |
CheetahBytes -> bytes::Bytes |
No | No |
Bytes -> CheetahString::try_from |
Yes | Yes |
CheetahBytes -> CheetahString::try_from |
Yes | Yes |
Bytes -> CheetahString::try_copy_from_bytes |
Yes | Yes |
&CheetahBytes -> try_copy_to_cheetah_string |
Yes | Yes |
use bytes::Bytes;
use cheetah_string::{CheetahBytes, CheetahString};
let raw = Bytes::from_static(b"orders");
let bytes = CheetahBytes::from(raw);
let text = bytes.try_copy_to_cheetah_string().unwrap();
assert_eq!(text, "orders");
let invalid = Bytes::from_static(&[0xff]);
let error = CheetahString::try_copy_from_bytes(invalid.clone()).unwrap_err();
assert_eq!(error.into_bytes(), invalid);The full executable contract is in
docs/bytes-interop.md.
| Feature | Default | Contract |
|---|---|---|
std |
Yes | Standard-library integration |
serde |
No | Serialization and deserialization |
bytes |
No | CheetahBytes and explicit byte/text conversion |
experimental-simd |
No | Isolated x86_64 SSE2 benchmark path; not recommended for production |
simd |
No | Deprecated alpha compatibility alias for experimental-simd |
experimental-packed |
No | Unstable packed-representation prototype |
Optional features do not change the stable CheetahString layout.
The repository includes RocketMQ-shaped Criterion workloads for property building, remoting-header parsing, topic insertion and lookup, plus explicit layout and allocation contracts. Blocking timing decisions run only on a dedicated fixed CPU with two reversed base/head rounds.
cargo test --test layout_snapshot --all-features
cargo test --test allocation_contract --all-features -- --test-threads=1
cargo bench --bench comprehensive
cargo bench --bench mq_properties
cargo bench --bench mq_remoting_header
cargo bench --bench mq_topicThresholds, metadata requirements, and reproduction commands are documented in
docs/performance-gates.md. Hosted-runner and local
benchmark results are diagnostic; they do not independently establish a
release-grade performance pass.
The architecture/optimization design scores 96/100 only when all 14 versioned conditions are evidenced. PR performance may pass while that aggregate remains incomplete; final comparison only certifies its performance scope, while release verification fails closed on every missing live attestation. See the release evidence discovery contract.
Every deterministic CI run covers formatting, Clippy, Rust 1.75, all features,
no_std, exact layout, and allocation contracts. Nightly validation adds Miri,
Linux AddressSanitizer, transition fuzzing, and split differential fuzzing.
The unsafe constructors are explicitly named and require the caller to prove UTF-8 validity. Safe byte constructors validate before creating text.
The historical local diagnostic record, with its own candidate identity,
execution counts, exclusions, and SHA-256 log digests, is in
bench-results/safety/2026-07-26-local/summary.md.
Historical downstream compile and representative-test diagnostics are in the
archived crater summary.
Neither record substitutes for an exact-candidate release attestation. The
stable unsafe-site inventory is in
docs/stable-unsafe-audit.md.
- v2 to v3 migration
- ADR 001: immutable canonical value
- ADR 002: bytes copy boundary
- ADR 003: SIMD policy
- ADR 004: split capability
- ADR 005: performance gates
- ADR 006: rejected packed boundary
The v3 alpha temporarily retains several deprecated v2 spellings so large read-only consumers can validate the new representation incrementally. Deprecated names do not retain mutable v2 semantics.
Licensed under either of Apache License 2.0 or MIT, at your option.