Struct arcstr::ArcStr [−][src]
#[repr(transparent)]pub struct ArcStr(_);
Expand description
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 thearcstr::literal!
macro. This is probably the killer feature, to be honest.These “static”
ArcStr
s 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)
-
ArcStr
s fromarcstr::literal!
can be turned into&'static str
safely at any time usingArcStr::as_static
. (This returns an Option, which isNone
if theArcStr
was not static) -
This should be unsurprising given the literal functionality, but
ArcStr::new
is able to be aconst
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 yourArc
s 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
ArcStr
s 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
ArcStr
s. (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
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");
Returns the length of this ArcStr
in bytes.
Examples
let a = ArcStr::from("foo"); assert_eq!(a.len(), 3);
Returns true if this ArcStr
is empty.
Examples
assert!(!ArcStr::from("foo").is_empty()); assert!(ArcStr::new().is_empty());
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");
Extract a byte slice containing the string’s data.
Examples
let foobar = ArcStr::from("foobar"); assert_eq!(foobar.as_bytes(), b"foobar");
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");
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");
Returns true if the two ArcStr
s 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: const
s 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));
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()));
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 ArcStr
s 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));
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 ArcStr
s 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);
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.
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.
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.
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(), "");
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
This method returns an ordering between self
and other
values if one exists. Read more
This method tests less than (for self
and other
) and is used by the <
operator. Read more
This method tests less than or equal to (for self
and other
) and is used by the <=
operator. Read more
This method tests greater than (for self
and other
) and is used by the >
operator. Read more
Auto Trait Implementations
Blanket Implementations
Mutably borrows from an owned value. Read more