Trust Boundaries
Checked entry points validate the message header and fixed block. verify
walks the complete dynamic tail before bulk access:
#![allow(unused)]
fn main() {
pub fn demo_try_vs_trusted(valid_car: &[u8]) -> Result<(), Box<dyn std::error::Error>> {
// `decode` validates template_id, schema_id, version, and the
// version-aware fixed body extent at message start (offset 0).
let _dec = CarDecoder::try_decode(valid_car, 0)?;
// `verify` walks the complete dynamic tail (groups + var-data), not a
// header-only peek — use it when you need full structural acceptance
// without materialising a long-lived decoder stage chain.
CarDecoder::verify(valid_car)?;
// Truncated buffers fail checked entry points with Result errors.
assert!(
CarDecoder::try_decode(&valid_car[..8.min(valid_car.len())], 0).is_err(),
"truncated buffer should fail try_decode"
);
if valid_car.len() > 16 {
assert!(
CarDecoder::verify(&valid_car[..16]).is_err(),
"truncated buffer should fail verify (incomplete tail)"
);
}
// `wrap` still returns Result and validates the body extent given acting
// block_length + version (message start, not sbe-tool body offset).
let mut hdr_bytes = [0u8; 8];
hdr_bytes.copy_from_slice(&valid_car[..8]);
let hdr = MessageHeader(hdr_bytes);
let dec = CarDecoder::try_wrap(valid_car, 0, hdr.block_length() as usize, hdr.version())?;
assert_eq!(dec.serial_number(), 1234);
Ok(())
}
}
(This code comes from the sbe-feature-tour sample crate.)
Three-tier constructors
| Tier | Entry | Bad buffer |
|---|---|---|
| Checked | try_wrap / try_wrap_and_apply_header / try_decode | Result::Err (all failures) |
| Trusted | bare wrap / wrap_and_apply_header | panic after the same extent proof |
| Trusted hybrid | bare decode | panic if short; Err on wrong template/schema only |
| Unchecked | unsafe wrap_unchecked / wrap_and_apply_header_unchecked | UB — prove extent first |
| Unchecked hybrid | unsafe decode_unchecked | UB on OOB extent; Err on wrong template/schema |
Bare decode looks like try_decode (Result) but short buffers still panic
— prefer try_decode when every failure must be a Result. Full table and
the ladder from untrusted bytes to typed fields:
Trust Boundary (core concepts). sbe-tool
offsets: Coming from sbe-tool.
Trust boundary
The constructor is the single trust checkpoint. After a safe constructor
proves header + version-aware fixed extent, field accessors and setters are
branch-free (unchecked loads/stores justified by that proof). Dynamic
group/var-data tails still check on consume. Use *_unchecked only when you
have proven the fixed extent independently (benchmarks, pre-validated buffers).