1use super::super::iana::{OptionCode, SecurityAlgorithm};
18use super::super::message_builder::OptBuilder;
19use super::super::wire::{Compose, Composer, ParseError};
20use super::{
21 BuildDataError, ComposeOptData, LongOptData, Opt, OptData, ParseOptData,
22};
23use core::marker::PhantomData;
24use core::{borrow, fmt, hash, mem, slice};
25use octseq::builder::{EmptyBuilder, FromBuilder, OctetsBuilder};
26use octseq::octets::{Octets, OctetsFrom};
27use octseq::parse::Parser;
28
29#[derive(Clone, Copy)]
49#[repr(transparent)]
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 = SecurityAlgorithm>,
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 mem::transmute(slice)
157 }
158
159 fn check_slice(slice: &[u8]) -> Result<(), ParseError> {
161 LongOptData::check_len(slice.len())?;
162 if slice.len() % usize::from(u16::COMPOSE_LEN) != 0 {
163 return Err(ParseError::form_error("invalid understood data"));
164 }
165 Ok(())
166 }
167}
168
169impl<Variant, Octs: AsRef<[u8]>> Understood<Variant, Octs> {
170 pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
172 parser: &mut Parser<'a, Src>,
173 ) -> Result<Self, ParseError> {
174 Self::from_octets(parser.parse_octets(parser.remaining())?)
175 }
176}
177
178impl<Variant, Octs: ?Sized> Understood<Variant, Octs> {
179 pub fn as_octets(&self) -> &Octs {
181 &self.octets
182 }
183
184 pub fn into_octets(self) -> Octs
186 where
187 Octs: Sized,
188 {
189 self.octets
190 }
191
192 pub fn as_slice(&self) -> &[u8]
194 where
195 Octs: AsRef<[u8]>,
196 {
197 self.octets.as_ref()
198 }
199
200 pub fn for_slice(&self) -> &Understood<Variant, [u8]>
202 where
203 Octs: AsRef<[u8]>,
204 {
205 unsafe {
206 Understood::<Variant, _>::from_slice_unchecked(
207 self.octets.as_ref(),
208 )
209 }
210 }
211
212 pub fn iter(&self) -> SecurityAlgorithmIter<'_>
214 where
215 Octs: AsRef<[u8]>,
216 {
217 SecurityAlgorithmIter::new(self.octets.as_ref())
218 }
219}
220
221impl Understood<DauVariant, ()> {
222 pub(super) const CODE: OptionCode = OptionCode::DAU;
223}
224
225impl Understood<DhuVariant, ()> {
226 pub(super) const CODE: OptionCode = OptionCode::DHU;
227}
228
229impl Understood<N3uVariant, ()> {
230 pub(super) const CODE: OptionCode = OptionCode::N3U;
231}
232
233impl<Variant, O, OO> OctetsFrom<Understood<Variant, O>>
236 for Understood<Variant, OO>
237where
238 OO: OctetsFrom<O>,
239{
240 type Error = OO::Error;
241
242 fn try_octets_from(
243 source: Understood<Variant, O>,
244 ) -> Result<Self, Self::Error> {
245 Ok(unsafe {
246 Self::from_octets_unchecked(OO::try_octets_from(source.octets)?)
247 })
248 }
249}
250
251impl<Variant, Octs> AsRef<[u8]> for Understood<Variant, Octs>
254where
255 Octs: AsRef<[u8]> + ?Sized,
256{
257 fn as_ref(&self) -> &[u8] {
258 self.as_slice()
259 }
260}
261
262impl<Variant, Octs> borrow::Borrow<[u8]> for Understood<Variant, Octs>
263where
264 Octs: AsRef<[u8]> + ?Sized,
265{
266 fn borrow(&self) -> &[u8] {
267 self.as_slice()
268 }
269}
270
271impl<Var, OtherVar, Octs, OtherOcts>
274 PartialEq<Understood<OtherVar, OtherOcts>> for Understood<Var, Octs>
275where
276 Octs: AsRef<[u8]> + ?Sized,
277 OtherOcts: AsRef<[u8]> + ?Sized,
278{
279 fn eq(&self, other: &Understood<OtherVar, OtherOcts>) -> bool {
280 self.as_slice().eq(other.as_slice())
281 }
282}
283
284impl<Variant, Octs: AsRef<[u8]> + ?Sized> Eq for Understood<Variant, Octs> {}
285
286impl<Variant, Octs: AsRef<[u8]>> hash::Hash for Understood<Variant, Octs> {
289 fn hash<H: hash::Hasher>(&self, state: &mut H) {
290 self.as_slice().hash(state)
291 }
292}
293
294impl<Octs: ?Sized> OptData for Understood<DauVariant, Octs> {
297 fn code(&self) -> OptionCode {
298 OptionCode::DAU
299 }
300}
301
302impl<Octs: ?Sized> OptData for Understood<DhuVariant, Octs> {
303 fn code(&self) -> OptionCode {
304 OptionCode::DHU
305 }
306}
307
308impl<Octs: ?Sized> OptData for Understood<N3uVariant, Octs> {
309 fn code(&self) -> OptionCode {
310 OptionCode::N3U
311 }
312}
313
314impl<'a, Octs: Octets + ?Sized> ParseOptData<'a, Octs>
315 for Understood<DauVariant, Octs::Range<'a>>
316{
317 fn parse_option(
318 code: OptionCode,
319 parser: &mut Parser<'a, Octs>,
320 ) -> Result<Option<Self>, ParseError> {
321 if code == OptionCode::DAU {
322 Self::parse(parser).map(Some)
323 } else {
324 Ok(None)
325 }
326 }
327}
328
329impl<'a, Octs: Octets + ?Sized> ParseOptData<'a, Octs>
330 for Understood<DhuVariant, Octs::Range<'a>>
331{
332 fn parse_option(
333 code: OptionCode,
334 parser: &mut Parser<'a, Octs>,
335 ) -> Result<Option<Self>, ParseError> {
336 if code == OptionCode::DHU {
337 Self::parse(parser).map(Some)
338 } else {
339 Ok(None)
340 }
341 }
342}
343
344impl<'a, Octs: Octets + ?Sized> ParseOptData<'a, Octs>
345 for Understood<N3uVariant, Octs::Range<'a>>
346{
347 fn parse_option(
348 code: OptionCode,
349 parser: &mut Parser<'a, Octs>,
350 ) -> Result<Option<Self>, ParseError> {
351 if code == OptionCode::N3U {
352 Self::parse(parser).map(Some)
353 } else {
354 Ok(None)
355 }
356 }
357}
358
359impl<Variant, Octs> ComposeOptData for Understood<Variant, Octs>
360where
361 Self: OptData,
362 Octs: AsRef<[u8]> + ?Sized,
363{
364 fn compose_len(&self) -> u16 {
365 self.octets
366 .as_ref()
367 .len()
368 .try_into()
369 .expect("long option data")
370 }
371
372 fn compose_option<Target: OctetsBuilder + ?Sized>(
373 &self,
374 target: &mut Target,
375 ) -> Result<(), Target::AppendError> {
376 target.append_slice(self.octets.as_ref())
377 }
378}
379
380impl<'a, Variant, Octs> IntoIterator for &'a Understood<Variant, Octs>
383where
384 Octs: AsRef<[u8]> + ?Sized,
385{
386 type Item = SecurityAlgorithm;
387 type IntoIter = SecurityAlgorithmIter<'a>;
388
389 fn into_iter(self) -> Self::IntoIter {
390 self.iter()
391 }
392}
393
394impl<Variant, Octs> fmt::Display for Understood<Variant, Octs>
397where
398 Octs: AsRef<[u8]> + ?Sized,
399{
400 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
401 let mut first = true;
402
403 for v in self.octets.as_ref() {
404 if first {
405 write!(f, "{}", *v)?;
406 first = false;
407 } else {
408 write!(f, ", {}", *v)?
409 }
410 }
411 Ok(())
412 }
413}
414
415impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Understood<DauVariant, Octs> {
418 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
419 f.debug_tuple("Understood<DauVariant>")
420 .field(&format_args!("{}", self))
421 .finish()
422 }
423}
424
425impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Understood<DhuVariant, Octs> {
426 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
427 f.debug_tuple("Understood<DhuVariant>")
428 .field(&format_args!("{}", self))
429 .finish()
430 }
431}
432
433impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Understood<N3uVariant, Octs> {
434 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
435 f.debug_tuple("Understood<N3uVariant>")
436 .field(&format_args!("{}", self))
437 .finish()
438 }
439}
440
441#[cfg(feature = "serde")]
444impl<V, Octs: AsRef<[u8]>> serde::Serialize for Understood<V, Octs> {
445 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
446 where
447 S: serde::Serializer,
448 {
449 use serde::ser::SerializeSeq;
450 let mut list = serializer.serialize_seq(None)?;
451 for item in self.iter() {
452 list.serialize_element(&item)?;
453 }
454 list.end()
455 }
456}
457
458impl<Octs: Octets> Opt<Octs> {
461 pub fn dau(&self) -> Option<Dau<Octs::Range<'_>>> {
466 self.first()
467 }
468
469 pub fn dhu(&self) -> Option<Dhu<Octs::Range<'_>>> {
473 self.first()
474 }
475
476 pub fn n3u(&self) -> Option<N3u<Octs::Range<'_>>> {
480 self.first()
481 }
482}
483
484impl<Target: Composer> OptBuilder<'_, Target> {
485 pub fn dau(
490 &mut self,
491 algs: &impl AsRef<[SecurityAlgorithm]>,
492 ) -> Result<(), BuildDataError> {
493 Ok(self.push_raw_option(
494 OptionCode::DAU,
495 u16::try_from(
496 algs.as_ref().len()
497 * usize::from(SecurityAlgorithm::COMPOSE_LEN),
498 )
499 .map_err(|_| BuildDataError::LongOptData)?,
500 |octs| {
501 algs.as_ref().iter().try_for_each(|item| item.compose(octs))
502 },
503 )?)
504 }
505
506 pub fn dhu(
510 &mut self,
511 algs: &impl AsRef<[SecurityAlgorithm]>,
512 ) -> Result<(), BuildDataError> {
513 Ok(self.push_raw_option(
514 OptionCode::DHU,
515 u16::try_from(
516 algs.as_ref().len()
517 * usize::from(SecurityAlgorithm::COMPOSE_LEN),
518 )
519 .map_err(|_| BuildDataError::LongOptData)?,
520 |octs| {
521 algs.as_ref().iter().try_for_each(|item| item.compose(octs))
522 },
523 )?)
524 }
525
526 pub fn n3u(
530 &mut self,
531 algs: &impl AsRef<[SecurityAlgorithm]>,
532 ) -> Result<(), BuildDataError> {
533 Ok(self.push_raw_option(
534 OptionCode::N3U,
535 u16::try_from(
536 algs.as_ref().len()
537 * usize::from(SecurityAlgorithm::COMPOSE_LEN),
538 )
539 .map_err(|_| BuildDataError::LongOptData)?,
540 |octs| {
541 algs.as_ref().iter().try_for_each(|item| item.compose(octs))
542 },
543 )?)
544 }
545}
546
547pub struct SecurityAlgorithmIter<'a>(slice::Iter<'a, u8>);
550
551impl<'a> SecurityAlgorithmIter<'a> {
552 fn new(slice: &'a [u8]) -> Self {
553 SecurityAlgorithmIter(slice.iter())
554 }
555}
556
557impl Iterator for SecurityAlgorithmIter<'_> {
558 type Item = SecurityAlgorithm;
559
560 fn next(&mut self) -> Option<Self::Item> {
561 self.0.next().map(|x| SecurityAlgorithm::from_int(*x))
562 }
563}
564
565#[cfg(test)]
568#[cfg(all(feature = "std", feature = "bytes"))]
569mod test {
570 use super::super::test::test_option_compose_parse;
571 use super::*;
572
573 #[test]
574 #[allow(clippy::redundant_closure)] fn dau_compose_parse() {
576 test_option_compose_parse(
577 &Dau::from_octets("foof").unwrap(),
578 |parser| Dau::parse(parser),
579 );
580 }
581}