use core::fmt;
use super::{payload, unit, Decode, Decoder, Error};
#[derive(Debug, PartialEq)]
pub enum Packet<'a, 'd, U> {
NullIdle { flow: u8 },
NullAlign { flow: u8 },
Normal(Normal<'a, 'd, U>),
}
impl<'a, 'd, U> Packet<'a, 'd, U> {
pub fn flow(&self) -> u8 {
match self {
Self::NullIdle { flow } => *flow,
Self::NullAlign { flow } => *flow,
Self::Normal(p) => p.flow(),
}
}
pub fn is_null(&self) -> bool {
matches!(self, Self::NullIdle { .. } | Self::NullAlign { .. })
}
pub fn into_normal(self) -> Option<Normal<'a, 'd, U>> {
match self {
Self::Normal(n) => Some(n),
_ => None,
}
}
}
impl<'a, 'd, U> From<Normal<'a, 'd, U>> for Packet<'a, 'd, U> {
fn from(normal: Normal<'a, 'd, U>) -> Self {
Self::Normal(normal)
}
}
impl<'a, 'd, U> Decode<'a, 'd, U> for Packet<'a, 'd, U> {
fn decode(decoder: &'a mut Decoder<'d, U>) -> Result<Self, Error> {
if decoder.bytes_left() == 0 {
return Err(Error::InsufficientData(core::num::NonZeroUsize::MIN));
}
let length = decoder.read_bits(5)?;
let flow = decoder.read_bits(2)?;
let extend = decoder.read_bit()?;
match core::num::NonZeroU8::new(length) {
Some(length) => {
let src_id = decoder.read_bits(decoder.hart_index_width)?;
let timestamp = extend
.then(|| decoder.read_bits(8 * decoder.timestamp_width))
.transpose()?;
decoder
.split_data(decoder.byte_pos() + length.get() as usize)
.map(|remaining| {
Normal {
flow,
src_id,
timestamp,
decoder,
remaining,
}
.into()
})
}
_ if extend => Ok(Self::NullAlign { flow }),
_ => Ok(Self::NullIdle { flow }),
}
}
}
pub struct Normal<'a, 'd, U> {
flow: u8,
src_id: u16,
timestamp: Option<u64>,
decoder: &'a mut Decoder<'d, U>,
remaining: &'d [u8],
}
impl<'a, 'd, U> Normal<'a, 'd, U> {
pub fn flow(&self) -> u8 {
self.flow
}
pub fn src_id(&self) -> u16 {
self.src_id
}
pub fn timestamp(&self) -> Option<u64> {
self.timestamp
}
}
impl<'a, 'd, U: unit::Unit> Normal<'a, 'd, U> {
pub fn payload(self) -> Result<payload::Payload<U::IOptions, U::DOptions>, Error> {
let width = self.decoder.trace_type_width;
match self.decoder.read_bits::<u8>(width)? {
0 => Decode::decode(self.decoder).map(payload::Payload::InstructionTrace),
1 => Ok(payload::Payload::DataTrace),
unknown => Err(Error::UnknownTraceType(unknown)),
}
}
}
impl<U> fmt::Debug for Normal<'_, '_, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Normal")
.field("flow", &self.flow)
.field("src_id", &self.src_id)
.field("timestamp", &self.timestamp)
.field("unaligned_payload", &self.decoder.remaining_data())
.finish_non_exhaustive()
}
}
impl<U> PartialEq for Normal<'_, '_, U> {
fn eq(&self, other: &Self) -> bool {
PartialEq::eq(
&(
self.flow,
self.src_id,
self.timestamp,
self.decoder.remaining_data(),
),
&(
other.flow,
other.src_id,
other.timestamp,
other.decoder.remaining_data(),
),
)
}
}
impl<'a, 'd, U> Drop for Normal<'a, 'd, U> {
fn drop(&mut self) {
self.decoder.reset(self.remaining);
}
}