rust
33 lines · 6 steps
Zero-copy HTML escaping with Cow in Rust
How Cow lets escape_html avoid allocating when there's nothing to escape.
Explained by
highlit
1use std::borrow::Cow;
2
3pub fn escape_html(input: &str) -> Cow<'_, str> {
4 let needs_escape = input
5 .bytes()
6 .any(|b| matches!(b, b'&' | b'<' | b'>' | b'"' | b'\''));
7
8 if !needs_escape {
9 return Cow::Borrowed(input);
10 }
11
12 let mut escaped = String::with_capacity(input.len() + 16);
13 for ch in input.chars() {
14 match ch {
15 '&' => escaped.push_str("&"),
16 '<' => escaped.push_str("<"),
17 '>' => escaped.push_str(">"),
18 '"' => escaped.push_str("""),
19 '\'' => escaped.push_str("'"),
20 other => escaped.push(other),
21 }
22 }
23
24 Cow::Owned(escaped)
25}
26
27pub fn render_comment(author: &str, body: &str) -> String {
28 format!(
29 "<article class=\"comment\">\n <h3>{}</h3>\n <p>{}</p>\n</article>",
30 escape_html(author),
31 escape_html(body),
32 )
33}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Cow lets a function return either a borrow or an owned value from one signature, deferring allocation until it's actually needed.
- 2A cheap upfront scan can spare the common case from any allocation at all.
- 3Pre-sizing the output buffer with with_capacity trims reallocations when you already know the growth is small.
Related explainers
rust
use serde::Deserialize; #[derive(Debug, Deserialize)] #[serde(untagged)]
Parsing flexible JSON shapes with serde
deserialization
enums
json
Intermediate
6 steps
rust
use std::cmp::{Ordering, Reverse}; use std::collections::BinaryHeap; use std::fs::File; use std::io::{self, BufRead, BufReader, BufWriter, Lines, Write};
K-way merge of sorted logs in Rust
binary-heap
k-way-merge
streaming-io
Intermediate
8 steps
rust
use axum::{ extract::{Path, State}, response::sse::{Event, KeepAlive, Sse}, };
Streaming import progress with SSE in Axum
server-sent-events
streams
watch-channel
Advanced
7 steps
rust
use std::f64::consts::PI; #[derive(Debug, Clone, Copy)] pub struct LatLng {
Building geographic bounding boxes in Rust
geospatial
value-types
option
Intermediate
7 steps
rust
use chrono::{Duration, NaiveDate}; #[derive(Debug)] pub struct DateRange {
Parsing and iterating date ranges in Rust
error-handling
iterators
parsing
Intermediate
7 steps
rust
use std::collections::VecDeque; use std::sync::{Arc, Condvar, Mutex}; use std::time::{Duration, Instant};
Building a counting semaphore in Rust
concurrency
synchronization
condition-variable
Advanced
9 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/zero-copy-html-escaping-with-cow-in-rust-explained-rust-732a/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.