domain/rdata/
aaaa.rs

1//! Record data from [RFC 3596]: AAAA records.
2//!
3//! This RFC defines the Aaaa record type.
4//!
5//! [RFC 3596]: https://tools.ietf.org/html/rfc3596
6
7use crate::base::cmp::CanonicalOrd;
8use crate::base::iana::Rtype;
9use crate::base::net::Ipv6Addr;
10use crate::base::rdata::{ComposeRecordData, ParseRecordData, RecordData};
11use crate::base::scan::{Scanner, ScannerError};
12use crate::base::wire::{Composer, Parse, ParseError};
13use core::cmp::Ordering;
14use core::convert::Infallible;
15use core::str::FromStr;
16use core::{fmt, str};
17use octseq::octets::OctetsFrom;
18use octseq::parse::Parser;
19
20//------------ Aaaa ---------------------------------------------------------
21
22#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24pub struct Aaaa {
25    addr: Ipv6Addr,
26}
27
28impl Aaaa {
29    #[must_use]
30    pub fn new(addr: Ipv6Addr) -> Aaaa {
31        Aaaa { addr }
32    }
33
34    #[must_use]
35    pub fn addr(&self) -> Ipv6Addr {
36        self.addr
37    }
38    pub fn set_addr(&mut self, addr: Ipv6Addr) {
39        self.addr = addr
40    }
41
42    pub(super) fn convert_octets<E>(self) -> Result<Self, E> {
43        Ok(self)
44    }
45
46    pub(super) fn flatten<E>(self) -> Result<Self, E> {
47        Ok(self)
48    }
49
50    pub fn parse<Octs: AsRef<[u8]> + ?Sized>(
51        parser: &mut Parser<Octs>,
52    ) -> Result<Self, ParseError> {
53        Ipv6Addr::parse(parser).map(Self::new)
54    }
55
56    pub fn scan<S: Scanner>(scanner: &mut S) -> Result<Self, S::Error> {
57        let token = scanner.scan_octets()?;
58        let token = str::from_utf8(token.as_ref())
59            .map_err(|_| S::Error::custom("expected IPv6 address"))?;
60        Aaaa::from_str(token)
61            .map_err(|_| S::Error::custom("expected IPv6 address"))
62    }
63}
64
65//--- From and FromStr
66
67impl From<Ipv6Addr> for Aaaa {
68    fn from(addr: Ipv6Addr) -> Self {
69        Self::new(addr)
70    }
71}
72
73impl From<Aaaa> for Ipv6Addr {
74    fn from(data: Aaaa) -> Self {
75        data.addr
76    }
77}
78
79impl FromStr for Aaaa {
80    type Err = <Ipv6Addr as core::str::FromStr>::Err;
81
82    fn from_str(s: &str) -> Result<Self, Self::Err> {
83        Ipv6Addr::from_str(s).map(Aaaa::new)
84    }
85}
86
87//--- OctetsFrom
88
89impl OctetsFrom<Aaaa> for Aaaa {
90    type Error = Infallible;
91
92    fn try_octets_from(source: Aaaa) -> Result<Self, Self::Error> {
93        Ok(source)
94    }
95}
96
97//--- CanonicalOrd
98
99impl CanonicalOrd for Aaaa {
100    fn canonical_cmp(&self, other: &Self) -> Ordering {
101        self.cmp(other)
102    }
103}
104
105//--- RecordData, ParseRecordData, ComposeRecordData
106
107impl RecordData for Aaaa {
108    fn rtype(&self) -> Rtype {
109        Rtype::Aaaa
110    }
111}
112
113impl<'a, Octs: AsRef<[u8]> + ?Sized> ParseRecordData<'a, Octs> for Aaaa {
114    fn parse_rdata(
115        rtype: Rtype,
116        parser: &mut Parser<'a, Octs>,
117    ) -> Result<Option<Self>, ParseError> {
118        if rtype == Rtype::Aaaa {
119            Self::parse(parser).map(Some)
120        } else {
121            Ok(None)
122        }
123    }
124}
125
126impl ComposeRecordData for Aaaa {
127    fn rdlen(&self, _compress: bool) -> Option<u16> {
128        Some(16)
129    }
130
131    fn compose_rdata<Target: Composer + ?Sized>(
132        &self,
133        target: &mut Target,
134    ) -> Result<(), Target::AppendError> {
135        target.append_slice(&self.addr().octets())
136    }
137
138    fn compose_canonical_rdata<Target: Composer + ?Sized>(
139        &self,
140        target: &mut Target,
141    ) -> Result<(), Target::AppendError> {
142        self.compose_rdata(target)
143    }
144}
145
146//--- Display
147
148impl fmt::Display for Aaaa {
149    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
150        self.addr.fmt(f)
151    }
152}
153
154//--- AsRef and AsMut
155
156impl AsRef<Ipv6Addr> for Aaaa {
157    fn as_ref(&self) -> &Ipv6Addr {
158        &self.addr
159    }
160}
161
162impl AsMut<Ipv6Addr> for Aaaa {
163    fn as_mut(&mut self) -> &mut Ipv6Addr {
164        &mut self.addr
165    }
166}
167
168//============ Testing ======================================================
169
170#[cfg(test)]
171#[cfg(all(feature = "std", feature = "bytes"))]
172mod test {
173    use super::*;
174    use crate::base::rdata::test::{
175        test_compose_parse, test_rdlen, test_scan,
176    };
177
178    #[test]
179    fn aaaa_compose_parse_scan() {
180        let addr = "2001:db9::12:13";
181        let rdata = Aaaa::from_str(addr).unwrap();
182        test_rdlen(&rdata);
183        test_compose_parse(&rdata, Aaaa::parse);
184        test_scan(&[addr], Aaaa::scan, &rdata);
185    }
186}