niso-structured-clone
Generated from crates/niso-structured-clone/CONTRACT.md when the site was built at 7aa23e2.
Purpose
Section titled “Purpose”HTML’s structured serialization as bytes: the format the glue’s SER and
DESER (glue/structured-clone.js) write and read, its decoder and encoder in
Rust, and the graph inspection the core needs on a serialized value
(own_property and create_data_property for IndexedDB key paths and key
injection, buffer_source, js_string for string keys). The format is
specified in docs/structured-clone.md.
It does not walk JS values (only an engine can; the glue does), run StructuredSerialize or StructuredDeserialize, or own transfer: a transferred object is the index of something carried beside the bytes (MessagePorts in niso-core’s messaging). It is pure: no host, no state, no threads.
Platform objects are its host-object hook. A serializable platform object
(0x1E, Record::Platform) is its interface’s name and one data value, and
the crate reads and writes that pair without knowing the interface: the
interface’s owner runs its serialization steps, chooses the data, and on
deserialization checks the data and throws DataCloneError for data it would
not write or a realm the interface is not exposed in. DOMException, DOMRect,
ImageData, Blob, File and CryptoKey use it today, with their owners’ steps in
their glue sections (docs/structured-clone.md lists each one’s data). So Blob and File
bytes, CryptoKey algorithms and key material, and secure contexts are not
this crate’s concern, and an interface added later needs no change here.
Public surface
Section titled “Public surface”- Rust:
VERSION;JsString,js_string,to_rust_string;VIEW_KINDS,ERROR_NAMES;BigInt,Value,Record;Serializedwithprimitive,decode,encode,add,record,own_property,create_data_property,buffer_source;array_index.testing(below) and, behind thecontract-testsfeature,contract. - C:
niso_structured_clone_decode,_free,_value,_entry(include/structured-clone.h, its section of the composed niso_runtime.h). They are implemented in niso-capi’s clone.rs over this crate’s API until step 6c generates per-crate shims. - Format: docs/structured-clone.md, the byte format this crate and the glue read and write, with each platform object’s data. It is part of this contract and one of the crate’s sources: a change to it is a contract change, reviewed with this file.
- IDL: none.
- Glue: glue/structured-clone.js (
SC), which writes and reads this format, composed into the glue in the monolith’s order until glue modules exist (step 6c).
niso-core re-exports the crate as niso_core::structured_clone.
Host requirements
Section titled “Host requirements”None.
May assume from dependencies
Section titled “May assume from dependencies”- niso-base:
ErrorCode,Result,err.
Guarantees
Section titled “Guarantees”- Round trip: every corpus value (
testing::values()) decodes to the graph it was written from, and encoding that again gives the same bytes. Objects are numbered in the order the format writes them (a view after its buffer). contract::round_trip. - Input that ends early, has bytes past the value or another version is
rejected with an
Errorwhose code isDataClone, never a panic: it is bad input the caller can act on, andInternalis kept for broken invariants. contract::rejects_truncated_input. - Decoding arbitrary bytes returns
Okor aDataCloneerror and never panics. contract::never_panics (corrupted corpus values). - Objects nest at most 256 deep when read; deeper input is rejected, and
that depth decodes on a 512 KB thread. contract::depth_limit, and the
unit test
max_depth_fits_a_512_kb_thread. js_stringgives a string’s UTF-16 code units, soJsStringorder is JS’s string order (not Rust’sstrorder), andto_rust_stringturns code units back with lone surrogates as U+FFFD. contract::js_strings.- A platform object decodes to its interface name and its data as written, whatever the data is; checking it is the interface owner’s step (see Purpose). contract::platform_objects_are_opaque, on the Blob, File and CryptoKey records the glue writes.
Threads
Section titled “Threads”All types are plain data and Send; every function may be called from any
thread. Workers’ messages are decoded on the receiving agent’s thread.
Performance and memory
Section titled “Performance and memory”Decoding allocates the decoded graph and nothing proportional to an
unchecked length: every length is checked against the input first. About
1.6 KB of stack per nesting level in a debug build
(cargo test -p niso-structured-clone --lib stack_per_level -- --ignored).
cargo test -p niso-structured-clone runs in under a second after an edit.
None needed: the crate is pure. testing::values() is a corpus of graphs
for this crate’s suite and for crates that store or send serialized values:
every primitive and record kind, cycles, back-references, a view of each
kind, length-tracking views, transferred buffers, Map and Set with object
keys, errors with causes, sparse arrays, platform objects (a DOMException,
and a Blob, File and CryptoKey with the data the glue writes), the deepest
nesting and strings that are not well-formed UTF-16. testing::nested_arrays
builds a graph of a given depth.
Standalone use
Section titled “Standalone use”Read or write structured serialization bytes from any Rust program, for
example to inspect what a page stored in IndexedDB:
Serialized::decode(&bytes)?.own_property(&v.value, &js_string("id")).