1use bytes::Bytes;
2use ndn_tlv::TlvWriter;
3
4use super::{CachePolicyType, LpHeaders, is_lp_packet, nni};
5use crate::tlv_type;
6
7pub fn encode_lp_nack(reason: crate::nack::NackReason, interest_wire: &[u8]) -> Bytes {
18 let mut w = TlvWriter::new();
19 w.write_nested(tlv_type::LP_PACKET, |w| {
20 w.write_nested(tlv_type::NACK, |w| {
22 let (buf, len) = nni(reason.code());
23 w.write_tlv(tlv_type::NACK_REASON, &buf[..len]);
24 });
25 w.write_tlv(tlv_type::LP_FRAGMENT, interest_wire);
27 });
28 w.finish()
29}
30
31pub fn encode_lp_packet(packet: &[u8]) -> Bytes {
41 if is_lp_packet(packet) {
42 return Bytes::copy_from_slice(packet);
43 }
44 let mut w = TlvWriter::new();
45 w.write_nested(tlv_type::LP_PACKET, |w| {
46 w.write_tlv(tlv_type::LP_FRAGMENT, packet);
47 });
48 w.finish()
49}
50
51pub fn encode_lp_reliable(
57 fragment: &[u8],
58 sequence: u64,
59 frag_info: Option<(u64, u64)>,
60 acks: &[u64],
61) -> Bytes {
62 let mut w = TlvWriter::new();
63 w.write_nested(tlv_type::LP_PACKET, |w| {
64 let (buf, len) = nni(sequence);
65 w.write_tlv(tlv_type::LP_SEQUENCE, &buf[..len]);
66 if let Some((idx, count)) = frag_info {
67 let (buf, len) = nni(idx);
68 w.write_tlv(tlv_type::LP_FRAG_INDEX, &buf[..len]);
69 let (buf, len) = nni(count);
70 w.write_tlv(tlv_type::LP_FRAG_COUNT, &buf[..len]);
71 }
72 for &ack in acks {
73 let (buf, len) = nni(ack);
74 w.write_tlv(tlv_type::LP_ACK, &buf[..len]);
75 }
76 w.write_tlv(tlv_type::LP_FRAGMENT, fragment);
77 });
78 w.finish()
79}
80
81pub fn encode_lp_acks(acks: &[u64]) -> Bytes {
83 let mut w = TlvWriter::new();
84 w.write_nested(tlv_type::LP_PACKET, |w| {
85 for &ack in acks {
86 let (buf, len) = nni(ack);
87 w.write_tlv(tlv_type::LP_ACK, &buf[..len]);
88 }
89 });
90 w.finish()
91}
92
93pub fn encode_lp_with_headers(fragment: &[u8], headers: &LpHeaders) -> Bytes {
97 let mut w = TlvWriter::new();
98 w.write_nested(tlv_type::LP_PACKET, |w| {
99 if let Some(ref token) = headers.pit_token {
102 w.write_tlv(tlv_type::LP_PIT_TOKEN, token);
103 }
104 if let Some(id) = headers.incoming_face_id {
106 let (buf, len) = nni(id);
107 w.write_tlv(tlv_type::LP_INCOMING_FACE_ID, &buf[..len]);
108 }
109 if let Some(ref cp) = headers.cache_policy {
111 w.write_nested(tlv_type::LP_CACHE_POLICY, |w| {
112 let code = match cp {
113 CachePolicyType::NoCache => 1u64,
114 CachePolicyType::Other(c) => *c,
115 };
116 let (buf, len) = nni(code);
117 w.write_tlv(tlv_type::LP_CACHE_POLICY_TYPE, &buf[..len]);
118 });
119 }
120 if let Some(mark) = headers.congestion_mark {
122 let (buf, len) = nni(mark);
123 w.write_tlv(tlv_type::LP_CONGESTION_MARK, &buf[..len]);
124 }
125 w.write_tlv(tlv_type::LP_FRAGMENT, fragment);
127 });
128 w.finish()
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134 use crate::encode::encode_interest;
135 use crate::lp::{LpPacket, is_lp_packet};
136 use crate::nack::NackReason;
137 use crate::{Interest, Name, NameComponent};
138 use bytes::Bytes;
139
140 fn name(comps: &[&[u8]]) -> Name {
141 Name::from_components(
142 comps
143 .iter()
144 .map(|c| NameComponent::generic(Bytes::copy_from_slice(c))),
145 )
146 }
147
148 #[test]
149 fn is_lp_packet_checks_first_byte() {
150 assert!(is_lp_packet(&[0x64, 0x00]));
151 assert!(!is_lp_packet(&[0x05, 0x00]));
152 assert!(!is_lp_packet(&[]));
153 }
154
155 #[test]
156 fn encode_lp_packet_wraps_bare_interest() {
157 let n = name(&[b"test"]);
158 let interest_wire = encode_interest(&n, None);
159
160 let lp_wire = encode_lp_packet(&interest_wire);
161 assert!(is_lp_packet(&lp_wire));
162
163 let lp = LpPacket::decode(lp_wire).unwrap();
164 assert!(lp.nack.is_none());
165 let interest = Interest::decode(lp.fragment.unwrap()).unwrap();
166 assert_eq!(*interest.name, n);
167 }
168
169 #[test]
170 fn encode_lp_packet_passthrough_existing_lp() {
171 let n = name(&[b"test"]);
172 let interest_wire = encode_interest(&n, None);
173 let lp_wire = encode_lp_nack(NackReason::NoRoute, &interest_wire);
174
175 let rewrapped = encode_lp_packet(&lp_wire);
177 assert_eq!(rewrapped, lp_wire);
178 }
179}