maciejhirsz/beef
{ "createdAt": "2020-03-12T14:39:45Z", "defaultBranch": "master", "description": "Faster, more compact implementation of std::borrow::Cow", "fullName": "maciejhirsz/beef", "homepage": "https://crates.io/crates/beef", "language": "Rust", "name": "beef", "pushedAt": "2023-04-13T18:42:07Z", "stargazersCount": 368, "topics": [ "cursed", "no-std", "rust", "rust-lang" ], "updatedAt": "2025-11-21T23:18:23Z", "url": "https://github.com/maciejhirsz/beef"}Faster, more compact implementation of Cow.
Changelog - Documentation - Cargo - Repository
use beef::Cow;
let borrowed: Cow<str> = Cow::borrowed("Hello");let owned: Cow<str> = Cow::owned(String::from("World"));
assert_eq!( format!("{} {}!", borrowed, owned), "Hello World!",);There are two versions of Cow exposed by this crate:
beef::Cowis 3 words wide: pointer, length, and capacity. It stores the ownership tag in capacity.beef::lean::Cowis 2 words wide, storing length, capacity, and the ownership tag all in one word.
Both versions are leaner than the std::borrow::Cow:
use std::mem::size_of;
const WORD: usize = size_of::<usize>();
assert_eq!(size_of::<std::borrow::Cow<str>>(), 4 * WORD);assert_eq!(size_of::<beef::Cow<str>>(), 3 * WORD);assert_eq!(size_of::<beef::lean::Cow<str>>(), 2 * WORD);How does it work?
Section titled “How does it work?”The standard library Cow is an enum with two variants:
pub enum Cow<'a, B> where B: 'a + ToOwned + ?Sized,{ Borrowed(&'a B), Owned(<B as ToOwned>::Owned),}For the most common pairs of values - &str and String, or &[u8] and Vec<u8> - this
means that the entire enum is 4 words wide:
Padding | v +-----------+-----------+-----------+-----------+Borrowed: | Tag | Pointer | Length | XXXXXXXXX | +-----------+-----------+-----------+-----------+
+-----------+-----------+-----------+-----------+Owned: | Tag | Pointer | Length | Capacity | +-----------+-----------+-----------+-----------+Instead of being an enum with a tag, beef::Cow uses capacity to determine whether the
value it’s holding is owned (capacity is greater than 0), or borrowed (capacity is 0).
beef::lean::Cow goes even further and puts length and capacity on a single 64 word.
+-----------+-----------+-----------+beef::Cow | Pointer | Length | Capacity? | +-----------+-----------+-----------+
+-----------+-----------+beef::lean::Cow | Pointer | Cap | Len | +-----------+-----------+Any owned Vec or String that has 0 capacity is effectively treated as a borrowed
value. Since having no capacity means there is no actual allocation behind the pointer,
this is safe.
Benchmarks
Section titled “Benchmarks”cargo +nightly benchMicrobenchmarking obtaining a &str reference is rather flaky and you can have widely different results. In general the following seems to hold true:
beef::Cowandbeef::lean::Coware faster thanstd::borrow::Cowat obtaining a reference&T. This makes sense since we avoid the enum tag branching.- The 3-word
beef::Cowis faster at creating borrowed variants, but slower at creating owned variants thanstd::borrow::Cow. - The 2-word
beef::lean::Cowis faster at both.
running 9 teststest beef_as_ref ... bench: 57 ns/iter (+/- 15)test beef_create ... bench: 135 ns/iter (+/- 5)test beef_create_mixed ... bench: 659 ns/iter (+/- 52)test lean_beef_as_ref ... bench: 50 ns/iter (+/- 2)test lean_beef_create ... bench: 77 ns/iter (+/- 3)test lean_beef_create_mixed ... bench: 594 ns/iter (+/- 52)test std_as_ref ... bench: 70 ns/iter (+/- 6)test std_create ... bench: 142 ns/iter (+/- 7)test std_create_mixed ... bench: 663 ns/iter (+/- 32)License
Section titled “License”This crate is distributed under the terms of both the MIT license and the Apache License (Version 2.0). Choose whichever one works best for you.
See [LICENSE-APACHE]!(LICENSE-APACHE) and [LICENSE-MIT]!(LICENSE-MIT) for details.