Skip to main content

matter_clusters/gen/
electrical_power_measurement.rs

1//! ElectricalPowerMeasurement cluster (0x0090).
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 = 0x0090;
19/// Cluster revision.
20pub const CLUSTER_REVISION: u16 = 3;
21
22/// Command IDs (requests and responses).
23pub mod command_id {}
24
25/// Attribute IDs (cluster-specific).
26pub mod attribute_id {
27    /// `PowerMode`.
28    pub const POWER_MODE: u32 = 0x0000;
29    /// `NumberOfMeasurementTypes`.
30    pub const NUMBER_OF_MEASUREMENT_TYPES: u32 = 0x0001;
31    /// `Accuracy`.
32    pub const ACCURACY: u32 = 0x0002;
33    /// `Ranges`.
34    pub const RANGES: u32 = 0x0003;
35    /// `Voltage`.
36    pub const VOLTAGE: u32 = 0x0004;
37    /// `ActiveCurrent`.
38    pub const ACTIVE_CURRENT: u32 = 0x0005;
39    /// `ReactiveCurrent`.
40    pub const REACTIVE_CURRENT: u32 = 0x0006;
41    /// `ApparentCurrent`.
42    pub const APPARENT_CURRENT: u32 = 0x0007;
43    /// `ActivePower`.
44    pub const ACTIVE_POWER: u32 = 0x0008;
45    /// `ReactivePower`.
46    pub const REACTIVE_POWER: u32 = 0x0009;
47    /// `ApparentPower`.
48    pub const APPARENT_POWER: u32 = 0x000A;
49    /// `RmsVoltage`.
50    pub const RMS_VOLTAGE: u32 = 0x000B;
51    /// `RmsCurrent`.
52    pub const RMS_CURRENT: u32 = 0x000C;
53    /// `RmsPower`.
54    pub const RMS_POWER: u32 = 0x000D;
55    /// `Frequency`.
56    pub const FREQUENCY: u32 = 0x000E;
57    /// `HarmonicCurrents`.
58    pub const HARMONIC_CURRENTS: u32 = 0x000F;
59    /// `HarmonicPhases`.
60    pub const HARMONIC_PHASES: u32 = 0x0010;
61    /// `PowerFactor`.
62    pub const POWER_FACTOR: u32 = 0x0011;
63    /// `NeutralCurrent`.
64    pub const NEUTRAL_CURRENT: u32 = 0x0012;
65}
66
67bitflags::bitflags! {
68    /// `ElectricalPowerMeasurement` feature bits (FeatureMap).
69    #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
70    pub struct Feature: u32 {
71        /// DirectCurrent (DIRC).
72        const DIRC = 1 << 0;
73        /// AlternatingCurrent (ALTC).
74        const ALTC = 1 << 1;
75        /// PolyphasePower (POLY).
76        const POLY = 1 << 2;
77        /// Harmonics (HARM).
78        const HARM = 1 << 3;
79        /// PowerQuality (PWRQ).
80        const PWRQ = 1 << 4;
81    }
82}
83
84/// `HarmonicMeasurementStruct` struct.
85#[derive(Clone, Debug, PartialEq)]
86#[non_exhaustive]
87pub struct HarmonicMeasurementStruct {
88    /// Field Order (tag 0).
89    pub order: u8,
90    /// Field Measurement (tag 1).
91    pub measurement: Nullable<i64>,
92}
93
94/// `MeasurementAccuracyRangeStruct` struct.
95#[derive(Clone, Debug, PartialEq)]
96#[non_exhaustive]
97pub struct MeasurementAccuracyRangeStruct {
98    /// Field RangeMin (tag 0).
99    pub range_min: i64,
100    /// Field RangeMax (tag 1).
101    pub range_max: i64,
102    /// Field PercentMax (tag 2).
103    pub percent_max: Option<u16>,
104    /// Field PercentMin (tag 3).
105    pub percent_min: Option<u16>,
106    /// Field PercentTypical (tag 4).
107    pub percent_typical: Option<u16>,
108    /// Field FixedMax (tag 5).
109    pub fixed_max: Option<u64>,
110    /// Field FixedMin (tag 6).
111    pub fixed_min: Option<u64>,
112    /// Field FixedTypical (tag 7).
113    pub fixed_typical: Option<u64>,
114}
115
116/// `MeasurementAccuracyStruct` struct.
117#[derive(Clone, Debug, PartialEq)]
118#[non_exhaustive]
119pub struct MeasurementAccuracyStruct {
120    /// Field MeasurementType (tag 0).
121    pub measurement_type: MeasurementTypeEnum,
122    /// Field Measured (tag 1).
123    pub measured: bool,
124    /// Field MinMeasuredValue (tag 2).
125    pub min_measured_value: i64,
126    /// Field MaxMeasuredValue (tag 3).
127    pub max_measured_value: i64,
128    /// Field AccuracyRanges (tag 4).
129    pub accuracy_ranges: Vec<MeasurementAccuracyRangeStruct>,
130}
131
132/// `MeasurementRangeStruct` struct.
133#[derive(Clone, Debug, PartialEq)]
134#[non_exhaustive]
135pub struct MeasurementRangeStruct {
136    /// Field MeasurementType (tag 0).
137    pub measurement_type: MeasurementTypeEnum,
138    /// Field Min (tag 1).
139    pub min: i64,
140    /// Field Max (tag 2).
141    pub max: i64,
142    /// Field StartTimestamp (tag 3).
143    pub start_timestamp: Option<u32>,
144    /// Field EndTimestamp (tag 4).
145    pub end_timestamp: Option<u32>,
146    /// Field MinTimestamp (tag 5).
147    pub min_timestamp: Option<u32>,
148    /// Field MaxTimestamp (tag 6).
149    pub max_timestamp: Option<u32>,
150    /// Field StartSystime (tag 7).
151    pub start_systime: Option<u64>,
152    /// Field EndSystime (tag 8).
153    pub end_systime: Option<u64>,
154    /// Field MinSystime (tag 9).
155    pub min_systime: Option<u64>,
156    /// Field MaxSystime (tag 10).
157    pub max_systime: Option<u64>,
158}
159
160/// `MeasurementTypeEnum` (enum16).
161#[derive(Copy, Clone, Debug, PartialEq, Eq)]
162pub enum MeasurementTypeEnum {
163    /// Unspecified = 0.
164    Unspecified,
165    /// Voltage = 1.
166    Voltage,
167    /// ActiveCurrent = 2.
168    ActiveCurrent,
169    /// ReactiveCurrent = 3.
170    ReactiveCurrent,
171    /// ApparentCurrent = 4.
172    ApparentCurrent,
173    /// ActivePower = 5.
174    ActivePower,
175    /// ReactivePower = 6.
176    ReactivePower,
177    /// ApparentPower = 7.
178    ApparentPower,
179    /// RmsVoltage = 8.
180    RmsVoltage,
181    /// RmsCurrent = 9.
182    RmsCurrent,
183    /// RmsPower = 10.
184    RmsPower,
185    /// Frequency = 11.
186    Frequency,
187    /// PowerFactor = 12.
188    PowerFactor,
189    /// NeutralCurrent = 13.
190    NeutralCurrent,
191    /// ElectricalEnergy = 14.
192    ElectricalEnergy,
193    /// ReactiveEnergy = 15.
194    ReactiveEnergy,
195    /// ApparentEnergy = 16.
196    ApparentEnergy,
197    /// A value not known to this codegen revision.
198    Unknown(u16),
199}
200
201impl MeasurementTypeEnum {
202    /// Decode from its raw discriminant (unknown → `Unknown`).
203    #[must_use]
204    pub fn from_raw(v: u16) -> Self {
205        match v {
206            0 => Self::Unspecified,
207            1 => Self::Voltage,
208            2 => Self::ActiveCurrent,
209            3 => Self::ReactiveCurrent,
210            4 => Self::ApparentCurrent,
211            5 => Self::ActivePower,
212            6 => Self::ReactivePower,
213            7 => Self::ApparentPower,
214            8 => Self::RmsVoltage,
215            9 => Self::RmsCurrent,
216            10 => Self::RmsPower,
217            11 => Self::Frequency,
218            12 => Self::PowerFactor,
219            13 => Self::NeutralCurrent,
220            14 => Self::ElectricalEnergy,
221            15 => Self::ReactiveEnergy,
222            16 => Self::ApparentEnergy,
223            other => Self::Unknown(other),
224        }
225    }
226    /// The raw discriminant.
227    #[must_use]
228    pub fn to_raw(self) -> u16 {
229        match self {
230            Self::Unspecified => 0,
231            Self::Voltage => 1,
232            Self::ActiveCurrent => 2,
233            Self::ReactiveCurrent => 3,
234            Self::ApparentCurrent => 4,
235            Self::ActivePower => 5,
236            Self::ReactivePower => 6,
237            Self::ApparentPower => 7,
238            Self::RmsVoltage => 8,
239            Self::RmsCurrent => 9,
240            Self::RmsPower => 10,
241            Self::Frequency => 11,
242            Self::PowerFactor => 12,
243            Self::NeutralCurrent => 13,
244            Self::ElectricalEnergy => 14,
245            Self::ReactiveEnergy => 15,
246            Self::ApparentEnergy => 16,
247            Self::Unknown(v) => v,
248        }
249    }
250}
251
252/// `PowerModeEnum` (enum8).
253#[derive(Copy, Clone, Debug, PartialEq, Eq)]
254pub enum PowerModeEnum {
255    /// Unknown = 0.
256    Unknown,
257    /// Dc = 1.
258    Dc,
259    /// Ac = 2.
260    Ac,
261    /// A value not known to this codegen revision.
262    Unrecognized(u8),
263}
264
265impl PowerModeEnum {
266    /// Decode from its raw discriminant (unknown → `Unrecognized`).
267    #[must_use]
268    pub fn from_raw(v: u8) -> Self {
269        match v {
270            0 => Self::Unknown,
271            1 => Self::Dc,
272            2 => Self::Ac,
273            other => Self::Unrecognized(other),
274        }
275    }
276    /// The raw discriminant.
277    #[must_use]
278    pub fn to_raw(self) -> u8 {
279        match self {
280            Self::Unknown => 0,
281            Self::Dc => 1,
282            Self::Ac => 2,
283            Self::Unrecognized(v) => v,
284        }
285    }
286}
287
288impl HarmonicMeasurementStruct {
289    /// Decode the fields of an already-opened anonymous structure
290    /// (reader positioned after the struct start; consumes to its end).
291    ///
292    /// # Errors
293    /// Returns [`ClusterError`] on a malformed structure or missing required field.
294    pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
295        let mut f_order: Option<u8> = None;
296        let mut f_measurement: Option<Nullable<i64>> = None;
297        loop {
298            match r.next()? {
299                Some(Element::ContainerEnd) => break,
300                Some(Element::Scalar {
301                    tag: Tag::Context(0),
302                    value: Value::Uint(v),
303                }) => {
304                    f_order =
305                        Some(u8::try_from(v).map_err(|_| ClusterError::InvalidLength("Order"))?)
306                }
307                Some(Element::Scalar {
308                    tag: Tag::Context(1),
309                    value: Value::Null,
310                }) => f_measurement = Some(Nullable::Null),
311                Some(Element::Scalar {
312                    tag: Tag::Context(1),
313                    value: Value::Int(v),
314                }) => {
315                    f_measurement = Some(Nullable::Value(
316                        i64::try_from(v).map_err(|_| ClusterError::InvalidLength("Measurement"))?,
317                    ))
318                }
319                None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
320                Some(Element::ContainerStart { .. }) => r.skip_container()?,
321                Some(_) => {} // unknown/future scalar — skip
322            }
323        }
324        Ok(Self {
325            order: f_order.ok_or(ClusterError::MissingField("Order"))?,
326            measurement: f_measurement.ok_or(ClusterError::MissingField("Measurement"))?,
327        })
328    }
329    /// Decode from a standalone anonymous TLV structure.
330    ///
331    /// # Errors
332    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
333    pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
334        let mut r = TlvReader::new(tlv);
335        match r.next()? {
336            Some(Element::ContainerStart {
337                kind: ContainerKind::Structure,
338                ..
339            }) => {}
340            _ => {
341                return Err(ClusterError::UnexpectedType {
342                    context: "HarmonicMeasurementStruct",
343                })
344            }
345        }
346        Self::decode_from(&mut r)
347    }
348    /// Write this struct's fields into an already-open container.
349    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
350    pub fn write_fields(&self, w: &mut TlvWriter<'_>) {
351        w.put_uint(Tag::Context(0), u64::from(self.order))
352            .expect("infallible: vec writer");
353        match &self.measurement {
354            Nullable::Null => w.put_null(Tag::Context(1)).expect("infallible: vec writer"),
355            Nullable::Value(measurement) => {
356                w.put_int(Tag::Context(1), i64::from(*measurement))
357                    .expect("infallible: vec writer");
358            }
359        }
360    }
361    /// Encode as a standalone anonymous TLV structure.
362    #[must_use]
363    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
364    pub fn encode(&self) -> Vec<u8> {
365        let mut buf = Vec::new();
366        let mut w = TlvWriter::new(&mut buf);
367        w.start_structure(Tag::Anonymous)
368            .expect("infallible: vec writer");
369        self.write_fields(&mut w);
370        w.end_container().expect("infallible: vec writer");
371        buf
372    }
373}
374
375impl MeasurementAccuracyRangeStruct {
376    /// Decode the fields of an already-opened anonymous structure
377    /// (reader positioned after the struct start; consumes to its end).
378    ///
379    /// # Errors
380    /// Returns [`ClusterError`] on a malformed structure or missing required field.
381    pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
382        let mut f_range_min: Option<i64> = None;
383        let mut f_range_max: Option<i64> = None;
384        let mut f_percent_max: Option<u16> = None;
385        let mut f_percent_min: Option<u16> = None;
386        let mut f_percent_typical: Option<u16> = None;
387        let mut f_fixed_max: Option<u64> = None;
388        let mut f_fixed_min: Option<u64> = None;
389        let mut f_fixed_typical: Option<u64> = None;
390        loop {
391            match r.next()? {
392                Some(Element::ContainerEnd) => break,
393                Some(Element::Scalar {
394                    tag: Tag::Context(0),
395                    value: Value::Int(v),
396                }) => {
397                    f_range_min = Some(
398                        i64::try_from(v).map_err(|_| ClusterError::InvalidLength("RangeMin"))?,
399                    )
400                }
401                Some(Element::Scalar {
402                    tag: Tag::Context(1),
403                    value: Value::Int(v),
404                }) => {
405                    f_range_max = Some(
406                        i64::try_from(v).map_err(|_| ClusterError::InvalidLength("RangeMax"))?,
407                    )
408                }
409                Some(Element::Scalar {
410                    tag: Tag::Context(2),
411                    value: Value::Uint(v),
412                }) => {
413                    f_percent_max = Some(
414                        u16::try_from(v).map_err(|_| ClusterError::InvalidLength("PercentMax"))?,
415                    )
416                }
417                Some(Element::Scalar {
418                    tag: Tag::Context(3),
419                    value: Value::Uint(v),
420                }) => {
421                    f_percent_min = Some(
422                        u16::try_from(v).map_err(|_| ClusterError::InvalidLength("PercentMin"))?,
423                    )
424                }
425                Some(Element::Scalar {
426                    tag: Tag::Context(4),
427                    value: Value::Uint(v),
428                }) => {
429                    f_percent_typical = Some(
430                        u16::try_from(v)
431                            .map_err(|_| ClusterError::InvalidLength("PercentTypical"))?,
432                    )
433                }
434                Some(Element::Scalar {
435                    tag: Tag::Context(5),
436                    value: Value::Uint(v),
437                }) => {
438                    f_fixed_max = Some(
439                        u64::try_from(v).map_err(|_| ClusterError::InvalidLength("FixedMax"))?,
440                    )
441                }
442                Some(Element::Scalar {
443                    tag: Tag::Context(6),
444                    value: Value::Uint(v),
445                }) => {
446                    f_fixed_min = Some(
447                        u64::try_from(v).map_err(|_| ClusterError::InvalidLength("FixedMin"))?,
448                    )
449                }
450                Some(Element::Scalar {
451                    tag: Tag::Context(7),
452                    value: Value::Uint(v),
453                }) => {
454                    f_fixed_typical = Some(
455                        u64::try_from(v)
456                            .map_err(|_| ClusterError::InvalidLength("FixedTypical"))?,
457                    )
458                }
459                None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
460                Some(Element::ContainerStart { .. }) => r.skip_container()?,
461                Some(_) => {} // unknown/future scalar — skip
462            }
463        }
464        Ok(Self {
465            range_min: f_range_min.ok_or(ClusterError::MissingField("RangeMin"))?,
466            range_max: f_range_max.ok_or(ClusterError::MissingField("RangeMax"))?,
467            percent_max: f_percent_max,
468            percent_min: f_percent_min,
469            percent_typical: f_percent_typical,
470            fixed_max: f_fixed_max,
471            fixed_min: f_fixed_min,
472            fixed_typical: f_fixed_typical,
473        })
474    }
475    /// Decode from a standalone anonymous TLV structure.
476    ///
477    /// # Errors
478    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
479    pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
480        let mut r = TlvReader::new(tlv);
481        match r.next()? {
482            Some(Element::ContainerStart {
483                kind: ContainerKind::Structure,
484                ..
485            }) => {}
486            _ => {
487                return Err(ClusterError::UnexpectedType {
488                    context: "MeasurementAccuracyRangeStruct",
489                })
490            }
491        }
492        Self::decode_from(&mut r)
493    }
494    /// Write this struct's fields into an already-open container.
495    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
496    pub fn write_fields(&self, w: &mut TlvWriter<'_>) {
497        w.put_int(Tag::Context(0), i64::from(self.range_min))
498            .expect("infallible: vec writer");
499        w.put_int(Tag::Context(1), i64::from(self.range_max))
500            .expect("infallible: vec writer");
501        if let Some(percent_max) = &self.percent_max {
502            w.put_uint(Tag::Context(2), u64::from(*percent_max))
503                .expect("infallible: vec writer");
504        }
505        if let Some(percent_min) = &self.percent_min {
506            w.put_uint(Tag::Context(3), u64::from(*percent_min))
507                .expect("infallible: vec writer");
508        }
509        if let Some(percent_typical) = &self.percent_typical {
510            w.put_uint(Tag::Context(4), u64::from(*percent_typical))
511                .expect("infallible: vec writer");
512        }
513        if let Some(fixed_max) = &self.fixed_max {
514            w.put_uint(Tag::Context(5), u64::from(*fixed_max))
515                .expect("infallible: vec writer");
516        }
517        if let Some(fixed_min) = &self.fixed_min {
518            w.put_uint(Tag::Context(6), u64::from(*fixed_min))
519                .expect("infallible: vec writer");
520        }
521        if let Some(fixed_typical) = &self.fixed_typical {
522            w.put_uint(Tag::Context(7), u64::from(*fixed_typical))
523                .expect("infallible: vec writer");
524        }
525    }
526    /// Encode as a standalone anonymous TLV structure.
527    #[must_use]
528    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
529    pub fn encode(&self) -> Vec<u8> {
530        let mut buf = Vec::new();
531        let mut w = TlvWriter::new(&mut buf);
532        w.start_structure(Tag::Anonymous)
533            .expect("infallible: vec writer");
534        self.write_fields(&mut w);
535        w.end_container().expect("infallible: vec writer");
536        buf
537    }
538}
539
540impl MeasurementAccuracyStruct {
541    /// Decode the fields of an already-opened anonymous structure
542    /// (reader positioned after the struct start; consumes to its end).
543    ///
544    /// # Errors
545    /// Returns [`ClusterError`] on a malformed structure or missing required field.
546    pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
547        let mut f_measurement_type: Option<MeasurementTypeEnum> = None;
548        let mut f_measured: Option<bool> = None;
549        let mut f_min_measured_value: Option<i64> = None;
550        let mut f_max_measured_value: Option<i64> = None;
551        let mut f_accuracy_ranges: Option<Vec<MeasurementAccuracyRangeStruct>> = None;
552        loop {
553            match r.next()? {
554                Some(Element::ContainerEnd) => break,
555                Some(Element::Scalar {
556                    tag: Tag::Context(0),
557                    value: Value::Uint(v),
558                }) => {
559                    f_measurement_type = Some(MeasurementTypeEnum::from_raw(
560                        u16::try_from(v)
561                            .map_err(|_| ClusterError::InvalidLength("MeasurementType"))?,
562                    ))
563                }
564                Some(Element::Scalar {
565                    tag: Tag::Context(1),
566                    value: Value::Bool(v),
567                }) => f_measured = Some(v),
568                Some(Element::Scalar {
569                    tag: Tag::Context(2),
570                    value: Value::Int(v),
571                }) => {
572                    f_min_measured_value = Some(
573                        i64::try_from(v)
574                            .map_err(|_| ClusterError::InvalidLength("MinMeasuredValue"))?,
575                    )
576                }
577                Some(Element::Scalar {
578                    tag: Tag::Context(3),
579                    value: Value::Int(v),
580                }) => {
581                    f_max_measured_value = Some(
582                        i64::try_from(v)
583                            .map_err(|_| ClusterError::InvalidLength("MaxMeasuredValue"))?,
584                    )
585                }
586                Some(Element::ContainerStart {
587                    tag: Tag::Context(4),
588                    kind: ContainerKind::Array,
589                }) => {
590                    let mut out = Vec::new();
591                    loop {
592                        match r.next()? {
593                            Some(Element::ContainerEnd) => break,
594                            Some(Element::ContainerStart {
595                                kind: ContainerKind::Structure,
596                                ..
597                            }) => {
598                                out.push(MeasurementAccuracyRangeStruct::decode_from(r)?);
599                            }
600                            None => {
601                                return Err(ClusterError::Tlv(
602                                    matter_codec::Error::UnclosedContainer,
603                                ))
604                            }
605                            Some(Element::ContainerStart { .. }) => r.skip_container()?,
606                            Some(_) => {} // skip unknown scalar
607                        }
608                    }
609                    f_accuracy_ranges = Some(out);
610                }
611                None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
612                Some(Element::ContainerStart { .. }) => r.skip_container()?,
613                Some(_) => {} // unknown/future scalar — skip
614            }
615        }
616        Ok(Self {
617            measurement_type: f_measurement_type
618                .ok_or(ClusterError::MissingField("MeasurementType"))?,
619            measured: f_measured.ok_or(ClusterError::MissingField("Measured"))?,
620            min_measured_value: f_min_measured_value
621                .ok_or(ClusterError::MissingField("MinMeasuredValue"))?,
622            max_measured_value: f_max_measured_value
623                .ok_or(ClusterError::MissingField("MaxMeasuredValue"))?,
624            accuracy_ranges: f_accuracy_ranges
625                .ok_or(ClusterError::MissingField("AccuracyRanges"))?,
626        })
627    }
628    /// Decode from a standalone anonymous TLV structure.
629    ///
630    /// # Errors
631    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
632    pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
633        let mut r = TlvReader::new(tlv);
634        match r.next()? {
635            Some(Element::ContainerStart {
636                kind: ContainerKind::Structure,
637                ..
638            }) => {}
639            _ => {
640                return Err(ClusterError::UnexpectedType {
641                    context: "MeasurementAccuracyStruct",
642                })
643            }
644        }
645        Self::decode_from(&mut r)
646    }
647}
648
649impl MeasurementRangeStruct {
650    /// Decode the fields of an already-opened anonymous structure
651    /// (reader positioned after the struct start; consumes to its end).
652    ///
653    /// # Errors
654    /// Returns [`ClusterError`] on a malformed structure or missing required field.
655    pub fn decode_from(r: &mut TlvReader<'_>) -> Result<Self, ClusterError> {
656        let mut f_measurement_type: Option<MeasurementTypeEnum> = None;
657        let mut f_min: Option<i64> = None;
658        let mut f_max: Option<i64> = None;
659        let mut f_start_timestamp: Option<u32> = None;
660        let mut f_end_timestamp: Option<u32> = None;
661        let mut f_min_timestamp: Option<u32> = None;
662        let mut f_max_timestamp: Option<u32> = None;
663        let mut f_start_systime: Option<u64> = None;
664        let mut f_end_systime: Option<u64> = None;
665        let mut f_min_systime: Option<u64> = None;
666        let mut f_max_systime: Option<u64> = None;
667        loop {
668            match r.next()? {
669                Some(Element::ContainerEnd) => break,
670                Some(Element::Scalar {
671                    tag: Tag::Context(0),
672                    value: Value::Uint(v),
673                }) => {
674                    f_measurement_type = Some(MeasurementTypeEnum::from_raw(
675                        u16::try_from(v)
676                            .map_err(|_| ClusterError::InvalidLength("MeasurementType"))?,
677                    ))
678                }
679                Some(Element::Scalar {
680                    tag: Tag::Context(1),
681                    value: Value::Int(v),
682                }) => {
683                    f_min = Some(i64::try_from(v).map_err(|_| ClusterError::InvalidLength("Min"))?)
684                }
685                Some(Element::Scalar {
686                    tag: Tag::Context(2),
687                    value: Value::Int(v),
688                }) => {
689                    f_max = Some(i64::try_from(v).map_err(|_| ClusterError::InvalidLength("Max"))?)
690                }
691                Some(Element::Scalar {
692                    tag: Tag::Context(3),
693                    value: Value::Uint(v),
694                }) => {
695                    f_start_timestamp = Some(
696                        u32::try_from(v)
697                            .map_err(|_| ClusterError::InvalidLength("StartTimestamp"))?,
698                    )
699                }
700                Some(Element::Scalar {
701                    tag: Tag::Context(4),
702                    value: Value::Uint(v),
703                }) => {
704                    f_end_timestamp = Some(
705                        u32::try_from(v)
706                            .map_err(|_| ClusterError::InvalidLength("EndTimestamp"))?,
707                    )
708                }
709                Some(Element::Scalar {
710                    tag: Tag::Context(5),
711                    value: Value::Uint(v),
712                }) => {
713                    f_min_timestamp = Some(
714                        u32::try_from(v)
715                            .map_err(|_| ClusterError::InvalidLength("MinTimestamp"))?,
716                    )
717                }
718                Some(Element::Scalar {
719                    tag: Tag::Context(6),
720                    value: Value::Uint(v),
721                }) => {
722                    f_max_timestamp = Some(
723                        u32::try_from(v)
724                            .map_err(|_| ClusterError::InvalidLength("MaxTimestamp"))?,
725                    )
726                }
727                Some(Element::Scalar {
728                    tag: Tag::Context(7),
729                    value: Value::Uint(v),
730                }) => {
731                    f_start_systime = Some(
732                        u64::try_from(v)
733                            .map_err(|_| ClusterError::InvalidLength("StartSystime"))?,
734                    )
735                }
736                Some(Element::Scalar {
737                    tag: Tag::Context(8),
738                    value: Value::Uint(v),
739                }) => {
740                    f_end_systime = Some(
741                        u64::try_from(v).map_err(|_| ClusterError::InvalidLength("EndSystime"))?,
742                    )
743                }
744                Some(Element::Scalar {
745                    tag: Tag::Context(9),
746                    value: Value::Uint(v),
747                }) => {
748                    f_min_systime = Some(
749                        u64::try_from(v).map_err(|_| ClusterError::InvalidLength("MinSystime"))?,
750                    )
751                }
752                Some(Element::Scalar {
753                    tag: Tag::Context(10),
754                    value: Value::Uint(v),
755                }) => {
756                    f_max_systime = Some(
757                        u64::try_from(v).map_err(|_| ClusterError::InvalidLength("MaxSystime"))?,
758                    )
759                }
760                None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
761                Some(Element::ContainerStart { .. }) => r.skip_container()?,
762                Some(_) => {} // unknown/future scalar — skip
763            }
764        }
765        Ok(Self {
766            measurement_type: f_measurement_type
767                .ok_or(ClusterError::MissingField("MeasurementType"))?,
768            min: f_min.ok_or(ClusterError::MissingField("Min"))?,
769            max: f_max.ok_or(ClusterError::MissingField("Max"))?,
770            start_timestamp: f_start_timestamp,
771            end_timestamp: f_end_timestamp,
772            min_timestamp: f_min_timestamp,
773            max_timestamp: f_max_timestamp,
774            start_systime: f_start_systime,
775            end_systime: f_end_systime,
776            min_systime: f_min_systime,
777            max_systime: f_max_systime,
778        })
779    }
780    /// Decode from a standalone anonymous TLV structure.
781    ///
782    /// # Errors
783    /// Returns [`ClusterError`] if the bytes are not an anonymous structure or a field is malformed.
784    pub fn decode(tlv: &[u8]) -> Result<Self, ClusterError> {
785        let mut r = TlvReader::new(tlv);
786        match r.next()? {
787            Some(Element::ContainerStart {
788                kind: ContainerKind::Structure,
789                ..
790            }) => {}
791            _ => {
792                return Err(ClusterError::UnexpectedType {
793                    context: "MeasurementRangeStruct",
794                })
795            }
796        }
797        Self::decode_from(&mut r)
798    }
799    /// Write this struct's fields into an already-open container.
800    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
801    pub fn write_fields(&self, w: &mut TlvWriter<'_>) {
802        w.put_uint(Tag::Context(0), u64::from(self.measurement_type.to_raw()))
803            .expect("infallible: vec writer");
804        w.put_int(Tag::Context(1), i64::from(self.min))
805            .expect("infallible: vec writer");
806        w.put_int(Tag::Context(2), i64::from(self.max))
807            .expect("infallible: vec writer");
808        if let Some(start_timestamp) = &self.start_timestamp {
809            w.put_uint(Tag::Context(3), u64::from(*start_timestamp))
810                .expect("infallible: vec writer");
811        }
812        if let Some(end_timestamp) = &self.end_timestamp {
813            w.put_uint(Tag::Context(4), u64::from(*end_timestamp))
814                .expect("infallible: vec writer");
815        }
816        if let Some(min_timestamp) = &self.min_timestamp {
817            w.put_uint(Tag::Context(5), u64::from(*min_timestamp))
818                .expect("infallible: vec writer");
819        }
820        if let Some(max_timestamp) = &self.max_timestamp {
821            w.put_uint(Tag::Context(6), u64::from(*max_timestamp))
822                .expect("infallible: vec writer");
823        }
824        if let Some(start_systime) = &self.start_systime {
825            w.put_uint(Tag::Context(7), u64::from(*start_systime))
826                .expect("infallible: vec writer");
827        }
828        if let Some(end_systime) = &self.end_systime {
829            w.put_uint(Tag::Context(8), u64::from(*end_systime))
830                .expect("infallible: vec writer");
831        }
832        if let Some(min_systime) = &self.min_systime {
833            w.put_uint(Tag::Context(9), u64::from(*min_systime))
834                .expect("infallible: vec writer");
835        }
836        if let Some(max_systime) = &self.max_systime {
837            w.put_uint(Tag::Context(10), u64::from(*max_systime))
838                .expect("infallible: vec writer");
839        }
840    }
841    /// Encode as a standalone anonymous TLV structure.
842    #[must_use]
843    #[allow(clippy::expect_used)] // Vec-backed TlvWriter is infallible.
844    pub fn encode(&self) -> Vec<u8> {
845        let mut buf = Vec::new();
846        let mut w = TlvWriter::new(&mut buf);
847        w.start_structure(Tag::Anonymous)
848            .expect("infallible: vec writer");
849        self.write_fields(&mut w);
850        w.end_container().expect("infallible: vec writer");
851        buf
852    }
853}
854
855/// Decode the `PowerMode` attribute value.
856///
857/// # Errors
858/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
859pub fn decode_power_mode(tlv: &[u8]) -> Result<PowerModeEnum, ClusterError> {
860    let mut r = TlvReader::new(tlv);
861    match r.next()? {
862        Some(Element::Scalar {
863            value: Value::Uint(v),
864            ..
865        }) => Ok(PowerModeEnum::from_raw(
866            u8::try_from(v).map_err(|_| ClusterError::InvalidLength("PowerMode"))?,
867        )),
868        _ => Err(ClusterError::UnexpectedType {
869            context: "PowerMode",
870        }),
871    }
872}
873
874/// Decode the `NumberOfMeasurementTypes` attribute value.
875///
876/// # Errors
877/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
878pub fn decode_number_of_measurement_types(tlv: &[u8]) -> Result<u8, ClusterError> {
879    let mut r = TlvReader::new(tlv);
880    match r.next()? {
881        Some(Element::Scalar {
882            value: Value::Uint(v),
883            ..
884        }) => {
885            Ok(u8::try_from(v)
886                .map_err(|_| ClusterError::InvalidLength("NumberOfMeasurementTypes"))?)
887        }
888        _ => Err(ClusterError::UnexpectedType {
889            context: "NumberOfMeasurementTypes",
890        }),
891    }
892}
893
894/// Decode the `Accuracy` attribute value.
895///
896/// # Errors
897/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
898pub fn decode_accuracy(tlv: &[u8]) -> Result<Vec<MeasurementAccuracyStruct>, ClusterError> {
899    let mut r = TlvReader::new(tlv);
900    match r.next()? {
901        Some(Element::ContainerStart {
902            kind: ContainerKind::Array,
903            ..
904        }) => {}
905        _ => {
906            return Err(ClusterError::UnexpectedType {
907                context: "Accuracy",
908            })
909        }
910    }
911    let r = &mut r;
912    let mut out = Vec::new();
913    loop {
914        match r.next()? {
915            Some(Element::ContainerEnd) => break,
916            Some(Element::ContainerStart {
917                kind: ContainerKind::Structure,
918                ..
919            }) => {
920                out.push(MeasurementAccuracyStruct::decode_from(r)?);
921            }
922            None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
923            Some(Element::ContainerStart { .. }) => r.skip_container()?,
924            Some(_) => {} // skip unknown scalar
925        }
926    }
927    Ok(out)
928}
929
930/// Decode the `Ranges` attribute value.
931///
932/// # Errors
933/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
934pub fn decode_ranges(tlv: &[u8]) -> Result<Vec<MeasurementRangeStruct>, ClusterError> {
935    let mut r = TlvReader::new(tlv);
936    match r.next()? {
937        Some(Element::ContainerStart {
938            kind: ContainerKind::Array,
939            ..
940        }) => {}
941        _ => return Err(ClusterError::UnexpectedType { context: "Ranges" }),
942    }
943    let r = &mut r;
944    let mut out = Vec::new();
945    loop {
946        match r.next()? {
947            Some(Element::ContainerEnd) => break,
948            Some(Element::ContainerStart {
949                kind: ContainerKind::Structure,
950                ..
951            }) => {
952                out.push(MeasurementRangeStruct::decode_from(r)?);
953            }
954            None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
955            Some(Element::ContainerStart { .. }) => r.skip_container()?,
956            Some(_) => {} // skip unknown scalar
957        }
958    }
959    Ok(out)
960}
961
962/// Decode the `Voltage` attribute value.
963///
964/// # Errors
965/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
966pub fn decode_voltage(tlv: &[u8]) -> Result<Nullable<i64>, ClusterError> {
967    let mut r = TlvReader::new(tlv);
968    match r.next()? {
969        Some(Element::Scalar {
970            value: Value::Null, ..
971        }) => Ok(Nullable::Null),
972        Some(Element::Scalar {
973            value: Value::Int(v),
974            ..
975        }) => Ok(Nullable::Value(
976            i64::try_from(v).map_err(|_| ClusterError::InvalidLength("Voltage"))?,
977        )),
978        _ => Err(ClusterError::UnexpectedType { context: "Voltage" }),
979    }
980}
981
982/// Decode the `ActiveCurrent` attribute value.
983///
984/// # Errors
985/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
986pub fn decode_active_current(tlv: &[u8]) -> Result<Nullable<i64>, ClusterError> {
987    let mut r = TlvReader::new(tlv);
988    match r.next()? {
989        Some(Element::Scalar {
990            value: Value::Null, ..
991        }) => Ok(Nullable::Null),
992        Some(Element::Scalar {
993            value: Value::Int(v),
994            ..
995        }) => {
996            Ok(Nullable::Value(i64::try_from(v).map_err(|_| {
997                ClusterError::InvalidLength("ActiveCurrent")
998            })?))
999        }
1000        _ => Err(ClusterError::UnexpectedType {
1001            context: "ActiveCurrent",
1002        }),
1003    }
1004}
1005
1006/// Decode the `ReactiveCurrent` attribute value.
1007///
1008/// # Errors
1009/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1010pub fn decode_reactive_current(tlv: &[u8]) -> Result<Nullable<i64>, ClusterError> {
1011    let mut r = TlvReader::new(tlv);
1012    match r.next()? {
1013        Some(Element::Scalar {
1014            value: Value::Null, ..
1015        }) => Ok(Nullable::Null),
1016        Some(Element::Scalar {
1017            value: Value::Int(v),
1018            ..
1019        }) => {
1020            Ok(Nullable::Value(i64::try_from(v).map_err(|_| {
1021                ClusterError::InvalidLength("ReactiveCurrent")
1022            })?))
1023        }
1024        _ => Err(ClusterError::UnexpectedType {
1025            context: "ReactiveCurrent",
1026        }),
1027    }
1028}
1029
1030/// Decode the `ApparentCurrent` attribute value.
1031///
1032/// # Errors
1033/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1034pub fn decode_apparent_current(tlv: &[u8]) -> Result<Nullable<i64>, ClusterError> {
1035    let mut r = TlvReader::new(tlv);
1036    match r.next()? {
1037        Some(Element::Scalar {
1038            value: Value::Null, ..
1039        }) => Ok(Nullable::Null),
1040        Some(Element::Scalar {
1041            value: Value::Int(v),
1042            ..
1043        }) => {
1044            Ok(Nullable::Value(i64::try_from(v).map_err(|_| {
1045                ClusterError::InvalidLength("ApparentCurrent")
1046            })?))
1047        }
1048        _ => Err(ClusterError::UnexpectedType {
1049            context: "ApparentCurrent",
1050        }),
1051    }
1052}
1053
1054/// Decode the `ActivePower` attribute value.
1055///
1056/// # Errors
1057/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1058pub fn decode_active_power(tlv: &[u8]) -> Result<Nullable<i64>, ClusterError> {
1059    let mut r = TlvReader::new(tlv);
1060    match r.next()? {
1061        Some(Element::Scalar {
1062            value: Value::Null, ..
1063        }) => Ok(Nullable::Null),
1064        Some(Element::Scalar {
1065            value: Value::Int(v),
1066            ..
1067        }) => Ok(Nullable::Value(
1068            i64::try_from(v).map_err(|_| ClusterError::InvalidLength("ActivePower"))?,
1069        )),
1070        _ => Err(ClusterError::UnexpectedType {
1071            context: "ActivePower",
1072        }),
1073    }
1074}
1075
1076/// Decode the `ReactivePower` attribute value.
1077///
1078/// # Errors
1079/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1080pub fn decode_reactive_power(tlv: &[u8]) -> Result<Nullable<i64>, ClusterError> {
1081    let mut r = TlvReader::new(tlv);
1082    match r.next()? {
1083        Some(Element::Scalar {
1084            value: Value::Null, ..
1085        }) => Ok(Nullable::Null),
1086        Some(Element::Scalar {
1087            value: Value::Int(v),
1088            ..
1089        }) => {
1090            Ok(Nullable::Value(i64::try_from(v).map_err(|_| {
1091                ClusterError::InvalidLength("ReactivePower")
1092            })?))
1093        }
1094        _ => Err(ClusterError::UnexpectedType {
1095            context: "ReactivePower",
1096        }),
1097    }
1098}
1099
1100/// Decode the `ApparentPower` attribute value.
1101///
1102/// # Errors
1103/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1104pub fn decode_apparent_power(tlv: &[u8]) -> Result<Nullable<i64>, ClusterError> {
1105    let mut r = TlvReader::new(tlv);
1106    match r.next()? {
1107        Some(Element::Scalar {
1108            value: Value::Null, ..
1109        }) => Ok(Nullable::Null),
1110        Some(Element::Scalar {
1111            value: Value::Int(v),
1112            ..
1113        }) => {
1114            Ok(Nullable::Value(i64::try_from(v).map_err(|_| {
1115                ClusterError::InvalidLength("ApparentPower")
1116            })?))
1117        }
1118        _ => Err(ClusterError::UnexpectedType {
1119            context: "ApparentPower",
1120        }),
1121    }
1122}
1123
1124/// Decode the `RmsVoltage` attribute value.
1125///
1126/// # Errors
1127/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1128pub fn decode_rms_voltage(tlv: &[u8]) -> Result<Nullable<i64>, ClusterError> {
1129    let mut r = TlvReader::new(tlv);
1130    match r.next()? {
1131        Some(Element::Scalar {
1132            value: Value::Null, ..
1133        }) => Ok(Nullable::Null),
1134        Some(Element::Scalar {
1135            value: Value::Int(v),
1136            ..
1137        }) => Ok(Nullable::Value(
1138            i64::try_from(v).map_err(|_| ClusterError::InvalidLength("RmsVoltage"))?,
1139        )),
1140        _ => Err(ClusterError::UnexpectedType {
1141            context: "RmsVoltage",
1142        }),
1143    }
1144}
1145
1146/// Decode the `RmsCurrent` attribute value.
1147///
1148/// # Errors
1149/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1150pub fn decode_rms_current(tlv: &[u8]) -> Result<Nullable<i64>, ClusterError> {
1151    let mut r = TlvReader::new(tlv);
1152    match r.next()? {
1153        Some(Element::Scalar {
1154            value: Value::Null, ..
1155        }) => Ok(Nullable::Null),
1156        Some(Element::Scalar {
1157            value: Value::Int(v),
1158            ..
1159        }) => Ok(Nullable::Value(
1160            i64::try_from(v).map_err(|_| ClusterError::InvalidLength("RmsCurrent"))?,
1161        )),
1162        _ => Err(ClusterError::UnexpectedType {
1163            context: "RmsCurrent",
1164        }),
1165    }
1166}
1167
1168/// Decode the `RmsPower` attribute value.
1169///
1170/// # Errors
1171/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1172pub fn decode_rms_power(tlv: &[u8]) -> Result<Nullable<i64>, ClusterError> {
1173    let mut r = TlvReader::new(tlv);
1174    match r.next()? {
1175        Some(Element::Scalar {
1176            value: Value::Null, ..
1177        }) => Ok(Nullable::Null),
1178        Some(Element::Scalar {
1179            value: Value::Int(v),
1180            ..
1181        }) => Ok(Nullable::Value(
1182            i64::try_from(v).map_err(|_| ClusterError::InvalidLength("RmsPower"))?,
1183        )),
1184        _ => Err(ClusterError::UnexpectedType {
1185            context: "RmsPower",
1186        }),
1187    }
1188}
1189
1190/// Decode the `Frequency` attribute value.
1191///
1192/// # Errors
1193/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1194pub fn decode_frequency(tlv: &[u8]) -> Result<Nullable<i64>, ClusterError> {
1195    let mut r = TlvReader::new(tlv);
1196    match r.next()? {
1197        Some(Element::Scalar {
1198            value: Value::Null, ..
1199        }) => Ok(Nullable::Null),
1200        Some(Element::Scalar {
1201            value: Value::Int(v),
1202            ..
1203        }) => Ok(Nullable::Value(
1204            i64::try_from(v).map_err(|_| ClusterError::InvalidLength("Frequency"))?,
1205        )),
1206        _ => Err(ClusterError::UnexpectedType {
1207            context: "Frequency",
1208        }),
1209    }
1210}
1211
1212/// Decode the `HarmonicCurrents` attribute value.
1213///
1214/// # Errors
1215/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1216pub fn decode_harmonic_currents(
1217    tlv: &[u8],
1218) -> Result<Nullable<Vec<HarmonicMeasurementStruct>>, ClusterError> {
1219    let mut r = TlvReader::new(tlv);
1220    match r.next()? {
1221        Some(Element::Scalar {
1222            value: Value::Null, ..
1223        }) => return Ok(Nullable::Null),
1224        Some(Element::ContainerStart {
1225            kind: ContainerKind::Array,
1226            ..
1227        }) => {}
1228        _ => {
1229            return Err(ClusterError::UnexpectedType {
1230                context: "HarmonicCurrents",
1231            })
1232        }
1233    }
1234    let r = &mut r;
1235    let mut out = Vec::new();
1236    loop {
1237        match r.next()? {
1238            Some(Element::ContainerEnd) => break,
1239            Some(Element::ContainerStart {
1240                kind: ContainerKind::Structure,
1241                ..
1242            }) => {
1243                out.push(HarmonicMeasurementStruct::decode_from(r)?);
1244            }
1245            None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
1246            Some(Element::ContainerStart { .. }) => r.skip_container()?,
1247            Some(_) => {} // skip unknown scalar
1248        }
1249    }
1250    Ok(Nullable::Value(out))
1251}
1252
1253/// Decode the `HarmonicPhases` attribute value.
1254///
1255/// # Errors
1256/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1257pub fn decode_harmonic_phases(
1258    tlv: &[u8],
1259) -> Result<Nullable<Vec<HarmonicMeasurementStruct>>, ClusterError> {
1260    let mut r = TlvReader::new(tlv);
1261    match r.next()? {
1262        Some(Element::Scalar {
1263            value: Value::Null, ..
1264        }) => return Ok(Nullable::Null),
1265        Some(Element::ContainerStart {
1266            kind: ContainerKind::Array,
1267            ..
1268        }) => {}
1269        _ => {
1270            return Err(ClusterError::UnexpectedType {
1271                context: "HarmonicPhases",
1272            })
1273        }
1274    }
1275    let r = &mut r;
1276    let mut out = Vec::new();
1277    loop {
1278        match r.next()? {
1279            Some(Element::ContainerEnd) => break,
1280            Some(Element::ContainerStart {
1281                kind: ContainerKind::Structure,
1282                ..
1283            }) => {
1284                out.push(HarmonicMeasurementStruct::decode_from(r)?);
1285            }
1286            None => return Err(ClusterError::Tlv(matter_codec::Error::UnclosedContainer)),
1287            Some(Element::ContainerStart { .. }) => r.skip_container()?,
1288            Some(_) => {} // skip unknown scalar
1289        }
1290    }
1291    Ok(Nullable::Value(out))
1292}
1293
1294/// Decode the `PowerFactor` attribute value.
1295///
1296/// # Errors
1297/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1298pub fn decode_power_factor(tlv: &[u8]) -> Result<Nullable<i64>, ClusterError> {
1299    let mut r = TlvReader::new(tlv);
1300    match r.next()? {
1301        Some(Element::Scalar {
1302            value: Value::Null, ..
1303        }) => Ok(Nullable::Null),
1304        Some(Element::Scalar {
1305            value: Value::Int(v),
1306            ..
1307        }) => Ok(Nullable::Value(
1308            i64::try_from(v).map_err(|_| ClusterError::InvalidLength("PowerFactor"))?,
1309        )),
1310        _ => Err(ClusterError::UnexpectedType {
1311            context: "PowerFactor",
1312        }),
1313    }
1314}
1315
1316/// Decode the `NeutralCurrent` attribute value.
1317///
1318/// # Errors
1319/// Returns [`ClusterError`] on a type mismatch or out-of-range value.
1320pub fn decode_neutral_current(tlv: &[u8]) -> Result<Nullable<i64>, ClusterError> {
1321    let mut r = TlvReader::new(tlv);
1322    match r.next()? {
1323        Some(Element::Scalar {
1324            value: Value::Null, ..
1325        }) => Ok(Nullable::Null),
1326        Some(Element::Scalar {
1327            value: Value::Int(v),
1328            ..
1329        }) => {
1330            Ok(Nullable::Value(i64::try_from(v).map_err(|_| {
1331                ClusterError::InvalidLength("NeutralCurrent")
1332            })?))
1333        }
1334        _ => Err(ClusterError::UnexpectedType {
1335            context: "NeutralCurrent",
1336        }),
1337    }
1338}