[][src]Struct arcstr::ArcStr

#[repr(transparent)]pub struct ArcStr(_);

A better atomically-reference counted string type.

Benefits of ArcStr over Arc<str>

  • It's possible to create a const ArcStr from a literal via the arcstr::literal! macro. This is probably the killer feature, to be honest.

    These "static" ArcStrs are zero cost, take no heap allocation, and don't even need to perform atomic reads/writes when being cloned or dropped (nor at any other time).

    They even get stored in the read-only memory of your executable, which can be beneficial for performance and memory usage. (In theory your linker may even dedupe these for you, but usually not)

  • ArcStrs from arcstr::literal! can be turned into &'static str safely at any time using ArcStr::as_static. (This returns an Option, which is None if the ArcStr was not static)

  • This should be unsurprising given the literal functionality, but ArcStr::new is able to be a const function.

  • ArcStr is thin, e.g. only a single pointer. Great for cases where you want to keep the data structure lightweight or need to do some FFI stuff with it.

  • ArcStr is totally immutable. No need to lose sleep because you're afraid of code which thinks it has a right to mutate your Arcs just because it holds the only reference...

  • Lower reference counting operations are lower overhead because we don't support Weak references. This can be a drawback for some use cases, but improves performance for the common case of no-weak-refs.

What does "zero-cost literals" mean?

In a few places I call the literal arcstrs "zero-cost". No overhead most accesses accesses (aside from stuff like as_static which obviously requires it). and it imposes a extra branch in both clone and drop.

This branch in clone/drop is not on the result of an atomic load, and is just a normal memory read. This is actually what allows literal/static ArcStrs to avoid needing to perform any atomic operations in those functions, which seems likely more than cover the cost.

(Additionally, it's almost certain that in the future we'll be able to reduce the synchronization required for atomic instructions. This is due to our guarantee of immutability and lack of support for Weak.)

Usage

As a const

The big unique feature of ArcStr is the ability to create static/const ArcStrs. (See the macro docs or the feature overview

const WOW: ArcStr = arcstr::literal!("cool robot!");
assert_eq!(WOW, "cool robot!");

As a str

(This is not unique to ArcStr, but is a frequent source of confusion I've seen): ArcStr implements Deref<Target = str>, and so all functions and methods from str work on it, even though we don't expose them on ArcStr directly.

let s = ArcStr::from("something");
// These go through `Deref`, so they work even though
// there is no `ArcStr::eq_ignore_ascii_case` function
assert!(s.eq_ignore_ascii_case("SOMETHING"));

Additionally, &ArcStr can be passed to any function which accepts &str. For example:

fn accepts_str(s: &str) {
    // s...
}

let test_str: ArcStr = "test".into();
// This works even though `&test_str` is normally an `&ArcStr`
accepts_str(&test_str);

// Of course, this works for functionality from the standard library as well.
let test_but_loud = ArcStr::from("TEST");
assert!(test_str.eq_ignore_ascii_case(&test_but_loud));

Implementations

impl ArcStr[src]

pub const fn new() -> Self[src]

Construct a new empty string.

Examples

let s = ArcStr::new();
assert_eq!(s, "");

pub fn as_str(&self) -> &str[src]

Extract a string slice containing our data.

Note: This is an equivalent to our Deref implementation, but can be more readable than &*s in the cases where a manual invocation of Deref would be required.

Examples

let s = ArcStr::from("abc");
assert_eq!(s.as_str(), "abc");

pub fn len(&self) -> usize[src]

Returns the length of this ArcStr in bytes.

Examples

let a = ArcStr::from("foo");
assert_eq!(a.len(), 3);

pub fn is_empty(&self) -> bool[src]

Returns true if this ArcStr is empty.

Examples

assert!(!ArcStr::from("foo").is_empty());
assert!(ArcStr::new().is_empty());

pub fn to_string(&self) -> String[src]

Convert us to a std::string::String.

This is provided as an inherent method to avoid needing to route through the Display machinery, but is equivalent to ToString::to_string.

Examples

let s = ArcStr::from("abc");
assert_eq!(s.to_string(), "abc");

pub fn as_bytes(&self) -> &[u8][src]

Extract a byte slice containing the string's data.

Examples

let foobar = ArcStr::from("foobar");
assert_eq!(foobar.as_bytes(), b"foobar");

pub fn into_raw(this: Self) -> NonNull<()>[src]

Return the raw pointer this ArcStr wraps, for advanced use cases.

Note that in addition to the NonNull constraint expressed in the type signature, we also guarantee the pointer has an alignment of at least 8 bytes, even on platforms where a lower alignment would be acceptable.

Examples

let s = ArcStr::from("abcd");
let p = ArcStr::into_raw(s);
// Some time later...
let s = unsafe { ArcStr::from_raw(p) };
assert_eq!(s, "abcd");

pub unsafe fn from_raw(ptr: NonNull<()>) -> Self[src]

The opposite version of Self::into_raw. Still intended only for advanced use cases.

Safety

This function must be used on a valid pointer returned from ArcStr::into_raw. Additionally, you must ensure that a given ArcStr instance is only dropped once.

Examples

let s = ArcStr::from("abcd");
let p = ArcStr::into_raw(s);
// Some time later...
let s = unsafe { ArcStr::from_raw(p) };
assert_eq!(s, "abcd");

pub fn ptr_eq(lhs: &Self, rhs: &Self) -> bool[src]

Returns true if the two ArcStrs point to the same allocation.

Note that functions like PartialEq check this already, so there's no performance benefit to doing something like ArcStr::ptr_eq(&a1, &a2) || (a1 == a2).

Caveat: consts aren't guaranteed to only occur in an executable a single time, and so this may be non-deterministic for ArcStr defined in a const with arcstr::literal!, unless one was created by a clone() on the other.

Examples

use arcstr::ArcStr;

let foobar = ArcStr::from("foobar");
let same_foobar = foobar.clone();
let other_foobar = ArcStr::from("foobar");
assert!(ArcStr::ptr_eq(&foobar, &same_foobar));
assert!(!ArcStr::ptr_eq(&foobar, &other_foobar));

const YET_AGAIN_A_DIFFERENT_FOOBAR: ArcStr = arcstr::literal!("foobar");
let strange_new_foobar = YET_AGAIN_A_DIFFERENT_FOOBAR.clone();
let wild_blue_foobar = strange_new_foobar.clone();
assert!(ArcStr::ptr_eq(&strange_new_foobar, &wild_blue_foobar));

pub fn strong_count(this: &Self) -> Option<usize>[src]

Returns the number of references that exist to this ArcStr. If this is a static ArcStr (For example, one from arcstr::literal!), returns None.

Despite the difference in return type, this is named to match the method from the stdlib's Arc: Arc::strong_count.

If you aren't sure how to handle static ArcStr in the context of this return value, ArcStr::strong_count(&s).unwrap_or(usize::MAX) is frequently reasonable.

Safety

This method by itself is safe, but using it correctly requires extra care. Another thread can change the strong count at any time, including potentially between calling this method and acting on the result.

However, it may never change from None to Some or from Some to None for a given ArcStr — whether or not it is static is determined at construction, and never changes.

Examples

Dynamic ArcStr

let foobar = ArcStr::from("foobar");
assert_eq!(Some(1), ArcStr::strong_count(&foobar));
let also_foobar = ArcStr::clone(&foobar);
assert_eq!(Some(2), ArcStr::strong_count(&foobar));
assert_eq!(Some(2), ArcStr::strong_count(&also_foobar));

Static ArcStr

let baz = arcstr::literal!("baz");
assert_eq!(None, ArcStr::strong_count(&baz));
// Similarly:
assert_eq!(None, ArcStr::strong_count(&ArcStr::default()));

pub fn is_static(this: &Self) -> bool[src]

Returns true if this is a "static" ArcStr. For example, if it was created from a call to arcstr::literal!), returned by ArcStr::new, etc.

Static ArcStrs can be converted to &'static str for free using ArcStr::as_static, without leaking memory — they're static constants in the program (somewhere).

Examples

const STATIC: ArcStr = arcstr::literal!("Electricity!");
assert!(ArcStr::is_static(&STATIC));

let still_static = arcstr::literal!("Shocking!");
assert!(ArcStr::is_static(&still_static));
assert!(
    ArcStr::is_static(&still_static.clone()),
    "Cloned statics are still static"
);

let nonstatic = ArcStr::from("Grounded...");
assert!(!ArcStr::is_static(&nonstatic));

pub fn as_static(this: &Self) -> Option<&'static str>[src]

Returns true if this is a "static"/"literal" ArcStr. For example, if it was created from a call to literal!), returned by ArcStr::new, etc.

Static ArcStrs can be converted to &'static str for free using ArcStr::as_static, without leaking memory — they're static constants in the program (somewhere).

Examples

const STATIC: ArcStr = arcstr::literal!("Electricity!");
assert_eq!(ArcStr::as_static(&STATIC), Some("Electricity!"));

// Note that they don't have to be consts, just made using `literal!`:
let still_static = arcstr::literal!("Shocking!");
assert_eq!(ArcStr::as_static(&still_static), Some("Shocking!"));
// Cloning a static still produces a static.
assert_eq!(ArcStr::as_static(&still_static.clone()), Some("Shocking!"));

// But it won't work for strings from other sources.
let nonstatic = ArcStr::from("Grounded...");
assert_eq!(ArcStr::as_static(&nonstatic), None);

pub fn substr(&self, range: impl RangeBounds<usize>) -> Substr[src]

feature = "substr" Returns a substr of self over the given range.

Examples

use arcstr::{ArcStr, Substr};

let a = ArcStr::from("abcde");
let b: Substr = a.substr(2..);

assert_eq!(b, "cde");

Panics

If any of the following are untrue, we panic

  • range.start() <= range.end()
  • range.end() <= self.len()
  • self.is_char_boundary(start) && self.is_char_boundary(end)
  • These can be conveniently verified in advance using self.get(start..end).is_some() if needed.

pub fn substr_from(&self, substr: &str) -> Substr[src]

feature = "substr" Returns a Substr of self over the given &str.

It is not rare to end up with a &str which holds a view into a ArcStr's backing data. A common case is when using functionality that takes and returns &str and are entirely unaware of arcstr, for example: str::trim().

This function allows you to reconstruct a Substr from a &str which is a view into this ArcStr's backing string.

Examples

use arcstr::{ArcStr, Substr};
let text = ArcStr::from("   abc");
let trimmed = text.trim();
let substr: Substr = text.substr_from(trimmed);
assert_eq!(substr, "abc");
// for illustration
assert!(ArcStr::ptr_eq(substr.parent(), &text));
assert_eq!(substr.range(), 3..6);

Panics

Panics if substr isn't a view into our memory.

Also panics if substr is a view into our memory but is >= u32::MAX bytes away from our start, if we're a 64-bit machine and substr-usize-indices is not enabled.

pub fn try_substr_from(&self, substr: &str) -> Option<Substr>[src]

feature = "substr" If possible, returns a Substr of self over the given &str.

This is a fallible version of ArcStr::substr_from.

It is not rare to end up with a &str which holds a view into a ArcStr's backing data. A common case is when using functionality that takes and returns &str and are entirely unaware of arcstr, for example: str::trim().

This function allows you to reconstruct a Substr from a &str which is a view into this ArcStr's backing string.

Examples

use arcstr::{ArcStr, Substr};
let text = ArcStr::from("   abc");
let trimmed = text.trim();
let substr: Option<Substr> = text.try_substr_from(trimmed);
assert_eq!(substr.unwrap(), "abc");
// `&str`s not derived from `self` will return None.
let not_substr = text.try_substr_from("abc");
assert!(not_substr.is_none());

Panics

Panics if substr is a view into our memory but is >= u32::MAX bytes away from our start, if we're a 64-bit machine and substr-usize-indices is not enabled.

pub fn try_substr_using(&self, f: impl FnOnce(&str) -> &str) -> Option<Substr>[src]

feature = "substr" Compute a derived &str a function of &str => &str, and produce a Substr of the result if possible.

The function may return either a derived string, or any empty string.

This function is mainly a wrapper around ArcStr::try_substr_from. If you're coming to arcstr from the shared_string crate, this is the moral equivalent of the slice_with function.

Examples

use arcstr::{ArcStr, Substr};
let text = ArcStr::from("   abc");
let trimmed: Option<Substr> = text.try_substr_using(str::trim);
assert_eq!(trimmed.unwrap(), "abc");
let other = text.try_substr_using(|_s| "different string!");
assert_eq!(other, None);
// As a special case, this is allowed.
let empty = text.try_substr_using(|_s| "");
assert_eq!(empty.unwrap(), "");

pub fn substr_using(&self, f: impl FnOnce(&str) -> &str) -> Substr[src]

feature = "substr" Compute a derived &str a function of &str => &str, and produce a Substr of the result.

The function may return either a derived string, or any empty string. Returning anything else will result in a panic.

This function is mainly a wrapper around ArcStr::try_substr_from. If you're coming to arcstr from the shared_string crate, this is the likely closest to the slice_with_unchecked function, but this panics instead of UB on dodginess.

Examples

use arcstr::{ArcStr, Substr};
let text = ArcStr::from("   abc");
let trimmed: Substr = text.substr_using(str::trim);
assert_eq!(trimmed, "abc");
// As a special case, this is allowed.
let empty = text.substr_using(|_s| "");
assert_eq!(empty, "");

Trait Implementations

impl AsRef<[u8]> for ArcStr[src]

impl AsRef<str> for ArcStr[src]

impl Borrow<str> for ArcStr[src]

impl Clone for ArcStr[src]

impl Debug for ArcStr[src]

impl Default for ArcStr[src]

impl Deref for ArcStr[src]

type Target = str

The resulting type after dereferencing.

impl Display for ArcStr[src]

impl Drop for ArcStr[src]

impl Eq for ArcStr[src]

impl<'_> From<&'_ ArcStr> for ArcStr[src]

impl<'_> From<&'_ ArcStr> for Substr[src]

impl<'_> From<&'_ String> for ArcStr[src]

impl<'_> From<&'_ mut str> for ArcStr[src]

impl<'_> From<&'_ str> for ArcStr[src]

impl<'a> From<&'a ArcStr> for Cow<'a, str>[src]

impl From<Arc<str>> for ArcStr[src]

impl From<ArcStr> for Box<str>[src]

impl From<ArcStr> for Rc<str>[src]

impl From<ArcStr> for Arc<str>[src]

impl<'a> From<ArcStr> for Cow<'a, str>[src]

impl From<ArcStr> for Substr[src]

impl From<Box<str>> for ArcStr[src]

impl<'a> From<Cow<'a, str>> for ArcStr[src]

impl From<Rc<str>> for ArcStr[src]

impl From<String> for ArcStr[src]

impl FromStr for ArcStr[src]

type Err = Infallible

The associated error which can be returned from parsing.

impl Hash for ArcStr[src]

impl Index<Range<usize>> for ArcStr[src]

type Output = str

The returned type after indexing.

impl Index<RangeFrom<usize>> for ArcStr[src]

type Output = str

The returned type after indexing.

impl Index<RangeFull> for ArcStr[src]

type Output = str

The returned type after indexing.

impl Index<RangeInclusive<usize>> for ArcStr[src]

type Output = str

The returned type after indexing.

impl Index<RangeTo<usize>> for ArcStr[src]

type Output = str

The returned type after indexing.

impl Index<RangeToInclusive<usize>> for ArcStr[src]

type Output = str

The returned type after indexing.

impl Ord for ArcStr[src]

impl<'a> PartialEq<&'a str> for ArcStr[src]

impl<'a> PartialEq<Arc<str>> for ArcStr[src]

impl PartialEq<ArcStr> for ArcStr[src]

impl<'a> PartialEq<ArcStr> for str[src]

impl<'a> PartialEq<ArcStr> for &'a str[src]

impl<'a> PartialEq<ArcStr> for String[src]

impl<'a> PartialEq<ArcStr> for Cow<'a, str>[src]

impl<'a> PartialEq<ArcStr> for Box<str>[src]

impl<'a> PartialEq<ArcStr> for Arc<str>[src]

impl<'a> PartialEq<ArcStr> for Rc<str>[src]

impl PartialEq<ArcStr> for Substr[src]

impl<'a> PartialEq<Box<str>> for ArcStr[src]

impl<'a> PartialEq<Cow<'a, str>> for ArcStr[src]

impl<'a> PartialEq<Rc<str>> for ArcStr[src]

impl<'a> PartialEq<String> for ArcStr[src]

impl PartialEq<Substr> for ArcStr[src]

impl<'a> PartialEq<str> for ArcStr[src]

impl PartialOrd<ArcStr> for ArcStr[src]

impl Send for ArcStr[src]

impl Sync for ArcStr[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

impl<T> ToString for T where
    T: Display + ?Sized
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.