1use bytes::Bytes;
2
3use crate::tlv_type;
4use crate::{Interest, PacketError};
5use ndn_tlv::{TlvReader, TlvWriter};
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
9pub enum NackReason {
10 NoRoute,
12 Duplicate,
14 Congestion,
16 NotYet,
18 Other(u64),
20}
21
22impl NackReason {
23 pub fn code(&self) -> u64 {
24 match self {
25 NackReason::Congestion => 50,
26 NackReason::Duplicate => 100,
27 NackReason::NoRoute => 150,
28 NackReason::NotYet => 160,
29 NackReason::Other(c) => *c,
30 }
31 }
32
33 pub fn from_code(code: u64) -> Self {
34 match code {
35 50 => NackReason::Congestion,
36 100 => NackReason::Duplicate,
37 150 => NackReason::NoRoute,
38 160 => NackReason::NotYet,
39 c => NackReason::Other(c),
40 }
41 }
42}
43
44#[derive(Debug)]
46pub struct Nack {
47 pub reason: NackReason,
48 pub interest: Interest,
49}
50
51impl Nack {
52 pub fn new(interest: Interest, reason: NackReason) -> Self {
53 Self { reason, interest }
54 }
55
56 pub fn decode(raw: Bytes) -> Result<Self, PacketError> {
61 let first = *raw
62 .first()
63 .ok_or(PacketError::Tlv(ndn_tlv::TlvError::UnexpectedEof))?;
64
65 if first as u64 == tlv_type::LP_PACKET {
67 let lp = crate::lp::LpPacket::decode(raw)?;
68 let reason = lp.nack.ok_or_else(|| {
69 PacketError::MalformedPacket("LpPacket has no Nack header".into())
70 })?;
71 let fragment = lp.fragment.ok_or_else(|| {
72 PacketError::MalformedPacket("Nack LpPacket has no fragment".into())
73 })?;
74 let interest = Interest::decode(fragment)?;
75 return Ok(Self { reason, interest });
76 }
77
78 let mut reader = TlvReader::new(raw.clone());
80 let (typ, value) = reader.read_tlv()?;
81 if typ != tlv_type::NACK {
82 return Err(PacketError::UnknownPacketType(typ));
83 }
84 let mut inner = TlvReader::new(value);
85
86 let mut reason = NackReason::Other(0);
87 let mut interest_raw: Option<Bytes> = None;
88
89 while !inner.is_empty() {
90 let (t, v) = inner.read_tlv()?;
91 match t {
92 t if t == tlv_type::NACK_REASON => {
93 let mut code = 0u64;
94 for &b in v.iter() {
95 code = (code << 8) | b as u64;
96 }
97 reason = NackReason::from_code(code);
98 }
99 t if t == tlv_type::INTEREST => {
100 let mut w = TlvWriter::new();
101 w.write_tlv(tlv_type::INTEREST, &v);
102 interest_raw = Some(w.finish());
103 }
104 _ => {}
105 }
106 }
107
108 let interest_bytes = interest_raw.ok_or(PacketError::Tlv(
109 ndn_tlv::TlvError::MissingField("Interest inside Nack"),
110 ))?;
111 let interest = Interest::decode(interest_bytes)?;
112 Ok(Self { reason, interest })
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119 use crate::{Name, NameComponent};
120 use bytes::Bytes;
121 use ndn_tlv::TlvWriter;
122
123 fn build_nack(reason_code: u8, name_components: &[&[u8]]) -> Bytes {
124 let mut interest_inner = TlvWriter::new();
126 interest_inner.write_nested(tlv_type::NAME, |w| {
127 for comp in name_components {
128 w.write_tlv(tlv_type::NAME_COMPONENT, comp);
129 }
130 });
131
132 let mut w = TlvWriter::new();
133 w.write_nested(tlv_type::NACK, |w| {
134 w.write_tlv(tlv_type::NACK_REASON, &[reason_code]);
135 w.write_tlv(tlv_type::INTEREST, &interest_inner.finish());
138 });
139 w.finish()
140 }
141
142 #[test]
145 fn nack_reason_known_codes() {
146 let cases = [
147 (NackReason::Congestion, 50),
148 (NackReason::Duplicate, 100),
149 (NackReason::NoRoute, 150),
150 (NackReason::NotYet, 160),
151 ];
152 for (reason, code) in cases {
153 assert_eq!(reason.code(), code);
154 assert_eq!(NackReason::from_code(code), reason);
155 }
156 }
157
158 #[test]
159 fn nack_reason_unknown_code_roundtrip() {
160 let reason = NackReason::Other(42);
161 assert_eq!(reason.code(), 42);
162 assert_eq!(NackReason::from_code(42), NackReason::Other(42));
163 }
164
165 #[test]
168 fn nack_new_stores_fields() {
169 let name = Name::from_components([NameComponent::generic(Bytes::from_static(b"test"))]);
170 let interest = Interest::new(name.clone());
171 let nack = Nack::new(interest, NackReason::NoRoute);
172 assert_eq!(nack.reason, NackReason::NoRoute);
173 assert_eq!(*nack.interest.name, name);
174 }
175
176 #[test]
179 fn decode_nack_reason_and_name() {
180 let raw = build_nack(150, &[b"edu", b"ucla"]); let nack = Nack::decode(raw).unwrap();
182 assert_eq!(nack.reason, NackReason::NoRoute);
183 assert_eq!(nack.interest.name.len(), 2);
184 assert_eq!(nack.interest.name.components()[0].value.as_ref(), b"edu");
185 }
186
187 #[test]
188 fn decode_nack_congestion() {
189 let raw = build_nack(50, &[b"test"]);
190 let nack = Nack::decode(raw).unwrap();
191 assert_eq!(nack.reason, NackReason::Congestion);
192 }
193
194 #[test]
195 fn decode_nack_wrong_outer_type_errors() {
196 let mut w = TlvWriter::new();
197 w.write_tlv(0x05, &[]); assert!(matches!(
199 Nack::decode(w.finish()).unwrap_err(),
200 crate::PacketError::UnknownPacketType(0x05)
201 ));
202 }
203
204 #[test]
205 fn decode_nack_missing_interest_errors() {
206 let mut w = TlvWriter::new();
207 w.write_nested(tlv_type::NACK, |w| {
208 w.write_tlv(tlv_type::NACK_REASON, &[50]);
209 });
211 assert!(Nack::decode(w.finish()).is_err());
212 }
213}