matter-clusters 0.1.0

Matter protocol cluster definitions (generated from the spec).
Documentation
//! Descriptor cluster (0x001D).
//! @generated by `cargo xtask codegen` — do not edit.

#![allow(
    clippy::all,
    clippy::pedantic,
    dead_code,
    unreachable_pub,
    unused_imports
)]

use crate::datatypes::SemanticTagStruct;
use crate::error::ClusterError;
use crate::types::Nullable;
use matter_codec::{ContainerKind, Element, Tag, TlvReader, TlvWriter, Value};

/// Cluster ID.
pub const CLUSTER_ID: u32 = 0x001D;
/// Cluster revision.
pub const CLUSTER_REVISION: u16 = 3;

/// Command IDs (requests and responses).
pub mod command_id {}

/// Attribute IDs (cluster-specific).
pub mod attribute_id {
    /// `DeviceTypeList`.
    pub const DEVICE_TYPE_LIST: u32 = 0x0000;
    /// `ServerList`.
    pub const SERVER_LIST: u32 = 0x0001;
    /// `ClientList`.
    pub const CLIENT_LIST: u32 = 0x0002;
    /// `PartsList`.
    pub const PARTS_LIST: u32 = 0x0003;
    /// `TagList`.
    pub const TAG_LIST: u32 = 0x0004;
    /// `EndpointUniqueId`.
    pub const ENDPOINT_UNIQUE_ID: u32 = 0x0005;
}

bitflags::bitflags! {
    /// `Descriptor` feature bits (FeatureMap).
    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
    pub struct Feature: u32 {
        /// TagList (TAGLIST).
        const TAGLIST = 1 << 0;
    }
}

/// `DeviceTypeStruct` struct.
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub struct DeviceTypeStruct {
    /// Field DeviceType (tag 0).
    pub device_type: u32,
    /// Field Revision (tag 1).
    pub revision: u16,
}

impl DeviceTypeStruct {
    /// Decode the fields of an already-opened anonymous structure
    /// (reader positioned after the struct start; consumes to its end).
    ///
    /// # Errors
    /// Returns [`ClusterError`] on a malformed structure or missing required field.
    pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
        let mut f_device_type: Option<u32> = None;
        let mut f_revision: Option<u16> = None;
        loop {
            match r.next()? {
                Some(Element::ContainerEnd) => break,
                Some(Element::Scalar {
                    tag: Tag::Context(0),
                    value: Value::Uint(v),
                }) => {
                    f_device_type = Some(
                        u32::try_from(v).map_err(|_| ClusterError::InvalidLength("DeviceType"))?,
                    )
                }
                Some(Element::Scalar {
                    tag: Tag::Context(1),
                    value: Value::Uint(v),
                }) => {
                    f_revision = Some(
                        u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Revision"))?,
                    )
                }
                None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
                Some(Element::ContainerStart { .. }) => r.skip_container()?,
                Some(_) => {} // unknown/future scalar — skip
            }
        }
        Ok(Self {
            device_type: f_device_type.ok_or(ClusterError::MissingField("DeviceType"))?,
            revision: f_revision.ok_or(ClusterError::MissingField("Revision"))?,
        })
    }
    /// Decode from a standalone anonymous TLV structure.
    ///
    /// # Errors
    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
    pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
        let mut r = TlvReader::new(tlv);
        match r.next()? {
            Some(Element::ContainerStart {
                kind: ContainerKind::Structure,
                ..
            }) => {}
            _ => {
                return Err(ClusterError::UnexpectedType {
                    context: "DeviceTypeStruct",
                })
            }
        }
        Self::decode_from(&mut r)
    }
    /// Write this struct's fields into an already-open container.
    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
    pub fn write_fields(&self, w: &mut TlvWriter<'_>) {
        w.put_uint(Tag::Context(0), u64::from(self.device_type))
            .expect("infallible: vec writer");
        w.put_uint(Tag::Context(1), u64::from(self.revision))
            .expect("infallible: vec writer");
    }
    /// Encode as a standalone anonymous TLV structure.
    #[must_use]
    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
    pub fn encode(&self) -> Vec<u8> {
        let mut buf = Vec::new();
        let mut w = TlvWriter::new(&mut buf);
        w.start_structure(Tag::Anonymous)
            .expect("infallible: vec writer");
        self.write_fields(&mut w);
        w.end_container().expect("infallible: vec writer");
        buf
    }
}

/// Decode the `DeviceTypeList` attribute value.
///
/// # Errors
/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
pub fn decode_device_type_list(tlv: &[u8]) -> Result<Vec<DeviceTypeStruct>, ClusterError> {
    let mut r = TlvReader::new(tlv);
    match r.next()? {
        Some(Element::ContainerStart {
            kind: ContainerKind::Array,
            ..
        }) => {}
        _ => {
            return Err(ClusterError::UnexpectedType {
                context: "DeviceTypeList",
            })
        }
    }
    let r = &mut r;
    let mut out = Vec::new();
    loop {
        match r.next()? {
            Some(Element::ContainerEnd) => break,
            Some(Element::ContainerStart {
                kind: ContainerKind::Structure,
                ..
            }) => {
                out.push(DeviceTypeStruct::decode_from(r)?);
            }
            None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
            Some(Element::ContainerStart { .. }) => r.skip_container()?,
            Some(_) => {} // skip unknown scalar
        }
    }
    Ok(out)
}

/// Decode the `ServerList` attribute value.
///
/// # Errors
/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
pub fn decode_server_list(tlv: &[u8]) -> Result<Vec<u32>, ClusterError> {
    let mut r = TlvReader::new(tlv);
    match r.next()? {
        Some(Element::ContainerStart {
            kind: ContainerKind::Array,
            ..
        }) => {}
        _ => {
            return Err(ClusterError::UnexpectedType {
                context: "ServerList",
            })
        }
    }
    let r = &mut r;
    let mut out = Vec::new();
    loop {
        match r.next()? {
            Some(Element::ContainerEnd) => break,
            Some(Element::Scalar {
                value: Value::Uint(v),
                ..
            }) => {
                out.push(u32::try_from(v).map_err(|_| ClusterError::InvalidLength("ServerList"))?)
            }
            None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
            Some(Element::ContainerStart { .. }) => r.skip_container()?,
            Some(_) => {} // skip unknown scalar
        }
    }
    Ok(out)
}

/// Decode the `ClientList` attribute value.
///
/// # Errors
/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
pub fn decode_client_list(tlv: &[u8]) -> Result<Vec<u32>, ClusterError> {
    let mut r = TlvReader::new(tlv);
    match r.next()? {
        Some(Element::ContainerStart {
            kind: ContainerKind::Array,
            ..
        }) => {}
        _ => {
            return Err(ClusterError::UnexpectedType {
                context: "ClientList",
            })
        }
    }
    let r = &mut r;
    let mut out = Vec::new();
    loop {
        match r.next()? {
            Some(Element::ContainerEnd) => break,
            Some(Element::Scalar {
                value: Value::Uint(v),
                ..
            }) => {
                out.push(u32::try_from(v).map_err(|_| ClusterError::InvalidLength("ClientList"))?)
            }
            None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
            Some(Element::ContainerStart { .. }) => r.skip_container()?,
            Some(_) => {} // skip unknown scalar
        }
    }
    Ok(out)
}

/// Decode the `PartsList` attribute value.
///
/// # Errors
/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
pub fn decode_parts_list(tlv: &[u8]) -> Result<Vec<u16>, ClusterError> {
    let mut r = TlvReader::new(tlv);
    match r.next()? {
        Some(Element::ContainerStart {
            kind: ContainerKind::Array,
            ..
        }) => {}
        _ => {
            return Err(ClusterError::UnexpectedType {
                context: "PartsList",
            })
        }
    }
    let r = &mut r;
    let mut out = Vec::new();
    loop {
        match r.next()? {
            Some(Element::ContainerEnd) => break,
            Some(Element::Scalar {
                value: Value::Uint(v),
                ..
            }) => out.push(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("PartsList"))?),
            None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
            Some(Element::ContainerStart { .. }) => r.skip_container()?,
            Some(_) => {} // skip unknown scalar
        }
    }
    Ok(out)
}

/// Decode the `TagList` attribute value.
///
/// # Errors
/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
pub fn decode_tag_list(tlv: &[u8]) -> Result<Vec<SemanticTagStruct>, ClusterError> {
    let mut r = TlvReader::new(tlv);
    match r.next()? {
        Some(Element::ContainerStart {
            kind: ContainerKind::Array,
            ..
        }) => {}
        _ => return Err(ClusterError::UnexpectedType { context: "TagList" }),
    }
    let r = &mut r;
    let mut out = Vec::new();
    loop {
        match r.next()? {
            Some(Element::ContainerEnd) => break,
            Some(Element::ContainerStart {
                kind: ContainerKind::Structure,
                ..
            }) => {
                out.push(SemanticTagStruct::decode_from(r)?);
            }
            None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
            Some(Element::ContainerStart { .. }) => r.skip_container()?,
            Some(_) => {} // skip unknown scalar
        }
    }
    Ok(out)
}

/// Decode the `EndpointUniqueId` attribute value.
///
/// # Errors
/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
pub fn decode_endpoint_unique_id(tlv: &[u8]) -> Result<String, ClusterError> {
    let mut r = TlvReader::new(tlv);
    match r.next()? {
        Some(Element::Scalar {
            value: Value::Utf8(v),
            ..
        }) => Ok(v),
        _ => Err(ClusterError::UnexpectedType {
            context: "EndpointUniqueId",
        }),
    }
}