pktscope-core 0.2.0

Core engine for pktscope: live/offline capture, protocol decoders, flow tracking, filters, and egress monitoring
Documentation
use std::collections::VecDeque;

use crate::decode::DecodedPacket;

pub struct PacketRing {
    packets: VecDeque<DecodedPacket>,
    capacity: usize,
}

impl PacketRing {
    pub fn new(capacity: usize) -> Self {
        Self {
            packets: VecDeque::with_capacity(capacity.min(8192)),
            capacity,
        }
    }

    pub fn push(&mut self, pkt: DecodedPacket) -> Option<DecodedPacket> {
        let evicted = if self.packets.len() >= self.capacity {
            self.packets.pop_front()
        } else {
            None
        };
        self.packets.push_back(pkt);
        evicted
    }

    pub fn len(&self) -> usize {
        self.packets.len()
    }

    #[allow(dead_code)]
    pub fn is_empty(&self) -> bool {
        self.packets.is_empty()
    }

    pub fn get(&self, index: usize) -> Option<&DecodedPacket> {
        self.packets.get(index)
    }

    #[allow(dead_code)]
    pub fn iter(&self) -> impl Iterator<Item = &DecodedPacket> {
        self.packets.iter()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::decode::{ColorHint, DecodedPacket, PacketSummary};

    fn dummy_packet(num: u64) -> DecodedPacket {
        DecodedPacket {
            number: num,
            timestamp: chrono::Utc::now(),
            wire_len: 64,
            data: vec![0u8; 64],
            layers: vec![],
            summary: PacketSummary {
                source: "0.0.0.0".into(),
                destination: "0.0.0.0".into(),
                protocol: "TEST".into(),
                length: 64,
                info: String::new(),
                color_hint: ColorHint::Other,
            },
            process: None,
            retransmission: false,
        }
    }

    #[test]
    fn test_push_and_get() {
        let mut ring = PacketRing::new(10);
        ring.push(dummy_packet(0));
        ring.push(dummy_packet(1));
        assert_eq!(ring.len(), 2);
        assert_eq!(ring.get(0).unwrap().number, 0);
        assert_eq!(ring.get(1).unwrap().number, 1);
    }

    #[test]
    fn test_capacity_eviction() {
        let mut ring = PacketRing::new(3);
        for i in 0..5 {
            ring.push(dummy_packet(i));
        }
        assert_eq!(ring.len(), 3);
        assert_eq!(ring.get(0).unwrap().number, 2);
        assert_eq!(ring.get(1).unwrap().number, 3);
        assert_eq!(ring.get(2).unwrap().number, 4);
    }

    #[test]
    fn test_empty() {
        let ring = PacketRing::new(10);
        assert!(ring.is_empty());
        assert_eq!(ring.len(), 0);
        assert!(ring.get(0).is_none());
    }
}