1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! EDNS Options from RFC 6975.

use core::slice;
use super::super::iana::{OptionCode, SecAlg};
use super::super::message_builder::OptBuilder;
use super::super::octets::{
    Compose, OctetsBuilder, OctetsRef, Parse, ParseError, Parser, ShortBuf
};
use super::CodeOptData;


//------------ Dau, Dhu, N3u -------------------------------------------------

macro_rules! option_type {
    ( $name:ident ) => {
        #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
        pub struct $name<Octets> {
            octets: Octets,
        }

        impl<Octets> $name<Octets> {
            pub fn from_octets(octets: Octets) -> Self {
                $name { octets }
            }

            pub fn iter(&self) -> SecAlgsIter
            where Octets: AsRef<[u8]> {
                SecAlgsIter::new(self.octets.as_ref())
            }
        }

        impl $name<()> {
            pub fn push<Target: OctetsBuilder>(
                builder: &mut OptBuilder<Target>,
                algs: &[SecAlg]
            ) -> Result<(), ShortBuf> {
                assert!(algs.len() <= ::std::u16::MAX as usize);
                builder.push_raw_option(OptionCode::$name, |target| {
                    target.append_all(|target| {
                        for alg in algs {
                            alg.to_int().compose(target)?;
                        }
                        Ok(())
                    })
                })
            }
        }

        //--- Parse and Compose

        impl<Ref: OctetsRef> Parse<Ref> for $name<Ref::Range> {
            fn parse(parser: &mut Parser<Ref>) -> Result<Self, ParseError> {
                let len = parser.remaining();
                parser.parse_octets(len).map(Self::from_octets)
            }

            fn skip(parser: &mut Parser<Ref>) -> Result<(), ParseError> {
                parser.advance_to_end();
                Ok(())
            }
        }

        impl<Octets: AsRef<[u8]>> Compose for $name<Octets> {
            fn compose<T: OctetsBuilder>(
                &self,
                target: &mut T
            ) -> Result<(), ShortBuf> {
                target.append_slice(self.octets.as_ref())
            }
        }


        //--- CodeOptData
        
        impl<Octets> CodeOptData for $name<Octets> {
            const CODE: OptionCode = OptionCode::$name;
        }

        
        //--- IntoIter

        impl<'a, Octets: AsRef<[u8]>> IntoIterator for &'a $name<Octets> {
            type Item = SecAlg;
            type IntoIter = SecAlgsIter<'a>;

            fn into_iter(self) -> Self::IntoIter {
                self.iter()
            }
        }
    }
}

option_type!(Dau);
option_type!(Dhu);
option_type!(N3u);


//------------ SecAlgsIter ---------------------------------------------------

pub struct SecAlgsIter<'a>(slice::Iter<'a, u8>);

impl<'a> SecAlgsIter<'a> {
    fn new(slice: &'a [u8]) -> Self {
        SecAlgsIter(slice.iter())
    }
}

impl<'a> Iterator for SecAlgsIter<'a> {
    type Item = SecAlg;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|x| SecAlg::from_int(*x))
    }
}