Method Chaining

ergo-sbe encoders are designed so the entire encode reads as one expression, from wrap_and_apply_header through .fixed(...) and every dynamic tail, ending in .encoded_length_with_header(). Bind only the resulting length; do not retain intermediate encoder variables.

Prefer (one chain, one let):

#![allow(unused)]
fn main() {
let mut buf = [0u8; HeartbeatEncoder::compute_length_with_header()];
// Buffer is exact size from const compute_length_with_header — no bounds check needed.
let len = HeartbeatEncoder::try_wrap_and_apply_header(&mut buf, 0)?
    .fixed(&HeartbeatFixedFields { sequence: 7, timestamp: 0 })
    .encoded_length_with_header();
let dec = HeartbeatDecoder::try_from(&buf[..len])?;
assert_eq!(dec.sequence(), 7);
}

(From book/examples/heartbeat-encode.rs — compiled against the feature-tour codec.)

Staged chaining vs fixed-only

For a fixed-only message like Heartbeat, wrap* returns HeartbeatEncoder<'_, H, FieldsUnfixed>. .fixed(&HeartbeatFixedFields { … }) consumes that value and returns FieldsFixed, which is the only phase that exposes as_bytes_with_header / as_body_bytes / encoded_length* / into_remaining_mut. Individual field setters stay on the unfixed phase and on raw_fixed(); they are not on that complete view.

Avoid (interrupted chain, rebinding):

// Each `let` breaks the chain and splays the pipeline across the screen.
// The `.unwrap()` calls are a code smell — the fallible chain should use `?`.
let enc = CarEncoder::wrap_and_apply_header(&mut buf, 0).fixed(&fields);
let enc = enc.fuel_figures(2, |g| { ... }).unwrap();
let enc = enc.manufacturer(b"Honda").unwrap();
let len = enc.encoded_length_with_header();

Every encoder stage is chainablefixed() and each tail method return the next stage (or Result<NextStage, _>) and compose with ? in the same expression. Intermediate encoder rebinding and manual .unwrap() defeat this design.

For the full Car example with groups and var-data, see the feature tour page.