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;