Domain Objects (DTOs)
Latency-sensitive paths: never use DTOs. Domain objects allocate (
Vec,String) and copy every field out of the wire buffer. If latency matters, use the zero-copy flyweight decoder instead. DTOs are for tooling, logging, and offline processing — not the hot path.
DTO construction still owns and allocates its Vec/String fields. Re-encode
does not add another allocation: wire-compatible flat groups automatically use
the generated bulk_add_domain(&[EntryDomain]) path, which validates one
complete output region and writes directly from the DTO slice. Groups with
nested tails, var-data, optional/versioned fields, domain conversions, or bool
domain remapping retain the general per-entry path.
Enable domain objects during generation when an owned application value is
more convenient than a zero-copy flyweight. This fixture uses DomainVarData::Strings:
#![allow(unused)] fn main() { pub fn demo_car_domain_dto(wire: &[u8]) -> Result<(), Box<dyn std::error::Error>> { let dec = CarDecoder::try_decode(wire, 0)?; // try_from_decoder (not TryFrom/From): two fallible sources — decoder vs // try_from_slice_with_header for framed bytes; materialisation can fail. let dto = CarDomain::try_from_decoder(dec)?; assert_eq!(dto.serial_number, 1234); assert!(dto.available); // bool domain field assert_eq!(dto.fuel_figures.len(), 2); assert_eq!(dto.fuel_figures[0].usage_description, "Urban"); assert_eq!(dto.manufacturer, "Honda"); const RE_PAD: usize = 512; assert!(wire.len() <= RE_PAD); let mut storage = [0u8; RE_PAD]; let n = dto.encode(&mut storage[..wire.len()])?; assert_eq!(&storage[..n], wire, "DTO re-encode must be byte-identical"); Ok(()) } }
(This code comes from the sbe-feature-tour sample crate.)