use std::convert::TryFrom;
use crate::{
checks::application::ams::{
AMS_HEADER_LEN, validate_ams_header_length, validate_cb_data_length, validate_cmd_id,
validate_state_flags,
},
errors::application::ams::AmsParseError,
};
#[cfg_attr(doc, aquamarine::aquamarine)]
#[derive(Debug)]
pub struct AmsPacket<'a> {
pub ams_target_net_id: [u8; 6], pub ams_target_port: u16,
pub ams_sender_net_id: [u8; 6],
pub ams_sender_port: u16,
pub cmd_id: u16,
pub state_flags: u16,
pub cb_data: u32,
pub error_code: u32,
pub invoke_id: u32,
pub data: &'a [u8],
}
impl<'a> TryFrom<&'a [u8]> for AmsPacket<'a> {
type Error = AmsParseError;
fn try_from(bytes: &'a [u8]) -> Result<Self, Self::Error> {
let len = bytes.len();
validate_ams_header_length(len)?;
let ams_target_net_id: [u8; 6] = bytes[0..6].try_into().unwrap();
let ams_target_port = u16::from_le_bytes(bytes[6..8].try_into().unwrap());
let ams_sender_net_id: [u8; 6] = bytes[8..14].try_into().unwrap();
let ams_sender_port = u16::from_le_bytes(bytes[14..16].try_into().unwrap());
let cmd_id = u16::from_le_bytes(bytes[16..18].try_into().unwrap());
let state_flags = u16::from_le_bytes(bytes[18..20].try_into().unwrap());
let cb_data = u32::from_le_bytes(bytes[20..24].try_into().unwrap());
let error_code = u32::from_le_bytes(bytes[24..28].try_into().unwrap());
let invoke_id = u32::from_le_bytes(bytes[28..32].try_into().unwrap());
let data_start = AMS_HEADER_LEN;
let actual_data_len = len - data_start;
validate_cb_data_length(cb_data, actual_data_len)?;
validate_cmd_id(cmd_id)?;
validate_state_flags(state_flags)?;
let data = &bytes[data_start..data_start + actual_data_len];
Ok(AmsPacket {
ams_target_net_id,
ams_target_port,
ams_sender_net_id,
ams_sender_port,
cmd_id,
state_flags,
cb_data,
error_code,
invoke_id,
data,
})
}
}