Module lenient_bytes
Expand description
Wire-shape-tolerant deserialization for schema Bytes fields — see
cratestack#783.
A schema Bytes field generates as a plain Vec<u8>, and Vec<u8>’s
Deserialize is serde’s blanket Vec<T> impl: a visitor with
visit_seq and nothing else. Over CBOR that accepts only an array
of integers (0x84 01 02 03 04) and hard-errors on a CBOR byte string
(0x44 01020304, RFC 8949 major type 2) with unexpected type bytes … expected array — the shape every other CBOR producer emits for binary
data, and the shape @cratestack/cbor now writes for a JS
Uint8Array/ArrayBuffer.
LenientBytes accepts both. visit_bytes/visit_byte_buf cover the
byte-string form, visit_seq keeps the integer-array form working
unchanged — which matters twice over: it is what every already-deployed
client (Rust, Dart, and any TypeScript caller doing the
Array.from(bytes) workaround) sends today, and it is the only shape
JSON can express, so the application/json transport is unaffected.
Inbound only. Nothing here changes what a generated Serialize
emits: a Bytes field still goes out as an array of integers on both
transports and in all three client languages. Flipping the outbound
shape to a byte string is a genuine wire break for every existing
decoder (the Dart client’s cratestackAsValueList, the TypeScript
client’s number[]), so it is deliberately not bundled here.
The deserialize_* wrappers exist one per generated field shape
rather than as a single generic function because #[serde(deserialize_with = "…")] names a concrete function whose return type must match the
field’s type exactly, and crate::shared::bytes_serde in
cratestack-macros picks between them from the field’s arity and
whether it is patch-wrapped. See that module for the mapping.
Structs§
- Lenient
Bytes Vec<u8>newtype whoseDeserializeaccepts a byte string or a sequence of integers. See the module docs.
Functions§
- deserialize_
bytes - A required
Bytesfield —Vec<u8>. - deserialize_
bytes_ list - A list-arity
Bytesfield —Vec<Vec<u8>>. Each element independently accepts either shape. - deserialize_
double_ option_ bytes - A patch-wrapped nullable
Bytesfield —Option<Option<Vec<u8>>>. TheBytescounterpart ofcrate::patch::deserialize_double_option(which can’t be reused: itsT: Deserializebound resolves toVec<u8>’s strict blanket impl, the exact thing this module works around). Same contract — the outerSomerecords “this key was present”, so it must be paired with#[serde(default, …)]. - deserialize_
optional_ bytes - A nullable
Bytesfield, or a patch-wrapped required one —Option<Vec<u8>>. Pair with#[serde(default, …)]: a customdeserialize_withopts the field out of serde-derive’s implicit “missingOption<T>field defaults toNone” (seecrate::patch). - deserialize_
optional_ bytes_ list - A patch-wrapped list-arity
Bytesfield —Option<Vec<Vec<u8>>>. Pair with#[serde(default, …)], perdeserialize_optional_bytes.