11 releases (6 breaking)
new 0.7.0 | Jan 10, 2025 |
---|---|
0.6.0 | Oct 8, 2024 |
0.5.1 | Aug 2, 2024 |
0.5.0 | Jun 25, 2024 |
0.2.0 | Jul 6, 2023 |
#26 in Memory management
2,909 downloads per month
Used in 16 crates
(2 directly)
445KB
10K
SLoC
hipstr
Yet another string type for Rust π¦
- no copy borrow via
borrowed
(aconst
constructor) orfrom_static
- no alloc small strings (23 bytes on 64-bit platform)
- no copy owned slices
- a niche:
Option<HipStr>
andHipStr
have the same size - zero dependency and compatible
no_std
withalloc
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): providesHipOsStr
andHipPath
types, and more trait implementations (for comparison and conversions)serde
: provides serialization/deserialization support withserde
borsh
: provides serialization/deserialization support withborsh
bstr
: provides compatibility with BurntSushi'sbstr
crateunstable
: do nothing, used to reveal unstable implementation details
β£οΈ Safety of hipstr
This crate makes extensive use of unsafe
code blocks. π€·
It leverages the 2-bit alignment niche present in pointers across most platforms (all platforms currently supported by the Rust compiler?) to discriminate between the three possible representations.
To make things safer, Rust is tested thoroughly on multiple platforms, normally and with Miri (the MIR interpreter).
π§ͺ Testing and Verification Strategy
To ensure safety and reliability, this crate undergoes thorough testing:
- Near 100% test coverage
- Cross-platform validation:
- 32-bit and 64-bit architectures
- little and big endian
In addition, this crate is checked with advanced dynamic verification methods:
- Concurrency testing using the Tokio's
loom
crate - Undefined behavior detection using Miri (the MIR interpreter)
β 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:
π₯οΈ Cross-platform testing
In the Github-provided CI, hipstr
is tested under:
- Linux
- Windows
- MacOS (ARM 64-bit LE)
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
𧡠Loom
This crates uses the loom
crate to check the custom "Arc" implementation. To
run the tests:
RUSTFLAGS='--cfg loom' cargo test --release loom
π Miri
This crate runs successfully with Miri:
MIRIFLAGS='-Zmiri-symbolic-alignment-check -Zmiri-permissive-provenance' cargo +nightly miri test
for SEED in $(seq 0 10); do
echo "Trying seed: $SEED"
MIRIFLAGS="-Zmiri-seed=$SEED -Zmiri-permissive-provenance" 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
Note: this crate leverages the "exposed provenance" semantics.
MIRIFLAGS=-Zmiri-permissive-provenance
silences the warning related to the use
of exposed provenance.
π¦ Similar crates
#[non_exhaustive]
Name | TS cheap-clone | Local cheap-clone | Inline | Cheap slice | Bytes | Borrow 'static |
Borrow any 'a |
Comment |
---|---|---|---|---|---|---|---|---|
hipstr |
β | β | β | β | β | β | β | obviously! |
arcstr |
β* | - | - | -** | - | β | - | *use a custom thin Arc , **heavy slice (with dedicated substring type) |
flexstr |
β* | β | β | - | - | β | - | *use (A)rc<str> instead of (A)rc<String> (remove a 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 |
- | - | β | - | - | - | - | |
kstring |
β | β | β | - | - | β | β* | safe mode, use boxed strings; * with second type |
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 π
ποΈ Performances
While speed is not the main motivator for hipstr
, it seems to be doing OK on that front.
See some actual benchmarks on Rust's String Rosetta.
π Author and licenses
For now, just me PoLazarus π»
Help welcome! π¨
MIT + Apache
Dependencies
~0β23MB
~305K SLoC