Skip to main content

matter_clusters/gen/
group_key_management.rs

1//! GroupKeyManagement cluster (0x003F).
2//! @generated by `cargo xtask codegen` — do not edit.
3
4#![allow(
5    clippy::all,
6    clippy::pedantic,
7    dead_code,
8    unreachable_pub,
9    unused_imports
10)]
11
12use crate::datatypes::SemanticTagStruct;
13use crate::error::ClusterError;
14use crate::types::Nullable;
15use matter_codec::{ContainerKind, Element, Tag, TlvReader, TlvWriter, Value};
16
17/// Cluster ID.
18pub const CLUSTER_ID: u32 = 0x003F;
19/// Cluster revision.
20pub const CLUSTER_REVISION: u16 = 2;
21
22/// Command IDs (requests and responses).
23pub mod command_id {
24    /// `KeySetWrite` (request).
25    pub const KEY_SET_WRITE: u32 = 0x00;
26    /// `KeySetRead` (request).
27    pub const KEY_SET_READ: u32 = 0x01;
28    /// `KeySetReadResponse` (response).
29    pub const KEY_SET_READ_RESPONSE: u32 = 0x02;
30    /// `KeySetRemove` (request).
31    pub const KEY_SET_REMOVE: u32 = 0x03;
32    /// `KeySetReadAllIndices` (request).
33    pub const KEY_SET_READ_ALL_INDICES: u32 = 0x04;
34    /// `KeySetReadAllIndicesResponse` (response).
35    pub const KEY_SET_READ_ALL_INDICES_RESPONSE: u32 = 0x05;
36}
37
38/// Attribute IDs (cluster-specific).
39pub mod attribute_id {
40    /// `GroupKeyMap`.
41    pub const GROUP_KEY_MAP: u32 = 0x0000;
42    /// `GroupTable`.
43    pub const GROUP_TABLE: u32 = 0x0001;
44    /// `MaxGroupsPerFabric`.
45    pub const MAX_GROUPS_PER_FABRIC: u32 = 0x0002;
46    /// `MaxGroupKeysPerFabric`.
47    pub const MAX_GROUP_KEYS_PER_FABRIC: u32 = 0x0003;
48}
49
50bitflags::bitflags! {
51    /// `GroupKeyManagement` feature bits (FeatureMap).
52    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
53    pub struct Feature: u32 {
54        /// CacheAndSync (CS).
55        const CS = 1 << 0;
56    }
57}
58
59/// `GroupInfoMapStruct` struct.
60#[derive(Clone, Debug, PartialEq)]
61#[non_exhaustive]
62pub struct GroupInfoMapStruct {
63    /// Field GroupId (tag 1).
64    pub group_id: u16,
65    /// Field Endpoints (tag 2).
66    pub endpoints: Vec<u16>,
67    /// Field GroupName (tag 3).
68    pub group_name: Option<String>,
69    /// Field FabricIndex (tag 254).
70    pub fabric_index: u8,
71}
72
73/// `GroupKeyMapStruct` struct.
74#[derive(Clone, Debug, PartialEq)]
75#[non_exhaustive]
76pub struct GroupKeyMapStruct {
77    /// Field GroupId (tag 1).
78    pub group_id: u16,
79    /// Field GroupKeySetId (tag 2).
80    pub group_key_set_id: u16,
81    /// Field FabricIndex (tag 254).
82    pub fabric_index: u8,
83}
84
85/// `GroupKeyMulticastPolicyEnum` (enum8).
86#[derive(Copy, Clone, Debug, PartialEq, Eq)]
87pub enum GroupKeyMulticastPolicyEnum {
88    /// PerGroupId = 0.
89    PerGroupId,
90    /// AllNodes = 1.
91    AllNodes,
92    /// A value not known to this codegen revision.
93    Unknown(u8),
94}
95
96impl GroupKeyMulticastPolicyEnum {
97    /// Decode from its raw discriminant (unknown → `Unknown`).
98    #[must_use]
99    pub fn from_raw(v: u8) -> Self {
100        match v {
101            0 => Self::PerGroupId,
102            1 => Self::AllNodes,
103            other => Self::Unknown(other),
104        }
105    }
106    /// The raw discriminant.
107    #[must_use]
108    pub fn to_raw(self) -> u8 {
109        match self {
110            Self::PerGroupId => 0,
111            Self::AllNodes => 1,
112            Self::Unknown(v) => v,
113        }
114    }
115}
116
117/// `GroupKeySecurityPolicyEnum` (enum8).
118#[derive(Copy, Clone, Debug, PartialEq, Eq)]
119pub enum GroupKeySecurityPolicyEnum {
120    /// TrustFirst = 0.
121    TrustFirst,
122    /// CacheAndSync = 1.
123    CacheAndSync,
124    /// A value not known to this codegen revision.
125    Unknown(u8),
126}
127
128impl GroupKeySecurityPolicyEnum {
129    /// Decode from its raw discriminant (unknown → `Unknown`).
130    #[must_use]
131    pub fn from_raw(v: u8) -> Self {
132        match v {
133            0 => Self::TrustFirst,
134            1 => Self::CacheAndSync,
135            other => Self::Unknown(other),
136        }
137    }
138    /// The raw discriminant.
139    #[must_use]
140    pub fn to_raw(self) -> u8 {
141        match self {
142            Self::TrustFirst => 0,
143            Self::CacheAndSync => 1,
144            Self::Unknown(v) => v,
145        }
146    }
147}
148
149/// `GroupKeySetStruct` struct.
150#[derive(Clone, Debug, PartialEq)]
151pub struct GroupKeySetStruct {
152    /// Field GroupKeySetId (tag 0).
153    pub group_key_set_id: u16,
154    /// Field GroupKeySecurityPolicy (tag 1).
155    pub group_key_security_policy: GroupKeySecurityPolicyEnum,
156    /// Field EpochKey0 (tag 2).
157    pub epoch_key0: Nullable<Vec<u8>>,
158    /// Field EpochStartTime0 (tag 3).
159    pub epoch_start_time0: Nullable<u64>,
160    /// Field EpochKey1 (tag 4).
161    pub epoch_key1: Nullable<Vec<u8>>,
162    /// Field EpochStartTime1 (tag 5).
163    pub epoch_start_time1: Nullable<u64>,
164    /// Field EpochKey2 (tag 6).
165    pub epoch_key2: Nullable<Vec<u8>>,
166    /// Field EpochStartTime2 (tag 7).
167    pub epoch_start_time2: Nullable<u64>,
168    /// Field GroupKeyMulticastPolicy (tag 8).
169    pub group_key_multicast_policy: Option<GroupKeyMulticastPolicyEnum>,
170    /// Field FabricIndex (tag 254).
171    pub fabric_index: Option<u8>,
172}
173
174impl GroupInfoMapStruct {
175    /// Decode the fields of an already-opened anonymous structure
176    /// (reader positioned after the struct start; consumes to its end).
177    ///
178    /// # Errors
179    /// Returns [`ClusterError`] on a malformed structure or missing required field.
180    pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
181        let mut f_group_id: Option<u16> = None;
182        let mut f_endpoints: Option<Vec<u16>> = None;
183        let mut f_group_name: Option<String> = None;
184        let mut f_fabric_index: Option<u8> = None;
185        loop {
186            match r.next()? {
187                Some(Element::ContainerEnd) => break,
188                Some(Element::Scalar {
189                    tag: Tag::Context(1),
190                    value: Value::Uint(v),
191                }) => {
192                    f_group_id =
193                        Some(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("GroupId"))?)
194                }
195                Some(Element::ContainerStart {
196                    tag: Tag::Context(2),
197                    kind: ContainerKind::Array,
198                }) => {
199                    let mut out = Vec::new();
200                    loop {
201                        match r.next()? {
202                            Some(Element::ContainerEnd) => break,
203                            Some(Element::Scalar {
204                                value: Value::Uint(v),
205                                ..
206                            }) => out.push(
207                                u16::try_from(v)
208                                    .map_err(|_| ClusterError::InvalidLength("Endpoints"))?,
209                            ),
210                            None => {
211                                return Err(ClusterError::Tlv(
212                                    matter_codec::Error::UnclosedContainer,
213                                ))
214                            }
215                            Some(Element::ContainerStart { .. }) => r.skip_container()?,
216                            Some(_) => {} // skip unknown scalar
217                        }
218                    }
219                    f_endpoints = Some(out);
220                }
221                Some(Element::Scalar {
222                    tag: Tag::Context(3),
223                    value: Value::Utf8(v),
224                }) => f_group_name = Some(v),
225                Some(Element::Scalar {
226                    tag: Tag::Context(254),
227                    value: Value::Uint(v),
228                }) => {
229                    f_fabric_index = Some(
230                        u8::try_from(v).map_err(|_| ClusterError::InvalidLength("FabricIndex"))?,
231                    )
232                }
233                None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
234                Some(Element::ContainerStart { .. }) => r.skip_container()?,
235                Some(_) => {} // unknown/future scalar — skip
236            }
237        }
238        Ok(Self {
239            group_id: f_group_id.ok_or(ClusterError::MissingField("GroupId"))?,
240            endpoints: f_endpoints.ok_or(ClusterError::MissingField("Endpoints"))?,
241            group_name: f_group_name,
242            fabric_index: f_fabric_index.ok_or(ClusterError::MissingField("FabricIndex"))?,
243        })
244    }
245    /// Decode from a standalone anonymous TLV structure.
246    ///
247    /// # Errors
248    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
249    pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
250        let mut r = TlvReader::new(tlv);
251        match r.next()? {
252            Some(Element::ContainerStart {
253                kind: ContainerKind::Structure,
254                ..
255            }) => {}
256            _ => {
257                return Err(ClusterError::UnexpectedType {
258                    context: "GroupInfoMapStruct",
259                })
260            }
261        }
262        Self::decode_from(&mut r)
263    }
264}
265
266impl GroupKeyMapStruct {
267    /// Decode the fields of an already-opened anonymous structure
268    /// (reader positioned after the struct start; consumes to its end).
269    ///
270    /// # Errors
271    /// Returns [`ClusterError`] on a malformed structure or missing required field.
272    pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
273        let mut f_group_id: Option<u16> = None;
274        let mut f_group_key_set_id: Option<u16> = None;
275        let mut f_fabric_index: Option<u8> = None;
276        loop {
277            match r.next()? {
278                Some(Element::ContainerEnd) => break,
279                Some(Element::Scalar {
280                    tag: Tag::Context(1),
281                    value: Value::Uint(v),
282                }) => {
283                    f_group_id =
284                        Some(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("GroupId"))?)
285                }
286                Some(Element::Scalar {
287                    tag: Tag::Context(2),
288                    value: Value::Uint(v),
289                }) => {
290                    f_group_key_set_id = Some(
291                        u16::try_from(v)
292                            .map_err(|_| ClusterError::InvalidLength("GroupKeySetId"))?,
293                    )
294                }
295                Some(Element::Scalar {
296                    tag: Tag::Context(254),
297                    value: Value::Uint(v),
298                }) => {
299                    f_fabric_index = Some(
300                        u8::try_from(v).map_err(|_| ClusterError::InvalidLength("FabricIndex"))?,
301                    )
302                }
303                None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
304                Some(Element::ContainerStart { .. }) => r.skip_container()?,
305                Some(_) => {} // unknown/future scalar — skip
306            }
307        }
308        Ok(Self {
309            group_id: f_group_id.ok_or(ClusterError::MissingField("GroupId"))?,
310            group_key_set_id: f_group_key_set_id
311                .ok_or(ClusterError::MissingField("GroupKeySetId"))?,
312            fabric_index: f_fabric_index.ok_or(ClusterError::MissingField("FabricIndex"))?,
313        })
314    }
315    /// Decode from a standalone anonymous TLV structure.
316    ///
317    /// # Errors
318    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
319    pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
320        let mut r = TlvReader::new(tlv);
321        match r.next()? {
322            Some(Element::ContainerStart {
323                kind: ContainerKind::Structure,
324                ..
325            }) => {}
326            _ => {
327                return Err(ClusterError::UnexpectedType {
328                    context: "GroupKeyMapStruct",
329                })
330            }
331        }
332        Self::decode_from(&mut r)
333    }
334    /// Write this struct's fields into an already-open container.
335    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
336    pub fn write_fields(&self, w: &mut TlvWriter<'_>) {
337        w.put_uint(Tag::Context(1), u64::from(self.group_id))
338            .expect("infallible: vec writer");
339        w.put_uint(Tag::Context(2), u64::from(self.group_key_set_id))
340            .expect("infallible: vec writer");
341        w.put_uint(Tag::Context(254), u64::from(self.fabric_index))
342            .expect("infallible: vec writer");
343    }
344    /// Encode as a standalone anonymous TLV structure.
345    #[must_use]
346    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
347    pub fn encode(&self) -> Vec<u8> {
348        let mut buf = Vec::new();
349        let mut w = TlvWriter::new(&mut buf);
350        w.start_structure(Tag::Anonymous)
351            .expect("infallible: vec writer");
352        self.write_fields(&mut w);
353        w.end_container().expect("infallible: vec writer");
354        buf
355    }
356}
357
358impl GroupKeySetStruct {
359    /// Decode the fields of an already-opened anonymous structure
360    /// (reader positioned after the struct start; consumes to its end).
361    ///
362    /// # Errors
363    /// Returns [`ClusterError`] on a malformed structure or missing required field.
364    pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
365        let mut f_group_key_set_id: Option<u16> = None;
366        let mut f_group_key_security_policy: Option<GroupKeySecurityPolicyEnum> = None;
367        let mut f_epoch_key0: Option<Nullable<Vec<u8>>> = None;
368        let mut f_epoch_start_time0: Option<Nullable<u64>> = None;
369        let mut f_epoch_key1: Option<Nullable<Vec<u8>>> = None;
370        let mut f_epoch_start_time1: Option<Nullable<u64>> = None;
371        let mut f_epoch_key2: Option<Nullable<Vec<u8>>> = None;
372        let mut f_epoch_start_time2: Option<Nullable<u64>> = None;
373        let mut f_group_key_multicast_policy: Option<GroupKeyMulticastPolicyEnum> = None;
374        let mut f_fabric_index: Option<u8> = None;
375        loop {
376            match r.next()? {
377                Some(Element::ContainerEnd) => break,
378                Some(Element::Scalar {
379                    tag: Tag::Context(0),
380                    value: Value::Uint(v),
381                }) => {
382                    f_group_key_set_id = Some(
383                        u16::try_from(v)
384                            .map_err(|_| ClusterError::InvalidLength("GroupKeySetId"))?,
385                    )
386                }
387                Some(Element::Scalar {
388                    tag: Tag::Context(1),
389                    value: Value::Uint(v),
390                }) => {
391                    f_group_key_security_policy = Some(GroupKeySecurityPolicyEnum::from_raw(
392                        u8::try_from(v)
393                            .map_err(|_| ClusterError::InvalidLength("GroupKeySecurityPolicy"))?,
394                    ))
395                }
396                Some(Element::Scalar {
397                    tag: Tag::Context(2),
398                    value: Value::Null,
399                }) => f_epoch_key0 = Some(Nullable::Null),
400                Some(Element::Scalar {
401                    tag: Tag::Context(2),
402                    value: Value::Bytes(v),
403                }) => f_epoch_key0 = Some(Nullable::Value(v)),
404                Some(Element::Scalar {
405                    tag: Tag::Context(3),
406                    value: Value::Null,
407                }) => f_epoch_start_time0 = Some(Nullable::Null),
408                Some(Element::Scalar {
409                    tag: Tag::Context(3),
410                    value: Value::Uint(v),
411                }) => {
412                    f_epoch_start_time0 =
413                        Some(Nullable::Value(u64::try_from(v).map_err(|_| {
414                            ClusterError::InvalidLength("EpochStartTime0")
415                        })?))
416                }
417                Some(Element::Scalar {
418                    tag: Tag::Context(4),
419                    value: Value::Null,
420                }) => f_epoch_key1 = Some(Nullable::Null),
421                Some(Element::Scalar {
422                    tag: Tag::Context(4),
423                    value: Value::Bytes(v),
424                }) => f_epoch_key1 = Some(Nullable::Value(v)),
425                Some(Element::Scalar {
426                    tag: Tag::Context(5),
427                    value: Value::Null,
428                }) => f_epoch_start_time1 = Some(Nullable::Null),
429                Some(Element::Scalar {
430                    tag: Tag::Context(5),
431                    value: Value::Uint(v),
432                }) => {
433                    f_epoch_start_time1 =
434                        Some(Nullable::Value(u64::try_from(v).map_err(|_| {
435                            ClusterError::InvalidLength("EpochStartTime1")
436                        })?))
437                }
438                Some(Element::Scalar {
439                    tag: Tag::Context(6),
440                    value: Value::Null,
441                }) => f_epoch_key2 = Some(Nullable::Null),
442                Some(Element::Scalar {
443                    tag: Tag::Context(6),
444                    value: Value::Bytes(v),
445                }) => f_epoch_key2 = Some(Nullable::Value(v)),
446                Some(Element::Scalar {
447                    tag: Tag::Context(7),
448                    value: Value::Null,
449                }) => f_epoch_start_time2 = Some(Nullable::Null),
450                Some(Element::Scalar {
451                    tag: Tag::Context(7),
452                    value: Value::Uint(v),
453                }) => {
454                    f_epoch_start_time2 =
455                        Some(Nullable::Value(u64::try_from(v).map_err(|_| {
456                            ClusterError::InvalidLength("EpochStartTime2")
457                        })?))
458                }
459                Some(Element::Scalar {
460                    tag: Tag::Context(8),
461                    value: Value::Uint(v),
462                }) => {
463                    f_group_key_multicast_policy = Some(GroupKeyMulticastPolicyEnum::from_raw(
464                        u8::try_from(v)
465                            .map_err(|_| ClusterError::InvalidLength("GroupKeyMulticastPolicy"))?,
466                    ))
467                }
468                Some(Element::Scalar {
469                    tag: Tag::Context(254),
470                    value: Value::Uint(v),
471                }) => {
472                    f_fabric_index = Some(
473                        u8::try_from(v).map_err(|_| ClusterError::InvalidLength("FabricIndex"))?,
474                    )
475                }
476                None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
477                Some(Element::ContainerStart { .. }) => r.skip_container()?,
478                Some(_) => {} // unknown/future scalar — skip
479            }
480        }
481        Ok(Self {
482            group_key_set_id: f_group_key_set_id
483                .ok_or(ClusterError::MissingField("GroupKeySetId"))?,
484            group_key_security_policy: f_group_key_security_policy
485                .ok_or(ClusterError::MissingField("GroupKeySecurityPolicy"))?,
486            epoch_key0: f_epoch_key0.ok_or(ClusterError::MissingField("EpochKey0"))?,
487            epoch_start_time0: f_epoch_start_time0
488                .ok_or(ClusterError::MissingField("EpochStartTime0"))?,
489            epoch_key1: f_epoch_key1.ok_or(ClusterError::MissingField("EpochKey1"))?,
490            epoch_start_time1: f_epoch_start_time1
491                .ok_or(ClusterError::MissingField("EpochStartTime1"))?,
492            epoch_key2: f_epoch_key2.ok_or(ClusterError::MissingField("EpochKey2"))?,
493            epoch_start_time2: f_epoch_start_time2
494                .ok_or(ClusterError::MissingField("EpochStartTime2"))?,
495            group_key_multicast_policy: f_group_key_multicast_policy,
496            fabric_index: f_fabric_index,
497        })
498    }
499    /// Decode from a standalone anonymous TLV structure.
500    ///
501    /// # Errors
502    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
503    pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
504        let mut r = TlvReader::new(tlv);
505        match r.next()? {
506            Some(Element::ContainerStart {
507                kind: ContainerKind::Structure,
508                ..
509            }) => {}
510            _ => {
511                return Err(ClusterError::UnexpectedType {
512                    context: "GroupKeySetStruct",
513                })
514            }
515        }
516        Self::decode_from(&mut r)
517    }
518    /// Write this struct's fields into an already-open container.
519    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
520    pub fn write_fields(&self, w: &mut TlvWriter<'_>) {
521        w.put_uint(Tag::Context(0), u64::from(self.group_key_set_id))
522            .expect("infallible: vec writer");
523        w.put_uint(
524            Tag::Context(1),
525            u64::from(self.group_key_security_policy.to_raw()),
526        )
527        .expect("infallible: vec writer");
528        match &self.epoch_key0 {
529            Nullable::Null => w.put_null(Tag::Context(2)).expect("infallible: vec writer"),
530            Nullable::Value(epoch_key0) => {
531                w.put_bytes(Tag::Context(2), &*epoch_key0)
532                    .expect("infallible: vec writer");
533            }
534        }
535        match &self.epoch_start_time0 {
536            Nullable::Null => w.put_null(Tag::Context(3)).expect("infallible: vec writer"),
537            Nullable::Value(epoch_start_time0) => {
538                w.put_uint(Tag::Context(3), u64::from(*epoch_start_time0))
539                    .expect("infallible: vec writer");
540            }
541        }
542        match &self.epoch_key1 {
543            Nullable::Null => w.put_null(Tag::Context(4)).expect("infallible: vec writer"),
544            Nullable::Value(epoch_key1) => {
545                w.put_bytes(Tag::Context(4), &*epoch_key1)
546                    .expect("infallible: vec writer");
547            }
548        }
549        match &self.epoch_start_time1 {
550            Nullable::Null => w.put_null(Tag::Context(5)).expect("infallible: vec writer"),
551            Nullable::Value(epoch_start_time1) => {
552                w.put_uint(Tag::Context(5), u64::from(*epoch_start_time1))
553                    .expect("infallible: vec writer");
554            }
555        }
556        match &self.epoch_key2 {
557            Nullable::Null => w.put_null(Tag::Context(6)).expect("infallible: vec writer"),
558            Nullable::Value(epoch_key2) => {
559                w.put_bytes(Tag::Context(6), &*epoch_key2)
560                    .expect("infallible: vec writer");
561            }
562        }
563        match &self.epoch_start_time2 {
564            Nullable::Null => w.put_null(Tag::Context(7)).expect("infallible: vec writer"),
565            Nullable::Value(epoch_start_time2) => {
566                w.put_uint(Tag::Context(7), u64::from(*epoch_start_time2))
567                    .expect("infallible: vec writer");
568            }
569        }
570        if let Some(group_key_multicast_policy) = &self.group_key_multicast_policy {
571            w.put_uint(
572                Tag::Context(8),
573                u64::from((*group_key_multicast_policy).to_raw()),
574            )
575            .expect("infallible: vec writer");
576        }
577        if let Some(fabric_index) = &self.fabric_index {
578            w.put_uint(Tag::Context(254), u64::from(*fabric_index))
579                .expect("infallible: vec writer");
580        }
581    }
582    /// Encode as a standalone anonymous TLV structure.
583    #[must_use]
584    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
585    pub fn encode(&self) -> Vec<u8> {
586        let mut buf = Vec::new();
587        let mut w = TlvWriter::new(&mut buf);
588        w.start_structure(Tag::Anonymous)
589            .expect("infallible: vec writer");
590        self.write_fields(&mut w);
591        w.end_container().expect("infallible: vec writer");
592        buf
593    }
594}
595
596/// Decode the `GroupKeyMap` attribute value.
597///
598/// # Errors
599/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
600pub fn decode_group_key_map(tlv: &[u8]) -> Result<Vec<GroupKeyMapStruct>, ClusterError> {
601    let mut r = TlvReader::new(tlv);
602    match r.next()? {
603        Some(Element::ContainerStart {
604            kind: ContainerKind::Array,
605            ..
606        }) => {}
607        _ => {
608            return Err(ClusterError::UnexpectedType {
609                context: "GroupKeyMap",
610            })
611        }
612    }
613    let r = &mut r;
614    let mut out = Vec::new();
615    loop {
616        match r.next()? {
617            Some(Element::ContainerEnd) => break,
618            Some(Element::ContainerStart {
619                kind: ContainerKind::Structure,
620                ..
621            }) => {
622                out.push(GroupKeyMapStruct::decode_from(r)?);
623            }
624            None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
625            Some(Element::ContainerStart { .. }) => r.skip_container()?,
626            Some(_) => {} // skip unknown scalar
627        }
628    }
629    Ok(out)
630}
631
632/// Decode the `GroupTable` attribute value.
633///
634/// # Errors
635/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
636pub fn decode_group_table(tlv: &[u8]) -> Result<Vec<GroupInfoMapStruct>, ClusterError> {
637    let mut r = TlvReader::new(tlv);
638    match r.next()? {
639        Some(Element::ContainerStart {
640            kind: ContainerKind::Array,
641            ..
642        }) => {}
643        _ => {
644            return Err(ClusterError::UnexpectedType {
645                context: "GroupTable",
646            })
647        }
648    }
649    let r = &mut r;
650    let mut out = Vec::new();
651    loop {
652        match r.next()? {
653            Some(Element::ContainerEnd) => break,
654            Some(Element::ContainerStart {
655                kind: ContainerKind::Structure,
656                ..
657            }) => {
658                out.push(GroupInfoMapStruct::decode_from(r)?);
659            }
660            None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
661            Some(Element::ContainerStart { .. }) => r.skip_container()?,
662            Some(_) => {} // skip unknown scalar
663        }
664    }
665    Ok(out)
666}
667
668/// Decode the `MaxGroupsPerFabric` attribute value.
669///
670/// # Errors
671/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
672pub fn decode_max_groups_per_fabric(tlv: &[u8]) -> Result<u16, ClusterError> {
673    let mut r = TlvReader::new(tlv);
674    match r.next()? {
675        Some(Element::Scalar {
676            value: Value::Uint(v),
677            ..
678        }) => Ok(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("MaxGroupsPerFabric"))?),
679        _ => Err(ClusterError::UnexpectedType {
680            context: "MaxGroupsPerFabric",
681        }),
682    }
683}
684
685/// Decode the `MaxGroupKeysPerFabric` attribute value.
686///
687/// # Errors
688/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
689pub fn decode_max_group_keys_per_fabric(tlv: &[u8]) -> Result<u16, ClusterError> {
690    let mut r = TlvReader::new(tlv);
691    match r.next()? {
692        Some(Element::Scalar {
693            value: Value::Uint(v),
694            ..
695        }) => {
696            Ok(u16::try_from(v)
697                .map_err(|_| ClusterError::InvalidLength("MaxGroupKeysPerFabric"))?)
698        }
699        _ => Err(ClusterError::UnexpectedType {
700            context: "MaxGroupKeysPerFabric",
701        }),
702    }
703}
704
705/// Encode the `KeySetWrite` command request payload.
706#[must_use]
707#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
708pub fn encode_key_set_write(group_key_set: GroupKeySetStruct) -> Vec<u8> {
709    let mut buf = Vec::new();
710    let mut w = TlvWriter::new(&mut buf);
711    w.start_structure(Tag::Anonymous)
712        .expect("infallible: vec writer");
713    w.start_structure(Tag::Context(0))
714        .expect("infallible: vec writer");
715    group_key_set.write_fields(&mut w);
716    w.end_container().expect("infallible: vec writer");
717    w.end_container().expect("infallible: vec writer");
718    buf
719}
720
721/// Encode the `KeySetRead` command request payload.
722#[must_use]
723#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
724pub fn encode_key_set_read(group_key_set_id: u16) -> Vec<u8> {
725    let mut buf = Vec::new();
726    let mut w = TlvWriter::new(&mut buf);
727    w.start_structure(Tag::Anonymous)
728        .expect("infallible: vec writer");
729    w.put_uint(Tag::Context(0), u64::from(group_key_set_id))
730        .expect("infallible: vec writer");
731    w.end_container().expect("infallible: vec writer");
732    buf
733}
734
735/// Decoded `KeySetReadResponse` payload.
736#[derive(Clone, Debug, PartialEq)]
737#[non_exhaustive]
738pub struct KeySetReadResponse {
739    /// Field GroupKeySet (tag 0).
740    pub group_key_set: GroupKeySetStruct,
741}
742
743impl KeySetReadResponse {
744    /// Decode the fields of an already-opened anonymous structure
745    /// (reader positioned after the struct start; consumes to its end).
746    ///
747    /// # Errors
748    /// Returns [`ClusterError`] on a malformed structure or missing required field.
749    pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
750        let mut f_group_key_set: Option<GroupKeySetStruct> = None;
751        loop {
752            match r.next()? {
753                Some(Element::ContainerEnd) => break,
754                Some(Element::ContainerStart {
755                    tag: Tag::Context(0),
756                    kind: ContainerKind::Structure,
757                }) => f_group_key_set = Some(GroupKeySetStruct::decode_from(r)?),
758                None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
759                Some(Element::ContainerStart { .. }) => r.skip_container()?,
760                Some(_) => {} // unknown/future scalar — skip
761            }
762        }
763        Ok(Self {
764            group_key_set: f_group_key_set.ok_or(ClusterError::MissingField("GroupKeySet"))?,
765        })
766    }
767    /// Decode from a standalone anonymous TLV structure.
768    ///
769    /// # Errors
770    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
771    pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
772        let mut r = TlvReader::new(tlv);
773        match r.next()? {
774            Some(Element::ContainerStart {
775                kind: ContainerKind::Structure,
776                ..
777            }) => {}
778            _ => {
779                return Err(ClusterError::UnexpectedType {
780                    context: "KeySetReadResponse",
781                })
782            }
783        }
784        Self::decode_from(&mut r)
785    }
786}
787
788/// Encode the `KeySetRemove` command request payload.
789#[must_use]
790#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
791pub fn encode_key_set_remove(group_key_set_id: u16) -> Vec<u8> {
792    let mut buf = Vec::new();
793    let mut w = TlvWriter::new(&mut buf);
794    w.start_structure(Tag::Anonymous)
795        .expect("infallible: vec writer");
796    w.put_uint(Tag::Context(0), u64::from(group_key_set_id))
797        .expect("infallible: vec writer");
798    w.end_container().expect("infallible: vec writer");
799    buf
800}
801
802/// Encode the `KeySetReadAllIndices` command request payload.
803#[must_use]
804#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
805pub fn encode_key_set_read_all_indices() -> Vec<u8> {
806    let mut buf = Vec::new();
807    let mut w = TlvWriter::new(&mut buf);
808    w.start_structure(Tag::Anonymous)
809        .expect("infallible: vec writer");
810    w.end_container().expect("infallible: vec writer");
811    buf
812}
813
814/// Decoded `KeySetReadAllIndicesResponse` payload.
815#[derive(Clone, Debug, PartialEq)]
816#[non_exhaustive]
817pub struct KeySetReadAllIndicesResponse {
818    /// Field GroupKeySetIDs (tag 0).
819    pub group_key_set_i_ds: Vec<u16>,
820}
821
822impl KeySetReadAllIndicesResponse {
823    /// Decode the fields of an already-opened anonymous structure
824    /// (reader positioned after the struct start; consumes to its end).
825    ///
826    /// # Errors
827    /// Returns [`ClusterError`] on a malformed structure or missing required field.
828    pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
829        let mut f_group_key_set_i_ds: Option<Vec<u16>> = None;
830        loop {
831            match r.next()? {
832                Some(Element::ContainerEnd) => break,
833                Some(Element::ContainerStart {
834                    tag: Tag::Context(0),
835                    kind: ContainerKind::Array,
836                }) => {
837                    let mut out = Vec::new();
838                    loop {
839                        match r.next()? {
840                            Some(Element::ContainerEnd) => break,
841                            Some(Element::Scalar {
842                                value: Value::Uint(v),
843                                ..
844                            }) => out.push(
845                                u16::try_from(v)
846                                    .map_err(|_| ClusterError::InvalidLength("GroupKeySetIDs"))?,
847                            ),
848                            None => {
849                                return Err(ClusterError::Tlv(
850                                    matter_codec::Error::UnclosedContainer,
851                                ))
852                            }
853                            Some(Element::ContainerStart { .. }) => r.skip_container()?,
854                            Some(_) => {} // skip unknown scalar
855                        }
856                    }
857                    f_group_key_set_i_ds = Some(out);
858                }
859                None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
860                Some(Element::ContainerStart { .. }) => r.skip_container()?,
861                Some(_) => {} // unknown/future scalar — skip
862            }
863        }
864        Ok(Self {
865            group_key_set_i_ds: f_group_key_set_i_ds
866                .ok_or(ClusterError::MissingField("GroupKeySetIDs"))?,
867        })
868    }
869    /// Decode from a standalone anonymous TLV structure.
870    ///
871    /// # Errors
872    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
873    pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
874        let mut r = TlvReader::new(tlv);
875        match r.next()? {
876            Some(Element::ContainerStart {
877                kind: ContainerKind::Structure,
878                ..
879            }) => {}
880            _ => {
881                return Err(ClusterError::UnexpectedType {
882                    context: "KeySetReadAllIndicesResponse",
883                })
884            }
885        }
886        Self::decode_from(&mut r)
887    }
888}