ndn_pipeline/context.rs
1use std::sync::Arc;
2
3use bytes::Bytes;
4use smallvec::SmallVec;
5
6use ndn_packet::{Data, Interest, Nack, Name};
7use ndn_store::PitToken;
8use ndn_transport::{AnyMap, FaceId};
9
10/// The packet as it progresses through decode stages.
11pub enum DecodedPacket {
12 /// Not yet decoded — the raw bytes are still in `PacketContext::raw_bytes`.
13 Raw,
14 Interest(Box<Interest>),
15 Data(Box<Data>),
16 Nack(Box<Nack>),
17}
18
19/// Per-packet state passed by value through pipeline stages.
20///
21/// Passing by value (rather than `&mut`) makes ownership explicit:
22/// a stage that short-circuits simply does not return the context,
23/// so Rust's ownership system prevents use-after-hand-off at compile time.
24pub struct PacketContext {
25 /// Wire-format bytes of the original packet.
26 pub raw_bytes: Bytes,
27 /// Face the packet arrived on.
28 pub face_id: FaceId,
29 /// Decoded name — hoisted to top level because every stage needs it.
30 /// `None` until `TlvDecodeStage` runs.
31 pub name: Option<Arc<Name>>,
32 /// Decoded packet — starts as `Raw`, transitions after TlvDecodeStage.
33 pub packet: DecodedPacket,
34 /// PIT token — written by PitCheckStage, `None` before that stage runs.
35 pub pit_token: Option<PitToken>,
36 /// NDNLPv2 PIT token (opaque, 1-32 bytes) from the incoming LP header.
37 /// Distinct from the internal `pit_token` hash — this is the wire-protocol
38 /// hop-by-hop token that must be echoed in Data/Nack responses.
39 pub lp_pit_token: Option<Bytes>,
40 /// Faces selected for forwarding by the strategy stage.
41 pub out_faces: SmallVec<[FaceId; 4]>,
42 /// Set to `true` by CsLookupStage on a cache hit.
43 pub cs_hit: bool,
44 /// Set to `true` by the security validation stage.
45 pub verified: bool,
46 /// Arrival time in nanoseconds since the Unix epoch (set by the face task).
47 pub arrival: u64,
48 /// Escape hatch for inter-stage communication not covered by explicit fields.
49 /// Use sparingly; prefer explicit fields for anything the core pipeline touches.
50 pub tags: AnyMap,
51}
52
53impl PacketContext {
54 pub fn new(raw_bytes: Bytes, face_id: FaceId, arrival: u64) -> Self {
55 Self {
56 raw_bytes,
57 face_id,
58 name: None,
59 packet: DecodedPacket::Raw,
60 pit_token: None,
61 lp_pit_token: None,
62 out_faces: SmallVec::new(),
63 cs_hit: false,
64 verified: false,
65 arrival,
66 tags: AnyMap::new(),
67 }
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use bytes::Bytes;
75 use ndn_transport::FaceId;
76
77 #[test]
78 fn packet_context_new_defaults() {
79 let raw = Bytes::from_static(b"\x05\x01\x00");
80 let ctx = PacketContext::new(raw.clone(), FaceId(7), 12345);
81 assert_eq!(ctx.raw_bytes, raw);
82 assert_eq!(ctx.face_id, FaceId(7));
83 assert_eq!(ctx.arrival, 12345);
84 assert!(ctx.name.is_none());
85 assert!(ctx.pit_token.is_none());
86 assert!(ctx.out_faces.is_empty());
87 assert!(!ctx.cs_hit);
88 assert!(!ctx.verified);
89 assert!(matches!(ctx.packet, DecodedPacket::Raw));
90 }
91}