mod errors;
pub mod well_known;
pub use errors::*;
use crate::{
errors::NetworkParseError,
mion::proto::parameter::well_known::{ValuableParameterDump, index_from_parameter_name},
};
use bytes::{BufMut, Bytes, BytesMut};
use std::fmt::{Display, Formatter, Result as FmtResult};
use valuable::{Fields, NamedField, NamedValues, StructDef, Structable, Valuable, Value};
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Valuable)]
pub enum PacketType {
Read,
Write,
}
impl From<&PacketType> for i32 {
fn from(value: &PacketType) -> Self {
match *value {
PacketType::Read => 0,
PacketType::Write => 1,
}
}
}
impl From<PacketType> for i32 {
fn from(value: PacketType) -> Self {
Self::from(&value)
}
}
impl TryFrom<i32> for PacketType {
type Error = MionParamProtocolError;
fn try_from(value: i32) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::Read),
1 => Ok(Self::Write),
_ => Err(MionParamProtocolError::PacketType(value)),
}
}
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Valuable)]
pub struct MionDumpParameters;
impl MionDumpParameters {
#[must_use]
pub const fn new() -> Self {
Self {}
}
}
impl Default for MionDumpParameters {
fn default() -> Self {
Self::new()
}
}
impl Display for MionDumpParameters {
fn fmt(&self, fmt: &mut Formatter<'_>) -> FmtResult {
write!(fmt, "MionDumpParameters")
}
}
impl TryFrom<Bytes> for MionDumpParameters {
type Error = NetworkParseError;
fn try_from(packet: Bytes) -> Result<Self, Self::Error> {
if packet.len() < 8 {
return Err(NetworkParseError::NotEnoughData(
"MionDumpParameters",
8,
packet.len(),
packet,
));
}
if packet.len() > 8 {
return Err(NetworkParseError::UnexpectedTrailer(
"MionDumpParameters",
packet.slice(8..),
));
}
let static_bytes: &'static [u8] = &[0_u8, 0, 0, 0, 0, 0, 0, 0];
if packet != static_bytes {
return Err(NetworkParseError::DoesntMatchStaticPayload(
"MionDumpParameters",
static_bytes,
packet,
));
}
Ok(Self)
}
}
impl From<&MionDumpParameters> for Bytes {
fn from(_: &MionDumpParameters) -> Self {
BytesMut::zeroed(8).freeze()
}
}
impl From<MionDumpParameters> for Bytes {
fn from(value: MionDumpParameters) -> Self {
Self::from(&value)
}
}
const DUMPED_MION_PARAMETERS_FIELDS: &[NamedField<'static>] = &[NamedField::new("parameters")];
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct DumpedMionParameters {
parameters: Bytes,
}
impl DumpedMionParameters {
#[must_use]
pub const fn get_raw_parameters(&self) -> &Bytes {
&self.parameters
}
pub fn get_parameter_by_name(&self, name: &str) -> Result<u8, MionParameterAPIError> {
index_from_parameter_name(name)
.map(|index| self.parameters[index])
.ok_or_else(|| MionParameterAPIError::NameNotKnown(name.to_owned()))
}
pub fn get_parameter_by_index(&self, index: usize) -> Result<u8, MionParameterAPIError> {
if index > 511 {
return Err(MionParameterAPIError::NotInRange(index));
}
Ok(self.parameters[index])
}
}
impl TryFrom<Bytes> for DumpedMionParameters {
type Error = NetworkParseError;
fn try_from(packet: Bytes) -> Result<Self, Self::Error> {
if packet.len() < 520 {
return Err(NetworkParseError::NotEnoughData(
"DumpedMionParameters",
520,
packet.len(),
packet,
));
}
if packet.len() > 520 {
return Err(NetworkParseError::UnexpectedTrailer(
"DumpedMionParameters",
packet.slice(520..),
));
}
let header = packet.slice(..8);
let packet_type = PacketType::try_from(i32::from_le_bytes([
header[0], header[1], header[2], header[3],
]))?;
if packet_type != PacketType::Read {
return Err(MionParamProtocolError::PacketType(i32::from(packet_type)).into());
}
let size_or_error = i32::from_le_bytes([header[4], header[5], header[6], header[7]]);
if size_or_error != 512 {
return Err(MionParamProtocolError::ErrorCode(size_or_error).into());
}
let parameters = packet.slice(8..);
Ok(Self { parameters })
}
}
impl From<&DumpedMionParameters> for Bytes {
fn from(value: &DumpedMionParameters) -> Self {
let mut buff = BytesMut::with_capacity(520);
buff.put_i32_le(i32::from(PacketType::Read));
buff.put_i32_le(512);
buff.extend_from_slice(&value.parameters);
buff.freeze()
}
}
impl From<DumpedMionParameters> for Bytes {
fn from(value: DumpedMionParameters) -> Self {
Self::from(&value)
}
}
impl Structable for DumpedMionParameters {
fn definition(&self) -> StructDef<'_> {
StructDef::new_static(
"DumpedMionParameters",
Fields::Named(DUMPED_MION_PARAMETERS_FIELDS),
)
}
}
impl Valuable for DumpedMionParameters {
fn as_value(&self) -> Value<'_> {
Value::Structable(self)
}
fn visit(&self, visitor: &mut dyn valuable::Visit) {
let dump = ValuableParameterDump(&self.parameters);
visitor.visit_named_fields(&NamedValues::new(
DUMPED_MION_PARAMETERS_FIELDS,
&[Valuable::as_value(&dump)],
));
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct SetMionParameters {
parameters: Bytes,
}
impl SetMionParameters {
pub fn new(parameters: Bytes) -> Result<Self, MionParameterAPIError> {
if parameters.len() != 512 {
return Err(MionParameterAPIError::BodyNotCorrectLength(
parameters.len(),
));
}
Ok(Self { parameters })
}
#[must_use]
pub const fn get_raw_parameters(&self) -> &Bytes {
&self.parameters
}
pub fn get_parameter_by_name(&self, name: &str) -> Result<u8, MionParameterAPIError> {
index_from_parameter_name(name)
.map(|index| self.parameters[index])
.ok_or_else(|| MionParameterAPIError::NameNotKnown(name.to_owned()))
}
pub fn get_parameter_by_index(&self, index: usize) -> Result<u8, MionParameterAPIError> {
if index > 511 {
return Err(MionParameterAPIError::NotInRange(index));
}
Ok(self.parameters[index])
}
}
impl TryFrom<Bytes> for SetMionParameters {
type Error = NetworkParseError;
fn try_from(packet: Bytes) -> Result<Self, Self::Error> {
if packet.len() < 520 {
return Err(NetworkParseError::NotEnoughData(
"SetMionParameters",
520,
packet.len(),
packet,
));
}
if packet.len() > 520 {
return Err(NetworkParseError::UnexpectedTrailer(
"SetMionParameters",
packet.slice(520..),
));
}
let header = packet.slice(..8);
let packet_type = PacketType::try_from(i32::from_le_bytes([
header[0], header[1], header[2], header[3],
]))?;
if packet_type != PacketType::Write {
return Err(MionParamProtocolError::PacketType(i32::from(packet_type)).into());
}
let size_or_error_code = i32::from_le_bytes([header[4], header[5], header[6], header[7]]);
if size_or_error_code != 512 {
return Err(MionParamProtocolError::ErrorCode(size_or_error_code).into());
}
let parameters = packet.slice(8..);
Ok(Self { parameters })
}
}
impl From<&SetMionParameters> for Bytes {
fn from(value: &SetMionParameters) -> Self {
let mut buff = BytesMut::with_capacity(520);
buff.put_i32_le(i32::from(PacketType::Write));
buff.put_i32_le(512);
buff.extend_from_slice(&value.parameters);
buff.freeze()
}
}
impl From<SetMionParameters> for Bytes {
fn from(value: SetMionParameters) -> Self {
Self::from(&value)
}
}
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub struct SetMionParametersResponse {
return_code: i32,
}
impl SetMionParametersResponse {
#[must_use]
pub const fn get_return_code(&self) -> i32 {
self.return_code
}
#[must_use]
pub const fn is_success(&self) -> bool {
self.return_code == 0
}
#[must_use]
pub const fn is_error(&self) -> bool {
self.return_code != 0
}
}
impl TryFrom<Bytes> for SetMionParametersResponse {
type Error = NetworkParseError;
fn try_from(packet: Bytes) -> Result<Self, Self::Error> {
if packet.len() < 12 {
return Err(NetworkParseError::NotEnoughData(
"SetMionParametersResponse",
12,
packet.len(),
packet,
));
}
if packet.len() > 12 {
return Err(NetworkParseError::UnexpectedTrailer(
"SetMionParametersResponse",
packet.slice(12..),
));
}
let header = packet.slice(..8);
let packet_type = PacketType::try_from(i32::from_le_bytes([
header[0], header[1], header[2], header[3],
]))?;
if packet_type != PacketType::Write {
return Err(MionParamProtocolError::PacketType(i32::from(packet_type)).into());
}
let size_or_status = i32::from_le_bytes([header[4], header[5], header[6], header[7]]);
if size_or_status != 4 {
return Err(MionParamProtocolError::ErrorCode(size_or_status).into());
}
let body = packet.slice(8..);
let return_code = i32::from_le_bytes([body[0], body[1], body[2], body[3]]);
Ok(Self { return_code })
}
}
impl From<&SetMionParametersResponse> for Bytes {
fn from(value: &SetMionParametersResponse) -> Self {
let mut buff = BytesMut::with_capacity(12);
buff.put_i32_le(i32::from(PacketType::Write));
buff.put_i32_le(4);
buff.put_i32_le(value.return_code);
buff.freeze()
}
}
impl From<SetMionParametersResponse> for Bytes {
fn from(value: SetMionParametersResponse) -> Self {
Self::from(&value)
}
}
#[cfg(test)]
mod unit_tests {
use super::*;
use bytes::Bytes;
use std::sync::LazyLock;
static REAL_LIFE_DUMPED_MION_PARAMETERS_PACKET: LazyLock<Vec<u8>> = LazyLock::new(|| {
vec![
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x0c, 0x0d,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff,
]
});
static REAL_LIFE_SET_MION_PARAMETERS_PACKET: LazyLock<Vec<u8>> = LazyLock::new(|| {
vec![
0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x0c, 0x0d,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x45,
]
});
#[test]
pub fn deser_mion_dump_parameters() {
{
assert!(
MionDumpParameters::try_from(Bytes::from(MionDumpParameters)).is_ok(),
"Deserializing a serialized MionDumpParameters was not a success!",
);
}
{
let short_data = vec![0x0; 4];
let too_much_data = vec![0x0; 16];
assert_eq!(
MionDumpParameters::try_from(Bytes::from(short_data.clone())),
Err(NetworkParseError::NotEnoughData(
"MionDumpParameters",
8,
short_data.len(),
Bytes::from(short_data),
)),
);
assert_eq!(
MionDumpParameters::try_from(Bytes::from(too_much_data.clone())),
Err(NetworkParseError::UnexpectedTrailer(
"MionDumpParameters",
Bytes::from(too_much_data).slice(8..),
)),
);
}
{
let invalid_static_packet = vec![0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0];
assert_eq!(
MionDumpParameters::try_from(Bytes::from(invalid_static_packet.clone())),
Err(NetworkParseError::DoesntMatchStaticPayload(
"MionDumpParameters",
&[0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0],
Bytes::from(invalid_static_packet),
)),
);
}
}
#[test]
pub fn deser_dumped_mion_parameters() {
{
let short_data = vec![0x0; 519];
let too_long_data = vec![0x0; 521];
assert_eq!(
DumpedMionParameters::try_from(Bytes::from(short_data.clone())),
Err(NetworkParseError::NotEnoughData(
"DumpedMionParameters",
520,
short_data.len(),
Bytes::from(short_data),
)),
);
assert_eq!(
DumpedMionParameters::try_from(Bytes::from(too_long_data.clone())),
Err(NetworkParseError::UnexpectedTrailer(
"DumpedMionParameters",
Bytes::from(too_long_data).slice(520..),
)),
);
}
{
let mut data = vec![0x0; 520];
data[0] = 11;
let packet_with_bad_data = Bytes::from(data);
assert_eq!(
DumpedMionParameters::try_from(packet_with_bad_data),
Err(MionParamProtocolError::PacketType(11).into()),
);
let mut data = vec![0x0; 520];
data[0] = 1;
let packet_with_bad_data = Bytes::from(data);
assert_eq!(
DumpedMionParameters::try_from(packet_with_bad_data),
Err(MionParamProtocolError::PacketType(1).into()),
);
}
{
let result = DumpedMionParameters::try_from(Bytes::from(
REAL_LIFE_DUMPED_MION_PARAMETERS_PACKET.clone(),
));
assert!(
result.is_ok(),
"Failed to parse a real life DumpedMionParameters packet:\n\n {result:?}",
);
let result_two = DumpedMionParameters::try_from(Bytes::from(result.unwrap()));
assert!(
result_two.is_ok(),
"Failed to round-trip real life DumpedMionParameters:\n\n {result_two:?}",
);
}
}
#[test]
pub fn dumped_mion_parameters_api() {
let parsed_packet = DumpedMionParameters::try_from(Bytes::from(
REAL_LIFE_DUMPED_MION_PARAMETERS_PACKET.clone(),
))
.expect("Failed to parse real life dumped mion parmaeters packet!");
assert_eq!(
parsed_packet.get_raw_parameters(),
&REAL_LIFE_DUMPED_MION_PARAMETERS_PACKET[8..],
".get_raw_parameters() for DumpedMionParameters did not return the correct body!",
);
assert_eq!(
parsed_packet.get_parameter_by_name("major-version"),
Ok(0x02),
);
assert_eq!(
parsed_packet.get_parameter_by_name("minor version"),
Ok(0x0C),
);
assert_eq!(
parsed_packet.get_parameter_by_name("5"),
Ok(0x0D),
);
assert_eq!(
parsed_packet.get_parameter_by_name("512"),
Err(MionParameterAPIError::NameNotKnown("512".to_owned())),
);
assert_eq!(parsed_packet.get_parameter_by_index(511), Ok(0xFF));
assert_eq!(
parsed_packet.get_parameter_by_index(512),
Err(MionParameterAPIError::NotInRange(512)),
);
}
#[test]
pub fn deser_set_mion_parameters() {
{
let short_data = vec![0x0; 519];
let too_long_data = vec![0x0; 521];
assert_eq!(
SetMionParameters::try_from(Bytes::from(short_data.clone())),
Err(NetworkParseError::NotEnoughData(
"SetMionParameters",
520,
short_data.len(),
Bytes::from(short_data),
)),
);
assert_eq!(
SetMionParameters::try_from(Bytes::from(too_long_data.clone())),
Err(NetworkParseError::UnexpectedTrailer(
"SetMionParameters",
Bytes::from(too_long_data).slice(520..),
)),
);
}
{
let mut data = vec![0x0; 520];
data[0] = 11;
let packet_with_bad_data = Bytes::from(data);
assert_eq!(
SetMionParameters::try_from(packet_with_bad_data),
Err(MionParamProtocolError::PacketType(11).into()),
);
let mut data = vec![0x0; 520];
data[0] = 0;
let packet_with_bad_data = Bytes::from(data);
assert_eq!(
SetMionParameters::try_from(packet_with_bad_data),
Err(MionParamProtocolError::PacketType(0).into()),
);
}
{
let result = SetMionParameters::try_from(Bytes::from(
REAL_LIFE_SET_MION_PARAMETERS_PACKET.clone(),
));
assert!(
result.is_ok(),
"Failed to parse a real life SetMionParameters packet:\n\n {result:?}",
);
let result_two = SetMionParameters::try_from(Bytes::from(result.unwrap()));
assert!(
result_two.is_ok(),
"Failed to round-trip real life SetMionParameters:\n\n {result_two:?}",
);
}
}
#[test]
pub fn set_mion_parameters_api() {
{
assert!(
SetMionParameters::new(Bytes::from(&REAL_LIFE_DUMPED_MION_PARAMETERS_PACKET[8..]))
.is_ok(),
"Failed to construct `SetMionParameters` from a valid dumped parameters set!",
);
assert_eq!(
SetMionParameters::new(Bytes::from(&REAL_LIFE_DUMPED_MION_PARAMETERS_PACKET[7..])),
Err(MionParameterAPIError::BodyNotCorrectLength(513)),
);
}
{
let parsed_packet = SetMionParameters::try_from(Bytes::from(
REAL_LIFE_SET_MION_PARAMETERS_PACKET.clone(),
))
.expect("Failed to parse real life set mion parameters packet!");
assert_eq!(
parsed_packet.get_raw_parameters(),
&REAL_LIFE_SET_MION_PARAMETERS_PACKET[8..],
".get_raw_parameters() for SetMionParameters did not return the correct body!",
);
assert_eq!(
parsed_packet.get_parameter_by_name("major-version"),
Ok(0x02),
);
assert_eq!(
parsed_packet.get_parameter_by_name("minor version"),
Ok(0x0C),
);
assert_eq!(
parsed_packet.get_parameter_by_name("5"),
Ok(0x0D),
);
assert_eq!(
parsed_packet.get_parameter_by_name("512"),
Err(MionParameterAPIError::NameNotKnown("512".to_owned())),
);
assert_eq!(parsed_packet.get_parameter_by_index(511), Ok(69));
assert_eq!(
parsed_packet.get_parameter_by_index(512),
Err(MionParameterAPIError::NotInRange(512)),
);
}
}
#[test]
pub fn deser_set_mion_parameters_response() {
{
let short_data = vec![0x0; 11];
let too_long_data = vec![0x0; 13];
assert_eq!(
SetMionParametersResponse::try_from(Bytes::from(short_data.clone())),
Err(NetworkParseError::NotEnoughData(
"SetMionParametersResponse",
12,
short_data.len(),
Bytes::from(short_data),
)),
);
assert_eq!(
SetMionParametersResponse::try_from(Bytes::from(too_long_data.clone())),
Err(NetworkParseError::UnexpectedTrailer(
"SetMionParametersResponse",
Bytes::from(too_long_data).slice(12..),
)),
);
}
{
assert_eq!(
SetMionParametersResponse::try_from(Bytes::from(vec![
0x11, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
])),
Err(MionParamProtocolError::PacketType(0x11).into()),
);
assert_eq!(
SetMionParametersResponse::try_from(Bytes::from(vec![
0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
])),
Err(MionParamProtocolError::PacketType(0).into()),
);
}
{
assert_eq!(
SetMionParametersResponse::try_from(Bytes::from(vec![
0x1, 0x0, 0x0, 0x0, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
])),
Err(MionParamProtocolError::ErrorCode(5).into()),
);
}
{
let result = SetMionParametersResponse::try_from(Bytes::from(vec![
0x1, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
]));
assert!(
result.is_ok(),
"Failed to respond to real life SetMionParametersResponse success!"
);
assert!(
SetMionParametersResponse::try_from(Bytes::from(result.unwrap())).is_ok(),
"Failed to round-trip real-life SetMionParametersResponse success!",
);
}
}
}