use crate::Error;
use byteorder::{BigEndian, WriteBytesExt};
pub trait WireFormat: Sized {
fn decode<T: std::io::Read>(reader: &mut T) -> Result<Option<Self>, Error>;
fn required_size(&self) -> usize;
fn encode<T: std::io::Write>(&self, writer: &mut T) -> Result<usize, Error>;
fn is_positive_response_suppressed(&self) -> bool {
false
}
}
struct WireFormatIterator<'a, T, R> {
reader: &'a mut R,
_phantom: std::marker::PhantomData<T>,
}
impl<T: WireFormat, R: std::io::Read> Iterator for WireFormatIterator<'_, T, R> {
type Item = Result<T, Error>;
fn next(&mut self) -> Option<Self::Item> {
match T::decode(self.reader.by_ref()) {
Ok(Some(value)) => Some(Ok(value)),
Ok(None) => None,
Err(e) => Some(Err(e)),
}
}
}
pub trait IterableWireFormat: WireFormat {
fn decode_iterable<T: std::io::Read>(
reader: &mut T,
) -> impl Iterator<Item = Result<Self, Error>> {
WireFormatIterator {
reader,
_phantom: std::marker::PhantomData,
}
}
}
pub trait SingleValueWireFormat: WireFormat {
fn decode_single_value<T: std::io::Read>(reader: &mut T) -> Result<Self, Error> {
Ok(Self::decode(reader)?.expect(
"SingleValueWireFormat is only valid to implement on types which never return none",
))
}
}
#[cfg(feature = "serde")]
mod maybe_serde {
pub trait Bound: serde::Serialize + for<'de> serde::Deserialize<'de> {}
impl<T> Bound for T where T: serde::Serialize + for<'de> serde::Deserialize<'de> {}
}
#[cfg(not(feature = "serde"))]
mod maybe_serde {
pub trait Bound {}
impl<T> Bound for T {}
}
#[cfg(feature = "utoipa")]
mod maybe_utoipa {
pub trait Bound: utoipa::ToSchema {}
impl<T> Bound for T where T: utoipa::ToSchema {}
}
#[cfg(not(feature = "utoipa"))]
mod maybe_utoipa {
pub trait Bound {}
impl<T> Bound for T {}
}
pub trait Identifier: TryFrom<u16> + Into<u16> + Clone + Copy + maybe_serde::Bound {
fn parse_from_list<R: std::io::Read>(reader: &mut R) -> Result<Vec<Self>, Error> {
WireFormatIterator {
reader,
_phantom: std::marker::PhantomData,
}
.collect()
}
fn parse_from_payload<R: std::io::Read>(reader: &mut R) -> Result<Option<Self>, Error> {
Self::decode(reader)
}
}
pub trait RoutineIdentifier: Identifier {}
impl<T> WireFormat for T
where
T: Identifier,
{
fn decode<R: std::io::Read>(reader: &mut R) -> Result<Option<Self>, Error> {
let mut identifier_data: [u8; 2] = [0; 2];
match reader.read(&mut identifier_data)? {
0 => return Ok(None),
1 => return Err(Error::IncorrectMessageLengthOrInvalidFormat),
2 => (),
_ => unreachable!("Impossible to read more than 2 bytes into 2 byte array"),
}
match Self::try_from(u16::from_be_bytes(identifier_data)) {
Ok(identifier) => Ok(Some(identifier)),
Err(_) => Err(Error::InvalidDiagnosticIdentifier(u16::from_be_bytes(
identifier_data,
))),
}
}
fn required_size(&self) -> usize {
2
}
fn encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, Error> {
writer.write_u16::<BigEndian>((*self).into())?;
Ok(2)
}
}
pub trait DiagnosticDefinition: 'static {
type DID: Identifier
+ Clone
+ std::fmt::Debug
+ Send
+ Sync
+ PartialEq
+ 'static
+ maybe_serde::Bound
+ maybe_utoipa::Bound;
type DiagnosticPayload: IterableWireFormat
+ Clone
+ std::fmt::Debug
+ Send
+ Sync
+ PartialEq
+ maybe_serde::Bound
+ maybe_utoipa::Bound
+ 'static;
type RID: RoutineIdentifier
+ Clone
+ std::fmt::Debug
+ Send
+ Sync
+ PartialEq
+ 'static
+ maybe_serde::Bound
+ maybe_utoipa::Bound;
type RoutinePayload: WireFormat
+ Clone
+ std::fmt::Debug
+ Send
+ Sync
+ PartialEq
+ 'static
+ maybe_serde::Bound
+ maybe_utoipa::Bound;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Identifier, UDSIdentifier};
use byteorder::ReadBytesExt;
use std::io::Cursor;
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Copy, Debug, Eq, Identifier, PartialEq)]
#[repr(u16)]
pub enum MyIdentifier {
Identifier1 = 0x0101,
Identifier2 = 0x0202,
Identifier3 = 0x0303,
UDSIdentifier(UDSIdentifier),
}
impl From<u16> for MyIdentifier {
fn from(value: u16) -> Self {
match value {
0x0101 => MyIdentifier::Identifier1,
0x0202 => MyIdentifier::Identifier2,
0x0303 => MyIdentifier::Identifier3,
_ => MyIdentifier::UDSIdentifier(UDSIdentifier::try_from(value).unwrap()),
}
}
}
impl From<MyIdentifier> for u16 {
fn from(value: MyIdentifier) -> Self {
match value {
MyIdentifier::Identifier1 => 0x0101,
MyIdentifier::Identifier2 => 0x0202,
MyIdentifier::Identifier3 => 0x0303,
MyIdentifier::UDSIdentifier(identifier) => u16::from(identifier),
}
}
}
#[derive(Debug)]
pub struct MyPayload {
identifier: MyIdentifier,
u8_value: u8,
}
#[test]
fn test_identifier() {
let mut buffer = Cursor::new(vec![0u8; 2]);
let identifier = MyIdentifier::Identifier1;
identifier.encode(&mut buffer).unwrap();
buffer.set_position(0);
let read_identifier = MyIdentifier::parse_from_list(&mut buffer).unwrap();
assert_eq!(identifier, read_identifier[0]);
}
#[test]
#[allow(clippy::match_same_arms)]
fn test_payload() {
let mut buffer = Cursor::new(vec![0x01, 0x01, 0xFF, 0x02, 0x02, 0xFF, 0x03, 0x03]);
while let Some(identifier) = MyIdentifier::parse_from_payload(&mut buffer).unwrap() {
match identifier {
MyIdentifier::Identifier1 | MyIdentifier::Identifier2 => {
let payload = MyPayload {
identifier,
u8_value: buffer.read_u8().unwrap(),
};
assert!(matches!(
payload.identifier,
MyIdentifier::Identifier1 | MyIdentifier::Identifier2
));
assert_eq!(payload.u8_value, 0xFF);
}
MyIdentifier::Identifier3 => (),
MyIdentifier::UDSIdentifier(_) => (),
}
}
println!("Testing printing");
}
}