use std::borrow::Cow;
use std::error::Error;
use std::io::Write;
use byteorder_slice::ByteOrder;
use byteorder_slice::byteorder::{ReadBytesExt, WriteBytesExt};
use super::block_common::{Block, PcapNgBlock};
use super::opt_common::CustomBinaryOption;
use crate::pcapng::PcapNgState;
use crate::PcapError;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CustomBlock<'a, const COPIABLE: bool> {
pub pen: u32,
pub payload: Cow<'a, [u8]>,
}
impl<'a> CustomBlock<'a, true> {
pub fn interpret<T: CustomCopiable<'a>>(&'a self) -> Result<Option<T>, PcapError> {
if self.pen != T::PEN {
return Ok(None)
}
T::from_slice(&self.payload)
.map_err(|e| PcapError::CustomConversionError(T::PEN, e.into()))
}
}
impl<'a> CustomBlock<'a, false> {
pub fn interpret<T: CustomNonCopiable<'a>>(&'a self, state: &T::State)
-> Result<Option<T>, PcapError>
{
if self.pen != T::PEN {
return Ok(None)
}
T::from_slice(state, &self.payload)
.map_err(|e| PcapError::CustomConversionError(T::PEN, e.into()))
}
}
impl<const COPIABLE: bool> CustomBlock<'_, COPIABLE> {
pub fn into_owned(self) -> CustomBlock<'static, COPIABLE> {
CustomBlock {
pen: self.pen,
payload: Cow::Owned(self.payload.into_owned())
}
}
}
pub trait CustomCopiable<'a> {
const PEN: u32;
type FromSliceError: Error + 'static + Send + Sync;
type WriteToError: Error + 'static + Send + Sync;
fn from_slice(slice: &'a [u8]) -> Result<Option<Self>, Self::FromSliceError>
where Self: Sized;
fn write_to<W: Write>(&self, writer: &mut W) -> Result<(), Self::WriteToError>;
fn into_custom_block(self) -> Result<CustomBlock<'a, true>, PcapError>
where Self: Sized
{
let mut data = Vec::new();
self.write_to(&mut data)
.map_err(|e| PcapError::CustomConversionError(Self::PEN, e.into()))?;
Ok(CustomBlock { pen: Self::PEN, payload: Cow::Owned(data) })
}
fn into_custom_option(self) -> Result<CustomBinaryOption<'a, true>, PcapError>
where Self: Sized
{
let mut data = Vec::new();
self.write_to(&mut data)
.map_err(|e| PcapError::CustomConversionError(Self::PEN, e.into()))?;
Ok(CustomBinaryOption { pen: Self::PEN, value: Cow::Owned(data) })
}
}
pub trait CustomNonCopiable<'a> {
const PEN: u32;
type State;
type FromSliceError: Error + 'static + Send + Sync;
type WriteToError: Error + 'static + Send + Sync;
fn from_slice(state: &Self::State, slice: &'a [u8]) -> Result<Option<Self>, Self::FromSliceError>
where Self: Sized;
fn write_to<W: Write>(&self, state: &Self::State, writer: &mut W)
-> Result<(), Self::WriteToError>;
fn into_custom_block(self, state: &Self::State) -> Result<CustomBlock<'a, false>, PcapError>
where Self: Sized
{
let mut data = Vec::new();
self.write_to(state, &mut data)
.map_err(|e| PcapError::CustomConversionError(Self::PEN, e.into()))?;
Ok(CustomBlock { pen: Self::PEN, payload: Cow::Owned(data) })
}
fn into_custom_option(self, state: &Self::State) -> Result<CustomBinaryOption<'a, false>, PcapError>
where Self: Sized
{
let mut data = Vec::new();
self.write_to(state, &mut data)
.map_err(|e| PcapError::CustomConversionError(Self::PEN, e.into()))?;
Ok(CustomBinaryOption { pen: Self::PEN, value: Cow::Owned(data) })
}
}
impl<'a, const COPIABLE: bool> PcapNgBlock<'a> for CustomBlock<'a, COPIABLE> {
fn from_slice<B: ByteOrder>(_state: &PcapNgState, mut slice: &'a [u8]) -> Result<(&'a [u8], Self), PcapError>
where
Self: Sized,
{
let pen = slice.read_u32::<B>()?;
Ok((&[], CustomBlock { pen, payload: Cow::Borrowed(slice) }))
}
fn write_to<B: ByteOrder, W: Write>(&self, _state: &PcapNgState, writer: &mut W) -> Result<usize, PcapError> {
writer.write_u32::<B>(self.pen)?;
writer.write_all(&self.payload)?;
Ok(4 + self.payload.len())
}
fn into_block(self) -> Block<'a> {
if COPIABLE {
Block::CustomCopiable(CustomBlock { pen: self.pen, payload: self.payload })
} else {
Block::CustomNonCopiable(CustomBlock { pen: self.pen, payload: self.payload })
}
}
}