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