rust 42 lines · 7 steps

Avoiding allocations with Cow in Rust

How Cow<str> lets string helpers borrow when nothing changes and only allocate when they must.

Explained by highlit
1use std::borrow::Cow;
2 
3fn sanitize_filename(input: &str) -> Cow<'_, str> {
4 if input.chars().all(|c| c.is_alphanumeric() || matches!(c, '.' | '-' | '_')) {
5 return Cow::Borrowed(input);
6 }
7 
8 let cleaned: String = input
9 .chars()
10 .map(|c| match c {
11 c if c.is_alphanumeric() => c,
12 '.' | '-' | '_' => c,
13 _ => '_',
14 })
15 .collect();
16 
17 Cow::Owned(cleaned)
18}
19 
20fn strip_prefix<'a>(path: &'a str, base: &str) -> Cow<'a, str> {
21 match path.strip_prefix(base) {
22 Some(rest) => Cow::Borrowed(rest.trim_start_matches('/')),
23 None => Cow::Borrowed(path),
24 }
25}
26 
27fn ensure_extension(name: Cow<'_, str>, ext: &str) -> Cow<'_, str> {
28 if name.ends_with(ext) {
29 name
30 } else {
31 let mut owned = name.into_owned();
32 owned.push_str(ext);
33 Cow::Owned(owned)
34 }
35}
36 
37fn build_asset_key(raw_path: &str, base: &str) -> String {
38 let relative = strip_prefix(raw_path, base);
39 let safe = sanitize_filename(&relative);
40 let finalized = ensure_extension(safe, ".bin");
41 finalized.into_owned()
42}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Cow lets a function return either a borrowed slice or an owned String behind one type, deferring allocation until it's genuinely needed.
  2. 2Checking the common case first and returning Cow::Borrowed keeps the fast path allocation-free.
  3. 3Chaining Cow-returning helpers preserves borrows across steps, so a single into_owned at the end materializes the result at most once.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Avoiding allocations with Cow in Rust — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code