mls_spec/
macros.rs

1macro_rules! impl_spec_enum {
2    (
3        $typename:ident($storage:ty);
4        serde_repr $serde_repr:literal;
5        reserved_priv $reserved_priv_range:expr => $range_error:expr;
6        default_range $spec_default_range:expr;
7        $(
8            $(#[cfg($attr:meta)])*
9            $identifier:ident = $value:expr
10        ),+
11    ) => {
12        #[derive(
13            Clone,
14            Copy,
15            PartialEq,
16            Eq,
17            Hash,
18            PartialOrd,
19            Ord,
20            tls_codec::TlsSerialize,
21            tls_codec::TlsDeserialize,
22            tls_codec::TlsSize
23        )]
24        #[cfg_attr(
25            feature = "serde",
26            derive(serde::Serialize, serde::Deserialize)
27        )]
28        #[cfg_attr(feature = "serde", serde(try_from = $serde_repr))]
29        #[repr(transparent)]
30        pub struct $typename($storage);
31
32        impl $typename {
33            $(
34                $(#[cfg($attr)])*
35                pub const $identifier: $storage = $value as $storage;
36            )+
37            pub(crate) const RESERVED_PRIVATE_USE_RANGE: std::ops::RangeInclusive<$storage> = $reserved_priv_range;
38            pub(crate) const SPEC_DEFAULT_RANGE: Option<std::ops::RangeInclusive<$storage>> = $spec_default_range;
39        }
40
41        impl $typename {
42            #[must_use]
43            pub fn all_without_spec_default() -> Vec<Self> {
44                let all = [
45                    $(
46                        $(#[cfg($attr)])*
47                        Self($value),
48                    )+
49                ];
50
51                all.into_iter()
52                    .filter(|elem| !elem.is_spec_default())
53                    .collect()
54            }
55
56            #[must_use]
57            pub const fn new_unchecked(value: $storage) -> Self {
58                Self(value)
59            }
60
61            pub fn new_private_use(value: $storage) -> crate::MlsSpecResult<Self> {
62                if !Self::RESERVED_PRIVATE_USE_RANGE.contains(&value) {
63                    return Err($range_error);
64                }
65
66                Ok(Self(value))
67            }
68
69            pub const fn is_spec_default(&self) -> bool {
70                let Some(default_range) = &Self::SPEC_DEFAULT_RANGE else {
71                    return false;
72                };
73                *default_range.start() <= self.0 && self.0 <= *default_range.end()
74            }
75
76            pub fn is_grease_value(&self) -> bool {
77                if Self::RESERVED_PRIVATE_USE_RANGE.contains(&self.0) {
78                    return false;
79                }
80
81                #[allow(irrefutable_let_patterns)]
82                let Ok(self_as_u16): Result<u16, _> = self.0.try_into() else {
83                    return false;
84                };
85
86                GREASE_VALUES.contains(&self_as_u16)
87            }
88        }
89
90        impl std::fmt::Display for $typename {
91            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92                write!(f, "{}", self.0)
93            }
94        }
95
96        impl std::fmt::Debug for $typename {
97            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98                let mut const_name = match self {
99                    $(
100                        $(#[cfg($attr)])*
101                        &Self(Self::$identifier) => Some(stringify!($identifier)),
102                    )+
103                    _ => None
104                };
105
106                let typename = stringify!($typename);
107
108                if let Some(const_name) = const_name.take() {
109                    write!(f, "{typename}::{const_name}")?;
110                } else {
111                    write!(f, "{typename}::UNKNOWN[{:4X}]", self.0)?;
112                }
113
114                Ok(())
115            }
116        }
117
118        impl std::ops::Deref for $typename {
119            type Target = $storage;
120
121            fn deref(&self) -> &Self::Target {
122                &self.0
123            }
124        }
125
126        impl TryFrom<$storage> for $typename {
127            type Error = crate::MlsSpecError;
128            fn try_from(value: $storage) -> Result<Self, Self::Error> {
129                match value {
130                    $(
131                        $(#[cfg($attr)])*
132                        Self::$identifier => Ok(Self(value)),
133                    )+
134                    v if Self::RESERVED_PRIVATE_USE_RANGE.contains(&v) => Ok(Self(value)),
135                    v if GREASE_VALUES.contains(&v) => Ok(Self(value)),
136                    _ => Err(crate::MlsSpecError::InvalidSpecValue)
137                }
138            }
139        }
140    };
141}
142
143pub(crate) use impl_spec_enum;
144
145macro_rules! ref_forward_tls_impl {
146    ($target:ident) => {
147        impl tls_codec::Size for &$target {
148            fn tls_serialized_len(&self) -> usize {
149                (*self).tls_serialized_len()
150            }
151        }
152
153        impl tls_codec::Serialize for &$target {
154            fn tls_serialize<W: std::io::Write>(
155                &self,
156                writer: &mut W,
157            ) -> Result<usize, tls_codec::Error> {
158                (*self).tls_serialize(writer)
159            }
160        }
161    };
162}
163
164pub(crate) use ref_forward_tls_impl;