Cow (Clone-on-Write) is a smart pointer that provides efficient handling of borrowed vs. owned data. It's defined as:
pub enum Cow<'a, B: ?Sized + ToOwned> {
Borrowed(&'a B),
Owned(<B as ToOwned>::Owned),
}The key insight is that Cow allows you to work with data that might be borrowed or owned, and only clones when mutation is actually needed. This is a powerful optimization pattern when:
Cow::Borrowed(data) - Wrap borrowed dataCow::Owned(data) - Wrap owned datacow.to_mut() - Get a mutable reference, cloning if borrowedcow.into_owned() - Convert to owned, cloning if borrowedCow::from(data) - Create from &str, String, &[T], Vec<T>, etc.Implement the following functions demonstrating Cow patterns:
maybe_uppercase - Convert to uppercase
only if any lowercase letters exist
Cow::Borrowed if already all
uppercase (or empty)Cow::Owned if conversion was neededensure_suffix - Ensure string ends with suffix
Cow::Borrowed if suffix already presentCow::Owned with suffix appended otherwisetrim_and_lowercase - Trim whitespace and
convert to lowercase
Cow::Borrowed only if string is
already trimmed and lowercaseCow::Owned otherwiseremove_zeros - Remove all zeros from a slice
Cow::Borrowed if no zeros existCow::Owned with zeros filtered outdeduplicate_sorted - Remove consecutive duplicates from sorted slice
Cow::Borrowed if no duplicatesCow::Owned with duplicates removedclamp_values - Clamp all values to a range [min, max]
Cow::Borrowed if all values already in rangeCow::Owned with clamped valuesensure_capacity - Ensure string has at
least N characters, padding with char if needed
to_mut() to modify only when necessarymodify_if_needed - Apply a transformation
function only if predicate returns true
to_mut() for efficient in-place
modification when already ownedTextProcessor - A struct demonstrating
Cow in a real-world scenario
Cow<'a, str>new(text: &'a str) - Create with borrowed
textfrom_owned(text: String) - Create with
owned textprocess(&mut self) - Apply processing
(trim + normalize whitespace)into_string(self) - Convert to Stringis_borrowed(&self) - Check if currently
borrowinguse cow_copy_on_write::*;
use std::borrow::Cow;
// Basic string operations
let result = maybe_uppercase("HELLO");
// Already uppercase
assert!(matches!(result, Cow::Borrowed(_)));
let result = maybe_uppercase("Hello");
assert_eq!(result, "HELLO"); // Needed conversion
// Suffix handling
let result = ensure_suffix("file.txt", ".txt");
// Already has suffix
assert!(matches!(result, Cow::Borrowed(_)));
let result = ensure_suffix("file", ".txt");
assert_eq!(result, "file.txt");
// Collection operations
let data = [1, 2, 3, 4];
let result = remove_zeros(&data);
assert!(matches!(result, Cow::Borrowed(_))); // No zeros
let data = [0, 1, 0, 2];
let result = remove_zeros(&data);
assert_eq!(result.as_ref(), &[1, 2]);
// Using to_mut() for efficient modification
let cow: Cow<str> = Cow::Borrowed("hi");
let result = ensure_capacity(cow, 5, '!');
assert_eq!(result, "hi!!!");
// TextProcessor
let mut processor = TextProcessor::new(" hello world ");
assert!(processor.is_borrowed());
processor.process();
// Now owned after processing
assert!(!processor.is_borrowed());
assert_eq!(processor.into_string(), "hello world");matches!(cow, Cow::Borrowed(_)) to check if borrowedto_mut() returns &mut B::Owned and clones if currently borrowedinto_owned() consumes the Cow and returns
owned dataCow<'a, str> with
Cow::Borrowed(&str) and Cow::Owned(String)Cow<'a, [T]> with
Cow::Borrowed(&[T]) and Cow::Owned(Vec<T>)Cow::from() trait creates
Cow::Borrowed from references and
Cow::Owned from owned types