1use super::super::cmp::CanonicalOrd;
6use super::super::scan::{Scanner, Symbol, Symbols};
7use super::super::wire::{FormError, ParseError};
8use super::builder::{DnameBuilder, FromStrError};
9use super::label::{Label, LabelTypeError, SplitLabelError};
10use super::relative::{DnameIter, RelativeDname};
11use super::traits::{FlattenInto, ToDname, ToLabelIter};
12#[cfg(feature = "bytes")]
13use bytes::Bytes;
14use core::ops::{Bound, RangeBounds};
15use core::str::FromStr;
16use core::{borrow, cmp, fmt, hash, str};
17use octseq::builder::{
18 EmptyBuilder, FreezeBuilder, FromBuilder, OctetsBuilder, Truncate,
19};
20use octseq::octets::{Octets, OctetsFrom};
21use octseq::parse::Parser;
22#[cfg(feature = "serde")]
23use octseq::serde::{DeserializeOctets, SerializeOctets};
24#[cfg(feature = "std")]
25use std::vec::Vec;
26
27#[derive(Clone)]
53pub struct Dname<Octs: ?Sized>(Octs);
54
55impl Dname<()> {
56 pub const MAX_LEN: usize = 255;
58}
59
60impl<Octs> Dname<Octs> {
63 pub const unsafe fn from_octets_unchecked(octets: Octs) -> Self {
74 Dname(octets)
75 }
76
77 pub fn from_octets(octets: Octs) -> Result<Self, DnameError>
83 where
84 Octs: AsRef<[u8]>,
85 {
86 Dname::check_slice(octets.as_ref())?;
87 Ok(unsafe { Dname::from_octets_unchecked(octets) })
88 }
89
90 pub fn from_symbols<Sym>(symbols: Sym) -> Result<Self, FromStrError>
91 where
92 Octs: FromBuilder,
93 <Octs as FromBuilder>::Builder: EmptyBuilder
94 + FreezeBuilder<Octets = Octs>
95 + AsRef<[u8]>
96 + AsMut<[u8]>,
97 Sym: IntoIterator<Item = Symbol>,
98 {
99 let mut symbols = symbols.into_iter();
102 let first = match symbols.next() {
103 Some(first) => first,
104 None => return Err(FromStrError::UnexpectedEnd),
105 };
106 if first == Symbol::Char('.') {
107 if symbols.next().is_some() {
108 return Err(FromStrError::EmptyLabel);
109 } else {
110 let mut builder =
112 <Octs as FromBuilder>::Builder::with_capacity(1);
113 builder
114 .append_slice(b"\0")
115 .map_err(|_| FromStrError::ShortBuf)?;
116 return Ok(unsafe {
117 Self::from_octets_unchecked(builder.freeze())
118 });
119 }
120 }
121
122 let mut builder = DnameBuilder::<Octs::Builder>::new();
123 builder.push_symbol(first)?;
124 builder.append_symbols(symbols)?;
125 builder.into_dname().map_err(Into::into)
126 }
127
128 pub fn from_chars<C>(chars: C) -> Result<Self, FromStrError>
147 where
148 Octs: FromBuilder,
149 <Octs as FromBuilder>::Builder: EmptyBuilder
150 + FreezeBuilder<Octets = Octs>
151 + AsRef<[u8]>
152 + AsMut<[u8]>,
153 C: IntoIterator<Item = char>,
154 {
155 Symbols::with(chars.into_iter(), |symbols| {
156 Self::from_symbols(symbols)
157 })
158 }
159
160 pub fn scan<S: Scanner<Dname = Self>>(
162 scanner: &mut S,
163 ) -> Result<Self, S::Error> {
164 scanner.scan_dname()
165 }
166
167 #[must_use]
178 pub fn root() -> Self
179 where
180 Octs: From<&'static [u8]>,
181 {
182 unsafe { Self::from_octets_unchecked(b"\0".as_ref().into()) }
183 }
184}
185
186impl Dname<[u8]> {
187 unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
189 &*(slice as *const [u8] as *const Dname<[u8]>)
190 }
191
192 pub fn from_slice(slice: &[u8]) -> Result<&Self, DnameError> {
208 Self::check_slice(slice)?;
209 Ok(unsafe { Self::from_slice_unchecked(slice) })
210 }
211
212 #[must_use]
214 pub fn root_slice() -> &'static Self {
215 unsafe { Self::from_slice_unchecked("\0".as_ref()) }
216 }
217
218 fn check_slice(mut slice: &[u8]) -> Result<(), DnameError> {
220 if slice.len() > Dname::MAX_LEN {
221 return Err(DnameError::LongName);
222 }
223 loop {
224 let (label, tail) = Label::split_from(slice)?;
225 if label.is_root() {
226 if tail.is_empty() {
227 break;
228 } else {
229 return Err(DnameError::TrailingData);
230 }
231 }
232 if tail.is_empty() {
233 return Err(DnameError::RelativeName);
234 }
235 slice = tail;
236 }
237 Ok(())
238 }
239}
240
241impl Dname<&'static [u8]> {
242 #[must_use]
244 pub fn root_ref() -> Self {
245 Self::root()
246 }
247}
248
249#[cfg(feature = "std")]
250impl Dname<Vec<u8>> {
251 #[must_use]
253 pub fn root_vec() -> Self {
254 Self::root()
255 }
256
257 pub fn vec_from_str(s: &str) -> Result<Self, FromStrError> {
259 FromStr::from_str(s)
260 }
261}
262
263#[cfg(feature = "bytes")]
264impl Dname<Bytes> {
265 pub fn root_bytes() -> Self {
267 Self::root()
268 }
269
270 pub fn bytes_from_str(s: &str) -> Result<Self, FromStrError> {
272 FromStr::from_str(s)
273 }
274}
275
276impl<Octs: ?Sized> Dname<Octs> {
279 pub fn as_octets(&self) -> &Octs {
283 &self.0
284 }
285
286 pub fn into_octets(self) -> Octs
288 where
289 Octs: Sized,
290 {
291 self.0
292 }
293
294 pub fn into_relative(mut self) -> RelativeDname<Octs>
296 where
297 Octs: Sized + AsRef<[u8]> + Truncate,
298 {
299 let len = self.0.as_ref().len() - 1;
300 self.0.truncate(len);
301 unsafe { RelativeDname::from_octets_unchecked(self.0) }
302 }
303
304 pub fn for_ref(&self) -> Dname<&Octs> {
306 unsafe { Dname::from_octets_unchecked(&self.0) }
307 }
308
309 pub fn as_slice(&self) -> &[u8]
313 where
314 Octs: AsRef<[u8]>,
315 {
316 self.0.as_ref()
317 }
318
319 pub fn for_slice(&self) -> &Dname<[u8]>
321 where
322 Octs: AsRef<[u8]>,
323 {
324 unsafe { Dname::from_slice_unchecked(self.0.as_ref()) }
325 }
326
327 pub fn make_canonical(&mut self)
332 where
333 Octs: AsMut<[u8]>,
334 {
335 Label::make_slice_canonical(self.0.as_mut());
336 }
337}
338
339impl<Octs: AsRef<[u8]> + ?Sized> Dname<Octs> {
342 pub fn is_root(&self) -> bool {
344 self.0.as_ref().len() == 1
345 }
346
347 #[allow(clippy::len_without_is_empty)] pub fn len(&self) -> usize {
350 self.0.as_ref().len()
351 }
352
353 pub fn fmt_with_dot(&self) -> impl fmt::Display + '_ {
354 DisplayWithDot(self.for_slice())
355 }
356}
357
358impl<Octs: AsRef<[u8]> + ?Sized> Dname<Octs> {
361 pub fn iter(&self) -> DnameIter {
363 DnameIter::new(self.0.as_ref())
364 }
365
366 pub fn iter_suffixes(&self) -> SuffixIter<'_, Octs> {
372 SuffixIter::new(self)
373 }
374
375 pub fn label_count(&self) -> usize {
377 self.iter().count()
378 }
379
380 pub fn first(&self) -> &Label {
382 self.iter().next().unwrap()
383 }
384
385 pub fn last(&self) -> &'static Label {
391 Label::root()
392 }
393
394 pub fn starts_with<'a, N: ToLabelIter + ?Sized>(
396 &'a self,
397 base: &'a N,
398 ) -> bool {
399 <Self as ToLabelIter>::starts_with(self, base)
400 }
401
402 pub fn ends_with<'a, N: ToLabelIter + ?Sized>(
404 &'a self,
405 base: &'a N,
406 ) -> bool {
407 <Self as ToLabelIter>::ends_with(self, base)
408 }
409
410 pub fn is_label_start(&self, mut index: usize) -> bool {
412 if index == 0 {
413 return true;
414 }
415 let mut tmp = self.as_slice();
416 while !tmp.is_empty() {
417 let (label, tail) = Label::split_from(tmp).unwrap();
418 let len = label.len() + 1;
419 if index < len || len == 1 {
420 return false;
422 } else if index == len {
423 return true;
424 }
425 index -= len;
426 tmp = tail;
427 }
428 false
429 }
430
431 fn check_index(&self, index: usize) {
433 if !self.is_label_start(index) {
434 panic!("index not at start of a label");
435 }
436 }
437
438 fn check_bounds(&self, bounds: &impl RangeBounds<usize>) {
440 match bounds.start_bound().cloned() {
441 Bound::Included(idx) => self.check_index(idx),
442 Bound::Excluded(_) => {
443 panic!("excluded lower bounds not supported");
444 }
445 Bound::Unbounded => {}
446 }
447 match bounds.end_bound().cloned() {
448 Bound::Included(idx) => self
449 .check_index(idx.checked_add(1).expect("end bound too big")),
450 Bound::Excluded(idx) => self.check_index(idx),
451 Bound::Unbounded => {
452 panic!("unbounded end bound (results in absolute name)")
453 }
454 }
455 }
456
457 pub fn slice(
480 &self,
481 range: impl RangeBounds<usize>,
482 ) -> &RelativeDname<[u8]> {
483 self.check_bounds(&range);
484 unsafe {
485 RelativeDname::from_slice_unchecked(self.0.as_ref().range(range))
486 }
487 }
488
489 pub fn slice_from(&self, begin: usize) -> &Dname<[u8]> {
507 self.check_index(begin);
508 unsafe { Dname::from_slice_unchecked(&self.0.as_ref()[begin..]) }
509 }
510
511 pub fn range(
529 &self,
530 range: impl RangeBounds<usize>,
531 ) -> RelativeDname<<Octs as Octets>::Range<'_>>
532 where
533 Octs: Octets,
534 {
535 self.check_bounds(&range);
536 unsafe { RelativeDname::from_octets_unchecked(self.0.range(range)) }
537 }
538
539 pub fn range_from(
551 &self,
552 begin: usize,
553 ) -> Dname<<Octs as Octets>::Range<'_>>
554 where
555 Octs: Octets,
556 {
557 self.check_index(begin);
558 unsafe { self.range_from_unchecked(begin) }
559 }
560
561 unsafe fn range_from_unchecked(
563 &self,
564 begin: usize,
565 ) -> Dname<<Octs as Octets>::Range<'_>>
566 where
567 Octs: Octets,
568 {
569 Dname::from_octets_unchecked(self.0.range(begin..))
570 }
571}
572
573impl<Octs: AsRef<[u8]> + ?Sized> Dname<Octs> {
574 pub fn split(
583 &self,
584 mid: usize,
585 ) -> (RelativeDname<Octs::Range<'_>>, Dname<Octs::Range<'_>>)
586 where
587 Octs: Octets,
588 {
589 self.check_index(mid);
590 unsafe {
591 (
592 RelativeDname::from_octets_unchecked(self.0.range(..mid)),
593 Dname::from_octets_unchecked(self.0.range(mid..)),
594 )
595 }
596 }
597
598 pub fn truncate(mut self, len: usize) -> RelativeDname<Octs>
608 where
609 Octs: Truncate + Sized,
610 {
611 self.check_index(len);
612 self.0.truncate(len);
613 unsafe { RelativeDname::from_octets_unchecked(self.0) }
614 }
615
616 pub fn split_first(&self) -> Option<(&Label, Dname<Octs::Range<'_>>)>
622 where
623 Octs: Octets,
624 {
625 if self.compose_len() == 1 {
626 return None;
627 }
628 let label = self.iter().next().unwrap();
629 Some((label, self.split(label.len() + 1).1))
630 }
631
632 pub fn parent(&self) -> Option<Dname<Octs::Range<'_>>>
636 where
637 Octs: Octets,
638 {
639 self.split_first().map(|(_, parent)| parent)
640 }
641
642 pub fn strip_suffix<N: ToDname + ?Sized>(
648 self,
649 base: &N,
650 ) -> Result<RelativeDname<Octs>, Self>
651 where
652 Octs: Truncate + Sized,
653 {
654 if self.ends_with(base) {
655 let len = self.0.as_ref().len() - usize::from(base.compose_len());
656 Ok(self.truncate(len))
657 } else {
658 Err(self)
659 }
660 }
661}
662
663impl<Octs> Dname<Octs> {
664 pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
666 parser: &mut Parser<'a, Src>,
667 ) -> Result<Self, ParseError> {
668 let len = Self::parse_name_len(parser)?;
669 Ok(unsafe { Self::from_octets_unchecked(parser.parse_octets(len)?) })
670 }
671
672 fn parse_name_len<Source: AsRef<[u8]> + ?Sized>(
674 parser: &Parser<Source>,
675 ) -> Result<usize, ParseError> {
676 let len = {
677 let mut tmp = parser.peek_all();
678 loop {
679 if tmp.is_empty() {
680 return Err(ParseError::ShortInput);
681 }
682 let (label, tail) = Label::split_from(tmp)?;
683 tmp = tail;
684 if label.is_root() {
685 break;
686 }
687 }
688 parser.remaining() - tmp.len()
689 };
690 if len > Dname::MAX_LEN {
691 Err(DnameError::LongName.into())
692 } else {
693 Ok(len)
694 }
695 }
696}
697
698impl<Octs> AsRef<Octs> for Dname<Octs> {
701 fn as_ref(&self) -> &Octs {
702 &self.0
703 }
704}
705
706impl<Octs: AsRef<[u8]> + ?Sized> AsRef<[u8]> for Dname<Octs> {
707 fn as_ref(&self) -> &[u8] {
708 self.0.as_ref()
709 }
710}
711
712impl<Octs, SrcOcts> OctetsFrom<Dname<SrcOcts>> for Dname<Octs>
715where
716 Octs: OctetsFrom<SrcOcts>,
717{
718 type Error = Octs::Error;
719
720 fn try_octets_from(source: Dname<SrcOcts>) -> Result<Self, Self::Error> {
721 Octs::try_octets_from(source.0)
722 .map(|octets| unsafe { Self::from_octets_unchecked(octets) })
723 }
724}
725
726impl<Octs> FromStr for Dname<Octs>
729where
730 Octs: FromBuilder,
731 <Octs as FromBuilder>::Builder: EmptyBuilder
732 + FreezeBuilder<Octets = Octs>
733 + AsRef<[u8]>
734 + AsMut<[u8]>,
735{
736 type Err = FromStrError;
737
738 fn from_str(s: &str) -> Result<Self, Self::Err> {
751 Self::from_chars(s.chars())
752 }
753}
754
755impl<Octs, Target> FlattenInto<Dname<Target>> for Dname<Octs>
758where
759 Target: OctetsFrom<Octs>,
760{
761 type AppendError = Target::Error;
762
763 fn try_flatten_into(self) -> Result<Dname<Target>, Self::AppendError> {
764 Target::try_octets_from(self.0)
765 .map(|octets| unsafe { Dname::from_octets_unchecked(octets) })
766 }
767}
768
769impl<Octs, N> PartialEq<N> for Dname<Octs>
772where
773 Octs: AsRef<[u8]> + ?Sized,
774 N: ToDname + ?Sized,
775{
776 fn eq(&self, other: &N) -> bool {
777 self.name_eq(other)
778 }
779}
780
781impl<Octs: AsRef<[u8]> + ?Sized> Eq for Dname<Octs> {}
782
783impl<Octs, N> PartialOrd<N> for Dname<Octs>
786where
787 Octs: AsRef<[u8]> + ?Sized,
788 N: ToDname + ?Sized,
789{
790 fn partial_cmp(&self, other: &N) -> Option<cmp::Ordering> {
797 Some(self.name_cmp(other))
798 }
799}
800
801impl<Octs: AsRef<[u8]> + ?Sized> Ord for Dname<Octs> {
802 fn cmp(&self, other: &Self) -> cmp::Ordering {
809 self.name_cmp(other)
810 }
811}
812
813impl<Octs, N> CanonicalOrd<N> for Dname<Octs>
814where
815 Octs: AsRef<[u8]> + ?Sized,
816 N: ToDname + ?Sized,
817{
818 fn canonical_cmp(&self, other: &N) -> cmp::Ordering {
819 self.name_cmp(other)
820 }
821}
822
823impl<Octs: AsRef<[u8]> + ?Sized> hash::Hash for Dname<Octs> {
826 fn hash<H: hash::Hasher>(&self, state: &mut H) {
827 for item in self.iter() {
828 item.hash(state)
829 }
830 }
831}
832
833impl<Octs> ToLabelIter for Dname<Octs>
836where
837 Octs: AsRef<[u8]> + ?Sized,
838{
839 type LabelIter<'a> = DnameIter<'a> where Octs: 'a;
840
841 fn iter_labels(&self) -> Self::LabelIter<'_> {
842 self.iter()
843 }
844
845 fn compose_len(&self) -> u16 {
846 u16::try_from(self.0.as_ref().len()).expect("long domain name")
847 }
848}
849
850impl<Octs: AsRef<[u8]> + ?Sized> ToDname for Dname<Octs> {
851 fn as_flat_slice(&self) -> Option<&[u8]> {
852 Some(self.0.as_ref())
853 }
854}
855
856impl<'a, Octs> IntoIterator for &'a Dname<Octs>
859where
860 Octs: AsRef<[u8]> + ?Sized,
861{
862 type Item = &'a Label;
863 type IntoIter = DnameIter<'a>;
864
865 fn into_iter(self) -> Self::IntoIter {
866 self.iter()
867 }
868}
869
870impl<Octs: AsRef<[u8]> + ?Sized> fmt::Display for Dname<Octs> {
873 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
879 if self.is_root() {
880 return f.write_str(".");
881 }
882
883 let mut iter = self.iter();
884 write!(f, "{}", iter.next().unwrap())?;
885 for label in iter {
886 if !label.is_root() {
887 write!(f, ".{}", label)?
888 }
889 }
890 Ok(())
891 }
892}
893
894impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Dname<Octs> {
897 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
898 write!(f, "Dname({})", self.fmt_with_dot())
899 }
900}
901
902impl<Octs: AsRef<[u8]>> AsRef<Dname<[u8]>> for Dname<Octs> {
905 fn as_ref(&self) -> &Dname<[u8]> {
906 self.for_slice()
907 }
908}
909
910impl<Octs: AsRef<[u8]>> borrow::Borrow<Dname<[u8]>> for Dname<Octs> {
930 fn borrow(&self) -> &Dname<[u8]> {
931 self.for_slice()
932 }
933}
934
935#[cfg(feature = "serde")]
938impl<Octs> serde::Serialize for Dname<Octs>
939where
940 Octs: AsRef<[u8]> + SerializeOctets + ?Sized,
941{
942 fn serialize<S: serde::Serializer>(
943 &self,
944 serializer: S,
945 ) -> Result<S::Ok, S::Error> {
946 if serializer.is_human_readable() {
947 serializer
948 .serialize_newtype_struct("Dname", &format_args!("{}", self))
949 } else {
950 serializer.serialize_newtype_struct(
951 "Dname",
952 &self.0.as_serialized_octets(),
953 )
954 }
955 }
956}
957
958#[cfg(feature = "serde")]
959impl<'de, Octs> serde::Deserialize<'de> for Dname<Octs>
960where
961 Octs: FromBuilder + DeserializeOctets<'de>,
962 <Octs as FromBuilder>::Builder: FreezeBuilder<Octets = Octs>
963 + EmptyBuilder
964 + AsRef<[u8]>
965 + AsMut<[u8]>,
966{
967 fn deserialize<D: serde::Deserializer<'de>>(
968 deserializer: D,
969 ) -> Result<Self, D::Error> {
970 use core::marker::PhantomData;
971
972 struct InnerVisitor<'de, T: DeserializeOctets<'de>>(T::Visitor);
973
974 impl<'de, Octs> serde::de::Visitor<'de> for InnerVisitor<'de, Octs>
975 where
976 Octs: FromBuilder + DeserializeOctets<'de>,
977 <Octs as FromBuilder>::Builder: FreezeBuilder<Octets = Octs>
978 + EmptyBuilder
979 + AsRef<[u8]>
980 + AsMut<[u8]>,
981 {
982 type Value = Dname<Octs>;
983
984 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
985 f.write_str("an absolute domain name")
986 }
987
988 fn visit_str<E: serde::de::Error>(
989 self,
990 v: &str,
991 ) -> Result<Self::Value, E> {
992 Dname::from_str(v).map_err(E::custom)
993 }
994
995 fn visit_borrowed_bytes<E: serde::de::Error>(
996 self,
997 value: &'de [u8],
998 ) -> Result<Self::Value, E> {
999 self.0.visit_borrowed_bytes(value).and_then(|octets| {
1000 Dname::from_octets(octets).map_err(E::custom)
1001 })
1002 }
1003
1004 #[cfg(feature = "std")]
1005 fn visit_byte_buf<E: serde::de::Error>(
1006 self,
1007 value: std::vec::Vec<u8>,
1008 ) -> Result<Self::Value, E> {
1009 self.0.visit_byte_buf(value).and_then(|octets| {
1010 Dname::from_octets(octets).map_err(E::custom)
1011 })
1012 }
1013 }
1014
1015 struct NewtypeVisitor<T>(PhantomData<T>);
1016
1017 impl<'de, Octs> serde::de::Visitor<'de> for NewtypeVisitor<Octs>
1018 where
1019 Octs: FromBuilder + DeserializeOctets<'de>,
1020 <Octs as FromBuilder>::Builder: EmptyBuilder
1021 + FreezeBuilder<Octets = Octs>
1022 + AsRef<[u8]>
1023 + AsMut<[u8]>,
1024 {
1025 type Value = Dname<Octs>;
1026
1027 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
1028 f.write_str("an absolute domain name")
1029 }
1030
1031 fn visit_newtype_struct<D: serde::Deserializer<'de>>(
1032 self,
1033 deserializer: D,
1034 ) -> Result<Self::Value, D::Error> {
1035 if deserializer.is_human_readable() {
1036 deserializer
1037 .deserialize_str(InnerVisitor(Octs::visitor()))
1038 } else {
1039 Octs::deserialize_with_visitor(
1040 deserializer,
1041 InnerVisitor(Octs::visitor()),
1042 )
1043 }
1044 }
1045 }
1046
1047 deserializer
1048 .deserialize_newtype_struct("Dname", NewtypeVisitor(PhantomData))
1049 }
1050}
1051
1052#[derive(Clone)]
1056pub struct SuffixIter<'a, Octs: ?Sized> {
1057 name: &'a Dname<Octs>,
1058 start: Option<usize>,
1059}
1060
1061impl<'a, Octs: ?Sized> SuffixIter<'a, Octs> {
1062 fn new(name: &'a Dname<Octs>) -> Self {
1064 SuffixIter {
1065 name,
1066 start: Some(0),
1067 }
1068 }
1069}
1070
1071impl<'a, Octs: Octets + ?Sized> Iterator for SuffixIter<'a, Octs> {
1072 type Item = Dname<Octs::Range<'a>>;
1073
1074 fn next(&mut self) -> Option<Self::Item> {
1075 let start = self.start?;
1076 let res = unsafe { self.name.range_from_unchecked(start) };
1077 let label = res.first();
1078 if label.is_root() {
1079 self.start = None;
1080 } else {
1081 self.start = Some(start + usize::from(label.compose_len()))
1082 }
1083 Some(res)
1084 }
1085}
1086
1087struct DisplayWithDot<'a>(&'a Dname<[u8]>);
1090
1091impl<'a> fmt::Display for DisplayWithDot<'a> {
1092 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1093 if self.0.is_root() {
1094 f.write_str(".")
1095 } else {
1096 let mut iter = self.0.iter();
1097 write!(f, "{}", iter.next().unwrap())?;
1098 for label in iter {
1099 write!(f, ".{}", label)?
1100 }
1101 Ok(())
1102 }
1103 }
1104}
1105
1106#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1112pub enum DnameError {
1113 BadLabel(LabelTypeError),
1115
1116 CompressedName,
1118
1119 LongName,
1121
1122 RelativeName,
1124
1125 TrailingData,
1127
1128 ShortInput,
1130}
1131
1132impl From<LabelTypeError> for DnameError {
1135 fn from(err: LabelTypeError) -> DnameError {
1136 DnameError::BadLabel(err)
1137 }
1138}
1139
1140impl From<SplitLabelError> for DnameError {
1141 fn from(err: SplitLabelError) -> DnameError {
1142 match err {
1143 SplitLabelError::Pointer(_) => DnameError::CompressedName,
1144 SplitLabelError::BadType(t) => DnameError::BadLabel(t),
1145 SplitLabelError::ShortInput => DnameError::ShortInput,
1146 }
1147 }
1148}
1149
1150impl From<DnameError> for FormError {
1151 fn from(err: DnameError) -> FormError {
1152 FormError::new(match err {
1153 DnameError::BadLabel(_) => "unknown label type",
1154 DnameError::CompressedName => "compressed domain name",
1155 DnameError::LongName => "long domain name",
1156 DnameError::RelativeName => "relative domain name",
1157 DnameError::TrailingData => "trailing data in buffer",
1158 DnameError::ShortInput => "unexpected end of buffer",
1159 })
1160 }
1161}
1162
1163impl From<DnameError> for ParseError {
1164 fn from(err: DnameError) -> ParseError {
1165 match err {
1166 DnameError::ShortInput => ParseError::ShortInput,
1167 other => ParseError::Form(other.into()),
1168 }
1169 }
1170}
1171
1172impl fmt::Display for DnameError {
1175 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1176 match *self {
1177 DnameError::BadLabel(ref err) => err.fmt(f),
1178 DnameError::CompressedName => {
1179 f.write_str("compressed domain name")
1180 }
1181 DnameError::LongName => f.write_str("long domain name"),
1182 DnameError::RelativeName => f.write_str("relative name"),
1183 DnameError::TrailingData => f.write_str("trailing data"),
1184 DnameError::ShortInput => ParseError::ShortInput.fmt(f),
1185 }
1186 }
1187}
1188
1189#[cfg(feature = "std")]
1190impl std::error::Error for DnameError {}
1191
1192#[cfg(test)]
1198pub(crate) mod test {
1199 use super::*;
1200
1201 #[cfg(feature = "std")]
1202 macro_rules! assert_panic {
1203 ( $cond:expr ) => {{
1204 let result = std::panic::catch_unwind(|| $cond);
1205 assert!(result.is_err());
1206 }};
1207 }
1208
1209 #[test]
1210 fn impls() {
1211 fn assert_to_dname<T: ToDname + ?Sized>(_: &T) {}
1212
1213 assert_to_dname(Dname::from_slice(b"\0".as_ref()).unwrap());
1214 assert_to_dname(&Dname::from_octets(b"\0").unwrap());
1215 assert_to_dname(&Dname::from_octets(b"\0".as_ref()).unwrap());
1216
1217 #[cfg(feature = "std")]
1218 {
1219 assert_to_dname(
1220 &Dname::from_octets(Vec::from(b"\0".as_ref())).unwrap(),
1221 );
1222 }
1223 }
1224
1225 #[cfg(feature = "bytes")]
1226 #[test]
1227 fn impls_bytes() {
1228 fn assert_to_dname<T: ToDname + ?Sized>(_: &T) {}
1229
1230 assert_to_dname(
1231 &Dname::from_octets(Bytes::from(b"\0".as_ref())).unwrap(),
1232 );
1233 }
1234
1235 #[test]
1236 fn root() {
1237 assert_eq!(Dname::root_ref().as_slice(), b"\0");
1238 #[cfg(feature = "std")]
1239 {
1240 assert_eq!(Dname::root_vec().as_slice(), b"\0");
1241 }
1242 assert_eq!(Dname::root_slice().as_slice(), b"\0");
1243 }
1244
1245 #[cfg(feature = "bytes")]
1246 #[test]
1247 fn root_bytes() {
1248 assert_eq!(Dname::root_bytes().as_slice(), b"\0");
1249 }
1250
1251 #[test]
1252 #[cfg(feature = "std")]
1253 fn from_slice() {
1254 assert_eq!(
1256 Dname::from_slice(b"\x03www\x07example\x03com\0")
1257 .unwrap()
1258 .as_slice(),
1259 b"\x03www\x07example\x03com\0"
1260 );
1261
1262 assert_eq!(
1264 Dname::from_slice(b"\x03www\x07example\x03com"),
1265 Err(DnameError::RelativeName)
1266 );
1267
1268 assert_eq!(
1270 Dname::from_slice(b"\x03www\x07exa"),
1271 Err(DnameError::ShortInput)
1272 );
1273
1274 let mut slice = [0u8; 65];
1276 slice[0] = 63;
1277 assert!(Dname::from_slice(&slice[..]).is_ok());
1278 let mut slice = [0u8; 66];
1279 slice[0] = 64;
1280 assert!(Dname::from_slice(&slice[..]).is_err());
1281
1282 let mut buf = std::vec::Vec::new();
1284 for _ in 0..25 {
1285 buf.extend_from_slice(b"\x09123456789");
1286 }
1287 assert_eq!(buf.len(), 250);
1288 let mut tmp = buf.clone();
1289 tmp.extend_from_slice(b"\x03123\0");
1290 assert_eq!(Dname::from_slice(&tmp).map(|_| ()), Ok(()));
1291 buf.extend_from_slice(b"\x041234\0");
1292 assert!(Dname::from_slice(&buf).is_err());
1293
1294 assert!(Dname::from_slice(b"\x03com\0\x03www\0").is_err());
1296
1297 assert_eq!(
1299 Dname::from_slice(b"\xa2asdasds"),
1300 Err(LabelTypeError::Undefined.into())
1301 );
1302 assert_eq!(
1303 Dname::from_slice(b"\x62asdasds"),
1304 Err(LabelTypeError::Extended(0x62).into())
1305 );
1306 assert_eq!(
1307 Dname::from_slice(b"\xccasdasds"),
1308 Err(DnameError::CompressedName)
1309 );
1310
1311 assert_eq!(Dname::from_slice(b""), Err(DnameError::ShortInput));
1313 }
1314
1315 #[test]
1320 fn into_relative() {
1321 assert_eq!(
1322 Dname::from_octets(b"\x03www\0".as_ref())
1323 .unwrap()
1324 .into_relative()
1325 .as_slice(),
1326 b"\x03www"
1327 );
1328 }
1329
1330 #[test]
1331 #[cfg(feature = "std")]
1332 fn make_canonical() {
1333 let mut name =
1334 RelativeDname::vec_from_str("wWw.exAmpLE.coM").unwrap();
1335 name.make_canonical();
1336 assert_eq!(
1337 name,
1338 RelativeDname::from_octets(b"\x03www\x07example\x03com").unwrap()
1339 );
1340 }
1341
1342 #[test]
1343 fn is_root() {
1344 assert!(Dname::from_slice(b"\0").unwrap().is_root());
1345 assert!(!Dname::from_slice(b"\x03www\0").unwrap().is_root());
1346 assert!(Dname::root_ref().is_root());
1347 }
1348
1349 pub fn cmp_iter<I>(mut iter: I, labels: &[&[u8]])
1350 where
1351 I: Iterator,
1352 I::Item: AsRef<[u8]>,
1353 {
1354 let mut labels = labels.iter();
1355 loop {
1356 match (iter.next(), labels.next()) {
1357 (Some(left), Some(right)) => {
1358 assert_eq!(left.as_ref(), *right)
1359 }
1360 (None, None) => break,
1361 (_, None) => panic!("extra items in iterator"),
1362 (None, _) => panic!("missing items in iterator"),
1363 }
1364 }
1365 }
1366
1367 #[test]
1368 fn iter() {
1369 cmp_iter(Dname::root_ref().iter(), &[b""]);
1370 cmp_iter(
1371 Dname::from_slice(b"\x03www\x07example\x03com\0")
1372 .unwrap()
1373 .iter(),
1374 &[b"www", b"example", b"com", b""],
1375 );
1376 }
1377
1378 pub fn cmp_iter_back<I>(mut iter: I, labels: &[&[u8]])
1379 where
1380 I: DoubleEndedIterator,
1381 I::Item: AsRef<[u8]>,
1382 {
1383 let mut labels = labels.iter();
1384 loop {
1385 match (iter.next_back(), labels.next()) {
1386 (Some(left), Some(right)) => {
1387 assert_eq!(left.as_ref(), *right)
1388 }
1389 (None, None) => break,
1390 (_, None) => panic!("extra items in iterator"),
1391 (None, _) => panic!("missing items in iterator"),
1392 }
1393 }
1394 }
1395
1396 #[test]
1397 fn iter_back() {
1398 cmp_iter_back(Dname::root_ref().iter(), &[b""]);
1399 cmp_iter_back(
1400 Dname::from_slice(b"\x03www\x07example\x03com\0")
1401 .unwrap()
1402 .iter(),
1403 &[b"", b"com", b"example", b"www"],
1404 );
1405 }
1406
1407 #[test]
1408 fn iter_suffixes() {
1409 cmp_iter(Dname::root_ref().iter_suffixes(), &[b"\0"]);
1410 cmp_iter(
1411 Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1412 .unwrap()
1413 .iter_suffixes(),
1414 &[
1415 b"\x03www\x07example\x03com\0",
1416 b"\x07example\x03com\0",
1417 b"\x03com\0",
1418 b"\0",
1419 ],
1420 );
1421 }
1422
1423 #[test]
1424 fn label_count() {
1425 assert_eq!(Dname::root_ref().label_count(), 1);
1426 assert_eq!(
1427 Dname::from_slice(b"\x03www\x07example\x03com\0")
1428 .unwrap()
1429 .label_count(),
1430 4
1431 );
1432 }
1433
1434 #[test]
1435 fn first() {
1436 assert_eq!(Dname::root_ref().first().as_slice(), b"");
1437 assert_eq!(
1438 Dname::from_slice(b"\x03www\x07example\x03com\0")
1439 .unwrap()
1440 .first()
1441 .as_slice(),
1442 b"www"
1443 );
1444 }
1445
1446 #[test]
1447 fn last() {
1448 assert_eq!(Dname::root_ref().last().as_slice(), b"");
1449 assert_eq!(
1450 Dname::from_slice(b"\x03www\x07example\x03com\0")
1451 .unwrap()
1452 .last()
1453 .as_slice(),
1454 b""
1455 );
1456 }
1457
1458 #[test]
1459 fn starts_with() {
1460 let root = Dname::root_ref();
1461 let wecr =
1462 Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1463 .unwrap();
1464
1465 assert!(root.starts_with(&root));
1466 assert!(wecr.starts_with(&wecr));
1467
1468 assert!(root.starts_with(&RelativeDname::empty_ref()));
1469 assert!(wecr.starts_with(&RelativeDname::empty_ref()));
1470
1471 let test = RelativeDname::from_slice(b"\x03www").unwrap();
1472 assert!(!root.starts_with(&test));
1473 assert!(wecr.starts_with(&test));
1474
1475 let test = RelativeDname::from_slice(b"\x03www\x07example").unwrap();
1476 assert!(!root.starts_with(&test));
1477 assert!(wecr.starts_with(&test));
1478
1479 let test =
1480 RelativeDname::from_slice(b"\x03www\x07example\x03com").unwrap();
1481 assert!(!root.starts_with(&test));
1482 assert!(wecr.starts_with(&test));
1483
1484 let test = RelativeDname::from_slice(b"\x07example\x03com").unwrap();
1485 assert!(!root.starts_with(&test));
1486 assert!(!wecr.starts_with(&test));
1487
1488 let test = RelativeDname::from_octets(b"\x03www".as_ref())
1489 .unwrap()
1490 .chain(
1491 RelativeDname::from_octets(b"\x07example".as_ref()).unwrap(),
1492 )
1493 .unwrap();
1494 assert!(!root.starts_with(&test));
1495 assert!(wecr.starts_with(&test));
1496
1497 let test = test
1498 .chain(RelativeDname::from_octets(b"\x03com".as_ref()).unwrap())
1499 .unwrap();
1500 assert!(!root.starts_with(&test));
1501 assert!(wecr.starts_with(&test));
1502 }
1503
1504 #[test]
1505 fn ends_with() {
1506 let root = Dname::root_ref();
1507 let wecr =
1508 Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1509 .unwrap();
1510
1511 for name in wecr.iter_suffixes() {
1512 if name.is_root() {
1513 assert!(root.ends_with(&name));
1514 } else {
1515 assert!(!root.ends_with(&name));
1516 }
1517 assert!(wecr.ends_with(&name));
1518 }
1519 }
1520
1521 #[test]
1522 fn is_label_start() {
1523 let wecr = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
1524
1525 assert!(wecr.is_label_start(0)); assert!(!wecr.is_label_start(1)); assert!(!wecr.is_label_start(2)); assert!(!wecr.is_label_start(3)); assert!(wecr.is_label_start(4)); assert!(!wecr.is_label_start(5)); assert!(!wecr.is_label_start(6)); assert!(!wecr.is_label_start(7)); assert!(!wecr.is_label_start(8)); assert!(!wecr.is_label_start(9)); assert!(!wecr.is_label_start(10)); assert!(!wecr.is_label_start(11)); assert!(wecr.is_label_start(12)); assert!(!wecr.is_label_start(13)); assert!(!wecr.is_label_start(14)); assert!(!wecr.is_label_start(15)); assert!(wecr.is_label_start(16)); assert!(!wecr.is_label_start(17)); assert!(!wecr.is_label_start(18)); }
1545
1546 #[test]
1547 #[cfg(feature = "std")]
1548 fn slice() {
1549 let wecr = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
1550
1551 assert_eq!(wecr.slice(..4).as_slice(), b"\x03www");
1552 assert_eq!(wecr.slice(..12).as_slice(), b"\x03www\x07example");
1553 assert_eq!(wecr.slice(4..12).as_slice(), b"\x07example");
1554 assert_eq!(wecr.slice(4..16).as_slice(), b"\x07example\x03com");
1555
1556 assert_panic!(wecr.slice(0..3));
1557 assert_panic!(wecr.slice(1..4));
1558 assert_panic!(wecr.slice(0..11));
1559 assert_panic!(wecr.slice(1..12));
1560 assert_panic!(wecr.slice(0..17));
1561 assert_panic!(wecr.slice(4..17));
1562 assert_panic!(wecr.slice(0..18));
1563 }
1564
1565 #[test]
1566 #[cfg(feature = "std")]
1567 fn slice_from() {
1568 let wecr = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
1569
1570 assert_eq!(
1571 wecr.slice_from(0).as_slice(),
1572 b"\x03www\x07example\x03com\0"
1573 );
1574 assert_eq!(wecr.slice_from(4).as_slice(), b"\x07example\x03com\0");
1575 assert_eq!(wecr.slice_from(12).as_slice(), b"\x03com\0");
1576 assert_eq!(wecr.slice_from(16).as_slice(), b"\0");
1577
1578 assert_panic!(wecr.slice_from(17));
1579 assert_panic!(wecr.slice_from(18));
1580 }
1581
1582 #[test]
1583 #[cfg(feature = "std")]
1584 fn range() {
1585 let wecr =
1586 Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1587 .unwrap();
1588
1589 assert_eq!(wecr.range(0..4).as_slice(), b"\x03www");
1590 assert_eq!(wecr.range(0..12).as_slice(), b"\x03www\x07example");
1591 assert_eq!(wecr.range(4..12).as_slice(), b"\x07example");
1592 assert_eq!(wecr.range(4..16).as_slice(), b"\x07example\x03com");
1593
1594 assert_panic!(wecr.range(0..3));
1595 assert_panic!(wecr.range(1..4));
1596 assert_panic!(wecr.range(0..11));
1597 assert_panic!(wecr.range(1..12));
1598 assert_panic!(wecr.range(0..17));
1599 assert_panic!(wecr.range(4..17));
1600 assert_panic!(wecr.range(0..18));
1601 }
1602
1603 #[test]
1604 #[cfg(feature = "std")]
1605 fn range_from() {
1606 let wecr =
1607 Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1608 .unwrap();
1609
1610 assert_eq!(
1611 wecr.range_from(0).as_slice(),
1612 b"\x03www\x07example\x03com\0"
1613 );
1614 assert_eq!(wecr.range_from(4).as_slice(), b"\x07example\x03com\0");
1615 assert_eq!(wecr.range_from(12).as_slice(), b"\x03com\0");
1616 assert_eq!(wecr.range_from(16).as_slice(), b"\0");
1617
1618 assert_panic!(wecr.range_from(17));
1619 assert_panic!(wecr.range_from(18));
1620 }
1621
1622 #[test]
1623 #[cfg(feature = "std")]
1624 fn split() {
1625 let wecr =
1626 Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1627 .unwrap();
1628
1629 let (left, right) = wecr.split(0);
1630 assert_eq!(left.as_slice(), b"");
1631 assert_eq!(right.as_slice(), b"\x03www\x07example\x03com\0");
1632
1633 let (left, right) = wecr.split(4);
1634 assert_eq!(left.as_slice(), b"\x03www");
1635 assert_eq!(right.as_slice(), b"\x07example\x03com\0");
1636
1637 let (left, right) = wecr.split(12);
1638 assert_eq!(left.as_slice(), b"\x03www\x07example");
1639 assert_eq!(right.as_slice(), b"\x03com\0");
1640
1641 let (left, right) = wecr.split(16);
1642 assert_eq!(left.as_slice(), b"\x03www\x07example\x03com");
1643 assert_eq!(right.as_slice(), b"\0");
1644
1645 assert_panic!(wecr.split(1));
1646 assert_panic!(wecr.split(14));
1647 assert_panic!(wecr.split(17));
1648 assert_panic!(wecr.split(18));
1649 }
1650
1651 #[test]
1652 #[cfg(feature = "std")]
1653 fn truncate() {
1654 let wecr =
1655 Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1656 .unwrap();
1657
1658 assert_eq!(wecr.clone().truncate(0).as_slice(), b"");
1659 assert_eq!(wecr.clone().truncate(4).as_slice(), b"\x03www");
1660 assert_eq!(
1661 wecr.clone().truncate(12).as_slice(),
1662 b"\x03www\x07example"
1663 );
1664 assert_eq!(
1665 wecr.clone().truncate(16).as_slice(),
1666 b"\x03www\x07example\x03com"
1667 );
1668
1669 assert_panic!(wecr.clone().truncate(1));
1670 assert_panic!(wecr.clone().truncate(14));
1671 assert_panic!(wecr.clone().truncate(17));
1672 assert_panic!(wecr.clone().truncate(18));
1673 }
1674
1675 #[test]
1676 fn split_first() {
1677 let wecr =
1678 Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1679 .unwrap();
1680
1681 let (label, wecr) = wecr.split_first().unwrap();
1682 assert_eq!(label, b"www".as_ref());
1683 assert_eq!(wecr.as_slice(), b"\x07example\x03com\0");
1684
1685 let (label, wecr) = wecr.split_first().unwrap();
1686 assert_eq!(label, b"example");
1687 assert_eq!(wecr.as_slice(), b"\x03com\0");
1688
1689 let (label, wecr) = wecr.split_first().unwrap();
1690 assert_eq!(label, b"com");
1691 assert_eq!(wecr.as_slice(), b"\0");
1692 assert!(wecr.split_first().is_none());
1693 }
1694
1695 #[test]
1696 fn parent() {
1697 let wecr =
1698 Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1699 .unwrap();
1700
1701 let wecr = wecr.parent().unwrap();
1702 assert_eq!(wecr.as_slice(), b"\x07example\x03com\0");
1703 let wecr = wecr.parent().unwrap();
1704 assert_eq!(wecr.as_slice(), b"\x03com\0");
1705 let wecr = wecr.parent().unwrap();
1706 assert_eq!(wecr.as_slice(), b"\0");
1707 assert!(wecr.parent().is_none());
1708 }
1709
1710 #[test]
1711 fn strip_suffix() {
1712 let wecr =
1713 Dname::from_octets(b"\x03www\x07example\x03com\0".as_ref())
1714 .unwrap();
1715 let ecr =
1716 Dname::from_octets(b"\x07example\x03com\0".as_ref()).unwrap();
1717 let cr = Dname::from_octets(b"\x03com\0".as_ref()).unwrap();
1718 let wenr =
1719 Dname::from_octets(b"\x03www\x07example\x03net\0".as_ref())
1720 .unwrap();
1721 let enr =
1722 Dname::from_octets(b"\x07example\x03net\0".as_ref()).unwrap();
1723 let nr = Dname::from_octets(b"\x03net\0".as_ref()).unwrap();
1724
1725 assert_eq!(wecr.clone().strip_suffix(&wecr).unwrap().as_slice(), b"");
1726 assert_eq!(
1727 wecr.clone().strip_suffix(&ecr).unwrap().as_slice(),
1728 b"\x03www"
1729 );
1730 assert_eq!(
1731 wecr.clone().strip_suffix(&cr).unwrap().as_slice(),
1732 b"\x03www\x07example"
1733 );
1734 assert_eq!(
1735 wecr.clone()
1736 .strip_suffix(&Dname::root_slice())
1737 .unwrap()
1738 .as_slice(),
1739 b"\x03www\x07example\x03com"
1740 );
1741
1742 assert_eq!(
1743 wecr.clone().strip_suffix(&wenr).unwrap_err().as_slice(),
1744 b"\x03www\x07example\x03com\0"
1745 );
1746 assert_eq!(
1747 wecr.clone().strip_suffix(&enr).unwrap_err().as_slice(),
1748 b"\x03www\x07example\x03com\0"
1749 );
1750 assert_eq!(
1751 wecr.clone().strip_suffix(&nr).unwrap_err().as_slice(),
1752 b"\x03www\x07example\x03com\0"
1753 );
1754 }
1755
1756 #[test]
1757 #[cfg(feature = "std")]
1758 fn parse() {
1759 let mut p = Parser::from_static(b"\x03www\x07example\x03com\0af");
1761 assert_eq!(
1762 Dname::parse(&mut p).unwrap().as_slice(),
1763 b"\x03www\x07example\x03com\0"
1764 );
1765 assert_eq!(p.peek_all(), b"af");
1766
1767 let mut p = Parser::from_static(b"\x03www\x07exam");
1769 assert_eq!(Dname::parse(&mut p), Err(ParseError::ShortInput));
1770
1771 let mut p = Parser::from_static(b"\x03www\x07example");
1773 assert_eq!(Dname::parse(&mut p), Err(ParseError::ShortInput));
1774
1775 let mut p = Parser::from_static(b"\x03com\x03www\x07example\xc0\0");
1777 p.advance(4).unwrap();
1778 assert_eq!(
1779 Dname::parse(&mut p),
1780 Err(DnameError::CompressedName.into())
1781 );
1782
1783 let mut p = Parser::from_static(b"\x03www\x07example\xbffoo");
1785 assert!(Dname::parse(&mut p).is_err());
1786
1787 let mut buf = Vec::new();
1789 for _ in 0..50 {
1790 buf.extend_from_slice(b"\x041234");
1791 }
1792 buf.extend_from_slice(b"\x03123\0");
1793 assert_eq!(buf.len(), 255);
1794 let mut p = Parser::from_ref(buf.as_slice());
1795 assert!(Dname::parse(&mut p).is_ok());
1796 assert_eq!(p.peek_all(), b"");
1797
1798 let mut buf = Vec::new();
1800 for _ in 0..51 {
1801 buf.extend_from_slice(b"\x041234");
1802 }
1803 buf.extend_from_slice(b"\0");
1804 assert_eq!(buf.len(), 256);
1805 let mut p = Parser::from_ref(buf.as_slice());
1806 assert_eq!(Dname::parse(&mut p), Err(DnameError::LongName.into()));
1807 }
1808
1809 #[test]
1813 #[cfg(feature = "std")]
1814 fn compose_canonical() {
1815 use octseq::builder::infallible;
1816
1817 let mut buf = Vec::new();
1818 infallible(
1819 Dname::from_slice(b"\x03wWw\x07exaMPle\x03com\0")
1820 .unwrap()
1821 .compose_canonical(&mut buf),
1822 );
1823 assert_eq!(buf.as_slice(), b"\x03www\x07example\x03com\0");
1824 }
1825
1826 #[test]
1827 #[cfg(feature = "std")]
1828 fn from_str() {
1829 use core::str::FromStr;
1834 use std::vec::Vec;
1835
1836 assert_eq!(
1837 Dname::<Vec<u8>>::from_str(".").unwrap().as_slice(),
1838 b"\0"
1839 );
1840 assert_eq!(
1841 Dname::<Vec<u8>>::from_str("www.example.com")
1842 .unwrap()
1843 .as_slice(),
1844 b"\x03www\x07example\x03com\0"
1845 );
1846 assert_eq!(
1847 Dname::<Vec<u8>>::from_str("www.example.com.")
1848 .unwrap()
1849 .as_slice(),
1850 b"\x03www\x07example\x03com\0"
1851 );
1852 }
1853
1854 #[test]
1855 fn eq() {
1856 assert_eq!(
1857 Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap(),
1858 Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap()
1859 );
1860 assert_eq!(
1861 Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap(),
1862 Dname::from_slice(b"\x03wWw\x07eXAMple\x03Com\0").unwrap()
1863 );
1864 assert_eq!(
1865 Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap(),
1866 &RelativeDname::from_octets(b"\x03www".as_ref())
1867 .unwrap()
1868 .chain(
1869 RelativeDname::from_octets(
1870 b"\x07example\x03com".as_ref()
1871 )
1872 .unwrap()
1873 )
1874 .unwrap()
1875 .chain(Dname::root_ref())
1876 .unwrap()
1877 );
1878 assert_eq!(
1879 Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap(),
1880 &RelativeDname::from_octets(b"\x03wWw".as_ref())
1881 .unwrap()
1882 .chain(
1883 RelativeDname::from_octets(
1884 b"\x07eXAMple\x03coM".as_ref()
1885 )
1886 .unwrap()
1887 )
1888 .unwrap()
1889 .chain(Dname::root_ref())
1890 .unwrap()
1891 );
1892 assert_ne!(
1893 Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap(),
1894 Dname::from_slice(b"\x03ww4\x07example\x03com\0").unwrap()
1895 );
1896 assert_ne!(
1897 Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap(),
1898 &RelativeDname::from_octets(b"\x03www".as_ref())
1899 .unwrap()
1900 .chain(
1901 RelativeDname::from_octets(
1902 b"\x073xample\x03com".as_ref()
1903 )
1904 .unwrap()
1905 )
1906 .unwrap()
1907 .chain(Dname::root_ref())
1908 .unwrap()
1909 );
1910 }
1911
1912 #[test]
1913 fn cmp() {
1914 use core::cmp::Ordering;
1915
1916 let names = [
1918 Dname::from_slice(b"\x07example\0").unwrap(),
1919 Dname::from_slice(b"\x01a\x07example\0").unwrap(),
1920 Dname::from_slice(b"\x08yljkjljk\x01a\x07example\0").unwrap(),
1921 Dname::from_slice(b"\x01Z\x01a\x07example\0").unwrap(),
1922 Dname::from_slice(b"\x04zABC\x01a\x07example\0").unwrap(),
1923 Dname::from_slice(b"\x01z\x07example\0").unwrap(),
1924 Dname::from_slice(b"\x01\x01\x01z\x07example\0").unwrap(),
1925 Dname::from_slice(b"\x01*\x01z\x07example\0").unwrap(),
1926 Dname::from_slice(b"\x01\xc8\x01z\x07example\0").unwrap(),
1927 ];
1928 for i in 0..names.len() {
1929 for j in 0..names.len() {
1930 let ord = i.cmp(&j);
1931 assert_eq!(names[i].partial_cmp(names[j]), Some(ord));
1932 assert_eq!(names[i].cmp(names[j]), ord);
1933 }
1934 }
1935
1936 let n1 = Dname::from_slice(b"\x03www\x07example\x03com\0").unwrap();
1937 let n2 = Dname::from_slice(b"\x03wWw\x07eXAMple\x03Com\0").unwrap();
1938 assert_eq!(n1.partial_cmp(n2), Some(Ordering::Equal));
1939 assert_eq!(n1.cmp(n2), Ordering::Equal);
1940 }
1941
1942 #[test]
1943 #[cfg(feature = "std")]
1944 fn hash() {
1945 use std::collections::hash_map::DefaultHasher;
1946 use std::hash::{Hash, Hasher};
1947
1948 let mut s1 = DefaultHasher::new();
1949 let mut s2 = DefaultHasher::new();
1950 Dname::from_slice(b"\x03www\x07example\x03com\0")
1951 .unwrap()
1952 .hash(&mut s1);
1953 Dname::from_slice(b"\x03wWw\x07eXAMple\x03Com\0")
1954 .unwrap()
1955 .hash(&mut s2);
1956 assert_eq!(s1.finish(), s2.finish());
1957 }
1958
1959 #[cfg(all(feature = "serde", feature = "std"))]
1962 #[test]
1963 fn ser_de() {
1964 use serde_test::{assert_tokens, Configure, Token};
1965
1966 let name = Dname::<Vec<u8>>::from_str("www.example.com.").unwrap();
1967 assert_tokens(
1968 &name.clone().compact(),
1969 &[
1970 Token::NewtypeStruct { name: "Dname" },
1971 Token::ByteBuf(b"\x03www\x07example\x03com\0"),
1972 ],
1973 );
1974 assert_tokens(
1975 &name.readable(),
1976 &[
1977 Token::NewtypeStruct { name: "Dname" },
1978 Token::Str("www.example.com"),
1979 ],
1980 );
1981 assert_tokens(
1982 &Dname::root_vec().readable(),
1983 &[Token::NewtypeStruct { name: "Dname" }, Token::Str(".")],
1984 );
1985 }
1986}