Skip to content

← Collections, Text and First Iterators step 3 of 21

Easy Primitives

Build a CSV record with one output buffer

Join fields into one CSV record, adding quotes where needed. Build the result in a shared output buffer instead of creating a new accumulated String for every field.

pub fn render_csv_line(fields: &[String]) -> String

Exact output rules

Preserve field order and place one comma between adjacent fields. Quote a field if it contains a comma, double quote, carriage return or newline. Surround that field with double quotes and write each double quote inside it twice. Copy every other character unchanged.

Do not quote other fields. Do not trim spaces, normalize line endings or add a record terminator. Tabs, other controls and Unicode are preserved; only the four characters above determine quoting in this exercise.

Fields Output
a, b, c a,b,c
a,b, c "a,b",c
he said "hi" "he said ""hi"""
Two empty fields ,
No fields or one empty field Empty string.

An embedded newline stays inside its quoted field, so a single record may span multiple physical lines. The task uses familiar CSV quoting rules while allowing arbitrary Rust string contents; follow the rules here rather than adding separate character validation.

Allocation budget

A generated test builds 5000 fields, then measures allocator calls during render_csv_line. The call must make at most 20 allocation or reallocation requests through the harness's global allocator. Input construction and JSON serialization are outside the measured interval.

The counter measures requests, not allocated bytes, live memory or execution time. Exact counts depend on library and compiler behavior. Reusing one output String avoids allocating a separate formatted result for each field; reserving capacity can reduce growth requests further. Preserve correct quoting whether or not you choose to reserve space.

Small tests compare the whole output. The generated test checks its UTF-8 byte length and allocation budget, so those two checks alone do not establish that the generated record's contents are correct.

Why write! needs an import

The starter calls write! on a String but has not imported the trait that provides the formatting method. Rust reports E0599. std::fmt::Write supplies text-formatting methods for String; std::io::Write is for byte-oriented outputs such as files and sockets.

Bringing the appropriate trait into scope enables method lookup. Trait methods still exist without the import and can also be called with fully qualified syntax. A missing import is one possible cause of E0599, not the explanation for every missing-method error.

This complete example writes formatted values into an existing String:

use std::fmt::Write as _;

fn main() {
    let mut out = String::from("items=");
    write!(&mut out, "{}", 3).unwrap();
    out.push_str("; ready");
    assert_eq!(out, "items=3; ready");
}

Formatting returns fmt::Result. That error represents a formatting failure, not every possible allocation failure. Writing these string contents into a String normally succeeds; adding the import still leaves CSV quoting to implement. You can also build this output entirely with push and push_str.

Append rather than rebuild

push appends a character, and push_str appends a string slice. If capacity runs out, the buffer can grow and existing bytes may need to move.

String addition takes its left operand by value. An expression such as out = out + part can reuse that String's buffer; it does not inherently rebuild the whole prefix on each iteration. It may still need to grow.

By contrast, out = format!("{out}{part}") formats the accumulated prefix into a new String each time. Repeatedly rebuilding a growing prefix can cause quadratic copying work. Appending to the existing buffer avoids that pattern.

Plain join is useful for fields that need no transformation, but CSV quoting may require escaping individual characters. Keep one output buffer, insert separators as needed, and append either an unchanged field or its quoted form. Use write! when formatting values into that buffer helps; use format! when a separately owned formatted result is actually needed.

Submissions must compile, pass the output and budget checks, and pass Clippy with warnings treated as errors. Clippy does not replace performance testing.