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}