domain/base/opt/
keytag.rs1use super::super::iana::OptionCode;
12use super::super::message_builder::OptBuilder;
13use super::super::wire::{Composer, ParseError};
14use super::{ComposeOptData, Opt, OptData, ParseOptData};
15use core::cmp::Ordering;
16use core::convert::TryInto;
17use core::{borrow, fmt, hash, mem};
18use octseq::builder::OctetsBuilder;
19use octseq::octets::{Octets, OctetsFrom};
20use octseq::parse::Parser;
21
22#[derive(Clone)]
30#[repr(transparent)]
31pub struct KeyTag<Octs: ?Sized> {
32 octets: Octs,
33}
34
35impl KeyTag<()> {
36 pub(super) const CODE: OptionCode = OptionCode::KEY_TAG;
38}
39
40impl<Octs> KeyTag<Octs> {
41 pub fn from_octets(octets: Octs) -> Result<Self, ParseError>
47 where
48 Octs: AsRef<[u8]>,
49 {
50 KeyTag::check_len(octets.as_ref().len())?;
51 Ok(unsafe { Self::from_octets_unchecked(octets) })
52 }
53
54 pub unsafe fn from_octets_unchecked(octets: Octs) -> Self {
62 Self { octets }
63 }
64
65 pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
66 parser: &mut Parser<'a, Src>,
67 ) -> Result<Self, ParseError> {
68 let len = parser.remaining();
69 KeyTag::check_len(len)?;
70 let octets = parser.parse_octets(len)?;
71 Ok(unsafe { Self::from_octets_unchecked(octets) })
72 }
73}
74
75impl KeyTag<[u8]> {
76 pub fn from_slice(slice: &[u8]) -> Result<&Self, ParseError> {
80 Self::check_len(slice.len())?;
81 Ok(unsafe { Self::from_slice_unchecked(slice) })
82 }
83
84 #[must_use]
92 pub unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
93 mem::transmute(slice)
95 }
96
97 fn check_len(len: usize) -> Result<(), ParseError> {
99 if len > usize::from(u16::MAX) {
100 Err(ParseError::form_error("long edns-key-tag option"))
101 } else if len % 2 == 1 {
102 Err(ParseError::form_error("invalid edns-key-tag option length"))
103 } else {
104 Ok(())
105 }
106 }
107}
108
109impl<Octs: ?Sized> KeyTag<Octs> {
110 pub fn as_octets(&self) -> &Octs {
115 &self.octets
116 }
117
118 pub fn into_octets(self) -> Octs
123 where
124 Octs: Sized,
125 {
126 self.octets
127 }
128
129 pub fn as_slice(&self) -> &[u8]
134 where
135 Octs: AsRef<[u8]>,
136 {
137 self.octets.as_ref()
138 }
139
140 pub fn as_slice_mut(&mut self) -> &mut [u8]
145 where
146 Octs: AsMut<[u8]>,
147 {
148 self.octets.as_mut()
149 }
150
151 pub fn iter(&self) -> KeyTagIter<'_>
153 where
154 Octs: AsRef<[u8]>,
155 {
156 KeyTagIter(self.octets.as_ref())
157 }
158}
159
160impl<Octs, SrcOcts> OctetsFrom<KeyTag<SrcOcts>> for KeyTag<Octs>
163where
164 Octs: OctetsFrom<SrcOcts>,
165{
166 type Error = Octs::Error;
167
168 fn try_octets_from(src: KeyTag<SrcOcts>) -> Result<Self, Self::Error> {
169 Octs::try_octets_from(src.octets)
170 .map(|octets| unsafe { Self::from_octets_unchecked(octets) })
171 }
172}
173
174impl<Octs: AsRef<[u8]> + ?Sized> AsRef<[u8]> for KeyTag<Octs> {
177 fn as_ref(&self) -> &[u8] {
178 self.as_slice()
179 }
180}
181
182impl<Octs: AsMut<[u8]> + ?Sized> AsMut<[u8]> for KeyTag<Octs> {
183 fn as_mut(&mut self) -> &mut [u8] {
184 self.as_slice_mut()
185 }
186}
187
188impl<Octs: AsRef<[u8]> + ?Sized> borrow::Borrow<[u8]> for KeyTag<Octs> {
189 fn borrow(&self) -> &[u8] {
190 self.as_slice()
191 }
192}
193
194impl<Octs> borrow::BorrowMut<[u8]> for KeyTag<Octs>
195where
196 Octs: AsMut<[u8]> + AsRef<[u8]> + ?Sized,
197{
198 fn borrow_mut(&mut self) -> &mut [u8] {
199 self.as_slice_mut()
200 }
201}
202
203impl<Octs: ?Sized> OptData for KeyTag<Octs> {
206 fn code(&self) -> OptionCode {
207 OptionCode::KEY_TAG
208 }
209}
210
211impl<'a, Octs: Octets> ParseOptData<'a, Octs> for KeyTag<Octs::Range<'a>> {
212 fn parse_option(
213 code: OptionCode,
214 parser: &mut Parser<'a, Octs>,
215 ) -> Result<Option<Self>, ParseError> {
216 if code == OptionCode::KEY_TAG {
217 Self::parse(parser).map(Some)
218 } else {
219 Ok(None)
220 }
221 }
222}
223
224impl<Octs: AsRef<[u8]> + ?Sized> ComposeOptData for KeyTag<Octs> {
225 fn compose_len(&self) -> u16 {
226 self.octets
227 .as_ref()
228 .len()
229 .try_into()
230 .expect("long option data")
231 }
232
233 fn compose_option<Target: OctetsBuilder + ?Sized>(
234 &self,
235 target: &mut Target,
236 ) -> Result<(), Target::AppendError> {
237 target.append_slice(self.octets.as_ref())
238 }
239}
240
241impl<'a, Octs: AsRef<[u8]> + ?Sized> IntoIterator for &'a KeyTag<Octs> {
244 type Item = u16;
245 type IntoIter = KeyTagIter<'a>;
246
247 fn into_iter(self) -> Self::IntoIter {
248 self.iter()
249 }
250}
251
252impl<Octets: AsRef<[u8]> + ?Sized> fmt::Display for KeyTag<Octets> {
255 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256 let mut first = true;
257
258 for v in self.octets.as_ref() {
259 if first {
260 write!(f, "{:X}", ((*v as u16) << 8) | *v as u16)?;
261 first = false;
262 } else {
263 write!(f, ", {:X}", ((*v as u16) << 8) | *v as u16)?;
264 }
265 }
266
267 Ok(())
268 }
269}
270
271impl<Octets: AsRef<[u8]> + ?Sized> fmt::Debug for KeyTag<Octets> {
272 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
273 write!(f, "KeyTag([{}])", self)
274 }
275}
276
277impl<Octs, Other> PartialEq<Other> for KeyTag<Octs>
280where
281 Octs: AsRef<[u8]> + ?Sized,
282 Other: AsRef<[u8]> + ?Sized,
283{
284 fn eq(&self, other: &Other) -> bool {
285 self.as_slice().eq(other.as_ref())
286 }
287}
288
289impl<Octs: AsRef<[u8]> + ?Sized> Eq for KeyTag<Octs> {}
290
291impl<Octs, Other> PartialOrd<Other> for KeyTag<Octs>
294where
295 Octs: AsRef<[u8]> + ?Sized,
296 Other: AsRef<[u8]> + ?Sized,
297{
298 fn partial_cmp(&self, other: &Other) -> Option<Ordering> {
299 self.as_slice().partial_cmp(other.as_ref())
300 }
301}
302
303impl<Octs: AsRef<[u8]> + ?Sized> Ord for KeyTag<Octs> {
304 fn cmp(&self, other: &Self) -> Ordering {
305 self.as_slice().cmp(other.as_slice())
306 }
307}
308
309impl<Octs: AsRef<[u8]> + ?Sized> hash::Hash for KeyTag<Octs> {
312 fn hash<H: hash::Hasher>(&self, state: &mut H) {
313 self.as_slice().hash(state)
314 }
315}
316
317impl<Octs: Octets> Opt<Octs> {
320 pub fn key_tag(&self) -> Option<KeyTag<Octs::Range<'_>>> {
325 self.first()
326 }
327}
328
329impl<Target: Composer> OptBuilder<'_, Target> {
330 pub fn key_tag(
335 &mut self,
336 key_tag: &KeyTag<impl AsRef<[u8]> + ?Sized>,
337 ) -> Result<(), Target::AppendError> {
338 self.push(key_tag)
339 }
340}
341
342#[cfg(feature = "serde")]
345impl<Octs: AsRef<[u8]>> serde::Serialize for KeyTag<Octs> {
346 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
347 where
348 S: serde::Serializer,
349 {
350 use serde::ser::SerializeSeq;
351
352 let mut list = serializer.serialize_seq(None)?;
353
354 for i in self.as_ref().iter() {
355 list.serialize_element(i)?;
356 }
357
358 list.end()
359 }
360}
361
362#[derive(Clone, Copy, Debug)]
369pub struct KeyTagIter<'a>(&'a [u8]);
370
371impl Iterator for KeyTagIter<'_> {
372 type Item = u16;
373
374 fn next(&mut self) -> Option<Self::Item> {
375 if self.0.len() < 2 {
376 None
377 } else {
378 let (item, tail) = self.0.split_at(2);
379 self.0 = tail;
380 Some(u16::from_be_bytes(item.try_into().unwrap()))
381 }
382 }
383}
384
385#[cfg(test)]
388#[cfg(all(feature = "std", feature = "bytes"))]
389mod test {
390 use super::super::test::test_option_compose_parse;
391 use super::*;
392
393 #[test]
394 #[allow(clippy::redundant_closure)] fn nsid_compose_parse() {
396 test_option_compose_parse(
397 &KeyTag::from_octets("fooo").unwrap(),
398 |parser| KeyTag::parse(parser),
399 );
400 }
401}