Advanced Lifetimes and Borrowing

Borrowed Data Structures

A borrowed data structure (also called a zero-copy view type) is a struct or enum parameterized by one or more lifetimes (such as Packet<'a> or AstNode<'src>) that stores slices (&'a str, &'a [u8]) pointing directly into an external backing buffer instead of allocating owned String or Vec<u8> copies on the heap.

Zero-Copy Parsing Architecture

When parsing structured text (JSON, HTTP headers, configuration files, source code) or binary network frames, allocating a separate String for every token or header field can dominate execution time. A borrowed data structure slices the input buffer in place:

Caller's Owned Backing Buffer (`raw_request: String` on Heap):
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| G | E | T |   | / | a | p | i | / | v | 1 |   | H | T | T | P | 1 |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
  ^       ^       ^                       ^       ^               ^
  |       |       |                       |       |               |
  +-------+       +-----------------------+       +---------------+
  method: &'a str       path: &'a str              version: &'a str
  (ptr, len = 3)        (ptr, len = 7)             (ptr, len = 5)
#[derive(Debug, PartialEq, Eq)]
struct HttpRequestLine<'buf> {
    method: &'buf str,
    path: &'buf str,
    version: &'buf str,
}

impl<'buf> HttpRequestLine<'buf> {
    fn parse(line: &'buf str) -> Option<Self> {
        let mut parts = line.split_whitespace();
        let method = parts.next()?;
        let path = parts.next()?;
        let version = parts.next()?;
        Some(Self {
            method,
            path,
            version,
        })
    }
}

fn main() {
    let raw_buffer = String::from("GET /api/v1/items HTTP/1.1\r\n");
    let parsed = HttpRequestLine::parse(&raw_buffer).unwrap();

    println!("parsed zero-copy view: {:?}", parsed);
}
parsed zero-copy view: HttpRequestLine { method: "GET", path: "/api/v1/items", version: "HTTP/1.1" }

While parsed is alive, the borrow checker prevents raw_buffer from being mutated or dropped, guaranteeing that parsed.method, parsed.path, and parsed.version never dangle.

Hybrid Borrowed-or-Owned Structures with Cow<'a, str>

Purely borrowed slices (&'a str) work when the substring appears verbatim in the input buffer. If a string occasionally requires unescaping (for example, replacing \" with " in JSON or decoding %20 in a URL), using std::borrow::Cow<'a, str> borrows verbatim substrings with zero allocation (Cow::Borrowed(&'a str)) and allocates a String (Cow::Owned(String)) only when an escape sequence is present:

use std::borrow::Cow;

#[derive(Debug)]
struct QueryParam<'a> {
    key: &'a str,
    value: Cow<'a, str>,
}

fn parse_param(pair: &str) -> Option<QueryParam<'_>> {
    let (key, raw_val) = pair.split_once('=')?;
    let value = if raw_val.contains('+') {
        Cow::Owned(raw_val.replace('+', " "))
    } else {
        Cow::Borrowed(raw_val)
    };
    Some(QueryParam { key, value })
}

fn main() {
    let p1 = parse_param("lang=rust").unwrap();
    let p2 = parse_param("title=advanced+lifetimes").unwrap();

    println!(
        "p1: {:?} (borrowed = {})",
        p1,
        matches!(p1.value, Cow::Borrowed(_))
    );
    println!(
        "p2: {:?} (borrowed = {})",
        p2,
        matches!(p2.value, Cow::Borrowed(_))
    );
}
p1: QueryParam { key: "lang", value: "rust" } (borrowed = true)
p2: QueryParam { key: "title", value: "advanced lifetimes" } (borrowed = false)

Detaching a Borrowed Structure via .into_owned()

By providing an into_owned(self) -> HttpRequestLine<'static> method on a Cow-based structure, callers can parse at zero-copy speed during request handling and convert only the specific structs that need to be stored long-term into 'static owned instances.

Design Approach Allocation Cost Ergonomics Across Threads / Async
Owned (String, Vec<u8>) 1 heap allocation per field High ('static, easy to store and send)
Purely Borrowed (&'a str, &'a [u8]) 0 allocations Tied to backing buffer lifetime 'a
Hybrid (Cow<'a, str>, Cow<'a, [u8]>) 0 on fast path; allocates only on mutation/unescape Can convert to 'static via Cow::into_owned
Shared Slice (Arc<str>, Bytes) Reference-count increment only High ('static, no lifetime parameters)