Expand description
§waterui-str
A memory-efficient, reference-counted string type optimized for both static and owned strings.
§Overview
waterui-str provides Str, a hybrid string type that automatically chooses between static string references and reference-counted owned strings. This design eliminates unnecessary allocations for static strings while enabling efficient cloning for owned strings through reference counting.
The crate is designed for no_std environments (with alloc), making it suitable for embedded systems and WebAssembly targets. It integrates seamlessly with WaterUI’s reactive system through the nami-core integration.
Key features:
- Zero-cost static strings: Static string literals stored as pointers without allocation
- Reference-counted owned strings: Efficient cloning through internal reference counting
- Transparent API: Derefs to
&str, works with all standard string operations - Reactive integration: Compatible with
WaterUI’snamireactive primitives viaimpl_constant! - Optional serde support: Serialize and deserialize with the
serdefeature
§Installation
Add to your Cargo.toml:
[dependencies]
waterui-str = "0.2"With serde support:
[dependencies]
waterui-str = { version = "0.2", features = ["serde"] }§Quick Start
use waterui_str::Str;
// Static strings - no allocation
let static_str = Str::from("hello");
// Owned strings - reference counted
let owned = Str::from(String::from("world"));
// Cheap cloning
let clone = owned.clone(); // Just increments ref count
// Transparent string operations
assert_eq!(static_str.len(), 5);
assert!(static_str.starts_with("hel"));
// Concatenation
let combined = static_str + " " + &owned;
assert_eq!(combined, "hello world");§Core Concepts
§Internal Representation
Str uses a clever tagged pointer representation:
- Positive length: Points to static string data (
&'static str) - Negative length: Points to
Shared(reference-countedString)
This allows zero-overhead discrimination between static and owned strings at runtime.
§Reference Counting
Owned strings use internal reference counting via Shared:
- Clone operations increment the reference count
- Drop operations decrement the count and free memory when reaching zero
- Reference counts are intentionally not exposed in the public API
§Memory Optimization
Empty strings always use a static empty string reference, regardless of how they’re created:
use waterui_str::Str;
let empty1 = Str::new();
let empty2 = Str::from("");
let empty3 = Str::from(String::new());
// All three use the same static "" reference§Examples
§Creating Strings
use waterui_str::Str;
// From static string literal
let s1 = Str::from("hello");
// From owned String
let s2 = Str::from(String::from("hello"));
// From UTF-8 bytes
let bytes = vec![104, 101, 108, 108, 111]; // "hello"
let s3 = Str::from_utf8(bytes).unwrap();
// Empty string
let s4 = Str::new();§String Manipulation
use waterui_str::Str;
let mut s = Str::from("hello");
s.append(" world");
assert_eq!(s, "hello world");
// Concatenation with +
let s1 = Str::from("foo");
let s2 = s1 + "bar";
assert_eq!(s2, "foobar");
// AddAssign
let mut s3 = Str::from("hello");
s3 += " world";
assert_eq!(s3, "hello world");§Iteration and Collection
use waterui_str::Str;
// Collect from iterator
let words = vec!["hello", " ", "world"];
let s: Str = words.into_iter().collect();
assert_eq!(s, "hello world");
// Extend
let mut s = Str::from("hello");
s.extend(vec![" ", "world"]);
assert_eq!(s, "hello world");§Conversion to String
use waterui_str::Str;
let s1 = Str::from(String::from("owned"));
let s2 = s1.clone();
// Convert to String - takes ownership if ref count is 1
let string1 = s1.into_string(); // Copies because s2 still exists
assert_eq!(string1, "owned");
// s2 is now the only reference
let string2 = s2.into_string(); // No copy, takes ownership
assert_eq!(string2, "owned");§API Overview
§Construction
Str::new()- Create empty stringStr::from_static(&'static str)- Create from static string literalStr::from_utf8(Vec<u8>)- Create from UTF-8 bytes with validationunsafe Str::from_utf8_unchecked(Vec<u8>)- Create from UTF-8 bytes without validation
§Inspection
as_str(&self) -> &str- Get string slicelen(&self) -> usize- Get byte lengthis_empty(&self) -> bool- Check if empty
§Modification
append(&mut self, &str)- Append stringinto_string(self) -> String- Convert to owned String
§Traits Implemented
Deref<Target = str>- Transparent access to string methodsClone- Efficient reference-counted cloningDefault- Empty stringDisplay,Debug- FormattingHash,Eq,Ord- Collections and comparisonsAsRef<str>,AsRef<[u8]>,Borrow<str>- ConversionsFromStr,FromIterator- Parsing and collectionAdd,AddAssign- ConcatenationExtend- Extension from iteratorsIndex<I>- Slice indexing
§Standard Library Integration (when std is available)
AsRef<OsStr>,AsRef<Path>- Filesystem operationsTryFrom<OsString>- OS string conversionToSocketAddrs- Network address resolution
§Design Rationale
§Why Not Cow<'static, str>?
While Cow<'static, str> provides similar functionality, Str offers:
- Better clone performance: Reference counting vs. full string copy for
Cow::Owned - Smaller size: Single pointer + length vs. discriminant + pointer + length
- Specialized API: Methods like
append()optimized for the use case
§Why Hide Reference Counts?
The internal reference count is deliberately not exposed in the public API. This:
- Prevents code from relying on reference count values
- Allows future optimization changes without breaking the API
- Encourages treating
Stras a simple value type
§Memory Safety
The crate includes extensive memory safety tests designed for Miri (Rust’s undefined behavior detector), covering:
- Clone/drop cycle patterns
- Interleaved operations
- Reference counting edge cases
- Pointer stability guarantees
- Large string handling
- Concurrent-like access patterns (single-threaded stress tests)
§Performance Characteristics
- Static strings: Zero allocation, zero cost to clone
- Owned strings: Single allocation, O(1) clone (ref count increment)
- Deref operations: Zero cost - compiles to a pointer dereference
into_string()with unique ownership: Zero copy, takes ownershipinto_string()with shared ownership: Single allocation and copy
§License
Licensed under the same terms as the WaterUI project.
Structs§
- Str
- A string type that can be either a static reference or a ref-counted owned string.