#string #string-representation #inline #reference-counting #cow #byte-slice

no-std hipstr

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

8 releases (4 breaking)

0.5.0 Jun 25, 2024
0.4.0 Dec 1, 2023
0.3.3 Oct 30, 2023
0.3.2 Aug 19, 2023
0.1.0 Jun 1, 2023

#45 in Memory management

Download history 5/week @ 2024-03-26 22/week @ 2024-04-02 5/week @ 2024-04-23 1/week @ 2024-05-14 10/week @ 2024-05-21 12/week @ 2024-05-28 7/week @ 2024-06-04 5/week @ 2024-06-11 135/week @ 2024-06-25 33/week @ 2024-07-02

168 downloads per month

MIT/Apache

345KB
7.5K SLoC

hipstr

Rust Clippy & Miri codecov Docs MIT OR Apache-2.0

Yet another string type 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
  • a niche: Option<HipStr> and HipStr have the same size
  • zero dependency and compatible no_std with alloc

Also byte strings, OS strings, and paths!

⚑ 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
drop(greetings); // the slice is owned, it exists even if greetings disappear

let chars = user.chars().count(); // "inherits" `&str` methods

✏️ Features

  • std (default): uses std rather than core and alloc, and also provides more trait implementations (for comparison, conversions, and errors)
  • 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 2-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 s390x-unknown-linux-gnu         # 32-bit BE
cross test --target powerpc64-unknown-linux-gnu     # 64-bit BE
cross test --target i686-unknown-linux-gnu          # 32-bit LE
cross test --target x86_64-unknown-linux-gnu        # 64-bit LE

NB: previously I used MIPS targets for big endian, but due to some LLVM-related issue they are not working anymore… see Rust issue #113065

πŸ” 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; };
done

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

#[non_exhaustive]

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:

string-comparison/chart.svg

πŸ“– Author and licenses

For now, just me PoLazarus πŸ‘»
Help welcome! 🚨

MIT + Apache

Dependencies