arcstr: Better reference-counted strings.

Build Status codecov Docs Latest Version Minimum Rust Version

This crate defines ArcStr, a reference counted string type. It's essentially trying to be a better Arc<str> or Arc<String>, at least for most use cases.

ArcStr intentionally gives up some of the features of Arc which are rarely-used for Arc<str> (Weak, Arc::make_mut, ...). And in exchange, it gets a number of features that are very useful, especially for strings. Notably robust support for cheap/zero-cost ArcStrs holding static data (for example, string literals).

(Aside from this, it's also a single pointer, which can be good for performance and FFI)

Additionally, if the substr feature is enabled (and it is by default) we provide a Substr type which is essentially a (ArcStr, Range<usize>) with better ergonomics and more functionality, which represents a shared slice of a "parent" ArcStr (Note that in reality, u32 is used for the index type, but this is not exposed in the API, and can be transparently changed via a cargo feature).

Feature overview

A quick tour of the distinguishing features (note that there's a list of benefits in the ArcStr documentation which covers some of the reasons you might want to use it over other alternatives). Note that it offers essentially the full set of functionality string-like functionality you probably would expect from an immutable string type — these are just the unique selling points:

```rust use arcstr::ArcStr; // Works in const: const AMAZING: ArcStr = arcstr::literal!("amazing constant"); assert_eq!(AMAZING, "amazing constant");

// arcstr::literal! input can come from include_str! too: const MYBESTFILES: ArcStr = arcstr::literal!(include_str!("my-best-files.txt")); ```

Or, you can define the literals in normal expressions. Note that these literals are essentially "Zero Cost". Specifically, below we not only don't allocate any heap memory to instantiate wow or any of the clones, we also don't have to perform any atomic reads or writes when cloning, or dropping them (or during any other operations on them).

```rust let wow: ArcStr = arcstr::literal!("Wow!"); assert_eq!("Wow!", wow); // This line is probably not something you want to do regularly, // but as mentioned, causes no extra allocations, nor performs any // atomic loads, stores, rmws, etc. let wowzers = wow.clone().clone().clone().clone();

// At some point in the future, we can get a &'static str out of one // of the literal ArcStrs too. let staticstr: Option<&'static str> = ArcStr::asstatic(&wowzers); asserteq!(staticstr, Some("Wow!"));

// Note that this returns None for dynamically allocated ArcStr: let dynamicarc = ArcStr::from(format!("cool {}", 123)); asserteq!(ArcStr::asstatic(&dynamicarc), None); ```

Open TODO: Include Substr usage here, as it has some compelling use cases too!

Usage

It's a normal rust crate, drop it in your Cargo.toml's dependencies section. In the somewhat unlikely case that you're here and don't know how:

```toml [dependencies]

...

arcstr = { version = "...", features = ["..."] } ```

The following cargo features are available. Only substr is on by default currently.

Use of unsafe and testing strategy

While this crate does contain a decent amount of unsafe code, we justify this in the following ways:

  1. We have a very high test coverage ratio (essentially the only uncovered functions are the out-of-memory handler (which just calls alloc::handle_alloc_error), and an extremely pathological integer overflow where we just abort).
  2. All tests pass under various sanitizers: asan, msan, tsan, and miri.
  3. We have a few loom models although I'd love to have more.
  4. Our tests pass on a ton of different targets (thanks to cross for many of these possible — easy even):

Additionally, we test on Rust stable, beta, nightly, and our MSRV (see badge above for MSRV).

Supported platforms

Note that the above is not a list of supported platforms. In general I expect arcstr to support all platform's Rust supports, except for ones with target_pointer_width="16", which should work if you turn off the substr feature. That said, if you'd like me to add a platform to the CI coverage to ensure it doesn't break, just ask* (although, if it's harder than adding a line for another cross target, I'll probably need you to justify why it's likely to not be covered by the existing platform tests).

* This is why there are riscv64.