1use super::super::iana::{OptionCode, SecurityAlgorithm};
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, mem, slice};
27use core::marker::PhantomData;
28
29
30#[derive(Clone, Copy)]
50#[repr(transparent)]
51pub struct Understood<Variant, Octs: ?Sized> {
52 marker: PhantomData<Variant>,
54
55 octets: Octs,
59}
60
61#[derive(Clone, Copy, Debug)]
66pub struct DauVariant;
67
68#[derive(Clone, Copy, Debug)]
73pub struct DhuVariant;
74
75#[derive(Clone, Copy, Debug)]
80pub struct N3uVariant;
81
82pub type Dau<Octs> = Understood<DauVariant, Octs>;
84
85pub type Dhu<Octs> = Understood<DhuVariant, Octs>;
87
88pub type N3u<Octs> = Understood<N3uVariant, Octs>;
90
91impl<Variant, Octs> Understood<Variant, Octs> {
92 pub fn from_octets(octets: Octs) -> Result<Self, ParseError>
97 where
98 Octs: AsRef<[u8]>,
99 {
100 Understood::<Variant, _>::check_slice(octets.as_ref())?;
101 Ok(unsafe { Self::from_octets_unchecked(octets) })
102 }
103
104 pub unsafe fn from_octets_unchecked(octets: Octs) -> Self {
111 Understood {
112 marker: PhantomData,
113 octets
114 }
115 }
116
117 pub fn from_sec_algs(
122 sec_algs: impl IntoIterator<Item = SecurityAlgorithm>
123 ) -> Result<Self, BuildDataError>
124 where
125 Octs: FromBuilder,
126 <Octs as FromBuilder>::Builder: EmptyBuilder
127 {
128 let mut octets = EmptyBuilder::empty();
129 for item in sec_algs {
130 item.compose(&mut octets)?;
131 }
132 let octets = Octs::from_builder(octets);
133 LongOptData::check_len(octets.as_ref().len())?;
134 Ok(unsafe { Self::from_octets_unchecked(octets) })
135 }
136}
137
138impl<Variant> Understood<Variant, [u8]> {
139 pub fn from_slice(slice: &[u8]) -> Result<&Self, ParseError> {
144 Understood::<Variant, _>::check_slice(slice)?;
145 Ok(unsafe { Self::from_slice_unchecked(slice) })
146 }
147
148 #[must_use]
155 pub unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
156 mem::transmute(slice)
158 }
159
160 fn check_slice(slice: &[u8]) -> Result<(), ParseError> {
162 LongOptData::check_len(slice.len())?;
163 if slice.len() % usize::from(u16::COMPOSE_LEN) != 0 {
164 return Err(ParseError::form_error("invalid understood data"))
165 }
166 Ok(())
167 }
168}
169
170impl<Variant, Octs: AsRef<[u8]>> Understood<Variant, Octs> {
171 pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
173 parser: &mut Parser<'a, Src>,
174 ) -> Result<Self, ParseError> {
175 Self::from_octets(parser.parse_octets(parser.remaining())?)
176 }
177}
178
179impl<Variant, Octs: ?Sized> Understood<Variant, Octs> {
180 pub fn as_octets(&self) -> &Octs {
182 &self.octets
183 }
184
185 pub fn into_octets(self) -> Octs
187 where
188 Octs: Sized,
189 {
190 self.octets
191 }
192
193 pub fn as_slice(&self) -> &[u8]
195 where
196 Octs: AsRef<[u8]>,
197 {
198 self.octets.as_ref()
199 }
200
201 pub fn for_slice(&self) -> &Understood<Variant, [u8]>
203 where
204 Octs: AsRef<[u8]>,
205 {
206 unsafe {
207 Understood::<Variant, _>::from_slice_unchecked(
208 self.octets.as_ref()
209 )
210 }
211 }
212
213 pub fn iter(&self) -> SecurityAlgorithmIter
215 where
216 Octs: AsRef<[u8]>,
217 {
218 SecurityAlgorithmIter::new(self.octets.as_ref())
219 }
220}
221
222impl Understood<DauVariant, ()> {
223 pub(super) const CODE: OptionCode = OptionCode::DAU;
224}
225
226impl Understood<DhuVariant, ()> {
227 pub(super) const CODE: OptionCode = OptionCode::DHU;
228}
229
230impl Understood<N3uVariant, ()> {
231 pub(super) const CODE: OptionCode = OptionCode::N3U;
232}
233
234impl<Variant, O, OO> OctetsFrom<Understood<Variant, O>>
237for Understood<Variant, OO>
238where
239 OO: OctetsFrom<O>,
240{
241 type Error = OO::Error;
242
243 fn try_octets_from(
244 source: Understood<Variant, O>
245 ) -> Result<Self, Self::Error> {
246 Ok(unsafe {
247 Self::from_octets_unchecked(
248 OO::try_octets_from(source.octets)?
249 )
250 })
251 }
252}
253
254impl<Variant, Octs> AsRef<[u8]> for Understood<Variant, Octs>
257where Octs: AsRef<[u8]> + ?Sized {
258 fn as_ref(&self) -> &[u8] {
259 self.as_slice()
260 }
261}
262
263impl<Variant, Octs> borrow::Borrow<[u8]> for Understood<Variant, Octs>
264where Octs: AsRef<[u8]> + ?Sized {
265 fn borrow(&self) -> &[u8] {
266 self.as_slice()
267 }
268}
269
270impl<Var, OtherVar, Octs, OtherOcts> PartialEq<Understood<OtherVar, OtherOcts>>
273for Understood<Var, Octs>
274where
275 Octs: AsRef<[u8]> + ?Sized,
276 OtherOcts: AsRef<[u8]> + ?Sized,
277{
278 fn eq(&self, other: &Understood<OtherVar, OtherOcts>) -> bool {
279 self.as_slice().eq(other.as_slice())
280 }
281}
282
283impl<Variant, Octs: AsRef<[u8]> + ?Sized> Eq for Understood<Variant, Octs> { }
284
285impl<Variant, Octs: AsRef<[u8]>> hash::Hash for Understood<Variant, Octs> {
288 fn hash<H: hash::Hasher>(&self, state: &mut H) {
289 self.as_slice().hash(state)
290 }
291}
292
293impl<Octs: ?Sized> OptData for Understood<DauVariant, Octs> {
296 fn code(&self) -> OptionCode {
297 OptionCode::DAU
298 }
299}
300
301impl<Octs: ?Sized> OptData for Understood<DhuVariant, Octs> {
302 fn code(&self) -> OptionCode {
303 OptionCode::DHU
304 }
305}
306
307impl<Octs: ?Sized> OptData for Understood<N3uVariant, Octs> {
308 fn code(&self) -> OptionCode {
309 OptionCode::N3U
310 }
311}
312
313impl<'a, Octs: Octets + ?Sized> ParseOptData<'a, Octs>
314for Understood<DauVariant, Octs::Range<'a>> {
315 fn parse_option(
316 code: OptionCode,
317 parser: &mut Parser<'a, Octs>,
318 ) -> Result<Option<Self>, ParseError> {
319 if code == OptionCode::DAU {
320 Self::parse(parser).map(Some)
321 }
322 else {
323 Ok(None)
324 }
325 }
326}
327
328impl<'a, Octs: Octets + ?Sized> ParseOptData<'a, Octs>
329for Understood<DhuVariant, Octs::Range<'a>> {
330 fn parse_option(
331 code: OptionCode,
332 parser: &mut Parser<'a, Octs>,
333 ) -> Result<Option<Self>, ParseError> {
334 if code == OptionCode::DHU {
335 Self::parse(parser).map(Some)
336 }
337 else {
338 Ok(None)
339 }
340 }
341}
342
343impl<'a, Octs: Octets + ?Sized> ParseOptData<'a, Octs>
344for Understood<N3uVariant, Octs::Range<'a>> {
345 fn parse_option(
346 code: OptionCode,
347 parser: &mut Parser<'a, Octs>,
348 ) -> Result<Option<Self>, ParseError> {
349 if code == OptionCode::N3U {
350 Self::parse(parser).map(Some)
351 }
352 else {
353 Ok(None)
354 }
355 }
356}
357
358impl<Variant, Octs> ComposeOptData for Understood<Variant, Octs>
359where
360 Self: OptData,
361 Octs: AsRef<[u8]> + ?Sized,
362{
363 fn compose_len(&self) -> u16 {
364 self.octets.as_ref().len().try_into().expect("long option data")
365 }
366
367 fn compose_option<Target: OctetsBuilder + ?Sized>(
368 &self, target: &mut Target
369 ) -> Result<(), Target::AppendError> {
370 target.append_slice(self.octets.as_ref())
371 }
372}
373
374impl<'a, Variant, Octs> IntoIterator for &'a Understood<Variant, Octs>
377where
378 Octs: AsRef<[u8]> + ?Sized
379{
380 type Item = SecurityAlgorithm;
381 type IntoIter = SecurityAlgorithmIter<'a>;
382
383 fn into_iter(self) -> Self::IntoIter {
384 self.iter()
385 }
386}
387
388impl<Variant, Octs> fmt::Display for Understood<Variant, Octs>
391where
392 Octs: AsRef<[u8]> + ?Sized,
393{
394 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
395 let mut first = true;
396
397 for v in self.octets.as_ref() {
398 if first {
399 write!(f, "{}", *v)?;
400 first = false;
401 } else {
402 write!(f, ", {}", *v)?
403 }
404 }
405 Ok(())
406 }
407}
408
409impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Understood<DauVariant, Octs> {
412 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
413 f.debug_tuple("Understood<DauVariant>")
414 .field(&format_args!("{}", self))
415 .finish()
416 }
417}
418
419impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Understood<DhuVariant, Octs> {
420 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
421 f.debug_tuple("Understood<DhuVariant>")
422 .field(&format_args!("{}", self))
423 .finish()
424 }
425}
426
427impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Understood<N3uVariant, Octs> {
428 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
429 f.debug_tuple("Understood<N3uVariant>")
430 .field(&format_args!("{}", self))
431 .finish()
432 }
433}
434
435#[cfg(feature = "serde")]
438impl<V, Octs: AsRef<[u8]>> serde::Serialize for Understood<V, Octs> {
439 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
440 where
441 S: serde::Serializer {
442 use serde::ser::SerializeSeq;
443 let mut list = serializer.serialize_seq(None)?;
444 for item in self.iter() {
445 list.serialize_element(&item)?;
446 }
447 list.end()
448 }
449}
450
451impl<Octs: Octets> Opt<Octs> {
454 pub fn dau(&self) -> Option<Dau<Octs::Range<'_>>> {
459 self.first()
460 }
461
462 pub fn dhu(&self) -> Option<Dhu<Octs::Range<'_>>> {
466 self.first()
467 }
468
469 pub fn n3u(&self) -> Option<N3u<Octs::Range<'_>>> {
473 self.first()
474 }
475}
476
477impl<Target: Composer> OptBuilder<'_, Target> {
478 pub fn dau(
483 &mut self, algs: &impl AsRef<[SecurityAlgorithm]>,
484 ) -> Result<(), BuildDataError> {
485 Ok(self.push_raw_option(
486 OptionCode::DAU,
487 u16::try_from(
488 algs.as_ref().len() * usize::from(SecurityAlgorithm::COMPOSE_LEN)
489 ).map_err(|_| BuildDataError::LongOptData)?,
490 |octs| {
491 algs.as_ref().iter().try_for_each(|item| item.compose(octs))
492 },
493 )?)
494 }
495
496 pub fn dhu(
500 &mut self, algs: &impl AsRef<[SecurityAlgorithm]>,
501 ) -> Result<(), BuildDataError> {
502 Ok(self.push_raw_option(
503 OptionCode::DHU,
504 u16::try_from(
505 algs.as_ref().len() * usize::from(SecurityAlgorithm::COMPOSE_LEN)
506 ).map_err(|_| BuildDataError::LongOptData)?,
507 |octs| {
508 algs.as_ref().iter().try_for_each(|item| item.compose(octs))
509 },
510 )?)
511 }
512
513 pub fn n3u(
517 &mut self, algs: &impl AsRef<[SecurityAlgorithm]>,
518 ) -> Result<(), BuildDataError> {
519 Ok(self.push_raw_option(
520 OptionCode::N3U,
521 u16::try_from(
522 algs.as_ref().len() * usize::from(SecurityAlgorithm::COMPOSE_LEN)
523 ).map_err(|_| BuildDataError::LongOptData)?,
524 |octs| {
525 algs.as_ref().iter().try_for_each(|item| item.compose(octs))
526 },
527 )?)
528 }
529}
530
531pub struct SecurityAlgorithmIter<'a>(slice::Iter<'a, u8>);
534
535impl<'a> SecurityAlgorithmIter<'a> {
536 fn new(slice: &'a [u8]) -> Self {
537 SecurityAlgorithmIter(slice.iter())
538 }
539}
540
541impl Iterator for SecurityAlgorithmIter<'_> {
542 type Item = SecurityAlgorithm;
543
544 fn next(&mut self) -> Option<Self::Item> {
545 self.0.next().map(|x| SecurityAlgorithm::from_int(*x))
546 }
547}
548
549#[cfg(test)]
552#[cfg(all(feature = "std", feature = "bytes"))]
553mod test {
554 use super::*;
555 use super::super::test::test_option_compose_parse;
556
557 #[test]
558 #[allow(clippy::redundant_closure)] fn dau_compose_parse() {
560 test_option_compose_parse(
561 &Dau::from_octets("foof").unwrap(),
562 |parser| Dau::parse(parser)
563 );
564 }
565}