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