pub(crate) fn normalised(value: &Value) -> ValueExpand description
Rewrite a value into the encoding this format requires of a writer, leaving what it says alone.
The two normative encoding rules — an integral value is written as a CBOR integer rather than a float, and a byte string as major type 2 rather than under RFC 8746’s tag 64 — bind the bytes a writer emits, so they bind every value it emits and not only the ones it understood. A store holds values this crate never looked at, and the JavaScript implementation’s decoder folds both shapes away before its own code sees them: it cannot emit either, whatever its store holds. A Rust writer that re-emitted them would produce different bytes for the same input file, which is the one thing those two rules exist to stop. SPEC.md extends both rules to stored values for exactly that reason — see its Interoperability section, under the shapes a CBOR library may normalise before a reader sees them.
Not the header’s alone: an event carries opaque values too — a control
message’s "msg", an annotation’s "data", an unknown event type’s
fields and TraceEvent::extra — and
they are written through this same function. Two copies of this rule that
had to agree would be the defect it exists to fix.
Applied on write and never on read: a value read into a store still compares equal to what the file carried, and the house style is the serialiser’s business. Recursive, because a stored value may be a whole tree and the rules are about every number and every byte string in it, and applied to map keys as well as values, which are encoded by the same rules as anything else.
One value changes rather than merely changing encoding: -0.0 written as
0 loses its sign. SPEC.md calls that out and accepts it — no field in a
trace gives negative zero a meaning — so there is deliberately no exception
for it here.
A map inside a stored value is deduplicated on the same terms as the store itself: SPEC.md forbids a conformant tool from emitting a map with a repeated key even having read one, and that binds every map a writer emits rather than only the outermost. Reading such a map still hands back both entries — that half is observable here and must be preserved — and writing it emits the first.