matter_clusters/
datatypes.rs1use crate::error::ClusterError;
5use crate::types::Nullable;
6use matter_codec::{ContainerKind, Element, Tag, TlvReader, Value};
7
8#[derive(Clone, Debug, PartialEq)]
14#[non_exhaustive]
15pub struct SemanticTagStruct {
16 pub mfg_code: Nullable<u16>,
18 pub namespace_id: u8,
20 pub tag: u8,
22 pub label: Option<Nullable<String>>,
24}
25
26impl SemanticTagStruct {
27 pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
35 let mut mfg_code: Option<Nullable<u16>> = None;
36 let mut namespace_id: Option<u8> = None;
37 let mut tag: Option<u8> = None;
38 let mut label: Option<Nullable<String>> = None;
39 loop {
40 match r.next()? {
41 Some(Element::ContainerEnd) => break,
42 Some(Element::Scalar {
43 tag: Tag::Context(0),
44 value: Value::Null,
45 }) => {
46 mfg_code = Some(Nullable::Null);
47 }
48 Some(Element::Scalar {
49 tag: Tag::Context(0),
50 value: Value::Uint(v),
51 }) => {
52 mfg_code =
53 Some(Nullable::Value(u16::try_from(v).map_err(|_| {
54 ClusterError::InvalidLength("SemanticTag.MfgCode")
55 })?));
56 }
57 Some(Element::Scalar {
58 tag: Tag::Context(1),
59 value: Value::Uint(v),
60 }) => {
61 namespace_id = Some(
62 u8::try_from(v)
63 .map_err(|_| ClusterError::InvalidLength("SemanticTag.NamespaceID"))?,
64 );
65 }
66 Some(Element::Scalar {
67 tag: Tag::Context(2),
68 value: Value::Uint(v),
69 }) => {
70 tag = Some(
71 u8::try_from(v)
72 .map_err(|_| ClusterError::InvalidLength("SemanticTag.Tag"))?,
73 );
74 }
75 Some(Element::Scalar {
76 tag: Tag::Context(3),
77 value: Value::Null,
78 }) => {
79 label = Some(Nullable::Null);
80 }
81 Some(Element::Scalar {
82 tag: Tag::Context(3),
83 value: Value::Utf8(s),
84 }) => {
85 label = Some(Nullable::Value(s));
86 }
87 None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
88 Some(Element::ContainerStart { .. }) => r.skip_container()?,
89 Some(_) => {}
90 }
91 }
92 Ok(Self {
93 mfg_code: mfg_code.ok_or(ClusterError::MissingField("SemanticTag.MfgCode"))?,
94 namespace_id: namespace_id
95 .ok_or(ClusterError::MissingField("SemanticTag.NamespaceID"))?,
96 tag: tag.ok_or(ClusterError::MissingField("SemanticTag.Tag"))?,
97 label,
98 })
99 }
100
101 pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
108 let mut r = TlvReader::new(tlv);
109 match r.next()? {
110 Some(Element::ContainerStart {
111 kind: ContainerKind::Structure,
112 ..
113 }) => {}
114 _ => {
115 return Err(ClusterError::UnexpectedType {
116 context: "SemanticTagStruct",
117 })
118 }
119 }
120 Self::decode_from(&mut r)
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 #![allow(clippy::unwrap_used, clippy::expect_used)]
127 use super::*;
128 use matter_codec::TlvWriter;
129
130 #[test]
131 fn decodes_a_minimal_tag() {
132 let mut buf = Vec::new();
134 let mut w = TlvWriter::new(&mut buf);
135 w.start_structure(Tag::Anonymous).unwrap();
136 w.put_null(Tag::Context(0)).unwrap();
137 w.put_uint(Tag::Context(1), 7).unwrap();
138 w.put_uint(Tag::Context(2), 3).unwrap();
139 w.end_container().unwrap();
140 let t = SemanticTagStruct::decode(&buf).unwrap();
141 assert_eq!(
142 t,
143 SemanticTagStruct {
144 mfg_code: Nullable::Null,
145 namespace_id: 7,
146 tag: 3,
147 label: None
148 }
149 );
150 }
151}