Expand description

Smart String

SmartString is a wrapper around String which offers automatic inlining of small strings. It comes in two flavours: LazyCompact, which takes up exactly as much space as a String and is generally a little faster, and Compact, which is the same as LazyCompact except it will aggressively re-inline any expanded Strings which become short enough to do so. LazyCompact is the default, and what you should be using unless you care considerably more about heap memory usage than performance.

What Is It For?

The intended use for SmartString is as a key type for a B-tree (such as std::collections::BTreeMap) or any kind of array operation where cache locality is critical.

In general, it’s a nice data type for reducing your heap allocations and increasing the locality of string data. If you use SmartString as a drop-in replacement for String, you’re almost certain to see a slight performance boost, as well as slightly reduced memory usage.

How To Use It?

SmartString has the exact same API as String, all the clever bits happen automatically behind the scenes, so you could just:

use smartstring::alias::String;
use std::fmt::Write;

let mut string = String::new();
string.push_str("This is just a string!");
write!(string, "Hello Joe!");
assert_eq!("Hello Joe!", string);

Give Me The Details

SmartString is the same size as String and relies on pointer alignment to be able to store a discriminant bit in its inline form that will never be present in its String form, thus giving us 24 bytes (on 64-bit architectures) minus one bit to encode our inline string. It uses 23 bytes to store the string data and the remaining 7 bits to encode the string’s length. When the available space is exceeded, it swaps itself out with a boxed string type containing its previous contents. Likewise, if the string’s length should drop below its inline capacity again, it deallocates the string and moves its contents inline.

In Compact mode, it is aggressive about inlining strings, meaning that if you modify a heap allocated string such that it becomes short enough for inlining, it will be inlined immediately and the allocated String will be dropped. This may cause multiple unintended allocations if you repeatedly adjust your string’s length across the inline capacity threshold, so if your string’s construction can get complicated and you’re relying on performance during construction, it might be better to construct it as a String and convert it once construction is done.

LazyCompact looks the same as Compact, except it never re-inlines a string that’s already been heap allocated, instead keeping the allocation around in case it needs it. This makes for less cache local strings, but is the best choice if you’re more worried about time spent on unnecessary allocations than cache locality.


It doesn’t aim to be more performant than String in the general case, except that it doesn’t trigger heap allocations for anything shorter than its inline capacity and so can be reasonably expected to exceed String’s performance perceptibly on shorter strings, as well as being more memory efficient in these cases. There will always be a slight overhead on all operations on boxed strings, compared to String.

Feature Flags

smartstring comes with optional support for the following crates through Cargo feature flags. You can enable them in your Cargo.toml file like this:

smartstring = { version = "*", features = ["proptest", "serde"] }
arbitraryArbitrary implementation for SmartString.
proptestA strategy for generating SmartStrings from a regular expression.
serdeSerialize and Deserialize implementations for SmartString.


Convenient type aliases.

proptest strategies (requires the proptest feature flag).


A compact string representation equal to String in size with guaranteed inlining.

A draining iterator for a SmartString.

A representation similar to Compact but which doesn’t re-inline strings.

A smart string.


The maximum capacity of an inline string, in bytes.


Marker trait for SmartString representations.