Skip to main content

rs_matter/tlv/traits/
bitflags.rs

1/*
2 *
3 *    Copyright (c) 2024-2025 Project CHIP Authors
4 *
5 *    Licensed under the Apache License, Version 2.0 (the "License");
6 *    you may not use this file except in compliance with the License.
7 *    You may obtain a copy of the License at
8 *
9 *        http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *    Unless required by applicable law or agreed to in writing, software
12 *    distributed under the License is distributed on an "AS IS" BASIS,
13 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *    See the License for the specific language governing permissions and
15 *    limitations under the License.
16 */
17
18//! TLV support for `bitflags!`.
19//! Bitflags are serialized and deserialized as TLV enumerations.
20
21/// Implements to/from TLV for the given enumeration that was
22/// created using `bitflags!`
23///
24/// NOTE:
25///   - bitflgs are generally unrestricted. The provided implementations
26///     do NOT attempt to validate flags for validity and the entire
27///     range of flags will be marshalled (including unknown flags)
28#[macro_export]
29macro_rules! bitflags_tlv {
30    ($enum_name:ident, $type:ident) => {
31        impl<'a> $crate::tlv::FromTLV<'a> for $enum_name {
32            fn from_tlv(
33                element: &$crate::tlv::TLVElement<'a>,
34            ) -> Result<Self, $crate::error::Error> {
35                Self::from_bits($crate::tlv::TLVElement::$type(element)?).ok_or_else(|| {
36                    $crate::error::Error::from($crate::error::ErrorCode::InvalidData)
37                })
38            }
39
40            fn nullable_from_tlv(
41                element: &$crate::tlv::TLVElement<'a>,
42            ) -> Result<Self, $crate::error::Error> {
43                let value = $crate::tlv::TLVElement::$type(element)?;
44
45                if value != $type::MAX {
46                    Self::from_bits(value).ok_or_else(|| {
47                        $crate::error::Error::from($crate::error::ErrorCode::InvalidData)
48                    })
49                } else {
50                    Err($crate::error::ErrorCode::ConstraintError.into())
51                }
52            }
53        }
54
55        impl $crate::tlv::ToTLV for $enum_name {
56            fn to_tlv<W: $crate::tlv::TLVWrite>(
57                &self,
58                tag: &$crate::tlv::TLVTag,
59                mut tw: W,
60            ) -> Result<(), $crate::error::Error> {
61                tw.$type(tag, self.bits())
62            }
63
64            fn tlv_iter(
65                &self,
66                tag: $crate::tlv::TLVTag,
67            ) -> impl Iterator<Item = Result<$crate::tlv::TLV<'_>, $crate::error::Error>> {
68                $crate::tlv::TLV::$type(tag, self.bits()).into_tlv_iter()
69            }
70
71            fn nullable_to_tlv<W: $crate::tlv::TLVWrite>(
72                &self,
73                tag: &$crate::tlv::TLVTag,
74                mut tw: W,
75            ) -> Result<(), $crate::error::Error> {
76                if self.bits() != $type::MAX {
77                    tw.$type(tag, self.bits())
78                } else {
79                    Err($crate::error::ErrorCode::ConstraintError.into())
80                }
81            }
82
83            fn nullable_tlv_iter(
84                &self,
85                tag: $crate::tlv::TLVTag,
86            ) -> impl Iterator<Item = Result<$crate::tlv::TLV<'_>, $crate::error::Error>> {
87                if self.bits() != $type::MAX {
88                    $crate::tlv::EitherIter::First(
89                        $crate::tlv::TLV::$type(tag, self.bits()).into_tlv_iter(),
90                    )
91                } else {
92                    $crate::tlv::EitherIter::Second(core::iter::once(Err(
93                        $crate::error::ErrorCode::ConstraintError.into(),
94                    )))
95                }
96            }
97        }
98    };
99}