matter-clusters 0.3.0

Matter protocol cluster definitions (generated from the spec).
Documentation
//! Binding cluster (0x001E).
//! @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 = 0x001E;
/// Cluster revision.
pub const CLUSTER_REVISION: u16 = 1;

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

/// Attribute IDs (cluster-specific).
pub mod attribute_id {
    /// `Binding`.
    pub const BINDING: u32 = 0x0000;
}

/// `TargetStruct` struct.
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub struct TargetStruct {
    /// Field Node (tag 1).
    pub node: Option<u64>,
    /// Field Group (tag 2).
    pub group: Option<u16>,
    /// Field Endpoint (tag 3).
    pub endpoint: Option<u16>,
    /// Field Cluster (tag 4).
    pub cluster: Option<u32>,
    /// Field FabricIndex (tag 254).
    pub fabric_index: u8,
}

impl TargetStruct {
    /// 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_node: Option<u64> = None;
        let mut f_group: Option<u16> = None;
        let mut f_endpoint: Option<u16> = None;
        let mut f_cluster: Option<u32> = None;
        let mut f_fabric_index: Option<u8> = None;
        loop {
            match r.next()? {
                Some(Element::ContainerEnd) => break,
                Some(Element::Scalar {
                    tag: Tag::Context(1),
                    value: Value::Uint(v),
                }) => {
                    f_node =
                        Some(u64::try_from(v).map_err(|_| ClusterError::InvalidLength("Node"))?)
                }
                Some(Element::Scalar {
                    tag: Tag::Context(2),
                    value: Value::Uint(v),
                }) => {
                    f_group =
                        Some(u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Group"))?)
                }
                Some(Element::Scalar {
                    tag: Tag::Context(3),
                    value: Value::Uint(v),
                }) => {
                    f_endpoint = Some(
                        u16::try_from(v).map_err(|_| ClusterError::InvalidLength("Endpoint"))?,
                    )
                }
                Some(Element::Scalar {
                    tag: Tag::Context(4),
                    value: Value::Uint(v),
                }) => {
                    f_cluster =
                        Some(u32::try_from(v).map_err(|_| ClusterError::InvalidLength("Cluster"))?)
                }
                Some(Element::Scalar {
                    tag: Tag::Context(254),
                    value: Value::Uint(v),
                }) => {
                    f_fabric_index = Some(
                        u8::try_from(v).map_err(|_| ClusterError::InvalidLength("FabricIndex"))?,
                    )
                }
                None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
                Some(Element::ContainerStart { .. }) => r.skip_container()?,
                Some(_) => {} // unknown/future scalar — skip
            }
        }
        Ok(Self {
            node: f_node,
            group: f_group,
            endpoint: f_endpoint,
            cluster: f_cluster,
            fabric_index: f_fabric_index.ok_or(ClusterError::MissingField("FabricIndex"))?,
        })
    }
    /// 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: "TargetStruct",
                })
            }
        }
        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<'_>) {
        if let Some(node) = &self.node {
            w.put_uint(Tag::Context(1), u64::from(*node))
                .expect("infallible: vec writer");
        }
        if let Some(group) = &self.group {
            w.put_uint(Tag::Context(2), u64::from(*group))
                .expect("infallible: vec writer");
        }
        if let Some(endpoint) = &self.endpoint {
            w.put_uint(Tag::Context(3), u64::from(*endpoint))
                .expect("infallible: vec writer");
        }
        if let Some(cluster) = &self.cluster {
            w.put_uint(Tag::Context(4), u64::from(*cluster))
                .expect("infallible: vec writer");
        }
        w.put_uint(Tag::Context(254), u64::from(self.fabric_index))
            .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 `Binding` attribute value.
///
/// # Errors
/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
pub fn decode_binding(tlv: &[u8]) -> Result<Vec<TargetStruct>, ClusterError> {
    let mut r = TlvReader::new(tlv);
    match r.next()? {
        Some(Element::ContainerStart {
            kind: ContainerKind::Array,
            ..
        }) => {}
        _ => return Err(ClusterError::UnexpectedType { context: "Binding" }),
    }
    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(TargetStruct::decode_from(r)?);
            }
            None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
            Some(Element::ContainerStart { .. }) => r.skip_container()?,
            Some(_) => {} // skip unknown scalar
        }
    }
    Ok(out)
}