Skip to main content

matter_clusters/gen/
access_control.rs

1//! AccessControl cluster (0x001F).
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 = 0x001F;
19/// Cluster revision.
20pub const CLUSTER_REVISION: u16 = 2;
21
22/// Command IDs (requests and responses).
23pub mod command_id {
24    /// `ReviewFabricRestrictions` (request).
25    pub const REVIEW_FABRIC_RESTRICTIONS: u32 = 0x00;
26    /// `ReviewFabricRestrictionsResponse` (response).
27    pub const REVIEW_FABRIC_RESTRICTIONS_RESPONSE: u32 = 0x01;
28}
29
30/// Attribute IDs (cluster-specific).
31pub mod attribute_id {
32    /// `Acl`.
33    pub const ACL: u32 = 0x0000;
34    /// `Extension`.
35    pub const EXTENSION: u32 = 0x0001;
36    /// `SubjectsPerAccessControlEntry`.
37    pub const SUBJECTS_PER_ACCESS_CONTROL_ENTRY: u32 = 0x0002;
38    /// `TargetsPerAccessControlEntry`.
39    pub const TARGETS_PER_ACCESS_CONTROL_ENTRY: u32 = 0x0003;
40    /// `AccessControlEntriesPerFabric`.
41    pub const ACCESS_CONTROL_ENTRIES_PER_FABRIC: u32 = 0x0004;
42    /// `CommissioningArl`.
43    pub const COMMISSIONING_ARL: u32 = 0x0005;
44    /// `Arl`.
45    pub const ARL: u32 = 0x0006;
46}
47
48bitflags::bitflags! {
49    /// `AccessControl` feature bits (FeatureMap).
50    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
51    pub struct Feature: u32 {
52        /// Extension (EXTS).
53        const EXTS = 1 << 0;
54        /// ManagedDevice (MNGD).
55        const MNGD = 1 << 1;
56    }
57}
58
59/// `AccessControlEntryAuthModeEnum` (enum8).
60#[derive(Copy, Clone, Debug, PartialEq, Eq)]
61pub enum AccessControlEntryAuthModeEnum {
62    /// Pase = 1.
63    Pase,
64    /// Case = 2.
65    Case,
66    /// Group = 3.
67    Group,
68    /// A value not known to this codegen revision.
69    Unknown(u8),
70}
71
72impl AccessControlEntryAuthModeEnum {
73    /// Decode from its raw discriminant (unknown → `Unknown`).
74    #[must_use]
75    pub fn from_raw(v: u8) -> Self {
76        match v {
77            1 => Self::Pase,
78            2 => Self::Case,
79            3 => Self::Group,
80            other => Self::Unknown(other),
81        }
82    }
83    /// The raw discriminant.
84    #[must_use]
85    pub fn to_raw(self) -> u8 {
86        match self {
87            Self::Pase => 1,
88            Self::Case => 2,
89            Self::Group => 3,
90            Self::Unknown(v) => v,
91        }
92    }
93}
94
95/// `AccessControlEntryPrivilegeEnum` (enum8).
96#[derive(Copy, Clone, Debug, PartialEq, Eq)]
97pub enum AccessControlEntryPrivilegeEnum {
98    /// View = 1.
99    View,
100    /// ProxyView = 2.
101    ProxyView,
102    /// Operate = 3.
103    Operate,
104    /// Manage = 4.
105    Manage,
106    /// Administer = 5.
107    Administer,
108    /// A value not known to this codegen revision.
109    Unknown(u8),
110}
111
112impl AccessControlEntryPrivilegeEnum {
113    /// Decode from its raw discriminant (unknown → `Unknown`).
114    #[must_use]
115    pub fn from_raw(v: u8) -> Self {
116        match v {
117            1 => Self::View,
118            2 => Self::ProxyView,
119            3 => Self::Operate,
120            4 => Self::Manage,
121            5 => Self::Administer,
122            other => Self::Unknown(other),
123        }
124    }
125    /// The raw discriminant.
126    #[must_use]
127    pub fn to_raw(self) -> u8 {
128        match self {
129            Self::View => 1,
130            Self::ProxyView => 2,
131            Self::Operate => 3,
132            Self::Manage => 4,
133            Self::Administer => 5,
134            Self::Unknown(v) => v,
135        }
136    }
137}
138
139/// `AccessControlEntryStruct` struct.
140#[derive(Clone, Debug, PartialEq)]
141#[non_exhaustive]
142pub struct AccessControlEntryStruct {
143    /// Field Privilege (tag 1).
144    pub privilege: AccessControlEntryPrivilegeEnum,
145    /// Field AuthMode (tag 2).
146    pub auth_mode: AccessControlEntryAuthModeEnum,
147    /// Field Subjects (tag 3).
148    pub subjects: Nullable<Vec<u64>>,
149    /// Field Targets (tag 4).
150    pub targets: Nullable<Vec<AccessControlTargetStruct>>,
151    /// Field FabricIndex (tag 254).
152    pub fabric_index: u8,
153}
154
155/// `AccessControlExtensionStruct` struct.
156#[derive(Clone, Debug, PartialEq)]
157#[non_exhaustive]
158pub struct AccessControlExtensionStruct {
159    /// Field Data (tag 1).
160    pub data: Vec<u8>,
161    /// Field FabricIndex (tag 254).
162    pub fabric_index: u8,
163}
164
165/// `AccessControlTargetStruct` struct.
166#[derive(Clone, Debug, PartialEq)]
167#[non_exhaustive]
168pub struct AccessControlTargetStruct {
169    /// Field Cluster (tag 0).
170    pub cluster: Nullable<u32>,
171    /// Field Endpoint (tag 1).
172    pub endpoint: Nullable<u16>,
173    /// Field DeviceType (tag 2).
174    pub device_type: Nullable<u32>,
175}
176
177/// `AccessRestrictionEntryStruct` struct.
178#[derive(Clone, Debug, PartialEq)]
179#[non_exhaustive]
180pub struct AccessRestrictionEntryStruct {
181    /// Field Endpoint (tag 0).
182    pub endpoint: u16,
183    /// Field Cluster (tag 1).
184    pub cluster: u32,
185    /// Field Restrictions (tag 2).
186    pub restrictions: Vec<AccessRestrictionStruct>,
187    /// Field FabricIndex (tag 254).
188    pub fabric_index: u8,
189}
190
191/// `AccessRestrictionStruct` struct.
192#[derive(Clone, Debug, PartialEq)]
193pub struct AccessRestrictionStruct {
194    /// Field Type (tag 0).
195    pub r#type: AccessRestrictionTypeEnum,
196    /// Field Id (tag 1).
197    pub id: Nullable<u32>,
198}
199
200/// `AccessRestrictionTypeEnum` (enum8).
201#[derive(Copy, Clone, Debug, PartialEq, Eq)]
202pub enum AccessRestrictionTypeEnum {
203    /// AttributeAccessForbidden = 0.
204    AttributeAccessForbidden,
205    /// AttributeWriteForbidden = 1.
206    AttributeWriteForbidden,
207    /// CommandForbidden = 2.
208    CommandForbidden,
209    /// EventForbidden = 3.
210    EventForbidden,
211    /// A value not known to this codegen revision.
212    Unknown(u8),
213}
214
215impl AccessRestrictionTypeEnum {
216    /// Decode from its raw discriminant (unknown → `Unknown`).
217    #[must_use]
218    pub fn from_raw(v: u8) -> Self {
219        match v {
220            0 => Self::AttributeAccessForbidden,
221            1 => Self::AttributeWriteForbidden,
222            2 => Self::CommandForbidden,
223            3 => Self::EventForbidden,
224            other => Self::Unknown(other),
225        }
226    }
227    /// The raw discriminant.
228    #[must_use]
229    pub fn to_raw(self) -> u8 {
230        match self {
231            Self::AttributeAccessForbidden => 0,
232            Self::AttributeWriteForbidden => 1,
233            Self::CommandForbidden => 2,
234            Self::EventForbidden => 3,
235            Self::Unknown(v) => v,
236        }
237    }
238}
239
240/// `ChangeTypeEnum` (enum8).
241#[derive(Copy, Clone, Debug, PartialEq, Eq)]
242pub enum ChangeTypeEnum {
243    /// Changed = 0.
244    Changed,
245    /// Added = 1.
246    Added,
247    /// Removed = 2.
248    Removed,
249    /// A value not known to this codegen revision.
250    Unknown(u8),
251}
252
253impl ChangeTypeEnum {
254    /// Decode from its raw discriminant (unknown → `Unknown`).
255    #[must_use]
256    pub fn from_raw(v: u8) -> Self {
257        match v {
258            0 => Self::Changed,
259            1 => Self::Added,
260            2 => Self::Removed,
261            other => Self::Unknown(other),
262        }
263    }
264    /// The raw discriminant.
265    #[must_use]
266    pub fn to_raw(self) -> u8 {
267        match self {
268            Self::Changed => 0,
269            Self::Added => 1,
270            Self::Removed => 2,
271            Self::Unknown(v) => v,
272        }
273    }
274}
275
276/// `CommissioningAccessRestrictionEntryStruct` struct.
277#[derive(Clone, Debug, PartialEq)]
278pub struct CommissioningAccessRestrictionEntryStruct {
279    /// Field Endpoint (tag 0).
280    pub endpoint: u16,
281    /// Field Cluster (tag 1).
282    pub cluster: u32,
283    /// Field Restrictions (tag 2).
284    pub restrictions: Vec<AccessRestrictionStruct>,
285}
286
287impl AccessControlEntryStruct {
288    /// Decode the fields of an already-opened anonymous structure
289    /// (reader positioned after the struct start; consumes to its end).
290    ///
291    /// # Errors
292    /// Returns [`ClusterError`] on a malformed structure or missing required field.
293    pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
294        let mut f_privilege: Option<AccessControlEntryPrivilegeEnum> = None;
295        let mut f_auth_mode: Option<AccessControlEntryAuthModeEnum> = None;
296        let mut f_subjects: Option<Nullable<Vec<u64>>> = None;
297        let mut f_targets: Option<Nullable<Vec<AccessControlTargetStruct>>> = None;
298        let mut f_fabric_index: Option<u8> = None;
299        loop {
300            match r.next()? {
301                Some(Element::ContainerEnd) => break,
302                Some(Element::Scalar {
303                    tag: Tag::Context(1),
304                    value: Value::Uint(v),
305                }) => {
306                    f_privilege = Some(AccessControlEntryPrivilegeEnum::from_raw(
307                        u8::try_from(v).map_err(|_| ClusterError::InvalidLength("Privilege"))?,
308                    ))
309                }
310                Some(Element::Scalar {
311                    tag: Tag::Context(2),
312                    value: Value::Uint(v),
313                }) => {
314                    f_auth_mode = Some(AccessControlEntryAuthModeEnum::from_raw(
315                        u8::try_from(v).map_err(|_| ClusterError::InvalidLength("AuthMode"))?,
316                    ))
317                }
318                Some(Element::Scalar {
319                    tag: Tag::Context(3),
320                    value: Value::Null,
321                }) => f_subjects = Some(Nullable::Null),
322                Some(Element::ContainerStart {
323                    tag: Tag::Context(3),
324                    kind: ContainerKind::Array,
325                }) => {
326                    let mut out = Vec::new();
327                    loop {
328                        match r.next()? {
329                            Some(Element::ContainerEnd) => break,
330                            Some(Element::Scalar {
331                                value: Value::Uint(v),
332                                ..
333                            }) => out.push(
334                                u64::try_from(v)
335                                    .map_err(|_| ClusterError::InvalidLength("Subjects"))?,
336                            ),
337                            None => {
338                                return Err(ClusterError::Tlv(
339                                    matter_codec::Error::UnclosedContainer,
340                                ))
341                            }
342                            Some(Element::ContainerStart { .. }) => r.skip_container()?,
343                            Some(_) => {} // skip unknown scalar
344                        }
345                    }
346                    f_subjects = Some(Nullable::Value(out));
347                }
348                Some(Element::Scalar {
349                    tag: Tag::Context(4),
350                    value: Value::Null,
351                }) => f_targets = Some(Nullable::Null),
352                Some(Element::ContainerStart {
353                    tag: Tag::Context(4),
354                    kind: ContainerKind::Array,
355                }) => {
356                    let mut out = Vec::new();
357                    loop {
358                        match r.next()? {
359                            Some(Element::ContainerEnd) => break,
360                            Some(Element::ContainerStart {
361                                kind: ContainerKind::Structure,
362                                ..
363                            }) => {
364                                out.push(AccessControlTargetStruct::decode_from(r)?);
365                            }
366                            None => {
367                                return Err(ClusterError::Tlv(
368                                    matter_codec::Error::UnclosedContainer,
369                                ))
370                            }
371                            Some(Element::ContainerStart { .. }) => r.skip_container()?,
372                            Some(_) => {} // skip unknown scalar
373                        }
374                    }
375                    f_targets = Some(Nullable::Value(out));
376                }
377                Some(Element::Scalar {
378                    tag: Tag::Context(254),
379                    value: Value::Uint(v),
380                }) => {
381                    f_fabric_index = Some(
382                        u8::try_from(v).map_err(|_| ClusterError::InvalidLength("FabricIndex"))?,
383                    )
384                }
385                None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
386                Some(Element::ContainerStart { .. }) => r.skip_container()?,
387                Some(_) => {} // unknown/future scalar — skip
388            }
389        }
390        Ok(Self {
391            privilege: f_privilege.ok_or(ClusterError::MissingField("Privilege"))?,
392            auth_mode: f_auth_mode.ok_or(ClusterError::MissingField("AuthMode"))?,
393            subjects: f_subjects.ok_or(ClusterError::MissingField("Subjects"))?,
394            targets: f_targets.ok_or(ClusterError::MissingField("Targets"))?,
395            fabric_index: f_fabric_index.ok_or(ClusterError::MissingField("FabricIndex"))?,
396        })
397    }
398    /// Decode from a standalone anonymous TLV structure.
399    ///
400    /// # Errors
401    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
402    pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
403        let mut r = TlvReader::new(tlv);
404        match r.next()? {
405            Some(Element::ContainerStart {
406                kind: ContainerKind::Structure,
407                ..
408            }) => {}
409            _ => {
410                return Err(ClusterError::UnexpectedType {
411                    context: "AccessControlEntryStruct",
412                })
413            }
414        }
415        Self::decode_from(&mut r)
416    }
417}
418
419impl AccessControlExtensionStruct {
420    /// Decode the fields of an already-opened anonymous structure
421    /// (reader positioned after the struct start; consumes to its end).
422    ///
423    /// # Errors
424    /// Returns [`ClusterError`] on a malformed structure or missing required field.
425    pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
426        let mut f_data: Option<Vec<u8>> = None;
427        let mut f_fabric_index: Option<u8> = None;
428        loop {
429            match r.next()? {
430                Some(Element::ContainerEnd) => break,
431                Some(Element::Scalar {
432                    tag: Tag::Context(1),
433                    value: Value::Bytes(v),
434                }) => f_data = Some(v),
435                Some(Element::Scalar {
436                    tag: Tag::Context(254),
437                    value: Value::Uint(v),
438                }) => {
439                    f_fabric_index = Some(
440                        u8::try_from(v).map_err(|_| ClusterError::InvalidLength("FabricIndex"))?,
441                    )
442                }
443                None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
444                Some(Element::ContainerStart { .. }) => r.skip_container()?,
445                Some(_) => {} // unknown/future scalar — skip
446            }
447        }
448        Ok(Self {
449            data: f_data.ok_or(ClusterError::MissingField("Data"))?,
450            fabric_index: f_fabric_index.ok_or(ClusterError::MissingField("FabricIndex"))?,
451        })
452    }
453    /// Decode from a standalone anonymous TLV structure.
454    ///
455    /// # Errors
456    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
457    pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
458        let mut r = TlvReader::new(tlv);
459        match r.next()? {
460            Some(Element::ContainerStart {
461                kind: ContainerKind::Structure,
462                ..
463            }) => {}
464            _ => {
465                return Err(ClusterError::UnexpectedType {
466                    context: "AccessControlExtensionStruct",
467                })
468            }
469        }
470        Self::decode_from(&mut r)
471    }
472    /// Write this struct's fields into an already-open container.
473    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
474    pub fn write_fields(&self, w: &mut TlvWriter<'_>) {
475        w.put_bytes(Tag::Context(1), &self.data)
476            .expect("infallible: vec writer");
477        w.put_uint(Tag::Context(254), u64::from(self.fabric_index))
478            .expect("infallible: vec writer");
479    }
480    /// Encode as a standalone anonymous TLV structure.
481    #[must_use]
482    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
483    pub fn encode(&self) -> Vec<u8> {
484        let mut buf = Vec::new();
485        let mut w = TlvWriter::new(&mut buf);
486        w.start_structure(Tag::Anonymous)
487            .expect("infallible: vec writer");
488        self.write_fields(&mut w);
489        w.end_container().expect("infallible: vec writer");
490        buf
491    }
492}
493
494impl AccessControlTargetStruct {
495    /// Decode the fields of an already-opened anonymous structure
496    /// (reader positioned after the struct start; consumes to its end).
497    ///
498    /// # Errors
499    /// Returns [`ClusterError`] on a malformed structure or missing required field.
500    pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
501        let mut f_cluster: Option<Nullable<u32>> = None;
502        let mut f_endpoint: Option<Nullable<u16>> = None;
503        let mut f_device_type: Option<Nullable<u32>> = None;
504        loop {
505            match r.next()? {
506                Some(Element::ContainerEnd) => break,
507                Some(Element::Scalar {
508                    tag: Tag::Context(0),
509                    value: Value::Null,
510                }) => f_cluster = Some(Nullable::Null),
511                Some(Element::Scalar {
512                    tag: Tag::Context(0),
513                    value: Value::Uint(v),
514                }) => {
515                    f_cluster = Some(Nullable::Value(
516                        u32::try_from(v).map_err(|_| ClusterError::InvalidLength("Cluster"))?,
517                    ))
518                }
519                Some(Element::Scalar {
520                    tag: Tag::Context(1),
521                    value: Value::Null,
522                }) => f_endpoint = Some(Nullable::Null),
523                Some(Element::Scalar {
524                    tag: Tag::Context(1),
525                    value: Value::Uint(v),
526                }) => {
527                    f_endpoint = Some(Nullable::Value(
528                        u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Endpoint"))?,
529                    ))
530                }
531                Some(Element::Scalar {
532                    tag: Tag::Context(2),
533                    value: Value::Null,
534                }) => f_device_type = Some(Nullable::Null),
535                Some(Element::Scalar {
536                    tag: Tag::Context(2),
537                    value: Value::Uint(v),
538                }) => {
539                    f_device_type = Some(Nullable::Value(
540                        u32::try_from(v).map_err(|_| ClusterError::InvalidLength("DeviceType"))?,
541                    ))
542                }
543                None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
544                Some(Element::ContainerStart { .. }) => r.skip_container()?,
545                Some(_) => {} // unknown/future scalar — skip
546            }
547        }
548        Ok(Self {
549            cluster: f_cluster.ok_or(ClusterError::MissingField("Cluster"))?,
550            endpoint: f_endpoint.ok_or(ClusterError::MissingField("Endpoint"))?,
551            device_type: f_device_type.ok_or(ClusterError::MissingField("DeviceType"))?,
552        })
553    }
554    /// Decode from a standalone anonymous TLV structure.
555    ///
556    /// # Errors
557    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
558    pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
559        let mut r = TlvReader::new(tlv);
560        match r.next()? {
561            Some(Element::ContainerStart {
562                kind: ContainerKind::Structure,
563                ..
564            }) => {}
565            _ => {
566                return Err(ClusterError::UnexpectedType {
567                    context: "AccessControlTargetStruct",
568                })
569            }
570        }
571        Self::decode_from(&mut r)
572    }
573    /// Write this struct's fields into an already-open container.
574    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
575    pub fn write_fields(&self, w: &mut TlvWriter<'_>) {
576        match &self.cluster {
577            Nullable::Null => w.put_null(Tag::Context(0)).expect("infallible: vec writer"),
578            Nullable::Value(cluster) => {
579                w.put_uint(Tag::Context(0), u64::from(*cluster))
580                    .expect("infallible: vec writer");
581            }
582        }
583        match &self.endpoint {
584            Nullable::Null => w.put_null(Tag::Context(1)).expect("infallible: vec writer"),
585            Nullable::Value(endpoint) => {
586                w.put_uint(Tag::Context(1), u64::from(*endpoint))
587                    .expect("infallible: vec writer");
588            }
589        }
590        match &self.device_type {
591            Nullable::Null => w.put_null(Tag::Context(2)).expect("infallible: vec writer"),
592            Nullable::Value(device_type) => {
593                w.put_uint(Tag::Context(2), u64::from(*device_type))
594                    .expect("infallible: vec writer");
595            }
596        }
597    }
598    /// Encode as a standalone anonymous TLV structure.
599    #[must_use]
600    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
601    pub fn encode(&self) -> Vec<u8> {
602        let mut buf = Vec::new();
603        let mut w = TlvWriter::new(&mut buf);
604        w.start_structure(Tag::Anonymous)
605            .expect("infallible: vec writer");
606        self.write_fields(&mut w);
607        w.end_container().expect("infallible: vec writer");
608        buf
609    }
610}
611
612impl AccessRestrictionEntryStruct {
613    /// Decode the fields of an already-opened anonymous structure
614    /// (reader positioned after the struct start; consumes to its end).
615    ///
616    /// # Errors
617    /// Returns [`ClusterError`] on a malformed structure or missing required field.
618    pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
619        let mut f_endpoint: Option<u16> = None;
620        let mut f_cluster: Option<u32> = None;
621        let mut f_restrictions: Option<Vec<AccessRestrictionStruct>> = None;
622        let mut f_fabric_index: Option<u8> = None;
623        loop {
624            match r.next()? {
625                Some(Element::ContainerEnd) => break,
626                Some(Element::Scalar {
627                    tag: Tag::Context(0),
628                    value: Value::Uint(v),
629                }) => {
630                    f_endpoint = Some(
631                        u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Endpoint"))?,
632                    )
633                }
634                Some(Element::Scalar {
635                    tag: Tag::Context(1),
636                    value: Value::Uint(v),
637                }) => {
638                    f_cluster =
639                        Some(u32::try_from(v).map_err(|_| ClusterError::InvalidLength("Cluster"))?)
640                }
641                Some(Element::ContainerStart {
642                    tag: Tag::Context(2),
643                    kind: ContainerKind::Array,
644                }) => {
645                    let mut out = Vec::new();
646                    loop {
647                        match r.next()? {
648                            Some(Element::ContainerEnd) => break,
649                            Some(Element::ContainerStart {
650                                kind: ContainerKind::Structure,
651                                ..
652                            }) => {
653                                out.push(AccessRestrictionStruct::decode_from(r)?);
654                            }
655                            None => {
656                                return Err(ClusterError::Tlv(
657                                    matter_codec::Error::UnclosedContainer,
658                                ))
659                            }
660                            Some(Element::ContainerStart { .. }) => r.skip_container()?,
661                            Some(_) => {} // skip unknown scalar
662                        }
663                    }
664                    f_restrictions = Some(out);
665                }
666                Some(Element::Scalar {
667                    tag: Tag::Context(254),
668                    value: Value::Uint(v),
669                }) => {
670                    f_fabric_index = Some(
671                        u8::try_from(v).map_err(|_| ClusterError::InvalidLength("FabricIndex"))?,
672                    )
673                }
674                None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
675                Some(Element::ContainerStart { .. }) => r.skip_container()?,
676                Some(_) => {} // unknown/future scalar — skip
677            }
678        }
679        Ok(Self {
680            endpoint: f_endpoint.ok_or(ClusterError::MissingField("Endpoint"))?,
681            cluster: f_cluster.ok_or(ClusterError::MissingField("Cluster"))?,
682            restrictions: f_restrictions.ok_or(ClusterError::MissingField("Restrictions"))?,
683            fabric_index: f_fabric_index.ok_or(ClusterError::MissingField("FabricIndex"))?,
684        })
685    }
686    /// Decode from a standalone anonymous TLV structure.
687    ///
688    /// # Errors
689    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
690    pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
691        let mut r = TlvReader::new(tlv);
692        match r.next()? {
693            Some(Element::ContainerStart {
694                kind: ContainerKind::Structure,
695                ..
696            }) => {}
697            _ => {
698                return Err(ClusterError::UnexpectedType {
699                    context: "AccessRestrictionEntryStruct",
700                })
701            }
702        }
703        Self::decode_from(&mut r)
704    }
705}
706
707impl AccessRestrictionStruct {
708    /// Decode the fields of an already-opened anonymous structure
709    /// (reader positioned after the struct start; consumes to its end).
710    ///
711    /// # Errors
712    /// Returns [`ClusterError`] on a malformed structure or missing required field.
713    pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
714        let mut f_type: Option<AccessRestrictionTypeEnum> = None;
715        let mut f_id: Option<Nullable<u32>> = None;
716        loop {
717            match r.next()? {
718                Some(Element::ContainerEnd) => break,
719                Some(Element::Scalar {
720                    tag: Tag::Context(0),
721                    value: Value::Uint(v),
722                }) => {
723                    f_type = Some(AccessRestrictionTypeEnum::from_raw(
724                        u8::try_from(v).map_err(|_| ClusterError::InvalidLength("Type"))?,
725                    ))
726                }
727                Some(Element::Scalar {
728                    tag: Tag::Context(1),
729                    value: Value::Null,
730                }) => f_id = Some(Nullable::Null),
731                Some(Element::Scalar {
732                    tag: Tag::Context(1),
733                    value: Value::Uint(v),
734                }) => {
735                    f_id = Some(Nullable::Value(
736                        u32::try_from(v).map_err(|_| ClusterError::InvalidLength("Id"))?,
737                    ))
738                }
739                None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
740                Some(Element::ContainerStart { .. }) => r.skip_container()?,
741                Some(_) => {} // unknown/future scalar — skip
742            }
743        }
744        Ok(Self {
745            r#type: f_type.ok_or(ClusterError::MissingField("Type"))?,
746            id: f_id.ok_or(ClusterError::MissingField("Id"))?,
747        })
748    }
749    /// Decode from a standalone anonymous TLV structure.
750    ///
751    /// # Errors
752    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
753    pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
754        let mut r = TlvReader::new(tlv);
755        match r.next()? {
756            Some(Element::ContainerStart {
757                kind: ContainerKind::Structure,
758                ..
759            }) => {}
760            _ => {
761                return Err(ClusterError::UnexpectedType {
762                    context: "AccessRestrictionStruct",
763                })
764            }
765        }
766        Self::decode_from(&mut r)
767    }
768    /// Write this struct's fields into an already-open container.
769    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
770    pub fn write_fields(&self, w: &mut TlvWriter<'_>) {
771        w.put_uint(Tag::Context(0), u64::from(self.r#type.to_raw()))
772            .expect("infallible: vec writer");
773        match &self.id {
774            Nullable::Null => w.put_null(Tag::Context(1)).expect("infallible: vec writer"),
775            Nullable::Value(id) => {
776                w.put_uint(Tag::Context(1), u64::from(*id))
777                    .expect("infallible: vec writer");
778            }
779        }
780    }
781    /// Encode as a standalone anonymous TLV structure.
782    #[must_use]
783    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
784    pub fn encode(&self) -> Vec<u8> {
785        let mut buf = Vec::new();
786        let mut w = TlvWriter::new(&mut buf);
787        w.start_structure(Tag::Anonymous)
788            .expect("infallible: vec writer");
789        self.write_fields(&mut w);
790        w.end_container().expect("infallible: vec writer");
791        buf
792    }
793}
794
795impl CommissioningAccessRestrictionEntryStruct {
796    /// Decode the fields of an already-opened anonymous structure
797    /// (reader positioned after the struct start; consumes to its end).
798    ///
799    /// # Errors
800    /// Returns [`ClusterError`] on a malformed structure or missing required field.
801    pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
802        let mut f_endpoint: Option<u16> = None;
803        let mut f_cluster: Option<u32> = None;
804        let mut f_restrictions: Option<Vec<AccessRestrictionStruct>> = None;
805        loop {
806            match r.next()? {
807                Some(Element::ContainerEnd) => break,
808                Some(Element::Scalar {
809                    tag: Tag::Context(0),
810                    value: Value::Uint(v),
811                }) => {
812                    f_endpoint = Some(
813                        u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Endpoint"))?,
814                    )
815                }
816                Some(Element::Scalar {
817                    tag: Tag::Context(1),
818                    value: Value::Uint(v),
819                }) => {
820                    f_cluster =
821                        Some(u32::try_from(v).map_err(|_| ClusterError::InvalidLength("Cluster"))?)
822                }
823                Some(Element::ContainerStart {
824                    tag: Tag::Context(2),
825                    kind: ContainerKind::Array,
826                }) => {
827                    let mut out = Vec::new();
828                    loop {
829                        match r.next()? {
830                            Some(Element::ContainerEnd) => break,
831                            Some(Element::ContainerStart {
832                                kind: ContainerKind::Structure,
833                                ..
834                            }) => {
835                                out.push(AccessRestrictionStruct::decode_from(r)?);
836                            }
837                            None => {
838                                return Err(ClusterError::Tlv(
839                                    matter_codec::Error::UnclosedContainer,
840                                ))
841                            }
842                            Some(Element::ContainerStart { .. }) => r.skip_container()?,
843                            Some(_) => {} // skip unknown scalar
844                        }
845                    }
846                    f_restrictions = Some(out);
847                }
848                None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
849                Some(Element::ContainerStart { .. }) => r.skip_container()?,
850                Some(_) => {} // unknown/future scalar — skip
851            }
852        }
853        Ok(Self {
854            endpoint: f_endpoint.ok_or(ClusterError::MissingField("Endpoint"))?,
855            cluster: f_cluster.ok_or(ClusterError::MissingField("Cluster"))?,
856            restrictions: f_restrictions.ok_or(ClusterError::MissingField("Restrictions"))?,
857        })
858    }
859    /// Decode from a standalone anonymous TLV structure.
860    ///
861    /// # Errors
862    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
863    pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
864        let mut r = TlvReader::new(tlv);
865        match r.next()? {
866            Some(Element::ContainerStart {
867                kind: ContainerKind::Structure,
868                ..
869            }) => {}
870            _ => {
871                return Err(ClusterError::UnexpectedType {
872                    context: "CommissioningAccessRestrictionEntryStruct",
873                })
874            }
875        }
876        Self::decode_from(&mut r)
877    }
878    /// Write this struct's fields into an already-open container.
879    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
880    pub fn write_fields(&self, w: &mut TlvWriter<'_>) {
881        w.put_uint(Tag::Context(0), u64::from(self.endpoint))
882            .expect("infallible: vec writer");
883        w.put_uint(Tag::Context(1), u64::from(self.cluster))
884            .expect("infallible: vec writer");
885        w.start_array(Tag::Context(2))
886            .expect("infallible: vec writer");
887        for el in &self.restrictions {
888            w.start_structure(Tag::Anonymous)
889                .expect("infallible: vec writer");
890            el.write_fields(w);
891            w.end_container().expect("infallible: vec writer");
892        }
893        w.end_container().expect("infallible: vec writer");
894    }
895    /// Encode as a standalone anonymous TLV structure.
896    #[must_use]
897    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
898    pub fn encode(&self) -> Vec<u8> {
899        let mut buf = Vec::new();
900        let mut w = TlvWriter::new(&mut buf);
901        w.start_structure(Tag::Anonymous)
902            .expect("infallible: vec writer");
903        self.write_fields(&mut w);
904        w.end_container().expect("infallible: vec writer");
905        buf
906    }
907}
908
909/// Decode the `Acl` attribute value.
910///
911/// # Errors
912/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
913pub fn decode_acl(tlv: &[u8]) -> Result<Vec<AccessControlEntryStruct>, ClusterError> {
914    let mut r = TlvReader::new(tlv);
915    match r.next()? {
916        Some(Element::ContainerStart {
917            kind: ContainerKind::Array,
918            ..
919        }) => {}
920        _ => return Err(ClusterError::UnexpectedType { context: "Acl" }),
921    }
922    let r = &mut r;
923    let mut out = Vec::new();
924    loop {
925        match r.next()? {
926            Some(Element::ContainerEnd) => break,
927            Some(Element::ContainerStart {
928                kind: ContainerKind::Structure,
929                ..
930            }) => {
931                out.push(AccessControlEntryStruct::decode_from(r)?);
932            }
933            None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
934            Some(Element::ContainerStart { .. }) => r.skip_container()?,
935            Some(_) => {} // skip unknown scalar
936        }
937    }
938    Ok(out)
939}
940
941/// Decode the `Extension` attribute value.
942///
943/// # Errors
944/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
945pub fn decode_extension(tlv: &[u8]) -> Result<Vec<AccessControlExtensionStruct>, ClusterError> {
946    let mut r = TlvReader::new(tlv);
947    match r.next()? {
948        Some(Element::ContainerStart {
949            kind: ContainerKind::Array,
950            ..
951        }) => {}
952        _ => {
953            return Err(ClusterError::UnexpectedType {
954                context: "Extension",
955            })
956        }
957    }
958    let r = &mut r;
959    let mut out = Vec::new();
960    loop {
961        match r.next()? {
962            Some(Element::ContainerEnd) => break,
963            Some(Element::ContainerStart {
964                kind: ContainerKind::Structure,
965                ..
966            }) => {
967                out.push(AccessControlExtensionStruct::decode_from(r)?);
968            }
969            None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
970            Some(Element::ContainerStart { .. }) => r.skip_container()?,
971            Some(_) => {} // skip unknown scalar
972        }
973    }
974    Ok(out)
975}
976
977/// Decode the `SubjectsPerAccessControlEntry` attribute value.
978///
979/// # Errors
980/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
981pub fn decode_subjects_per_access_control_entry(tlv: &[u8]) -> Result<u16, ClusterError> {
982    let mut r = TlvReader::new(tlv);
983    match r.next()? {
984        Some(Element::Scalar {
985            value: Value::Uint(v),
986            ..
987        }) => Ok(u16::try_from(v)
988            .map_err(|_| ClusterError::InvalidLength("SubjectsPerAccessControlEntry"))?),
989        _ => Err(ClusterError::UnexpectedType {
990            context: "SubjectsPerAccessControlEntry",
991        }),
992    }
993}
994
995/// Decode the `TargetsPerAccessControlEntry` attribute value.
996///
997/// # Errors
998/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
999pub fn decode_targets_per_access_control_entry(tlv: &[u8]) -> Result<u16, ClusterError> {
1000    let mut r = TlvReader::new(tlv);
1001    match r.next()? {
1002        Some(Element::Scalar {
1003            value: Value::Uint(v),
1004            ..
1005        }) => Ok(u16::try_from(v)
1006            .map_err(|_| ClusterError::InvalidLength("TargetsPerAccessControlEntry"))?),
1007        _ => Err(ClusterError::UnexpectedType {
1008            context: "TargetsPerAccessControlEntry",
1009        }),
1010    }
1011}
1012
1013/// Decode the `AccessControlEntriesPerFabric` attribute value.
1014///
1015/// # Errors
1016/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1017pub fn decode_access_control_entries_per_fabric(tlv: &[u8]) -> Result<u16, ClusterError> {
1018    let mut r = TlvReader::new(tlv);
1019    match r.next()? {
1020        Some(Element::Scalar {
1021            value: Value::Uint(v),
1022            ..
1023        }) => Ok(u16::try_from(v)
1024            .map_err(|_| ClusterError::InvalidLength("AccessControlEntriesPerFabric"))?),
1025        _ => Err(ClusterError::UnexpectedType {
1026            context: "AccessControlEntriesPerFabric",
1027        }),
1028    }
1029}
1030
1031/// Decode the `CommissioningArl` attribute value.
1032///
1033/// # Errors
1034/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1035pub fn decode_commissioning_arl(
1036    tlv: &[u8],
1037) -> Result<Vec<CommissioningAccessRestrictionEntryStruct>, ClusterError> {
1038    let mut r = TlvReader::new(tlv);
1039    match r.next()? {
1040        Some(Element::ContainerStart {
1041            kind: ContainerKind::Array,
1042            ..
1043        }) => {}
1044        _ => {
1045            return Err(ClusterError::UnexpectedType {
1046                context: "CommissioningArl",
1047            })
1048        }
1049    }
1050    let r = &mut r;
1051    let mut out = Vec::new();
1052    loop {
1053        match r.next()? {
1054            Some(Element::ContainerEnd) => break,
1055            Some(Element::ContainerStart {
1056                kind: ContainerKind::Structure,
1057                ..
1058            }) => {
1059                out.push(CommissioningAccessRestrictionEntryStruct::decode_from(r)?);
1060            }
1061            None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
1062            Some(Element::ContainerStart { .. }) => r.skip_container()?,
1063            Some(_) => {} // skip unknown scalar
1064        }
1065    }
1066    Ok(out)
1067}
1068
1069/// Decode the `Arl` attribute value.
1070///
1071/// # Errors
1072/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1073pub fn decode_arl(tlv: &[u8]) -> Result<Vec<AccessRestrictionEntryStruct>, ClusterError> {
1074    let mut r = TlvReader::new(tlv);
1075    match r.next()? {
1076        Some(Element::ContainerStart {
1077            kind: ContainerKind::Array,
1078            ..
1079        }) => {}
1080        _ => return Err(ClusterError::UnexpectedType { context: "Arl" }),
1081    }
1082    let r = &mut r;
1083    let mut out = Vec::new();
1084    loop {
1085        match r.next()? {
1086            Some(Element::ContainerEnd) => break,
1087            Some(Element::ContainerStart {
1088                kind: ContainerKind::Structure,
1089                ..
1090            }) => {
1091                out.push(AccessRestrictionEntryStruct::decode_from(r)?);
1092            }
1093            None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
1094            Some(Element::ContainerStart { .. }) => r.skip_container()?,
1095            Some(_) => {} // skip unknown scalar
1096        }
1097    }
1098    Ok(out)
1099}
1100
1101/// Encode the `ReviewFabricRestrictions` command request payload.
1102#[must_use]
1103#[allow(clippy::expect_used, clippy::missing_panics_doc)] // Vec-backed TlvWriter is infallible.
1104pub fn encode_review_fabric_restrictions(
1105    arl: &Vec<CommissioningAccessRestrictionEntryStruct>,
1106) -> Vec<u8> {
1107    let mut buf = Vec::new();
1108    let mut w = TlvWriter::new(&mut buf);
1109    w.start_structure(Tag::Anonymous)
1110        .expect("infallible: vec writer");
1111    w.start_array(Tag::Context(0))
1112        .expect("infallible: vec writer");
1113    for el in arl.iter() {
1114        w.start_structure(Tag::Anonymous)
1115            .expect("infallible: vec writer");
1116        el.write_fields(&mut w);
1117        w.end_container().expect("infallible: vec writer");
1118    }
1119    w.end_container().expect("infallible: vec writer");
1120    w.end_container().expect("infallible: vec writer");
1121    buf
1122}
1123
1124/// Decoded `ReviewFabricRestrictionsResponse` payload.
1125#[derive(Clone, Debug, PartialEq)]
1126#[non_exhaustive]
1127pub struct ReviewFabricRestrictionsResponse {
1128    /// Field Token (tag 0).
1129    pub token: u64,
1130}
1131
1132impl ReviewFabricRestrictionsResponse {
1133    /// Decode the fields of an already-opened anonymous structure
1134    /// (reader positioned after the struct start; consumes to its end).
1135    ///
1136    /// # Errors
1137    /// Returns [`ClusterError`] on a malformed structure or missing required field.
1138    pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
1139        let mut f_token: Option<u64> = None;
1140        loop {
1141            match r.next()? {
1142                Some(Element::ContainerEnd) => break,
1143                Some(Element::Scalar {
1144                    tag: Tag::Context(0),
1145                    value: Value::Uint(v),
1146                }) => {
1147                    f_token =
1148                        Some(u64::try_from(v).map_err(|_| ClusterError::InvalidLength("Token"))?)
1149                }
1150                None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
1151                Some(Element::ContainerStart { .. }) => r.skip_container()?,
1152                Some(_) => {} // unknown/future scalar — skip
1153            }
1154        }
1155        Ok(Self {
1156            token: f_token.ok_or(ClusterError::MissingField("Token"))?,
1157        })
1158    }
1159    /// Decode from a standalone anonymous TLV structure.
1160    ///
1161    /// # Errors
1162    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
1163    pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
1164        let mut r = TlvReader::new(tlv);
1165        match r.next()? {
1166            Some(Element::ContainerStart {
1167                kind: ContainerKind::Structure,
1168                ..
1169            }) => {}
1170            _ => {
1171                return Err(ClusterError::UnexpectedType {
1172                    context: "ReviewFabricRestrictionsResponse",
1173                })
1174            }
1175        }
1176        Self::decode_from(&mut r)
1177    }
1178}