turbocow
turbocow is a collection of compact, clone-on-write data structures — a
strict superset of ecow 0.3.0. All types present in ecow 0.3.0
(EcoVec, EcoString) are re-exported with identical APIs, so existing ecow
code can be migrated by replacing ecow with turbocow in Cargo.toml and
updating imports (ecow::EcoVec → turbocow::EcoVec, ecow::EcoString →
turbocow::EcoString). On top of that, turbocow adds map/set variants,
a byte-string type, inline-storage collections, and a zero-copy Referenced
storage variant for strings and vecs.
Install
[]
= "0.3.0-beta.2"
or via cargo add:
Types
| Type | Description |
|---|---|
EcoVec<T> |
Compact (2-word) reference-counted clone-on-write vector; same memory layout as &[T]. O(1) clone. |
EcoString |
Clone-on-write string, 15 bytes inline, spills to EcoVec<u8>. Strict superset of ecow 0.3.0's EcoString (adds insert/insert_str/remove, ToEcoString, AsRef<OsStr/Path>, Deref<Target=str>). |
EcoStr<'a> |
Lifetime-carrying string; supports a zero-copy Referenced (borrowed) storage variant. EcoString is EcoStr<'static> (owned). |
EcoByteString |
Byte-oriented counterpart of EcoString for arbitrary [u8] data. |
EcoMap<K, V> |
Reference-counted clone-on-write map backed by two EcoVecs (keys + values). O(1) clone. Linear-scan lookup — optimal for small maps. |
EcoSet<T> |
Reference-counted clone-on-write set backed by EcoMap<T, ()>. O(1) clone. |
SmallMap<K, V, N> |
Inline-storage map (N entries on the stack with an h2 sidecar, spills to hashbrown::HashMap). O(N) clone. |
SmallSet<T, N> |
Inline-storage set backed by SmallMap<T, (), N>. O(N) clone. |
SmallVec<'a, T, N> |
Inline-storage vec (N elements on the stack, spills to heap); supports a zero-copy Referenced variant. O(N) clone. |
eco_vec! |
Macro to construct an EcoVec from a list of elements (like vec!). |
eco_format! |
Macro to create an EcoString from a format string (like format!). |
ToEcoString |
Trait auto-implemented for any Display type; provides .to_eco_string(). |
Example
// This is stored inline.
let small = from;
// This spills to the heap, but only once: `big` and `third` share the
// same underlying allocation. Vectors and spilled strings are only
// really cloned upon mutation.
let big = small + " to earth! 🌱";
let mut third = big.clone;
// This allocates again to mutate `third` without affecting `big`.
assert_eq!;
assert_eq!;
Why should I use this instead of ...
| Type | Details |
|---|---|
Vec<T> / String |
Normal vectors are a great general purpose data structure. But they have a quite big footprint (3 machine words) and are expensive to clone. EcoVec is cheap to clone and only takes two words. |
Arc<Vec<T>> / Arc<String> |
These require two allocations instead of one and are less convenient to mutate. |
Arc<[T]> / Arc<str> |
While these require only one allocation, they aren't mutable. |
| Small vector | Different trade-off. Great when there are few, small Ts, but expensive to clone when spilled. SmallVec adds a zero-copy Referenced variant for borrowed data. |
| Small string | EcoString combines inline storage, a small footprint, efficient clone-on-write, and full mutability. EcoStr<'a> additionally supports zero-copy borrows. |
HashMap / BTreeMap |
Great general purpose maps, but expensive to clone. EcoMap gives O(1) clone via refcounting. SmallMap keeps small maps on the stack. |
Feature flags
| Feature | Default | Description |
|---|---|---|
std |
yes | Enables std integration: io::Write for EcoVec<u8>, AsRef<OsStr> / AsRef<Path> for EcoString. Implies alloc. |
alloc |
yes | Core heap support (required; turbocow is a heap-collections crate). Disable std but keep alloc for no_std builds. |
serde |
no | Serialize/Deserialize for all collection types. |
rkyv |
no | rkyv 0.8 Archive/Serialize/Deserialize for EcoVec, EcoString, EcoByteString. |
allocator-api2-v02 |
no | Custom-allocator support via the allocator-api2 0.2 shim (stable). |
allocator-api2-v03 |
no | Custom-allocator support via the allocator-api2 0.3 shim (stable). |
nightly-allocator-api |
no | Custom-allocator support via the real nightly allocator_api feature. See caveat below. |
nightly-fmt |
no | Enables the fmt::Arguments::as_str() fast-path in eco_format!. |
nightly-phantom-variance |
no | Uses PhantomCovariantLifetime from stdlib instead of a polyfill. |
loom |
no | Enables loom concurrency testing mode. |
Allocator feature notes: the stable
allocator-api2-v02andallocator-api2-v03shims are the supported way to plug in a custom allocator and build on stable Rust.nightly-allocator-apirequires a nightly toolchain; the library itself compiles with it, but turbocow's own integration tests (which usebump-scopeas a dev-dependency) currently fail on recent nightlies due to an upstreambump-scopevscore::alloc::Allocatortrait conflict — a dev-only issue that does not affect consumers. Thenightly-allocator-apiandallocator-api2-*backends are mutually exclusive; enabling them together (e.g. via--all-features) is unsupported.
no_std
turbocow supports no_std environments. Disable the std feature while
keeping alloc (bare no-alloc is not supported — turbocow is a
heap-collections crate):
[]
= { = "0.3", = false, = ["alloc"] }
MSRV
turbocow requires Rust 1.85 (edition 2024). This is intentionally higher than ecow's MSRV of 1.73; the "strict superset of ecow 0.3.0" guarantee applies to the public API, not to MSRV compatibility.
FAQ
Is it any good?
Yes.
No, really?
Ehhh~ this is half-mess, half-slop. I wanted a faster ecow with Allocator support for a very fast big scale parallel ninja parser I was prototyping, so I kind of vendored ecow and started messing around with the profiler until I've gotten it to do what I wanted.
Unfortunately I'm a rather messy programmer with an executive dysfunction, so it's been sitting an unfinished mess for over a year. But, given that since Opus 4.6 LLMs became kinda usable and I started needing it in more things, I have eventually poked the slop generator enough to end up with something that seemed publishable enough. It probably needs some actual polish on top of that (Allocator API support might've bitrotten a bit), but at least it works and does what I want. Treat is as an early-access beta, or something.
And at least, it's fast enough for what I needed it for.
Links
- Source: https://codeberg.org/jaen/turbocow
- Based on:
ecowby Typst — theEcoVecandEcoStringtypes are derived from ecow 0.3.0 and remain API-compatible.
License
This crate is dual-licensed under the MIT and Apache 2.0 licenses; see
LICENSE-MIT and LICENSE-APACHE.
Portions are derived from ecow 0.3.0 and from the Rust standard
library, which remain under their original MIT OR Apache-2.0 terms. Those
attributions are recorded in NOTICE.