copper-value
copper-value provides a way to capture serialization value trees for later processing.
Customizations are made to enable a more compact representation for the structured logging of copper.
Native payload descriptions
Enable cu29/self-describing-logs to describe native Encode bytes and decode them
into a Value tree offline. The feature enables std and reflection. Encode
derives supply the ValueDecode companion automatically; payload authors keep
their usual Reflect derive.
use ;
use *;
let description = ?;
let config = standard;
let mut bytes = ;
let len = encode_into_slice?;
let = description.decode?;
A description implements native bincode Encode and Decode. After transporting
it as bytes, an offline reader uses only the description, payload bytes, and the
producer's codec configuration. Decoding returns the exact number of consumed
bytes, allowing sequential values to be read from one buffer.
Descriptions preserve field names, original type identities, scalar widths, and
quantity storage units. Each type declares a static, typed ValueDecode::METADATA
slice using Copper's metadata vocabulary, shared through cu29-value-types.
All supported quantities retain their coherent storage unit in both scalar widths:
length is m, velocity is m·s⁻¹, and mass is kg. Copper clock values retain
nanosecond storage. Unit symbols are presentation output from typed storage units.
A handwritten type can attach existing Copper metadata:
use ;
use ;
;
Portable schemas contain metadata entries. schema.quantity() returns recognized
quantity metadata; entry.known() returns recognized typed metadata. Entries use
permanent numeric kind IDs and length-delimited bodies. Quantity kind 1 contains
exactly eight bytes: a little-endian u32 quantity ID followed by a little-endian
u32 storage alternative (1 for coherent storage, 2 for nanoseconds).
The outer kind and body length use the description's bincode configuration.
Copper assigns new IDs when its vocabulary grows and retains existing meanings.
An older reader preserves unknown kinds, quantities, and storage alternatives verbatim. It exposes the decoded payload value and leaves unsupported units uninterpreted. Invalid known combinations and malformed or truncated entries return a decoding error. Metadata framing supports evolving metadata alongside wire operations the reader already understands.
For a handwritten encoder, implement ValueDecode by delegating to the type
actually written. An opaque reflected wrapper encoding [f32; 4] declares:
Structurally reflected encoded fields must be present in reflection with the same
native type. Tuple fields require reflection to retain every declaration position.
Hidden encoded fields and ambiguous tuple mappings return a description-building
error. For opaque reflection, the static encoding recipe supplies the encoded
field names, declaration positions, and enum variants.
Skipped fields are excluded from the wire description. Missing nested descriptions and
custom codec descriptions fail compilation with self-describing-logs enabled.
Description construction and value decoding allocate in offline tooling. Native
message encoding keeps its existing byte layout and encoding pass. The portable
IR is experimental. Enable cu29-value/decode-catalog for offline catalog readers.
Applications enable cu29/self-describing-logs to generate and save the shared
compressed catalog only at startup, before resources. It occupies one static
section beside application metadata and contains ordered slot maps for every
compiled mission. Native recipes and names are borrowed from the application
image; sizing and compression use bounded working memory. See
examples/cu_self_describing_logs and doc/self-describing-logs.md.
Run just self-describing-logs-check at the Copper workspace root to verify this API.
Python Feature
With the python feature enabled, this crate also provides conversion helpers between
cu29_value::Value and Python objects via PyO3.
That bridge is used in two places:
cu-python-task, where Copper temporarily converts task inputs/state/outputs so a Python function can mutate themcu29-export, where Copper data is exposed to Python for offline analysis
Conversion behavior is intentionally simple:
Nonemaps toValue::Unit- Python lists and tuples map to
Value::Seq - Python dicts map to
Value::Map - Python integers are accepted up to 128-bit signed/unsigned range
- Python
bytesmaps toValue::Bytes
Coherent storage symbols use conventional Unicode SI notation, such as V, T,
N·m, and m·s⁻¹, from the shared cu29-value-types catalogue.
JSON and RON metadata include a typed quantity and its presentation symbol.
Readers interpret the permanent IDs and retain unknown metadata bodies.