use crate::{
define::TH_ESStreamInfo,
helper::packet::{
helper::{clear_info_relas, get_info_relas, set_info_relas},
packet_final::CPacketViewRela,
packet_view::CPacketView,
traits::AsCPacketView as _,
},
};
use anyhow::Result;
use bytes::Bytes;
#[derive(Clone)]
pub struct PacketFinal {
payload: Bytes,
info: TH_ESStreamInfo,
}
impl PacketFinal {
fn new(data: &[u8], info: TH_ESStreamInfo) -> Self {
let payload = bytes::Bytes::copy_from_slice(data);
Self { payload, info }
}
pub fn payload(&self) -> &[u8] {
&self.payload
}
pub fn info(&self) -> &TH_ESStreamInfo {
&self.info
}
}
#[derive(Clone)]
pub struct Packet {
core: PacketFinal,
relas: Vec<PacketFinal>,
}
impl Packet {
pub fn new(data: &[u8], info: &TH_ESStreamInfo) -> Self {
let mut relas = Vec::new();
let mut info = *info;
for rela in get_info_relas(&info) {
let rela_cloned = PacketFinal::new(rela.as_slice(), *rela.get_info());
relas.push(rela_cloned);
}
clear_info_relas(&mut info);
let core = PacketFinal::new(data, info);
Self { core, relas }
}
pub fn rela(&self) -> &[PacketFinal] {
&self.relas
}
pub fn core(&self) -> &PacketFinal {
&self.core
}
pub fn inspect<'a, F, T>(&'a self, f: F) -> Result<T>
where
F: FnOnce(CPacketView) -> Result<T>,
{
let base_info = *&self.core.info;
let mut v = Vec::new();
for rela in &self.relas {
let view = CPacketViewRela::new(rela.payload(), rela.info());
v.push(view);
}
let guard = set_info_relas(&base_info, &v);
f(CPacketView::new(self.core.payload(), guard.info()))
}
pub fn inspect_th_info<'a, F, T>(&'a self, f: F) -> Result<T>
where
F: FnOnce(&[u8], &TH_ESStreamInfo) -> Result<T>,
{
self.inspect(|packet_view| f(packet_view.as_slice(), packet_view.info()))
}
}
impl<'a> From<&CPacketView<'a>> for Packet {
fn from(value: &CPacketView) -> Self {
Packet::new(value.as_slice(), value.info())
}
}
impl<'a> From<CPacketView<'a>> for Packet {
fn from(value: CPacketView) -> Self {
Packet::from(&value)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_case_data_with_es() {
let rela_data: Vec<u8> = vec![4, 5, 6];
let rela_info = TH_ESStreamInfo {
streamType: 1,
..Default::default()
};
let data = vec![1, 2, 3];
let base_info = TH_ESStreamInfo {
streamType: 6,
..Default::default()
};
let relas = vec![CPacketViewRela::new(&rela_data, &rela_info)];
let guard = set_info_relas(&base_info, &relas);
let packet = Packet::new(&data, guard.info());
assert_eq!(packet.core().info().rela_count, 0); assert_eq!(packet.core().info().rela_info, 0); assert_eq!(packet.core().info().rela_data, 0); assert_eq!(packet.core().info().rela_data_len, 0);
assert_eq!(packet.core().info().streamType, 6);
assert_eq!(packet.core().payload(), [1, 2, 3]);
assert_eq!(packet.rela().len(), 1);
assert_eq!(packet.rela()[0].info().streamType, 1);
assert_eq!(packet.rela()[0].payload(), [4, 5, 6]);
let result = packet.inspect_th_info(move |payload, th_info| {
assert_eq!(payload, [1, 2, 3]);
let rela_view = get_info_relas(th_info);
assert_eq!(rela_view.len(), 1);
assert_eq!(rela_view[0].stream_type(), 1);
assert_eq!(rela_view[0].as_slice(), [4, 5, 6]);
Ok(())
});
assert!(result.is_ok());
{
let view: CPacketView = CPacketView::new(&data, guard.info());
let info = view.info();
assert_eq!(info.streamType, 6);
assert_eq!(view.as_slice(), [1, 2, 3]);
assert_eq!(view.relas().len(), 1);
assert_eq!(view.relas()[0].stream_type(), 1);
assert_eq!(view.relas()[0].as_slice(), [4, 5, 6]);
}
{
let view: CPacketView = CPacketView::new(&data, guard.info());
let packet_from_ref = Packet::from(&view);
assert_eq!(packet_from_ref.core().info().streamType, 6);
assert_eq!(packet_from_ref.core().payload(), [1, 2, 3]);
assert_eq!(packet_from_ref.rela().len(), 1);
assert_eq!(packet_from_ref.rela()[0].info().streamType, 1);
assert_eq!(packet_from_ref.rela()[0].payload(), [4, 5, 6]);
let packet_frezz = Packet::from(view);
assert_eq!(packet_frezz.core().info().streamType, 6);
assert_eq!(packet_frezz.core().payload(), [1, 2, 3]);
assert_eq!(packet_frezz.rela().len(), 1);
assert_eq!(packet_frezz.rela()[0].info().streamType, 1);
assert_eq!(packet_frezz.rela()[0].payload(), [4, 5, 6]);
}
}
}