1use serde::{Deserialize, Serialize};
4use tls_codec::{TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize, VLBytes};
5
6pub type ComponentId = u16;
8
9#[derive(
13 PartialEq,
14 Eq,
15 Clone,
16 Debug,
17 Serialize,
18 Deserialize,
19 TlsSerialize,
20 TlsDeserialize,
21 TlsDeserializeBytes,
22 TlsSize,
23)]
24pub struct ComponentData {
25 component_id: ComponentId,
26 data: VLBytes,
27}
28
29impl ComponentData {
30 pub fn id(&self) -> ComponentId {
32 self.component_id
33 }
34
35 pub fn into_data(self) -> VLBytes {
37 self.data
38 }
39
40 pub fn data(&self) -> &[u8] {
42 self.data.as_ref()
43 }
44
45 pub fn into_parts(self) -> (ComponentId, VLBytes) {
47 (self.component_id, self.data)
48 }
49
50 pub fn from_parts(component_id: ComponentId, data: VLBytes) -> Self {
52 Self { component_id, data }
53 }
54}
55
56#[repr(transparent)]
58pub struct UnknownComponentId(ComponentId);
59
60impl UnknownComponentId {
61 pub fn new(id: ComponentId) -> Option<Self> {
64 let is_grease = (id & 0x0f0f == 0x0a0a) && (id & 0xff == (id >> 8)) && id != 0xfafa;
65 (!is_grease && id < 0x8000).then_some(Self(id))
66 }
67}
68
69#[repr(transparent)]
71pub struct PrivateComponentId(ComponentId);
72
73impl PrivateComponentId {
74 pub fn new(id: u16) -> Option<Self> {
78 matches!(id, 0x8000..).then_some(Self(id))
79 }
80}
81
82#[cfg(feature = "extensions-draft")]
83#[repr(u16)]
84pub enum ComponentType {
86 Reserved = 0,
88 AppComponents = 1,
90 SafeAad = 2,
92 ComponentMediaTypes = 3,
94 LastResortKeyPackage = 4,
96 AppAck = 5,
98 Grease0A0A = 0x0a0a,
100 Grease1A1A = 0x1a1a,
102 Grease2A2A = 0x2a2a,
104 Grease3A3A = 0x3a3a,
106 Grease4A4A = 0x4a4a,
108 Grease5A5A = 0x5a5a,
110 Grease6A6A = 0x6a6a,
112 Grease7A7A = 0x7a7a,
114
115 Unknown(UnknownComponentId),
117
118 Private(PrivateComponentId),
120}
121
122impl From<ComponentId> for ComponentType {
123 fn from(value: ComponentId) -> Self {
124 #[allow(clippy::match_overlapping_arm)]
127 match value {
128 0 => Self::Reserved,
129 1 => Self::AppComponents,
130 2 => Self::SafeAad,
131 3 => Self::ComponentMediaTypes,
132 4 => Self::LastResortKeyPackage,
133 5 => Self::AppAck,
134
135 0x0a0a => Self::Grease0A0A,
136 0x1a1a => Self::Grease1A1A,
137 0x2a2a => Self::Grease2A2A,
138 0x3a3a => Self::Grease3A3A,
139 0x4a4a => Self::Grease4A4A,
140 0x5a5a => Self::Grease5A5A,
141 0x6a6a => Self::Grease6A6A,
142 0x7a7a => Self::Grease7A7A,
143
144 6..0x8000 => Self::Unknown(UnknownComponentId(value)),
145 0x8000.. => Self::Private(PrivateComponentId(value)),
146 }
147 }
148}
149
150impl From<ComponentType> for ComponentId {
151 fn from(value: ComponentType) -> Self {
152 match value {
153 ComponentType::Reserved => 0,
154 ComponentType::AppComponents => 1,
155 ComponentType::SafeAad => 2,
156 ComponentType::ComponentMediaTypes => 3,
157 ComponentType::LastResortKeyPackage => 4,
158 ComponentType::AppAck => 5,
159
160 ComponentType::Grease0A0A => 0x0a0a,
161 ComponentType::Grease1A1A => 0x1a1a,
162 ComponentType::Grease2A2A => 0x2a2a,
163 ComponentType::Grease3A3A => 0x3a3a,
164 ComponentType::Grease4A4A => 0x4a4a,
165 ComponentType::Grease5A5A => 0x5a5a,
166 ComponentType::Grease6A6A => 0x6a6a,
167 ComponentType::Grease7A7A => 0x7a7a,
168
169 ComponentType::Unknown(UnknownComponentId(id)) => id,
170 ComponentType::Private(PrivateComponentId(id)) => id,
171 }
172 }
173}
174
175#[cfg(feature = "extensions-draft")]
188#[derive(
189 PartialEq,
190 Eq,
191 Clone,
192 Debug,
193 Default,
194 Serialize,
195 Deserialize,
196 TlsSerialize,
197 TlsDeserialize,
198 TlsDeserializeBytes,
199 TlsSize,
200)]
201pub struct ComponentsList {
202 component_ids: Vec<ComponentId>,
203}
204
205#[cfg(feature = "extensions-draft")]
206impl ComponentsList {
207 pub fn new(component_ids: Vec<ComponentId>) -> Self {
209 Self { component_ids }
210 }
211
212 pub fn ids(&self) -> &[ComponentId] {
214 &self.component_ids
215 }
216
217 pub fn into_ids(self) -> Vec<ComponentId> {
219 self.component_ids
220 }
221}
222
223#[derive(Debug, TlsSerialize, TlsSize)]
225pub(crate) struct ComponentOperationLabel {
226 base_label: VLBytes,
228 component_id: ComponentId,
229 label: VLBytes,
230}
231
232const COMPONENT_OPERATION_BASE_LABEL: &[u8] = b"Application";
233
234impl ComponentOperationLabel {
235 pub fn new(component_id: ComponentId, label: &str) -> Self {
237 Self {
238 base_label: COMPONENT_OPERATION_BASE_LABEL.into(),
239 component_id,
240 label: label.as_bytes().into(),
241 }
242 }
243}