use super::decoder::{Decode, Decoder};
use super::encoder::{Encode, Encoder};
use super::{Error, payload, unit};
#[derive(Clone, Debug, PartialEq)]
pub enum Packet<P = payload::Payload> {
NullIdle { flow: u8 },
NullAlign { flow: u8 },
Normal(Normal<P>),
}
impl<P> Packet<P> {
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<P>> {
match self {
Self::Normal(n) => Some(n),
_ => None,
}
}
}
impl<P> From<Normal<P>> for Packet<P> {
fn from(normal: Normal<P>) -> Self {
Self::Normal(normal)
}
}
impl<'d, U> TryFrom<Packet<Decoder<'d, U>>> for Packet<payload::Payload<U::IOptions, U::DOptions>>
where
U: unit::Unit,
{
type Error = Error;
fn try_from(packet: Packet<Decoder<'d, U>>) -> Result<Self, Self::Error> {
match packet {
Packet::NullIdle { flow } => Ok(Self::NullIdle { flow }),
Packet::NullAlign { flow } => Ok(Self::NullAlign { flow }),
Packet::Normal(p) => p.try_into().map(Self::Normal),
}
}
}
impl<'d, U> Decode<'d, U> for Packet<payload::Payload<U::IOptions, U::DOptions>>
where
U: unit::Unit + Clone,
{
fn decode(decoder: &mut Decoder<'d, U>) -> Result<Self, Error> {
Packet::<Decoder<_>>::decode(decoder).and_then(TryFrom::try_from)
}
}
impl<'d, U: Clone> Decode<'d, U> for Packet<Decoder<'d, U>> {
fn decode(decoder: &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_width = decoder.hart_index_width();
let timestamp_width = decoder.timestamp_width();
let length = usize::from(length.get())
+ usize::from(src_id_width >> 3)
+ usize::from(timestamp_width);
let mut payload = decoder.split_off_to(length)?;
let src_id = payload.read_bits(src_id_width)?;
let timestamp = extend
.then(|| payload.read_bits(8 * timestamp_width))
.transpose()?;
Ok(Normal {
flow,
src_id,
timestamp,
payload,
}
.into())
}
_ if extend => Ok(Self::NullAlign { flow }),
_ => Ok(Self::NullIdle { flow }),
}
}
}
impl<'d, U, P> Encode<'d, U> for Packet<P>
where
U: unit::Unit,
Normal<P>: Encode<'d, U>,
{
fn encode(&self, encoder: &mut Encoder<'d, U>) -> Result<(), Error> {
let (flow, extend) = match self {
Self::NullIdle { flow } => (flow, 0x00),
Self::NullAlign { flow } => (flow, 0x80),
Self::Normal(n) => return encoder.encode(n),
};
encoder
.first_uncommitted_chunk::<1>()
.map(|h| h[0] = ((flow & 0x3) << 5) | extend)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Normal<P> {
flow: u8,
src_id: u16,
timestamp: Option<u64>,
payload: P,
}
impl<P> Normal<P> {
pub fn new(flow: u8, src_id: u16, payload: P) -> Self {
Self {
flow,
src_id,
timestamp: None,
payload,
}
}
pub fn with_timestamp(self, timestamp: u64) -> Self {
Self {
timestamp: Some(timestamp),
..self
}
}
pub fn flow(&self) -> u8 {
self.flow
}
pub fn src_id(&self) -> u16 {
self.src_id
}
pub fn timestamp(&self) -> Option<u64> {
self.timestamp
}
pub fn payload(&self) -> &P {
&self.payload
}
pub fn payload_mut(&mut self) -> &mut P {
&mut self.payload
}
}
impl<'d, U: unit::Unit> Normal<Decoder<'d, U>> {
pub fn decode_payload(mut self) -> Result<payload::Payload<U::IOptions, U::DOptions>, Error> {
let width = self.payload.trace_type_width();
match self.payload.read_bits::<u8>(width)? {
0 => Decode::decode(&mut self.payload).map(payload::Payload::InstructionTrace),
1 => Ok(payload::Payload::DataTrace),
unknown => Err(Error::UnknownTraceType(unknown)),
}
}
}
impl<'d, U> TryFrom<Normal<Decoder<'d, U>>> for Normal<payload::Payload<U::IOptions, U::DOptions>>
where
U: unit::Unit,
{
type Error = Error;
fn try_from(normal: Normal<Decoder<'d, U>>) -> Result<Self, Self::Error> {
let flow = normal.flow();
let src_id = normal.src_id();
let timestamp = normal.timestamp();
let res = Self::new(flow, src_id, normal.decode_payload()?);
if let Some(timestamp) = timestamp {
Ok(res.with_timestamp(timestamp))
} else {
Ok(res)
}
}
}
impl<U: unit::Unit> TryFrom<Normal<Decoder<'_, U>>> for payload::Payload<U::IOptions, U::DOptions> {
type Error = Error;
fn try_from(normal: Normal<Decoder<'_, U>>) -> Result<Self, Self::Error> {
normal.decode_payload()
}
}
impl<'d, U> Encode<'d, U> for Normal<payload::Payload<U::IOptions, U::DOptions>>
where
U: unit::Unit,
U::IOptions: Encode<'d, U>,
U::DOptions: Encode<'d, U>,
{
fn encode(&self, encoder: &mut Encoder<'d, U>) -> Result<(), Error> {
let head = &mut encoder.first_uncommitted_chunk::<1>()?[0];
let mut original_uncommitted = encoder
.uncommitted()
.checked_sub((encoder.hart_index_width() >> 3).into())
.ok_or(Error::BufferTooSmall)?;
encoder.write_bits(self.src_id(), encoder.hart_index_width())?;
if let Some(timestamp) = self.timestamp() {
original_uncommitted = original_uncommitted
.checked_sub(encoder.timestamp_width().into())
.ok_or(Error::BufferTooSmall)?;
encoder.write_bits(timestamp, 8 * encoder.timestamp_width())?;
}
match self.payload() {
payload::Payload::InstructionTrace(p) => {
encoder.write_bits(0u8, encoder.trace_type_width())?;
encoder.encode(p)?;
}
payload::Payload::DataTrace => {
encoder.write_bits(1u8, encoder.trace_type_width())?;
}
}
let len = original_uncommitted - encoder.uncommitted();
let len: u8 = len
.try_into()
.ok()
.filter(|l| *l < 32)
.ok_or(Error::PayloadTooBig(len))?;
let flow = (self.flow() & 0x3) << 5;
let extend = if self.timestamp().is_some() { 0x80 } else { 0 };
*head = len | flow | extend;
Ok(())
}
}