1use core::str::FromStr;
2
3#[cfg(not(feature = "std"))]
4use alloc::vec::Vec;
5
6use bytes::Bytes;
7use smallvec::SmallVec;
8
9use crate::PacketError;
10use crate::tlv_type;
11use ndn_tlv::TlvReader;
12
13#[derive(Clone, Debug, PartialEq, Eq, Hash)]
21pub struct NameComponent {
22 pub typ: u64,
23 pub value: Bytes,
24}
25
26impl PartialOrd for NameComponent {
27 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
28 Some(self.cmp(other))
29 }
30}
31
32impl Ord for NameComponent {
33 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
38 self.typ
39 .cmp(&other.typ)
40 .then_with(|| self.value.len().cmp(&other.value.len()))
41 .then_with(|| self.value.as_ref().cmp(other.value.as_ref()))
42 }
43}
44
45impl NameComponent {
46 pub fn new(typ: u64, value: Bytes) -> Self {
47 Self { typ, value }
48 }
49
50 pub fn generic(value: Bytes) -> Self {
51 Self {
52 typ: tlv_type::NAME_COMPONENT,
53 value,
54 }
55 }
56
57 pub fn blake3_digest(hash: [u8; 32]) -> Self {
63 Self::new(tlv_type::BLAKE3_DIGEST, Bytes::copy_from_slice(&hash))
64 }
65
66 pub fn as_blake3_digest(&self) -> Option<[u8; 32]> {
69 if self.typ == tlv_type::BLAKE3_DIGEST && self.value.len() == 32 {
70 let mut arr = [0u8; 32];
71 arr.copy_from_slice(&self.value);
72 Some(arr)
73 } else {
74 None
75 }
76 }
77
78 pub fn keyword(value: Bytes) -> Self {
80 Self::new(tlv_type::KEYWORD, value)
81 }
82
83 pub fn byte_offset(offset: u64) -> Self {
85 Self::new(tlv_type::BYTE_OFFSET, encode_nonnegtive_integer(offset))
86 }
87
88 pub fn version(v: u64) -> Self {
90 Self::new(tlv_type::VERSION, encode_nonnegtive_integer(v))
91 }
92
93 pub fn timestamp(ts: u64) -> Self {
95 Self::new(tlv_type::TIMESTAMP, encode_nonnegtive_integer(ts))
96 }
97
98 pub fn sequence_num(seq: u64) -> Self {
100 Self::new(tlv_type::SEQUENCE_NUM, encode_nonnegtive_integer(seq))
101 }
102
103 pub fn as_segment(&self) -> Option<u64> {
105 if self.typ == tlv_type::SEGMENT {
106 Some(decode_nonnegative_integer(&self.value))
107 } else {
108 None
109 }
110 }
111
112 pub fn as_byte_offset(&self) -> Option<u64> {
114 if self.typ == tlv_type::BYTE_OFFSET {
115 Some(decode_nonnegative_integer(&self.value))
116 } else {
117 None
118 }
119 }
120
121 pub fn as_version(&self) -> Option<u64> {
123 if self.typ == tlv_type::VERSION {
124 Some(decode_nonnegative_integer(&self.value))
125 } else {
126 None
127 }
128 }
129
130 pub fn as_timestamp(&self) -> Option<u64> {
132 if self.typ == tlv_type::TIMESTAMP {
133 Some(decode_nonnegative_integer(&self.value))
134 } else {
135 None
136 }
137 }
138
139 pub fn as_sequence_num(&self) -> Option<u64> {
141 if self.typ == tlv_type::SEQUENCE_NUM {
142 Some(decode_nonnegative_integer(&self.value))
143 } else {
144 None
145 }
146 }
147}
148
149fn encode_nonnegtive_integer(v: u64) -> Bytes {
156 let b = v.to_be_bytes();
157 Bytes::copy_from_slice(match v {
158 0..=0xFF => &b[7..],
159 0x100..=0xFFFF => &b[6..],
160 0x10000..=0xFFFF_FFFF => &b[4..],
161 _ => &b,
162 })
163}
164
165fn decode_nonnegative_integer(bytes: &[u8]) -> u64 {
167 let mut val: u64 = 0;
168 for &b in bytes {
169 val = (val << 8) | u64::from(b);
170 }
171 val
172}
173
174#[derive(Clone, Debug, PartialEq, Eq, Hash)]
182pub struct Name {
183 components: SmallVec<[NameComponent; 8]>,
184}
185
186impl PartialOrd for Name {
187 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
188 Some(self.cmp(other))
189 }
190}
191
192impl Ord for Name {
193 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
199 self.components.iter().cmp(other.components.iter())
200 }
201}
202
203impl Name {
204 pub fn root() -> Self {
206 Self {
207 components: SmallVec::new(),
208 }
209 }
210
211 pub fn from_components(components: impl IntoIterator<Item = NameComponent>) -> Self {
212 Self {
213 components: components.into_iter().collect(),
214 }
215 }
216
217 pub fn components(&self) -> &[NameComponent] {
218 &self.components
219 }
220
221 pub fn len(&self) -> usize {
222 self.components.len()
223 }
224
225 pub fn is_empty(&self) -> bool {
226 self.components.is_empty()
227 }
228
229 pub fn has_prefix(&self, prefix: &Name) -> bool {
231 if prefix.len() > self.len() {
232 return false;
233 }
234 self.components
235 .iter()
236 .zip(prefix.components.iter())
237 .all(|(a, b)| a == b)
238 }
239
240 pub fn decode(value: Bytes) -> Result<Self, PacketError> {
243 let mut reader = TlvReader::new(value);
244 let mut components = SmallVec::new();
245 while !reader.is_empty() {
246 let (typ, val) = reader.read_tlv()?;
247 components.push(NameComponent::new(typ, val));
248 }
249 Ok(Self { components })
250 }
251
252 pub fn append(mut self, value: impl AsRef<[u8]>) -> Self {
256 self.components
257 .push(NameComponent::generic(Bytes::copy_from_slice(
258 value.as_ref(),
259 )));
260 self
261 }
262
263 pub fn append_component(mut self, comp: NameComponent) -> Self {
265 self.components.push(comp);
266 self
267 }
268
269 pub fn append_segment(self, seg: u64) -> Self {
272 self.append_component(NameComponent::new(
273 tlv_type::SEGMENT,
274 encode_nonnegtive_integer(seg),
275 ))
276 }
277
278 pub fn append_version(self, v: u64) -> Self {
280 self.append_component(NameComponent::version(v))
281 }
282
283 pub fn append_timestamp(self, ts: u64) -> Self {
285 self.append_component(NameComponent::timestamp(ts))
286 }
287
288 pub fn append_sequence_num(self, seq: u64) -> Self {
290 self.append_component(NameComponent::sequence_num(seq))
291 }
292
293 pub fn append_byte_offset(self, off: u64) -> Self {
295 self.append_component(NameComponent::byte_offset(off))
296 }
297
298 pub fn append_blake3_digest(self, hash: [u8; 32]) -> Self {
302 self.append_component(NameComponent::blake3_digest(hash))
303 }
304
305 pub fn zone_root_from_hash(hash: [u8; 32]) -> Self {
315 Name::from_components([NameComponent::blake3_digest(hash)])
316 }
317
318 pub fn is_zone_root(&self) -> bool {
320 self.components().len() == 1
321 && self.components()[0].typ == crate::tlv_type::BLAKE3_DIGEST
322 && self.components()[0].value.len() == 32
323 }
324}
325
326impl FromStr for Name {
327 type Err = PacketError;
328
329 fn from_str(s: &str) -> Result<Self, Self::Err> {
339 let s = s.trim();
340 if s.is_empty() || s == "/" {
341 return Ok(Self::root());
342 }
343
344 if !s.starts_with('/') {
346 return Err(PacketError::MalformedPacket(
347 "name must start with '/'".into(),
348 ));
349 }
350
351 let mut components = SmallVec::new();
352 for part in s[1..].split('/') {
353 if part.is_empty() {
354 continue; }
356 let comp = if let Some(rest) = part.strip_prefix("seg=") {
358 if let Ok(n) = rest.parse::<u64>() {
359 NameComponent::new(tlv_type::SEGMENT, encode_nonnegtive_integer(n))
360 } else {
361 NameComponent::generic(Bytes::from(percent_decode(part).map_err(|_| {
362 PacketError::MalformedPacket("invalid percent-encoding in name".into())
363 })?))
364 }
365 } else if let Some(rest) = part.strip_prefix("v=") {
366 if let Ok(n) = rest.parse::<u64>() {
367 NameComponent::new(tlv_type::VERSION, encode_nonnegtive_integer(n))
368 } else {
369 NameComponent::generic(Bytes::from(percent_decode(part).map_err(|_| {
370 PacketError::MalformedPacket("invalid percent-encoding in name".into())
371 })?))
372 }
373 } else if let Some(rest) = part.strip_prefix("off=") {
374 if let Ok(n) = rest.parse::<u64>() {
375 NameComponent::new(tlv_type::BYTE_OFFSET, encode_nonnegtive_integer(n))
376 } else {
377 NameComponent::generic(Bytes::from(percent_decode(part).map_err(|_| {
378 PacketError::MalformedPacket("invalid percent-encoding in name".into())
379 })?))
380 }
381 } else if let Some(rest) = part.strip_prefix("t=") {
382 if let Ok(n) = rest.parse::<u64>() {
383 NameComponent::new(tlv_type::TIMESTAMP, encode_nonnegtive_integer(n))
384 } else {
385 NameComponent::generic(Bytes::from(percent_decode(part).map_err(|_| {
386 PacketError::MalformedPacket("invalid percent-encoding in name".into())
387 })?))
388 }
389 } else if let Some(rest) = part.strip_prefix("seq=") {
390 if let Ok(n) = rest.parse::<u64>() {
391 NameComponent::new(tlv_type::SEQUENCE_NUM, encode_nonnegtive_integer(n))
392 } else {
393 NameComponent::generic(Bytes::from(percent_decode(part).map_err(|_| {
394 PacketError::MalformedPacket("invalid percent-encoding in name".into())
395 })?))
396 }
397 } else {
398 let decoded = percent_decode(part).map_err(|_| {
399 PacketError::MalformedPacket("invalid percent-encoding in name".into())
400 })?;
401 NameComponent::generic(Bytes::from(decoded))
402 };
403 components.push(comp);
404 }
405
406 if components.is_empty() {
407 Ok(Self::root())
408 } else {
409 Ok(Self { components })
410 }
411 }
412}
413
414fn percent_decode(s: &str) -> Result<Vec<u8>, ()> {
416 let mut out = Vec::with_capacity(s.len());
417 let bytes = s.as_bytes();
418 let mut i = 0;
419 while i < bytes.len() {
420 if bytes[i] == b'%' {
421 if i + 2 >= bytes.len() {
422 return Err(());
423 }
424 let hi = hex_digit(bytes[i + 1])?;
425 let lo = hex_digit(bytes[i + 2])?;
426 out.push((hi << 4) | lo);
427 i += 3;
428 } else {
429 out.push(bytes[i]);
430 i += 1;
431 }
432 }
433 Ok(out)
434}
435
436fn hex_digit(b: u8) -> Result<u8, ()> {
437 match b {
438 b'0'..=b'9' => Ok(b - b'0'),
439 b'A'..=b'F' => Ok(b - b'A' + 10),
440 b'a'..=b'f' => Ok(b - b'a' + 10),
441 _ => Err(()),
442 }
443}
444
445#[macro_export]
455macro_rules! name {
456 ($s:expr) => {
457 <$crate::Name as ::core::str::FromStr>::from_str($s)
458 .expect(concat!("invalid NDN name: ", $s))
459 };
460}
461
462#[cfg(test)]
464pub(crate) fn build_name_value(components: &[&[u8]]) -> bytes::Bytes {
465 let mut w = ndn_tlv::TlvWriter::new();
466 for comp in components {
467 w.write_tlv(tlv_type::NAME_COMPONENT, comp);
468 }
469 w.finish()
470}
471
472fn percent_encode_component(f: &mut core::fmt::Formatter<'_>, value: &[u8]) -> core::fmt::Result {
474 for &b in value {
475 if b.is_ascii_graphic() && b != b'/' && b != b'%' {
476 write!(f, "{}", b as char)?;
477 } else {
478 write!(f, "%{b:02X}")?;
479 }
480 }
481 Ok(())
482}
483
484impl core::fmt::Display for Name {
485 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
486 write!(f, "/")?;
487 for (i, c) in self.components.iter().enumerate() {
488 if i > 0 {
489 write!(f, "/")?;
490 }
491 match c.typ {
492 tlv_type::BLAKE3_DIGEST => {
493 write!(f, "blake3digest=")?;
494 for &b in c.value.iter() {
495 write!(f, "{b:02x}")?;
496 }
497 }
498 tlv_type::IMPLICIT_SHA256 => {
499 write!(f, "sha256digest=")?;
500 for &b in c.value.iter() {
501 write!(f, "{b:02x}")?;
502 }
503 }
504 tlv_type::PARAMETERS_SHA256 => {
505 write!(f, "params-sha256=")?;
506 for &b in c.value.iter() {
507 write!(f, "{b:02x}")?;
508 }
509 }
510 tlv_type::KEYWORD => {
511 write!(f, "keyword=")?;
512 percent_encode_component(f, &c.value)?;
513 }
514 tlv_type::SEGMENT => {
515 write!(f, "seg={}", decode_nonnegative_integer(&c.value))?;
516 }
517 tlv_type::BYTE_OFFSET => {
518 write!(f, "off={}", decode_nonnegative_integer(&c.value))?;
519 }
520 tlv_type::VERSION => {
521 write!(f, "v={}", decode_nonnegative_integer(&c.value))?;
522 }
523 tlv_type::TIMESTAMP => {
524 write!(f, "t={}", decode_nonnegative_integer(&c.value))?;
525 }
526 tlv_type::SEQUENCE_NUM => {
527 write!(f, "seq={}", decode_nonnegative_integer(&c.value))?;
528 }
529 _ => {
530 percent_encode_component(f, &c.value)?;
532 }
533 }
534 }
535 Ok(())
536 }
537}
538
539#[cfg(test)]
540mod tests {
541 use super::*;
542 use std::collections::hash_map::DefaultHasher;
543 use std::hash::{Hash, Hasher};
544
545 fn hash_of(name: &Name) -> u64 {
546 let mut h = DefaultHasher::new();
547 name.hash(&mut h);
548 h.finish()
549 }
550
551 fn comp(s: &[u8]) -> NameComponent {
552 NameComponent::generic(bytes::Bytes::copy_from_slice(s))
553 }
554
555 #[test]
558 fn root_is_empty() {
559 let n = Name::root();
560 assert!(n.is_empty());
561 assert_eq!(n.len(), 0);
562 assert_eq!(n.components().len(), 0);
563 }
564
565 #[test]
566 fn from_components_stores_all() {
567 let n = Name::from_components([comp(b"edu"), comp(b"ucla"), comp(b"news")]);
568 assert_eq!(n.len(), 3);
569 assert_eq!(n.components()[0].value.as_ref(), b"edu");
570 assert_eq!(n.components()[1].value.as_ref(), b"ucla");
571 assert_eq!(n.components()[2].value.as_ref(), b"news");
572 }
573
574 #[test]
577 fn has_prefix_true() {
578 let name = Name::from_components([comp(b"edu"), comp(b"ucla"), comp(b"news")]);
579 let prefix = Name::from_components([comp(b"edu"), comp(b"ucla")]);
580 assert!(name.has_prefix(&prefix));
581 }
582
583 #[test]
584 fn has_prefix_equal_names() {
585 let name = Name::from_components([comp(b"edu"), comp(b"ucla")]);
586 assert!(name.has_prefix(&name.clone()));
587 }
588
589 #[test]
590 fn has_prefix_root_is_prefix_of_everything() {
591 let name = Name::from_components([comp(b"any"), comp(b"name")]);
592 assert!(name.has_prefix(&Name::root()));
593 }
594
595 #[test]
596 fn has_prefix_false_different_component() {
597 let name = Name::from_components([comp(b"edu"), comp(b"ucla")]);
598 let prefix = Name::from_components([comp(b"edu"), comp(b"mit")]);
599 assert!(!name.has_prefix(&prefix));
600 }
601
602 #[test]
603 fn has_prefix_false_prefix_longer_than_name() {
604 let name = Name::from_components([comp(b"edu")]);
605 let prefix = Name::from_components([comp(b"edu"), comp(b"ucla")]);
606 assert!(!name.has_prefix(&prefix));
607 }
608
609 #[test]
612 fn decode_empty_name() {
613 let name = Name::decode(bytes::Bytes::new()).unwrap();
614 assert!(name.is_empty());
615 }
616
617 #[test]
618 fn decode_one_component() {
619 let value = build_name_value(&[b"hello"]);
620 let name = Name::decode(value).unwrap();
621 assert_eq!(name.len(), 1);
622 assert_eq!(name.components()[0].value.as_ref(), b"hello");
623 assert_eq!(name.components()[0].typ, tlv_type::NAME_COMPONENT);
624 }
625
626 #[test]
627 fn decode_multiple_components() {
628 let value = build_name_value(&[b"edu", b"ucla", b"data"]);
629 let name = Name::decode(value).unwrap();
630 assert_eq!(name.len(), 3);
631 assert_eq!(name.components()[2].value.as_ref(), b"data");
632 }
633
634 #[test]
635 fn decode_preserves_component_type() {
636 let mut w = ndn_tlv::TlvWriter::new();
638 w.write_tlv(0x01, &[0xAA; 32]);
639 let value = w.finish();
640 let name = Name::decode(value).unwrap();
641 assert_eq!(name.components()[0].typ, 0x01);
642 }
643
644 #[test]
647 fn display_root() {
648 assert_eq!(Name::root().to_string(), "/");
649 }
650
651 #[test]
652 fn display_single_component() {
653 let n = Name::from_components([comp(b"ndn")]);
654 assert_eq!(n.to_string(), "/ndn");
655 }
656
657 #[test]
658 fn display_multi_component() {
659 let n = Name::from_components([comp(b"edu"), comp(b"ucla"), comp(b"data")]);
660 assert_eq!(n.to_string(), "/edu/ucla/data");
661 }
662
663 #[test]
664 fn display_non_ascii_percent_encoded() {
665 let n =
666 Name::from_components([NameComponent::generic(bytes::Bytes::from(vec![0x00, 0xFF]))]);
667 assert_eq!(n.to_string(), "/%00%FF");
669 }
670
671 #[test]
674 fn equal_names_have_equal_hash() {
675 let a = Name::from_components([comp(b"foo"), comp(b"bar")]);
676 let b = Name::from_components([comp(b"foo"), comp(b"bar")]);
677 assert_eq!(a, b);
678 assert_eq!(hash_of(&a), hash_of(&b));
679 }
680
681 #[test]
682 fn different_names_are_not_equal() {
683 let a = Name::from_components([comp(b"foo")]);
684 let b = Name::from_components([comp(b"bar")]);
685 assert_ne!(a, b);
686 }
687
688 #[test]
689 fn component_type_affects_equality() {
690 let generic = NameComponent::generic(bytes::Bytes::copy_from_slice(b"abc"));
691 let implicit = NameComponent {
692 typ: 0x01,
693 value: bytes::Bytes::copy_from_slice(b"abc"),
694 };
695 assert_ne!(generic, implicit);
696 }
697
698 #[test]
701 fn from_str_simple() {
702 let n: Name = "/edu/ucla/data".parse().unwrap();
703 assert_eq!(n.len(), 3);
704 assert_eq!(n.components()[0].value.as_ref(), b"edu");
705 assert_eq!(n.components()[2].value.as_ref(), b"data");
706 }
707
708 #[test]
709 fn from_str_root() {
710 let n: Name = "/".parse().unwrap();
711 assert!(n.is_empty());
712 }
713
714 #[test]
715 fn from_str_empty_string() {
716 let n: Name = "".parse().unwrap();
717 assert!(n.is_empty());
718 }
719
720 #[test]
721 fn from_str_trailing_slash() {
722 let n: Name = "/test/".parse().unwrap();
723 assert_eq!(n.len(), 1);
724 assert_eq!(n.components()[0].value.as_ref(), b"test");
725 }
726
727 #[test]
728 fn from_str_percent_decode() {
729 let n: Name = "/%00%FF".parse().unwrap();
730 assert_eq!(n.len(), 1);
731 assert_eq!(n.components()[0].value.as_ref(), &[0x00, 0xFF]);
732 }
733
734 #[test]
735 fn from_str_lowercase_hex() {
736 let n: Name = "/%0a%ff".parse().unwrap();
737 assert_eq!(n.components()[0].value.as_ref(), &[0x0A, 0xFF]);
738 }
739
740 #[test]
741 fn from_str_no_leading_slash_is_err() {
742 assert!("edu/ucla".parse::<Name>().is_err());
743 }
744
745 #[test]
746 fn from_str_bad_percent_is_err() {
747 assert!("/%ZZ".parse::<Name>().is_err());
748 }
749
750 #[test]
751 fn display_from_str_roundtrip() {
752 let original = Name::from_components([
753 comp(b"edu"),
754 comp(b"ucla"),
755 NameComponent::generic(bytes::Bytes::from(vec![0x00, 0xFF])),
756 ]);
757 let s = original.to_string();
758 let parsed: Name = s.parse().unwrap();
759 assert_eq!(original, parsed);
760 }
761
762 #[test]
765 fn append_builds_name() {
766 let n = Name::root().append("edu").append("ucla");
767 assert_eq!(n.len(), 2);
768 assert_eq!(n.to_string(), "/edu/ucla");
769 }
770
771 #[test]
772 fn append_segment() {
773 let n: Name = "/iperf".parse().unwrap();
774 let n = n.append_segment(42);
775 assert_eq!(n.len(), 2);
776 assert_eq!(n.components()[1].typ, tlv_type::SEGMENT);
777 }
778
779 #[test]
780 fn append_segment_zero() {
781 let n = Name::root().append_segment(0);
782 assert_eq!(n.components()[0].value.as_ref(), &[0u8]);
783 }
784
785 #[test]
788 fn name_macro() {
789 let n = name!("/iperf/data");
790 assert_eq!(n.len(), 2);
791 assert_eq!(n.to_string(), "/iperf/data");
792 }
793
794 #[test]
797 fn keyword_component_roundtrip() {
798 let c = NameComponent::keyword(Bytes::from_static(b"hello"));
799 assert_eq!(c.typ, tlv_type::KEYWORD);
800 assert_eq!(c.value.as_ref(), b"hello");
801 }
802
803 #[test]
804 fn byte_offset_roundtrip() {
805 let c = NameComponent::byte_offset(1024);
806 assert_eq!(c.typ, tlv_type::BYTE_OFFSET);
807 assert_eq!(c.as_byte_offset(), Some(1024));
808 }
809
810 #[test]
811 fn version_roundtrip() {
812 let c = NameComponent::version(7);
813 assert_eq!(c.typ, tlv_type::VERSION);
814 assert_eq!(c.as_version(), Some(7));
815 }
816
817 #[test]
818 fn timestamp_roundtrip() {
819 let c = NameComponent::timestamp(1_700_000_000);
820 assert_eq!(c.typ, tlv_type::TIMESTAMP);
821 assert_eq!(c.as_timestamp(), Some(1_700_000_000));
822 }
823
824 #[test]
825 fn sequence_num_roundtrip() {
826 let c = NameComponent::sequence_num(42);
827 assert_eq!(c.typ, tlv_type::SEQUENCE_NUM);
828 assert_eq!(c.as_sequence_num(), Some(42));
829 }
830
831 #[test]
832 fn zero_value_roundtrip() {
833 assert_eq!(NameComponent::version(0).as_version(), Some(0));
834 assert_eq!(NameComponent::sequence_num(0).as_sequence_num(), Some(0));
835 assert_eq!(NameComponent::byte_offset(0).as_byte_offset(), Some(0));
836 assert_eq!(NameComponent::timestamp(0).as_timestamp(), Some(0));
837 }
838
839 #[test]
840 fn accessor_wrong_type_returns_none() {
841 let c = NameComponent::version(5);
842 assert_eq!(c.as_segment(), None);
843 assert_eq!(c.as_byte_offset(), None);
844 assert_eq!(c.as_timestamp(), None);
845 assert_eq!(c.as_sequence_num(), None);
846 }
847
848 #[test]
849 fn as_segment_accessor() {
850 let n = Name::root().append_segment(99);
851 assert_eq!(n.components()[0].as_segment(), Some(99));
852 }
853
854 #[test]
857 fn builder_chaining_all_types() {
858 let n = Name::root()
859 .append("data")
860 .append_version(3)
861 .append_segment(0);
862 assert_eq!(n.len(), 3);
863 assert_eq!(n.components()[0].typ, tlv_type::NAME_COMPONENT);
864 assert_eq!(n.components()[1].typ, tlv_type::VERSION);
865 assert_eq!(n.components()[1].as_version(), Some(3));
866 assert_eq!(n.components()[2].typ, tlv_type::SEGMENT);
867 assert_eq!(n.components()[2].as_segment(), Some(0));
868 }
869
870 #[test]
871 fn builder_timestamp_and_sequence() {
872 let n = Name::root()
873 .append("sensor")
874 .append_timestamp(1_700_000)
875 .append_sequence_num(5)
876 .append_byte_offset(4096);
877 assert_eq!(n.len(), 4);
878 assert_eq!(n.components()[1].as_timestamp(), Some(1_700_000));
879 assert_eq!(n.components()[2].as_sequence_num(), Some(5));
880 assert_eq!(n.components()[3].as_byte_offset(), Some(4096));
881 }
882
883 #[test]
886 fn display_segment() {
887 let n = Name::root().append("data").append_segment(42);
888 assert_eq!(n.to_string(), "/data/seg=42");
889 }
890
891 #[test]
892 fn display_version() {
893 let n = Name::root().append("data").append_version(3);
894 assert_eq!(n.to_string(), "/data/v=3");
895 }
896
897 #[test]
898 fn display_timestamp() {
899 let n = Name::root().append("data").append_timestamp(1000);
900 assert_eq!(n.to_string(), "/data/t=1000");
901 }
902
903 #[test]
904 fn display_sequence_num() {
905 let n = Name::root().append("data").append_sequence_num(7);
906 assert_eq!(n.to_string(), "/data/seq=7");
907 }
908
909 #[test]
910 fn display_byte_offset() {
911 let n = Name::root().append("data").append_byte_offset(512);
912 assert_eq!(n.to_string(), "/data/off=512");
913 }
914
915 #[test]
916 fn display_keyword() {
917 let n = Name::root().append_component(NameComponent::keyword(Bytes::from_static(b"test")));
918 assert_eq!(n.to_string(), "/keyword=test");
919 }
920
921 #[test]
922 fn display_sha256digest() {
923 let digest = [0xABu8; 32];
924 let n = Name::root().append_component(NameComponent::new(
925 tlv_type::IMPLICIT_SHA256,
926 Bytes::copy_from_slice(&digest),
927 ));
928 let expected_hex: String = digest.iter().map(|b| format!("{b:02x}")).collect();
929 assert_eq!(n.to_string(), format!("/sha256digest={expected_hex}"));
930 }
931
932 #[test]
933 fn display_params_sha256() {
934 let digest = [0xCDu8; 32];
935 let n = Name::root().append_component(NameComponent::new(
936 tlv_type::PARAMETERS_SHA256,
937 Bytes::copy_from_slice(&digest),
938 ));
939 let expected_hex: String = digest.iter().map(|b| format!("{b:02x}")).collect();
940 assert_eq!(n.to_string(), format!("/params-sha256={expected_hex}"));
941 }
942
943 #[test]
944 fn display_mixed_typed_and_generic() {
945 let n = Name::root()
946 .append("ndn")
947 .append("data")
948 .append_version(3)
949 .append_segment(0);
950 assert_eq!(n.to_string(), "/ndn/data/v=3/seg=0");
951 }
952}