matter_codec/value.rs
1//! Matter TLV element values.
2//!
3//! Phase 3 of `matter-codec` adds container variants. The full TLV value
4//! space is now represented.
5
6use crate::tag::Tag;
7
8/// A decoded Matter TLV value, collapsed across wire widths.
9///
10/// Integer widths and float widths are erased from the public type — the
11/// encoder chooses the minimal wire width per the spec, and the decoder
12/// produces the same Rust type regardless of the width the bytes used. If
13/// you need exact-byte round-trip for non-minimal inputs, use the reader's
14/// span APIs ([`crate::TlvReader::element_span`] /
15/// [`crate::TlvReader::skip_container_span`] + [`crate::TlvReader::span_bytes`]),
16/// which expose an element's raw bytes for width-preserving re-emission.
17#[derive(Debug, Clone, PartialEq)]
18#[non_exhaustive]
19pub enum Value {
20 /// A boolean.
21 Bool(bool),
22
23 /// An unsigned integer, encoded on the wire in 1, 2, 4, or 8 bytes
24 /// (minimal width).
25 Uint(u64),
26
27 /// A signed integer, encoded on the wire in 1, 2, 4, or 8 bytes
28 /// (minimal width).
29 Int(i64),
30
31 /// A 4-byte IEEE 754 single-precision float.
32 Float(f32),
33
34 /// An 8-byte IEEE 754 double-precision float.
35 Double(f64),
36
37 /// A UTF-8 string. The wire format is a 1/2/4/8-byte little-endian
38 /// length field (writer picks the minimal width) followed by the
39 /// raw UTF-8 bytes. The reader rejects invalid UTF-8 with
40 /// [`crate::Error::InvalidUtf8`].
41 Utf8(String),
42
43 /// An octet string. The wire format is a 1/2/4/8-byte little-endian
44 /// length field (writer picks the minimal width) followed by the
45 /// raw bytes.
46 Bytes(Vec<u8>),
47
48 /// A structure. Each member carries its own tag; members are
49 /// typically context-tagged but the spec permits any non-anonymous
50 /// form.
51 Structure(Vec<(Tag, Value)>),
52
53 /// An array. Elements share a single type; the spec requires every
54 /// element to carry an anonymous tag, which the reader enforces and
55 /// the writer always emits.
56 Array(Vec<Value>),
57
58 /// A list. Members may carry any tag form (including anonymous), and
59 /// member types are not required to be uniform.
60 List(Vec<(Tag, Value)>),
61
62 /// The TLV null value (element type `0x14`).
63 Null,
64}
65
66/// A borrowed view of one decoded scalar TLV value — the zero-copy sibling
67/// of [`Value`]. Strings and byte strings borrow directly from the reader's
68/// input; scalars are carried by value. Containers never appear here: the
69/// streaming [`crate::TlvReader::next_ref`] API reports them as
70/// `ContainerStart`/`ContainerEnd` events, so no owned children are built.
71///
72/// `Utf8` carries the same IS1-truncated text the owned path presents (the
73/// text before the first `0x1F` localized-string separator); access to the
74/// raw suffix (LSID) remains a separate additive follow-up.
75#[derive(Debug, Clone, Copy, PartialEq)]
76#[non_exhaustive]
77pub enum ValueRef<'a> {
78 /// A boolean.
79 Bool(bool),
80 /// An unsigned integer (any wire width).
81 Uint(u64),
82 /// A signed integer (any wire width).
83 Int(i64),
84 /// A 4-byte IEEE 754 single-precision float.
85 Float(f32),
86 /// An 8-byte IEEE 754 double-precision float.
87 Double(f64),
88 /// A UTF-8 string borrowing the reader's input (IS1-truncated text).
89 Utf8(&'a str),
90 /// An octet string borrowing the reader's input.
91 Bytes(&'a [u8]),
92 /// The TLV null value.
93 Null,
94}
95
96impl From<ValueRef<'_>> for Value {
97 // Called once per materialised element by the reader's tree builder (and
98 // by every cross-crate `next()` caller through `Element::from`), so it is
99 // inlined: the discriminant match then folds into the caller's own match
100 // and only the string/bytes arms keep their allocation.
101 #[inline]
102 fn from(v: ValueRef<'_>) -> Self {
103 match v {
104 ValueRef::Bool(b) => Value::Bool(b),
105 ValueRef::Uint(n) => Value::Uint(n),
106 ValueRef::Int(n) => Value::Int(n),
107 ValueRef::Float(f) => Value::Float(f),
108 ValueRef::Double(f) => Value::Double(f),
109 ValueRef::Utf8(s) => Value::Utf8(String::from(s)),
110 ValueRef::Bytes(b) => Value::Bytes(b.to_vec()),
111 ValueRef::Null => Value::Null,
112 }
113 }
114}