A VALUE frame and its CRC trailer (Rust)

The smallest whole frame the Rust core produces: a VALUE with the opt-in CRC-32C trailer. encode computes the trailer from opt.CR; decode recomputes it and refuses a mismatch.

What to notice

  • The trailer is opt-in, and so is the protection. The same one-bit flip that decode refuses as FrameCrcFail with the trailer decodes silently without it. Integrity is a per-frame choice the sender makes, not a property of the codec (reference 01).

  • Twelve bytes: 4 + 4 + 4. Header, payload, CRC. The C++ and TypeScript cores produce the same bytes, and the shared conformance vectors keep all three in step.

  • The error names are the wire names. Error::FrameCrcFail.name() prints FRAME_CRC_FAIL, the spelling the C++ and TypeScript cores use.

Source

 1// SPDX-License-Identifier: Apache-2.0
 2// SPDX-FileCopyrightText: Copyright 2026 avatarsd LLC
 3
 4/*!
 5 * @brief One concept: a VALUE frame with a CRC trailer, and what `decode` says when a
 6 * byte flips in transit.
 7 *
 8 * Run: `cargo run --example value_crc` (from `bindings/rust/`).
 9 */
10
11use libtracer::{decode, encode, value_opts, CrcWidth, Error, ValueOptions};
12
13fn main() {
14    // A 4-byte reading, with the opt-in CRC-32C trailer (opt.CR = 1).
15    let reading = 21_500u32.to_le_bytes();
16    let opts = ValueOptions {
17        crc: true,
18        ..ValueOptions::default()
19    };
20    let frame = encode(&value_opts(&reading, &opts));
21
22    // 4-byte header + 4 payload bytes + 4 CRC bytes.
23    println!("frame ({} bytes): {:02x?}", frame.len(), frame);
24    assert_eq!(frame.len(), 4 + 4 + 4);
25
26    // Decoding checks the trailer and hands back the payload unchanged.
27    let tlv = decode(&frame).expect("an intact frame decodes");
28    assert_eq!(tlv.payload, reading);
29    let crc = tlv
30        .trailer
31        .and_then(|t| t.crc)
32        .expect("the trailer carries the CRC");
33    assert_eq!(crc.width, CrcWidth::Crc32c);
34    println!(
35        "decoded payload {:02x?}, crc32c {:#010x}",
36        tlv.payload, crc.value
37    );
38
39    // Flip one payload bit: the frame still parses, but the CRC no longer matches.
40    let mut damaged = frame.clone();
41    damaged[4] ^= 0x01;
42    assert_eq!(decode(&damaged), Err(Error::FrameCrcFail));
43    println!("one flipped bit -> {}", Error::FrameCrcFail.name());
44
45    // Without the trailer the same damage is invisible to the codec.
46    let mut bare = encode(&value_opts(&reading, &ValueOptions::default()));
47    bare[4] ^= 0x01;
48    assert!(decode(&bare).is_ok());
49    println!("same flip without a CRC -> decodes silently");
50}

Run it from bindings/rust/:

$ cargo run --example value_crc

See also: the trailer (C++) · data format reference.