#string #refcount #inline #arc-str #cow


Yet another string for Rust: zero-cost borrow and slicing, inline representation for small strings, (atomic) reference counting

5 unstable releases

0.3.2 Aug 19, 2023
0.3.1 Aug 14, 2023
0.3.0 Aug 12, 2023
0.2.0 Jul 6, 2023
0.1.0 Jun 1, 2023

#69 in Memory management

48 downloads per month


3.5K SLoC


Rust Clippy Miri codecov Docs MIT OR Apache-2.0

Yet another string for Rust ๐Ÿฆ€

  • no copy borrow via borrowed (a const constructor) or from_static
  • no alloc small strings (23 bytes on 64-bit platform)
  • no copy owned slices
  • zero dependency

And bytes too!

โšก Examples

use hipstr::HipStr;

let simple_greetings = HipStr::from_static("Hello world");
let _clone = simple_greetings.clone(); // no copy

let user = "John";
let greetings = HipStr::from(format!("Hello {}", user));
let _user = greetings.slice(6..): // no copy

โœ๏ธ Features

  • serde: provides serialization/deserialization support with serde crate
  • unstable: exposes internal Backend trait that may change at any moment

โ˜ฃ๏ธ Safety of hipstr

This crate uses unsafe extensively. ๐Ÿคท

It exploits the 1-bit alignment niche in pointers existing on most platforms (I think all Rustc supported platforms) to distinguish the inline representation from the other representations.

To make things safer, Rust is tested thoroughly on multiple platforms, normally and with Miri (the MIR interpreter).

๐Ÿงช Testing

โ˜” Coverage

This crate has near full line coverage:

cargo llvm-cov --all-features --html
# or
cargo tarpaulin --all-features --out html --engine llvm

Check out the current coverage on Codecov:

Coverage grid

๐Ÿ–ฅ๏ธ Cross-platform testing

You can easily run the test on various platforms with cross:

cross test --target mips-unknown-linux-gnu          # 32-bit BE
cross test --target mips64-unknown-linux-gnuabi64   # 64-bit BE
cross test --target i686-unknown-linux-gnu          # 32-bit LE
cross test --target x86_64-unknown-linux-gnu        # 64-bit LE

๐Ÿ” Miri

This crate runs successfully with Miri:

MIRIFLAGS=-Zmiri-symbolic-alignment-check cargo +nightly miri test

for SEED in $(seq 0 10); do
  echo "Trying seed: $SEED"
  MIRIFLAGS="-Zmiri-seed=$SEED" cargo +nightly miri test || { echo "Failing seed: $SEED"; break; };

To check with different word size and endianness:

# Big endian, 64-bit
cargo +nightly miri test --target mips64-unknown-linux-gnuabi64
# Little endian, 32-bit
cargo +nightly miri test --target i686-unknown-linux-gnu

๐Ÿ“ฆ Similar crates


Name Thread-safe cheap-clone Local cheap-clone Inline Cheap slice Bytes Cow<'a> Comment
hipstr ๐ŸŸข ๐ŸŸข ๐ŸŸข ๐ŸŸข ๐ŸŸข ๐ŸŸข obviously!
arcstr ๐ŸŸข* โŒ โŒ โŒ** โŒ โŒ *use a custom thin Arc, **heavy slice (with dedicated substring type)
flexstr ๐ŸŸข* ๐ŸŸข ๐ŸŸข โŒ โŒ โŒ *use an Arc<str> instead of an Arc<String> (remove one level of indirection but use fat pointers)
imstr ๐ŸŸข ๐ŸŸข โŒ ๐ŸŸข โŒ โŒ
faststr ๐ŸŸข โŒ ๐ŸŸข ๐ŸŸข โŒ โŒ zero-doc with complex API
fast-str ๐ŸŸข โŒ ๐ŸŸข ๐ŸŸข โŒ โŒ inline repr is opt-in
ecow ๐ŸŸข* โŒ ๐ŸŸข โŒ ๐ŸŸข** โŒ *on two words only ๐Ÿคค, **even any T
cowstr ๐ŸŸข โŒ โŒ โŒ* โŒ โŒ** *heavy slice, **contrary to its name
compact_str โŒ โŒ ๐ŸŸข โŒ ๐ŸŸข* โŒ *opt-in via smallvec
inline_string โŒ โŒ ๐ŸŸข โŒ โŒ โŒ
smartstring โŒ โŒ ๐ŸŸข โŒ โŒ โŒ
smallstr โŒ โŒ ๐ŸŸข โŒ โŒ โŒ
smol_str โŒ โŒ ๐ŸŸข* โŒ โŒ โŒ *but only inline string, here for reference

skipping specialized string types like tinystr (ASCII-only, bounded), or bstr, or bytestring, or...

In short, HipStr, one string type to rule them all ๐Ÿ˜‰

How standards proliferate

๐ŸŽ๏ธ Performances

While speed is not the main motivator for hipstr, it seems to be doing OK on that front.

On my i7-8550U, under Arch Linux over Windows 11/WSL 2 (yeah I know ๐Ÿ˜…), the creation of a HipStr from a slice is competitive with other crates and the std:


๐Ÿ“– Author and licenses

For now, just me PoLazarus ๐Ÿ‘ป
Help welcome! ๐Ÿšจ

MIT + Apache