use mac_parser::MACAddress;
use scroll::{
ctx::{MeasureWith, TryFromCtx, TryIntoCtx},
Endian, Pread, Pwrite,
};
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct AMSDUSubframe<Payload> {
pub destination_address: MACAddress,
pub source_address: MACAddress,
pub payload: Payload,
}
impl AMSDUSubframe<&'_ [u8]> {
pub const fn length_in_bytes(&self) -> usize {
14 + self.payload.len()
}
}
impl<Payload: MeasureWith<()>> MeasureWith<()> for AMSDUSubframe<Payload> {
fn measure_with(&self, ctx: &()) -> usize {
14 + self.payload.measure_with(ctx)
}
}
impl<'a> TryFromCtx<'a> for AMSDUSubframe<&'a [u8]> {
type Error = scroll::Error;
fn try_from_ctx(from: &'a [u8], _ctx: ()) -> Result<(Self, usize), Self::Error> {
let mut offset = 0;
let destination_address = from.gread(&mut offset)?;
let source_address = from.gread(&mut offset)?;
let length = from.gread_with::<u16>(&mut offset, Endian::Little)?;
let payload = from.gread_with(&mut offset, length as usize)?;
offset += 3;
offset &= !0b0000_0011;
Ok((
Self {
destination_address,
source_address,
payload,
},
offset,
))
}
}
impl<Payload: TryIntoCtx<Error = scroll::Error> + MeasureWith<()>> TryIntoCtx
for AMSDUSubframe<Payload>
{
type Error = scroll::Error;
fn try_into_ctx(self, buf: &mut [u8], _ctx: ()) -> Result<usize, Self::Error> {
let mut offset = 0;
buf.gwrite(self.destination_address, &mut offset)?;
buf.gwrite(self.source_address, &mut offset)?;
buf.gwrite_with(
self.payload.measure_with(&()) as u16,
&mut offset,
Endian::Little,
)?;
buf.gwrite(self.payload, &mut offset)?;
offset += 3;
offset &= !0b0000_0011;
Ok(offset)
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct AMSDUSubframeIterator<'a> {
pub(crate) bytes: Option<&'a [u8]>,
offset: usize,
}
impl<'a> AMSDUSubframeIterator<'a> {
pub const fn from_bytes(bytes: &'a [u8]) -> Self {
Self {
bytes: Some(bytes),
offset: 0,
}
}
pub const fn length_in_bytes(&self) -> usize {
match self.bytes {
Some(bytes) => bytes.len(),
None => 0,
}
}
}
impl<'a> Iterator for AMSDUSubframeIterator<'a> {
type Item = AMSDUSubframe<&'a [u8]>;
fn next(&mut self) -> Option<Self::Item> {
let sub_frame = self.bytes?.gread(&mut self.offset).ok();
match sub_frame {
Some(sub_frame) => Some(sub_frame),
None => {
self.bytes = None;
None
}
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub struct AMSDUPayload<Frames> {
pub sub_frames: Frames,
}
impl<'a> AMSDUPayload<&'a [AMSDUSubframe<&'a [u8]>]> {
pub const fn length_in_bytes(&self) -> usize {
let mut size = 0;
let mut i = 0;
while i != self.sub_frames.len() {
size += self.sub_frames[i].length_in_bytes();
i += 1;
}
size
}
}
impl<'a, Frames: IntoIterator<Item = &'a Payload> + Clone, Payload: MeasureWith<()> + 'a>
MeasureWith<()> for AMSDUPayload<Frames>
{
fn measure_with(&self, _ctx: &()) -> usize {
self.sub_frames
.clone()
.into_iter()
.map(|sub_frame| sub_frame.measure_with(&()))
.sum()
}
}
impl<
'a,
Frames: IntoIterator<Item = &'a Payload>,
Payload: Copy + TryIntoCtx<Error = scroll::Error> + 'a,
> TryIntoCtx for AMSDUPayload<Frames>
{
type Error = scroll::Error;
fn try_into_ctx(self, buf: &mut [u8], _ctx: ()) -> Result<usize, Self::Error> {
let mut offset = 0;
for sub_frame in self.sub_frames.into_iter() {
buf.gwrite(*sub_frame, &mut offset)?;
}
Ok(offset)
}
}