| Crates.io | flexstr |
| lib.rs | flexstr |
| version | 0.11.0 |
| created_at | 2022-02-26 04:36:42.635263+00 |
| updated_at | 2026-01-20 13:17:13.448127+00 |
| description | A flexible, simple to use, clone-efficient string type for Rust |
| homepage | |
| repository | https://github.com/nu11ptr/flexstr |
| max_upload_size | |
| id | 539790 |
| size | 203,348 |
A flexible, simple to use, clone-efficient String replacement for Rust. It unifies borrowed, inlined, referenced counted and boxed strings into a single type.
If you've used Cow, but you wish cloning owned strings was more performant and that being owned didn't always imply heap allocation, this crate might be what you are looking for. The operations are "lazy" (like Cow), and it tries not to do work the user is not expecting.
Users of previous versions: you should be aware this new version is a ground up rewrite with a solidly different thought process, API and design. Even if the previous versions didn't match your needs, this one might. Users should be aware that nearly all the string construction code is not yet present in this version. The new way to do this (workaround?) is to do the work as a
Stringand then import it into aLocalStrorSharedStr. Moving into and out of the boxed variant (from_owned) should be near zero cost.
clone when variant is Boxed is O(n)String (3 words wide, even inside an Option)serde/sqlx optional for serialization/deserialization/encode/decodeno_stdsafe feature that forbids any unsafe usage
OsStr/Path support on Windows requires at least one unsafe call (win_min_unsafe feature).str, CStr, OsStr, Path, [u8])forbid(unsafe_code) (performance penalty)sqlx feature)std (default)serde dependency and adds serialization/deserializationOsStr/Path. No other string types or operating systems are impacted (implies safe feature).
safe feature is enabledosstr and/or path feature(s) are enabledstr-based strings (default)[u8])CStr-based stringsOsStr-based stringsPath-based strings (implies osstr feature)It is just an enum that looks like this - you can probably guess much of how it works just by looking at it:
// `S` is just the raw string type (typically `str`)
// `R` is just an `Arc` or an `Rc`.
pub enum FlexStr<'s, S, R> {
Borrowed(&'s S),
Inlined(InlineFlexStr<S>),
RefCounted(R),
Boxed(Box<S>),
}
// You would typically use it via one of the type aliases, for example:
pub type LocalStr<'s> = FlexStr<'s, str, Rc<str>>;
pub type SharedStr<'s> = FlexStr<'s, str, Arc<str>>;
Even that you don't really need to concern yourself with. You can just use it how you would expect a simple wrapper to behave.
use flexstr::*;
// This will be a "Borrowed" variant
let hello: SharedStr = "hello".into();
assert!(hello.is_borrowed());
// This will be a "Boxed" variant
let world: SharedStr = "world".to_string().into();
assert!(world.is_boxed());
// This is now "Inlined" (since it is short)
let hello = hello.into_owned();
assert!(hello.is_inlined());
// This is now "Inlined" as well (since it is short)
let world = world.optimize();
assert!(world.is_inlined());
println!("{hello} {world}");
In general, it performs quite well given that it is mostly just a thin wrapper over the stdlib. See the benchmarks page for more details.
The code was written by hand with care (although AI tab completion was used). Any contributions should be completely understood by the contributor, whether AI assisted or not.
The tests on the otherhand were 90%+ generated by AI under my instruction. I've done a cursory review for sanity, but they need more work. Volunteers welcome.
This is currently experimental, however, I will be using this at a startup in production code, so it will become production ready at some point.
Contributions are welcome so long as they align to my vision for this crate. Currently, it does most of what I want it to do (outside of string construction and mutation, but I'm not ready to start on that yet).
This project is licensed optionally under either: