use crate::{Timestamp, rx_metadata::RxMetadata};
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub struct PacketView<'a> {
pub frame: &'a [u8],
pub timestamp: Timestamp,
pub rx_metadata: RxMetadata,
}
impl<'a> PacketView<'a> {
#[inline]
pub fn new(frame: &'a [u8], timestamp: Timestamp) -> Self {
Self {
frame,
timestamp,
rx_metadata: RxMetadata::default(),
}
}
#[inline]
pub fn with_rx_metadata(mut self, rx_metadata: RxMetadata) -> Self {
self.rx_metadata = rx_metadata;
self
}
#[inline]
pub fn with_source_idx(mut self, source_idx: u32) -> Self {
self.rx_metadata.source_idx = source_idx;
self
}
#[cfg(feature = "extractors")]
pub fn layers(&self) -> crate::Result<crate::layers::Layers<'a>> {
crate::layers::Layers::parse_ethernet(self.frame)
}
#[inline]
pub fn with_frame<'b>(self, frame: &'b [u8]) -> PacketView<'b>
where
'a: 'b,
{
PacketView {
frame,
timestamp: self.timestamp,
rx_metadata: self.rx_metadata,
}
}
}
pub trait AsPacketView {
fn as_packet_view(&self) -> PacketView<'_>;
}
impl<'a, T: AsPacketView + ?Sized> From<&'a T> for PacketView<'a> {
fn from(t: &'a T) -> Self {
t.as_packet_view()
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct OwnedPacketView {
pub frame: Vec<u8>,
pub timestamp: Timestamp,
pub rx_metadata: RxMetadata,
}
impl OwnedPacketView {
#[inline]
pub fn new(frame: Vec<u8>, timestamp: Timestamp) -> Self {
Self {
frame,
timestamp,
rx_metadata: RxMetadata::default(),
}
}
#[inline]
pub fn with_rx_metadata(mut self, rx_metadata: RxMetadata) -> Self {
self.rx_metadata = rx_metadata;
self
}
#[inline]
pub fn with_source_idx(mut self, source_idx: u32) -> Self {
self.rx_metadata.source_idx = source_idx;
self
}
pub fn as_view(&self) -> PacketView<'_> {
PacketView::new(&self.frame, self.timestamp).with_rx_metadata(self.rx_metadata)
}
}
impl AsPacketView for OwnedPacketView {
fn as_packet_view(&self) -> PacketView<'_> {
self.as_view()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn new_and_fields() {
let buf = [0u8; 8];
let v = PacketView::new(&buf, Timestamp::new(1, 2));
assert_eq!(v.frame.len(), 8);
assert_eq!(v.timestamp, Timestamp::new(1, 2));
}
#[test]
fn with_source_idx_sets_only_source_idx() {
let buf = [0u8; 8];
let v = PacketView::new(&buf, Timestamp::new(1, 2)).with_source_idx(5);
assert_eq!(v.rx_metadata.source_idx, 5);
assert!(v.rx_metadata.hw_timestamp.is_none());
assert!(v.rx_metadata.rx_hash.is_none());
let ov = OwnedPacketView::new(vec![0u8; 8], Timestamp::new(1, 2)).with_source_idx(9);
assert_eq!(ov.rx_metadata.source_idx, 9);
assert_eq!(ov.as_view().rx_metadata.source_idx, 9);
}
#[test]
fn with_frame_replaces_slice_keeps_ts() {
let outer = [1u8, 2, 3, 4];
let inner = [9u8, 9];
let v = PacketView::new(&outer, Timestamp::new(7, 0));
let w = v.with_frame(&inner);
assert_eq!(w.frame, &inner);
assert_eq!(w.timestamp, Timestamp::new(7, 0));
}
#[test]
fn as_packet_view_blanket_works() {
struct MyPacket {
bytes: Vec<u8>,
ts: Timestamp,
}
impl AsPacketView for MyPacket {
fn as_packet_view(&self) -> PacketView<'_> {
PacketView::new(&self.bytes, self.ts)
}
}
let pkt = MyPacket {
bytes: vec![1, 2, 3, 4],
ts: Timestamp::new(42, 0),
};
let v = pkt.as_packet_view();
assert_eq!(v.frame, &[1, 2, 3, 4]);
assert_eq!(v.timestamp, Timestamp::new(42, 0));
let v: PacketView<'_> = (&pkt).into();
assert_eq!(v.frame, &[1, 2, 3, 4]);
let boxed: Box<dyn AsPacketView> = Box::new(MyPacket {
bytes: vec![9],
ts: Timestamp::new(1, 0),
});
let v = boxed.as_packet_view();
assert_eq!(v.frame, &[9]);
}
}