1use super::super::iana::{OptionCode, SecAlg};
18use super::super::message_builder::OptBuilder;
19use super::super::wire::{Compose, Composer, ParseError};
20use super::{
21 BuildDataError, OptData, ComposeOptData, LongOptData, Opt, ParseOptData
22};
23use octseq::builder::{EmptyBuilder, FromBuilder, OctetsBuilder};
24use octseq::octets::{Octets, OctetsFrom};
25use octseq::parse::Parser;
26use core::{borrow, fmt, hash, slice};
27use core::marker::PhantomData;
28
29
30#[derive(Clone, Copy, Debug)]
50pub struct Understood<Variant, Octs: ?Sized> {
51 marker: PhantomData<Variant>,
53
54 octets: Octs,
58}
59
60#[derive(Clone, Copy, Debug)]
65pub struct DauVariant;
66
67#[derive(Clone, Copy, Debug)]
72pub struct DhuVariant;
73
74#[derive(Clone, Copy, Debug)]
79pub struct N3uVariant;
80
81pub type Dau<Octs> = Understood<DauVariant, Octs>;
83
84pub type Dhu<Octs> = Understood<DhuVariant, Octs>;
86
87pub type N3u<Octs> = Understood<N3uVariant, Octs>;
89
90impl<Variant, Octs> Understood<Variant, Octs> {
91 pub fn from_octets(octets: Octs) -> Result<Self, ParseError>
96 where
97 Octs: AsRef<[u8]>,
98 {
99 Understood::<Variant, _>::check_slice(octets.as_ref())?;
100 Ok(unsafe { Self::from_octets_unchecked(octets) })
101 }
102
103 pub unsafe fn from_octets_unchecked(octets: Octs) -> Self {
110 Understood {
111 marker: PhantomData,
112 octets
113 }
114 }
115
116 pub fn from_sec_algs(
121 sec_algs: impl IntoIterator<Item = SecAlg>
122 ) -> Result<Self, BuildDataError>
123 where
124 Octs: FromBuilder,
125 <Octs as FromBuilder>::Builder: EmptyBuilder
126 {
127 let mut octets = EmptyBuilder::empty();
128 for item in sec_algs {
129 item.compose(&mut octets)?;
130 }
131 let octets = Octs::from_builder(octets);
132 LongOptData::check_len(octets.as_ref().len())?;
133 Ok(unsafe { Self::from_octets_unchecked(octets) })
134 }
135}
136
137impl<Variant> Understood<Variant, [u8]> {
138 pub fn from_slice(slice: &[u8]) -> Result<&Self, ParseError> {
143 Understood::<Variant, _>::check_slice(slice)?;
144 Ok(unsafe { Self::from_slice_unchecked(slice) })
145 }
146
147 #[must_use]
154 pub unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
155 &*(slice as *const [u8] as *const Self)
156 }
157
158 fn check_slice(slice: &[u8]) -> Result<(), ParseError> {
160 LongOptData::check_len(slice.len())?;
161 if slice.len() % usize::from(u16::COMPOSE_LEN) != 0 {
162 return Err(ParseError::form_error("invalid understood data"))
163 }
164 Ok(())
165 }
166}
167
168impl<Variant, Octs: AsRef<[u8]>> Understood<Variant, Octs> {
169 pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
171 parser: &mut Parser<'a, Src>,
172 ) -> Result<Self, ParseError> {
173 Self::from_octets(parser.parse_octets(parser.remaining())?)
174 }
175}
176
177impl<Variant, Octs: ?Sized> Understood<Variant, Octs> {
178 pub fn as_octets(&self) -> &Octs {
180 &self.octets
181 }
182
183 pub fn into_octets(self) -> Octs
185 where
186 Octs: Sized,
187 {
188 self.octets
189 }
190
191 pub fn as_slice(&self) -> &[u8]
193 where
194 Octs: AsRef<[u8]>,
195 {
196 self.octets.as_ref()
197 }
198
199 pub fn for_slice(&self) -> &Understood<Variant, [u8]>
201 where
202 Octs: AsRef<[u8]>,
203 {
204 unsafe {
205 Understood::<Variant, _>::from_slice_unchecked(
206 self.octets.as_ref()
207 )
208 }
209 }
210
211 pub fn iter(&self) -> SecAlgsIter
213 where
214 Octs: AsRef<[u8]>,
215 {
216 SecAlgsIter::new(self.octets.as_ref())
217 }
218}
219
220impl<Variant, O, OO> OctetsFrom<Understood<Variant, O>>
223for Understood<Variant, OO>
224where
225 OO: OctetsFrom<O>,
226{
227 type Error = OO::Error;
228
229 fn try_octets_from(
230 source: Understood<Variant, O>
231 ) -> Result<Self, Self::Error> {
232 Ok(unsafe {
233 Self::from_octets_unchecked(
234 OO::try_octets_from(source.octets)?
235 )
236 })
237 }
238}
239
240impl<Variant, Octs> AsRef<[u8]> for Understood<Variant, Octs>
243where Octs: AsRef<[u8]> + ?Sized {
244 fn as_ref(&self) -> &[u8] {
245 self.as_slice()
246 }
247}
248
249impl<Variant, Octs> borrow::Borrow<[u8]> for Understood<Variant, Octs>
250where Octs: AsRef<[u8]> + ?Sized {
251 fn borrow(&self) -> &[u8] {
252 self.as_slice()
253 }
254}
255
256impl<Var, OtherVar, Octs, OtherOcts> PartialEq<Understood<OtherVar, OtherOcts>>
259for Understood<Var, Octs>
260where
261 Octs: AsRef<[u8]> + ?Sized,
262 OtherOcts: AsRef<[u8]> + ?Sized,
263{
264 fn eq(&self, other: &Understood<OtherVar, OtherOcts>) -> bool {
265 self.as_slice().eq(other.as_slice())
266 }
267}
268
269impl<Variant, Octs: AsRef<[u8]> + ?Sized> Eq for Understood<Variant, Octs> { }
270
271impl<Variant, Octs: AsRef<[u8]>> hash::Hash for Understood<Variant, Octs> {
274 fn hash<H: hash::Hasher>(&self, state: &mut H) {
275 self.as_slice().hash(state)
276 }
277}
278
279impl<Octs: ?Sized> OptData for Understood<DauVariant, Octs> {
282 fn code(&self) -> OptionCode {
283 OptionCode::Dau
284 }
285}
286
287impl<Octs: ?Sized> OptData for Understood<DhuVariant, Octs> {
288 fn code(&self) -> OptionCode {
289 OptionCode::Dhu
290 }
291}
292
293impl<Octs: ?Sized> OptData for Understood<N3uVariant, Octs> {
294 fn code(&self) -> OptionCode {
295 OptionCode::N3u
296 }
297}
298
299impl<'a, Octs: Octets + ?Sized> ParseOptData<'a, Octs>
300for Understood<DauVariant, Octs::Range<'a>> {
301 fn parse_option(
302 code: OptionCode,
303 parser: &mut Parser<'a, Octs>,
304 ) -> Result<Option<Self>, ParseError> {
305 if code == OptionCode::Dau {
306 Self::parse(parser).map(Some)
307 }
308 else {
309 Ok(None)
310 }
311 }
312}
313
314impl<'a, Octs: Octets + ?Sized> ParseOptData<'a, Octs>
315for Understood<DhuVariant, Octs::Range<'a>> {
316 fn parse_option(
317 code: OptionCode,
318 parser: &mut Parser<'a, Octs>,
319 ) -> Result<Option<Self>, ParseError> {
320 if code == OptionCode::Dhu {
321 Self::parse(parser).map(Some)
322 }
323 else {
324 Ok(None)
325 }
326 }
327}
328
329impl<'a, Octs: Octets + ?Sized> ParseOptData<'a, Octs>
330for Understood<N3uVariant, Octs::Range<'a>> {
331 fn parse_option(
332 code: OptionCode,
333 parser: &mut Parser<'a, Octs>,
334 ) -> Result<Option<Self>, ParseError> {
335 if code == OptionCode::N3u {
336 Self::parse(parser).map(Some)
337 }
338 else {
339 Ok(None)
340 }
341 }
342}
343
344impl<Variant, Octs> ComposeOptData for Understood<Variant, Octs>
345where
346 Self: OptData,
347 Octs: AsRef<[u8]> + ?Sized,
348{
349 fn compose_len(&self) -> u16 {
350 self.octets.as_ref().len().try_into().expect("long option data")
351 }
352
353 fn compose_option<Target: OctetsBuilder + ?Sized>(
354 &self, target: &mut Target
355 ) -> Result<(), Target::AppendError> {
356 target.append_slice(self.octets.as_ref())
357 }
358}
359
360impl<'a, Variant, Octs> IntoIterator for &'a Understood<Variant, Octs>
363where
364 Octs: AsRef<[u8]> + ?Sized
365{
366 type Item = SecAlg;
367 type IntoIter = SecAlgsIter<'a>;
368
369 fn into_iter(self) -> Self::IntoIter {
370 self.iter()
371 }
372}
373
374impl<Variant, Octs> fmt::Display for Understood<Variant, Octs>
377where
378 Octs: AsRef<[u8]> + ?Sized,
379{
380 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
381 let mut first = true;
382
383 for v in self.octets.as_ref() {
384 if first {
385 write!(f, "{}", *v)?;
386 first = false;
387 } else {
388 write!(f, ", {}", *v)?
389 }
390 }
391 Ok(())
392 }
393}
394
395impl<Octs: Octets> Opt<Octs> {
398 pub fn dau(&self) -> Option<Dau<Octs::Range<'_>>> {
403 self.first()
404 }
405
406 pub fn dhu(&self) -> Option<Dhu<Octs::Range<'_>>> {
410 self.first()
411 }
412
413 pub fn n3u(&self) -> Option<N3u<Octs::Range<'_>>> {
417 self.first()
418 }
419}
420
421impl<'a, Target: Composer> OptBuilder<'a, Target> {
422 pub fn dau(
427 &mut self, algs: &impl AsRef<[SecAlg]>,
428 ) -> Result<(), BuildDataError> {
429 Ok(self.push_raw_option(
430 OptionCode::Dau,
431 u16::try_from(
432 algs.as_ref().len() * usize::from(SecAlg::COMPOSE_LEN)
433 ).map_err(|_| BuildDataError::LongOptData)?,
434 |octs| {
435 algs.as_ref().iter().try_for_each(|item| item.compose(octs))
436 },
437 )?)
438 }
439
440 pub fn dhu(
444 &mut self, algs: &impl AsRef<[SecAlg]>,
445 ) -> Result<(), BuildDataError> {
446 Ok(self.push_raw_option(
447 OptionCode::Dhu,
448 u16::try_from(
449 algs.as_ref().len() * usize::from(SecAlg::COMPOSE_LEN)
450 ).map_err(|_| BuildDataError::LongOptData)?,
451 |octs| {
452 algs.as_ref().iter().try_for_each(|item| item.compose(octs))
453 },
454 )?)
455 }
456
457 pub fn n3u(
461 &mut self, algs: &impl AsRef<[SecAlg]>,
462 ) -> Result<(), BuildDataError> {
463 Ok(self.push_raw_option(
464 OptionCode::N3u,
465 u16::try_from(
466 algs.as_ref().len() * usize::from(SecAlg::COMPOSE_LEN)
467 ).map_err(|_| BuildDataError::LongOptData)?,
468 |octs| {
469 algs.as_ref().iter().try_for_each(|item| item.compose(octs))
470 },
471 )?)
472 }
473}
474
475pub struct SecAlgsIter<'a>(slice::Iter<'a, u8>);
478
479impl<'a> SecAlgsIter<'a> {
480 fn new(slice: &'a [u8]) -> Self {
481 SecAlgsIter(slice.iter())
482 }
483}
484
485impl<'a> Iterator for SecAlgsIter<'a> {
486 type Item = SecAlg;
487
488 fn next(&mut self) -> Option<Self::Item> {
489 self.0.next().map(|x| SecAlg::from_int(*x))
490 }
491}
492
493#[cfg(test)]
496#[cfg(all(feature = "std", feature = "bytes"))]
497mod test {
498 use super::*;
499 use super::super::test::test_option_compose_parse;
500
501 #[test]
502 #[allow(clippy::redundant_closure)] fn dau_compose_parse() {
504 test_option_compose_parse(
505 &Dau::from_octets("foof").unwrap(),
506 |parser| Dau::parse(parser)
507 );
508 }
509}