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(u16);
59
60impl UnknownComponentId {
61 pub fn new(id: u16) -> Option<Self> {
64 let is_grease = (id & 0x0f0f == 0x0a0a) && (id & 0xff == (id >> 8)) && id != 0xfefe;
65 (!is_grease && matches!(id, ..0x8000)).then_some(Self(id))
66 }
67}
68
69#[repr(transparent)]
71pub struct PrivateComponentId(u16);
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-08")]
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 Grease8A8A = 0x8a8a,
116 Grease9A9A = 0x9a9a,
118 GreaseAAAA = 0xaaaa,
120 GreaseBABA = 0xbaba,
122 GreaseCACA = 0xcaca,
124 GreaseDADA = 0xdada,
126 GreaseEAEA = 0xeaea,
128
129 Unknown(UnknownComponentId),
131
132 Private(PrivateComponentId),
134}
135
136impl From<ComponentId> for ComponentType {
137 fn from(value: ComponentId) -> Self {
138 #[allow(clippy::match_overlapping_arm)]
141 match value {
142 0 => Self::Reserved,
143 1 => Self::AppComponents,
144 2 => Self::SafeAad,
145 3 => Self::ComponentMediaTypes,
146 4 => Self::LastResortKeyPackage,
147 5 => Self::AppAck,
148
149 0x0a0a => Self::Grease0A0A,
150 0x1a1a => Self::Grease1A1A,
151 0x2a2a => Self::Grease2A2A,
152 0x3a3a => Self::Grease3A3A,
153 0x4a4a => Self::Grease4A4A,
154 0x5a5a => Self::Grease5A5A,
155 0x6a6a => Self::Grease6A6A,
156 0x7a7a => Self::Grease7A7A,
157 0x8a8a => Self::Grease8A8A,
158 0x9a9a => Self::Grease9A9A,
159 0xaaaa => Self::GreaseAAAA,
160 0xbaba => Self::GreaseBABA,
161 0xcaca => Self::GreaseCACA,
162 0xdada => Self::GreaseDADA,
163 0xeaea => Self::GreaseEAEA,
164
165 6..0x8000 => Self::Unknown(UnknownComponentId(value)),
166 0x8000.. => Self::Private(PrivateComponentId(value)),
167 }
168 }
169}
170
171impl From<ComponentType> for ComponentId {
172 fn from(value: ComponentType) -> Self {
173 match value {
174 ComponentType::Reserved => 0,
175 ComponentType::AppComponents => 1,
176 ComponentType::SafeAad => 2,
177 ComponentType::ComponentMediaTypes => 3,
178 ComponentType::LastResortKeyPackage => 4,
179 ComponentType::AppAck => 5,
180
181 ComponentType::Grease0A0A => 0x0a0a,
182 ComponentType::Grease1A1A => 0x1a1a,
183 ComponentType::Grease2A2A => 0x2a2a,
184 ComponentType::Grease3A3A => 0x3a3a,
185 ComponentType::Grease4A4A => 0x4a4a,
186 ComponentType::Grease5A5A => 0x5a5a,
187 ComponentType::Grease6A6A => 0x6a6a,
188 ComponentType::Grease7A7A => 0x7a7a,
189 ComponentType::Grease8A8A => 0x8a8a,
190 ComponentType::Grease9A9A => 0x9a9a,
191 ComponentType::GreaseAAAA => 0xaaaa,
192 ComponentType::GreaseBABA => 0xbaba,
193 ComponentType::GreaseCACA => 0xcaca,
194 ComponentType::GreaseDADA => 0xdada,
195 ComponentType::GreaseEAEA => 0xeaea,
196
197 ComponentType::Unknown(UnknownComponentId(id)) => id,
198 ComponentType::Private(PrivateComponentId(id)) => id,
199 }
200 }
201}
202
203#[derive(Debug, TlsSerialize, TlsSize)]
205pub(crate) struct ComponentOperationLabel {
206 base_label: VLBytes,
208 component_id: ComponentId,
209 label: VLBytes,
210}
211
212const COMPONENT_OPERATION_BASE_LABEL: &[u8] = b"Application";
213
214impl ComponentOperationLabel {
215 pub fn new(component_id: ComponentId, label: &str) -> Self {
217 Self {
218 base_label: COMPONENT_OPERATION_BASE_LABEL.into(),
219 component_id,
220 label: label.as_bytes().into(),
221 }
222 }
223}