1use super::super::scan::BadSymbol;
7use super::super::wire::{FormError, ParseError};
8use super::builder::{
9 LabelFromStrError, LabelFromStrErrorEnum, parse_escape,
10};
11use core::str::FromStr;
12use core::{borrow, cmp, fmt, hash, iter, mem, ops, slice};
13use octseq::builder::OctetsBuilder;
14
15#[repr(transparent)]
41pub struct Label([u8]);
42
43impl Label {
46 pub const MAX_LEN: usize = 63;
48
49 pub(super) const unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
55 unsafe { mem::transmute(slice) }
57 }
58
59 pub(super) unsafe fn from_slice_mut_unchecked(
65 slice: &mut [u8],
66 ) -> &mut Self {
67 unsafe { mem::transmute(slice) }
69 }
70
71 #[must_use]
75 pub fn root() -> &'static Self {
76 unsafe { Self::from_slice_unchecked(b"") }
77 }
78
79 #[must_use]
81 pub fn wildcard() -> &'static Self {
82 unsafe { Self::from_slice_unchecked(b"*") }
83 }
84
85 pub fn from_slice(slice: &[u8]) -> Result<&Self, LongLabelError> {
89 if slice.len() > Label::MAX_LEN {
90 Err(LongLabelError(()))
91 } else {
92 Ok(unsafe { Self::from_slice_unchecked(slice) })
93 }
94 }
95
96 pub fn from_slice_mut(
100 slice: &mut [u8],
101 ) -> Result<&mut Self, LongLabelError> {
102 if slice.len() > Label::MAX_LEN {
103 Err(LongLabelError(()))
104 } else {
105 Ok(unsafe { Self::from_slice_mut_unchecked(slice) })
106 }
107 }
108
109 pub const fn split_from(
114 slice: &[u8],
115 ) -> Result<(&Self, &[u8]), SplitLabelError> {
116 let head = match slice.first() {
117 Some(ch) => *ch,
118 None => return Err(SplitLabelError::ShortInput),
119 };
120 let end = match head {
121 0..=0x3F => (head as usize) + 1,
122 0x40..=0x7F => {
123 return Err(SplitLabelError::BadType(
124 LabelTypeError::Extended(head),
125 ));
126 }
127 0xC0..=0xFF => {
128 if slice.len() < 2 {
129 return Err(SplitLabelError::ShortInput);
130 }
131 let res = slice[1] as u16;
132 let res = res | (((head as u16) & 0x3F) << 8);
133 return Err(SplitLabelError::Pointer(res));
134 }
135 _ => {
136 return Err(SplitLabelError::BadType(
137 LabelTypeError::Undefined,
138 ));
139 }
140 };
141 if slice.len() < end {
142 return Err(SplitLabelError::ShortInput);
143 }
144
145 let (left, right) = slice.split_at(end);
146 let (_, label_data) = left.split_at(1);
147 Ok((unsafe { Self::from_slice_unchecked(label_data) }, right))
148 }
149
150 pub fn split_from_mut(
155 slice: &mut [u8],
156 ) -> Result<(&mut Self, &mut [u8]), SplitLabelError> {
157 let head = match slice.first_mut() {
158 Some(ch) => *ch,
159 None => return Err(SplitLabelError::ShortInput),
160 };
161 let end = match head {
162 0..=0x3F => (head as usize) + 1,
163 0x40..=0x7F => {
164 return Err(SplitLabelError::BadType(
165 LabelTypeError::Extended(head),
166 ));
167 }
168 0xC0..=0xFF => {
169 let res = match slice.get(1) {
170 Some(ch) => u16::from(*ch),
171 None => return Err(SplitLabelError::ShortInput),
172 };
173 let res = res | ((u16::from(head) & 0x3F) << 8);
174 return Err(SplitLabelError::Pointer(res));
175 }
176 _ => {
177 return Err(SplitLabelError::BadType(
178 LabelTypeError::Undefined,
179 ));
180 }
181 };
182 if slice.len() < end {
183 return Err(SplitLabelError::ShortInput);
184 }
185 let (left, right) = slice.split_at_mut(end);
186 Ok((
187 unsafe { Self::from_slice_mut_unchecked(&mut left[1..]) },
188 right,
189 ))
190 }
191
192 pub fn iter(&self) -> iter::Copied<slice::Iter<'_, u8>> {
194 self.as_slice().iter().copied()
195 }
196
197 #[must_use]
208 pub fn iter_slice(slice: &[u8], start: usize) -> SliceLabelsIter<'_> {
209 SliceLabelsIter { slice, start }
210 }
211
212 #[must_use]
214 pub const fn as_slice(&self) -> &[u8] {
215 &self.0
216 }
217
218 pub fn as_slice_mut(&mut self) -> &mut [u8] {
220 &mut self.0
221 }
222
223 pub fn make_canonical(&mut self) {
228 self.0.make_ascii_lowercase()
229 }
230
231 pub(super) fn make_slice_canonical(mut slice: &mut [u8]) {
242 while !slice.is_empty() {
243 let (head, tail) =
244 Label::split_from_mut(slice).expect("invalid name");
245 head.make_canonical();
246 slice = tail;
247 }
248 }
249
250 #[must_use]
254 pub fn to_canonical(&self) -> OwnedLabel {
255 let mut res = OwnedLabel::from_label(self);
256 res.make_canonical();
257 res
258 }
259
260 #[must_use]
262 pub fn composed_cmp(&self, other: &Self) -> cmp::Ordering {
263 match self.0.len().cmp(&other.0.len()) {
264 cmp::Ordering::Equal => {}
265 other => return other,
266 }
267 self.0.cmp(other.as_ref())
268 }
269
270 #[must_use]
272 pub fn lowercase_composed_cmp(&self, other: &Self) -> cmp::Ordering {
273 match self.0.len().cmp(&other.0.len()) {
274 cmp::Ordering::Equal => {}
275 other => return other,
276 }
277 self.cmp(other)
278 }
279
280 pub fn compose<Builder: OctetsBuilder + ?Sized>(
285 &self,
286 target: &mut Builder,
287 ) -> Result<(), Builder::AppendError> {
288 target.append_slice(&[self.len() as u8])?;
289 target.append_slice(self.as_slice())
290 }
291
292 pub fn compose_canonical<Builder: OctetsBuilder + ?Sized>(
298 &self,
299 target: &mut Builder,
300 ) -> Result<(), Builder::AppendError> {
301 target.append_slice(&[self.len() as u8])?;
302 for ch in self.into_iter() {
303 target.append_slice(&[ch.to_ascii_lowercase()])?;
304 }
305 Ok(())
306 }
307}
308
309impl Label {
312 #[must_use]
317 pub fn len(&self) -> usize {
318 self.as_slice().len()
319 }
320
321 #[must_use]
323 pub const fn is_empty(&self) -> bool {
324 self.as_slice().is_empty()
325 }
326
327 #[must_use]
329 pub const fn is_root(&self) -> bool {
330 self.is_empty()
331 }
332
333 #[must_use]
335 pub fn is_wildcard(&self) -> bool {
336 self.0.len() == 1 && self.0[0] == b'*'
337 }
338
339 #[must_use]
344 pub fn compose_len(&self) -> u16 {
345 u16::try_from(self.len()).expect("long label") + 1
346 }
347}
348
349impl AsRef<[u8]> for Label {
352 fn as_ref(&self) -> &[u8] {
353 self.as_slice()
354 }
355}
356
357impl AsMut<[u8]> for Label {
358 fn as_mut(&mut self) -> &mut [u8] {
359 self.as_slice_mut()
360 }
361}
362
363#[cfg(feature = "alloc")]
366impl alloc::borrow::ToOwned for Label {
367 type Owned = OwnedLabel;
368
369 fn to_owned(&self) -> Self::Owned {
370 self.into()
371 }
372}
373
374impl<T: AsRef<[u8]> + ?Sized> PartialEq<T> for Label {
377 fn eq(&self, other: &T) -> bool {
378 self.as_slice().eq_ignore_ascii_case(other.as_ref())
379 }
380}
381
382impl Eq for Label {}
383
384impl PartialOrd for Label {
387 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
397 Some(self.cmp(other))
398 }
399}
400
401impl Ord for Label {
402 fn cmp(&self, other: &Self) -> cmp::Ordering {
403 self.as_slice()
404 .iter()
405 .map(u8::to_ascii_lowercase)
406 .cmp(other.as_slice().iter().map(u8::to_ascii_lowercase))
407 }
408}
409
410impl hash::Hash for Label {
413 fn hash<H: hash::Hasher>(&self, state: &mut H) {
414 (self.len() as u8).hash(state);
417 for c in self.iter() {
418 c.to_ascii_lowercase().hash(state)
419 }
420 }
421}
422
423impl<'a> IntoIterator for &'a Label {
426 type Item = u8;
427 type IntoIter = iter::Copied<slice::Iter<'a, u8>>;
428
429 fn into_iter(self) -> Self::IntoIter {
430 self.iter()
431 }
432}
433
434impl fmt::Display for Label {
437 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
438 for ch in self.iter() {
439 if ch == b' ' || ch == b'.' || ch == b'\\' {
440 write!(f, "\\{}", ch as char)?;
441 } else if !(0x20..0x7F).contains(&ch) {
442 write!(f, "\\{:03}", ch)?;
443 } else {
444 write!(f, "{}", (ch as char))?;
445 }
446 }
447 Ok(())
448 }
449}
450
451impl fmt::Debug for Label {
452 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
453 f.write_str("Label(")?;
454 fmt::Display::fmt(self, f)?;
455 f.write_str(")")
456 }
457}
458
459#[derive(Clone, Copy)]
469pub struct OwnedLabel([u8; 64]);
470
471impl OwnedLabel {
472 #[must_use]
474 pub fn from_label(label: &Label) -> Self {
475 let mut res = [0; 64];
476 res[0] = label.len() as u8;
477 res[1..=label.len()].copy_from_slice(label.as_slice());
478 OwnedLabel(res)
479 }
480
481 pub fn from_chars(
483 mut chars: impl Iterator<Item = char>,
484 ) -> Result<Self, LabelFromStrError> {
485 let mut res = [0u8; 64];
486 while let Some(ch) = chars.next() {
487 if res[0] as usize >= Label::MAX_LEN {
488 return Err(LabelFromStrErrorEnum::LongLabel.into());
489 }
490 let ch = match ch {
491 ' '..='-' | '/'..='[' | ']'..='~' => ch as u8,
492 '\\' => parse_escape(&mut chars, res[0] > 0)?,
493 _ => return Err(BadSymbol::non_ascii().into()),
494 };
495 res[(res[0] as usize) + 1] = ch;
496 res[0] += 1;
497 }
498 Ok(OwnedLabel(res))
499 }
500
501 pub fn make_canonical(&mut self) {
506 self.0[1..].make_ascii_lowercase()
507 }
508
509 #[must_use]
511 pub fn as_label(&self) -> &Label {
512 unsafe {
513 Label::from_slice_unchecked(&self.0[1..=(self.0[0] as usize)])
514 }
515 }
516
517 pub fn as_label_mut(&mut self) -> &mut Label {
519 let len = self.0[0] as usize;
520 unsafe { Label::from_slice_mut_unchecked(&mut self.0[1..=len]) }
521 }
522
523 #[must_use]
525 pub fn as_wire_slice(&self) -> &[u8] {
526 let len = self.0[0] as usize;
527 &self.0[..=len]
528 }
529}
530
531impl<'a> From<&'a Label> for OwnedLabel {
534 fn from(label: &'a Label) -> Self {
535 Self::from_label(label)
536 }
537}
538
539impl FromStr for OwnedLabel {
542 type Err = LabelFromStrError;
543
544 fn from_str(s: &str) -> Result<Self, Self::Err> {
545 Self::from_chars(s.chars())
546 }
547}
548
549impl ops::Deref for OwnedLabel {
552 type Target = Label;
553
554 fn deref(&self) -> &Label {
555 self.as_label()
556 }
557}
558
559impl ops::DerefMut for OwnedLabel {
560 fn deref_mut(&mut self) -> &mut Label {
561 self.as_label_mut()
562 }
563}
564
565impl AsRef<Label> for OwnedLabel {
566 fn as_ref(&self) -> &Label {
567 self.as_label()
568 }
569}
570
571impl AsRef<[u8]> for OwnedLabel {
572 fn as_ref(&self) -> &[u8] {
573 self.as_label().as_slice()
574 }
575}
576
577impl AsMut<Label> for OwnedLabel {
578 fn as_mut(&mut self) -> &mut Label {
579 self.as_label_mut()
580 }
581}
582
583impl AsMut<[u8]> for OwnedLabel {
584 fn as_mut(&mut self) -> &mut [u8] {
585 self.as_label_mut().as_slice_mut()
586 }
587}
588
589impl borrow::Borrow<Label> for OwnedLabel {
590 fn borrow(&self) -> &Label {
591 self.as_label()
592 }
593}
594
595impl borrow::BorrowMut<Label> for OwnedLabel {
596 fn borrow_mut(&mut self) -> &mut Label {
597 self.as_label_mut()
598 }
599}
600
601impl<T: AsRef<Label>> PartialEq<T> for OwnedLabel {
604 fn eq(&self, other: &T) -> bool {
605 self.as_label().eq(other.as_ref())
606 }
607}
608
609impl Eq for OwnedLabel {}
610
611impl<T: AsRef<Label>> PartialOrd<T> for OwnedLabel {
614 fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
615 self.as_label().partial_cmp(other.as_ref())
616 }
617}
618
619impl Ord for OwnedLabel {
620 fn cmp(&self, other: &Self) -> cmp::Ordering {
621 self.as_label().cmp(other.as_ref())
622 }
623}
624
625impl hash::Hash for OwnedLabel {
628 fn hash<H: hash::Hasher>(&self, state: &mut H) {
629 self.as_label().hash(state)
630 }
631}
632
633impl fmt::Display for OwnedLabel {
636 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
637 self.as_label().fmt(f)
638 }
639}
640
641impl fmt::Debug for OwnedLabel {
642 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
643 f.debug_tuple("OwnedLabel").field(&self.as_label()).finish()
644 }
645}
646
647#[cfg(feature = "serde")]
650impl serde::Serialize for OwnedLabel {
651 fn serialize<S: serde::Serializer>(
652 &self,
653 serializer: S,
654 ) -> Result<S::Ok, S::Error> {
655 use octseq::serde::SerializeOctets;
656
657 if serializer.is_human_readable() {
658 serializer.serialize_newtype_struct(
659 "OwnedLabel",
660 &format_args!("{}", self),
661 )
662 } else {
663 serializer.serialize_newtype_struct(
664 "OwnedLabel",
665 &self.as_label().as_slice().as_serialized_octets(),
666 )
667 }
668 }
669}
670
671#[cfg(feature = "serde")]
672impl<'de> serde::Deserialize<'de> for OwnedLabel {
673 fn deserialize<D: serde::Deserializer<'de>>(
674 deserializer: D,
675 ) -> Result<Self, D::Error> {
676 use serde::de::Error;
677
678 struct InnerVisitor;
679
680 impl<'de> serde::de::Visitor<'de> for InnerVisitor {
681 type Value = OwnedLabel;
682
683 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
684 f.write_str("an domain name label")
685 }
686
687 fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
688 OwnedLabel::from_str(v).map_err(E::custom)
689 }
690
691 fn visit_borrowed_bytes<E: serde::de::Error>(
692 self,
693 value: &'de [u8],
694 ) -> Result<Self::Value, E> {
695 Label::from_slice(value)
696 .map(OwnedLabel::from_label)
697 .map_err(E::custom)
698 }
699 }
700
701 struct NewtypeVisitor;
702
703 impl<'de> serde::de::Visitor<'de> for NewtypeVisitor {
704 type Value = OwnedLabel;
705
706 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
707 f.write_str("an domain name label")
708 }
709
710 fn visit_newtype_struct<D: serde::Deserializer<'de>>(
711 self,
712 deserializer: D,
713 ) -> Result<Self::Value, D::Error> {
714 if deserializer.is_human_readable() {
715 deserializer.deserialize_str(InnerVisitor)
716 } else {
717 deserializer.deserialize_bytes(InnerVisitor)
718 }
719 }
720 }
721
722 deserializer.deserialize_newtype_struct("OwnedLabel", NewtypeVisitor)
723 }
724}
725
726pub struct SliceLabelsIter<'a> {
734 slice: &'a [u8],
736
737 start: usize,
741}
742
743impl<'a> Iterator for SliceLabelsIter<'a> {
744 type Item = &'a Label;
745
746 fn next(&mut self) -> Option<Self::Item> {
747 if self.start >= self.slice.len() {
748 return None;
749 }
750
751 loop {
752 match Label::split_from(&self.slice[self.start..]) {
753 Ok((label, _)) => {
754 if label.is_root() {
755 self.start = usize::MAX;
756 } else {
757 self.start += label.len() + 1;
758 }
759 return Some(label);
760 }
761 Err(SplitLabelError::Pointer(pos)) => {
762 let pos = pos as usize;
763 if pos > self.start {
764 self.start = usize::MAX;
767 return None;
768 }
769 self.start = pos;
770 continue;
771 }
772 Err(_) => {
773 self.start = usize::MAX;
774 return None;
775 }
776 }
777 }
778 }
779}
780
781#[derive(Clone, Copy, Debug, Eq, PartialEq)]
787pub enum LabelTypeError {
788 Undefined,
790
791 Extended(u8),
796}
797
798impl fmt::Display for LabelTypeError {
801 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
802 match *self {
803 LabelTypeError::Undefined => f.write_str("undefined label type"),
804 LabelTypeError::Extended(value) => {
805 write!(f, "unknown extended label 0x{:02x}", value)
806 }
807 }
808 }
809}
810
811impl core::error::Error for LabelTypeError {}
812
813#[derive(Clone, Copy, Debug, Eq, PartialEq)]
817pub struct LongLabelError(());
818
819impl fmt::Display for LongLabelError {
822 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
823 f.write_str("long label")
824 }
825}
826
827impl core::error::Error for LongLabelError {}
828
829#[derive(Clone, Copy, Debug, Eq, PartialEq)]
833pub enum SplitLabelError {
834 Pointer(u16),
836
837 BadType(LabelTypeError),
839
840 ShortInput,
842}
843
844impl From<LabelTypeError> for SplitLabelError {
847 fn from(err: LabelTypeError) -> SplitLabelError {
848 SplitLabelError::BadType(err)
849 }
850}
851
852impl From<SplitLabelError> for ParseError {
853 fn from(err: SplitLabelError) -> ParseError {
854 match err {
855 SplitLabelError::Pointer(_) => {
856 ParseError::Form(FormError::new("compressed domain name"))
857 }
858 SplitLabelError::BadType(_) => {
859 ParseError::Form(FormError::new("invalid label type"))
860 }
861 SplitLabelError::ShortInput => ParseError::ShortInput,
862 }
863 }
864}
865
866impl fmt::Display for SplitLabelError {
869 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
870 match *self {
871 SplitLabelError::Pointer(_) => {
872 f.write_str("compressed domain name")
873 }
874 SplitLabelError::BadType(ltype) => ltype.fmt(f),
875 SplitLabelError::ShortInput => ParseError::ShortInput.fmt(f),
876 }
877 }
878}
879
880impl core::error::Error for SplitLabelError {}
881
882#[cfg(test)]
885mod test {
886 use super::*;
887
888 #[test]
889 fn from_slice() {
890 let x = [0u8; 10];
891 assert_eq!(Label::from_slice(&x[..]).unwrap().as_slice(), &x[..]);
892 let x = [0u8; 63];
893 assert_eq!(Label::from_slice(&x[..]).unwrap().as_slice(), &x[..]);
894 let x = [0u8; 64];
895 assert!(Label::from_slice(&x[..]).is_err());
896 }
897
898 #[test]
899 fn split_from() {
900 assert_eq!(
902 Label::split_from(b"\x03www\x07example\x03com\0").unwrap(),
903 (
904 Label::from_slice(b"www").unwrap(),
905 &b"\x07example\x03com\0"[..]
906 )
907 );
908
909 assert_eq!(
911 Label::split_from(b"\x03www").unwrap(),
912 (Label::from_slice(b"www").unwrap(), &b""[..])
913 );
914
915 assert_eq!(
917 Label::split_from(b"\0some").unwrap(),
918 (Label::from_slice(b"").unwrap(), &b"some"[..])
919 );
920
921 assert_eq!(
923 Label::split_from(b"\x03ww"),
924 Err(SplitLabelError::ShortInput)
925 );
926
927 assert_eq!(Label::split_from(b""), Err(SplitLabelError::ShortInput));
929
930 assert_eq!(
932 Label::split_from(b"\xc0\x05foo"),
933 Err(SplitLabelError::Pointer(5))
934 );
935
936 assert_eq!(
938 Label::split_from(b"\xb3foo"),
939 Err(LabelTypeError::Undefined.into())
940 );
941
942 assert_eq!(
944 Label::split_from(b"\x66foo"),
945 Err(LabelTypeError::Extended(0x66).into())
946 );
947 }
948
949 #[test]
950 #[cfg(feature = "alloc")]
951 fn compose() {
952 use alloc::vec::Vec;
953 use octseq::builder::infallible;
954
955 let mut buf = Vec::new();
956 infallible(Label::root().compose(&mut buf));
957 assert_eq!(buf, &b"\0"[..]);
958
959 let mut buf = Vec::new();
960 let label = Label::from_slice(b"123").unwrap();
961 infallible(label.compose(&mut buf));
962 assert_eq!(buf, &b"\x03123"[..]);
963 }
964
965 #[test]
966 fn eq() {
967 assert_eq!(
968 Label::from_slice(b"example").unwrap(),
969 Label::from_slice(b"eXAMple").unwrap()
970 );
971 assert_ne!(
972 Label::from_slice(b"example").unwrap(),
973 Label::from_slice(b"e4ample").unwrap()
974 );
975 }
976
977 #[test]
978 fn cmp() {
979 use core::cmp::Ordering;
980
981 let labels = [
982 Label::root(),
983 Label::from_slice(b"\x01").unwrap(),
984 Label::from_slice(b"*").unwrap(),
985 Label::from_slice(b"\xc8").unwrap(),
986 ];
987 for i in 0..labels.len() {
988 for j in 0..labels.len() {
989 let ord = i.cmp(&j);
990 assert_eq!(labels[i].partial_cmp(labels[j]), Some(ord));
991 assert_eq!(labels[i].cmp(labels[j]), ord);
992 }
993 }
994
995 let l1 = Label::from_slice(b"example").unwrap();
996 let l2 = Label::from_slice(b"eXAMple").unwrap();
997 assert_eq!(l1.partial_cmp(l2), Some(Ordering::Equal));
998 assert_eq!(l1.cmp(l2), Ordering::Equal);
999 }
1000
1001 #[test]
1002 #[cfg(feature = "std")]
1003 fn hash() {
1004 use core::hash::{Hash, Hasher};
1005 use std::collections::hash_map::DefaultHasher;
1006
1007 let mut s1 = DefaultHasher::new();
1008 let mut s2 = DefaultHasher::new();
1009 Label::from_slice(b"example").unwrap().hash(&mut s1);
1010 Label::from_slice(b"eXAMple").unwrap().hash(&mut s2);
1011 assert_eq!(s1.finish(), s2.finish());
1012 }
1013
1014 #[cfg(feature = "serde")]
1017 #[test]
1018 fn owned_label_ser_de() {
1019 use serde_test::{Configure, Token, assert_tokens};
1020
1021 let label =
1022 OwnedLabel::from_label(Label::from_slice(b"fo.").unwrap());
1023 assert_tokens(
1024 &label.compact(),
1025 &[
1026 Token::NewtypeStruct { name: "OwnedLabel" },
1027 Token::BorrowedBytes(b"fo."),
1028 ],
1029 );
1030 assert_tokens(
1031 &label.readable(),
1032 &[
1033 Token::NewtypeStruct { name: "OwnedLabel" },
1034 Token::Str("fo\\."),
1035 ],
1036 );
1037 }
1038
1039 #[test]
1040 fn iter_slice() {
1041 assert_eq!(None, Label::iter_slice(&[], 0).next());
1042 assert_eq!(None, Label::iter_slice(&[], 1).next());
1043
1044 let buf = [
1046 0x07, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x03, 0x63, 0x6f,
1047 0x6d, 0x00,
1048 ];
1049
1050 let mut it = Label::iter_slice(&buf, 0);
1051 assert_eq!(Label::from_slice(b"example").ok(), it.next());
1052 assert_eq!(Label::from_slice(b"com").ok(), it.next());
1053 assert_eq!(Some(Label::root()), it.next());
1054 assert_eq!(None, it.next());
1055
1056 let mut it = Label::iter_slice(&buf, b"example".len() + 1);
1057 assert_eq!(
1058 Label::from_slice(b"com").ok(),
1059 it.next(),
1060 "should jump to 2nd label"
1061 );
1062
1063 let mut it = Label::iter_slice(&buf, buf.len() - 1);
1064 assert_eq!(
1065 Some(Label::root()),
1066 it.next(),
1067 "should jump to last/root label"
1068 );
1069 }
1070}