Crate str_cat

source ·
Expand description

This crate provides macros to efficiently concatenate strings without extra side-effect.

Usage

Basic usage

use str_cat::str_cat;

let world = "World".to_owned(); // not a literal, so you can't use `concat!`
let s = str_cat!("Hello", " ", world, "!");
assert_eq!(s, "Hello World!");

which is roughly equivalent to

let mut s = String::with_capacity("Hello".len() + " ".len() + world.len() + "!".len());
s.push_str("Hello");
s.push_str(" ");
s.push_str(&world);
s.push_str("!");

No extra side-effect

The macro runs without extra side-effect, which means all involved expressions are evaluated exactly once.

let mut get_world_calls = 0;
let mut get_world = || {
    get_world_calls += 1;
    "World"
};
let s = str_cat!("Hello", " ", get_world(), "!");
assert_eq!(s, "Hello World!");
assert_eq!(get_world_calls, 1);

which is roughly equivalent to

let world = get_world(); // evaluate the expression and store it for later use
let mut s = String::with_capacity("Hello".len() + " ".len() + world.len() + "!".len());
s.push_str("Hello");
s.push_str(" ");
s.push_str(&world);
s.push_str("!");

Append to an existing string

let mut s = "Hello".to_owned();
str_cat!(&mut s; " ", "World!");
assert_eq!(s, "Hello World!");

Reuse existing allocation

let mut s = "Hello World!".to_owned();
let ptr = s.as_ptr();
let cap = s.capacity();

s.clear();
str_cat!(&mut s; "Hello");
assert_eq!(s, "Hello");
// Did not grow
assert_eq!(s.as_ptr(), ptr);
assert_eq!(s.capacity(), cap);

Custom minimum capacity

let s = str_cat!(String::with_capacity(16); "foo", "bar");
assert_eq!(s, "foobar");
assert!(s.capacity() >= 16);

Argument types

Works with any expressions that can dereference to str when evaluated. Although it should be more simple and efficient to use format! instead when you can’t avoid explicit .to_string() calls.

// Just an example. It's better to use `format!` in this case.
let s = str_cat!(
    "Hello".to_owned(),
    Box::new(" "),
    ['W', 'o', 'r', 'l', 'd'].iter().collect::<String>(),
    '!'.to_string(),
    123456.to_string(),
);
assert_eq!(s, "Hello World!123456");

Variants

There are also variants for PathBuf, OsString and Vec.

use str_cat::os_str_cat;

// Works for anything that implements AsRef<OsStr>.
let s = os_str_cat!(
    OsStr::new("Hello"),
    OsStr::new(" ").to_owned(),
    Path::new("World"),
    "!",
);
assert_eq!(s, OsStr::new("Hello World!"));

Macros