use crate::{
Error, Identifier, IterableWireFormat, NegativeResponseCode, SingleValueWireFormat, WireFormat,
};
const WRITE_DID_NEGATIVE_RESPONSE_CODES: [NegativeResponseCode; 5] = [
NegativeResponseCode::IncorrectMessageLengthOrInvalidFormat,
NegativeResponseCode::ConditionsNotCorrect,
NegativeResponseCode::RequestOutOfRange,
NegativeResponseCode::SecurityAccessDenied,
NegativeResponseCode::GeneralProgrammingFailure,
];
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub struct WriteDataByIdentifierRequest<Payload> {
pub payload: Payload,
}
impl<Payload: IterableWireFormat> WriteDataByIdentifierRequest<Payload> {
pub fn new(payload: Payload) -> Self {
Self { payload }
}
#[must_use]
pub fn allowed_nack_codes() -> &'static [NegativeResponseCode] {
&WRITE_DID_NEGATIVE_RESPONSE_CODES
}
}
impl<Payload: IterableWireFormat> SingleValueWireFormat for WriteDataByIdentifierRequest<Payload> {}
impl<Payload: IterableWireFormat> WireFormat for WriteDataByIdentifierRequest<Payload> {
fn decode<R: std::io::Read>(reader: &mut R) -> Result<Option<Self>, Error> {
let payload = Payload::decode(reader)?.unwrap();
Ok(Some(Self { payload }))
}
fn required_size(&self) -> usize {
self.payload.required_size()
}
fn encode<T: std::io::Write>(&self, writer: &mut T) -> Result<usize, Error> {
self.payload.encode(writer)
}
}
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub struct WriteDataByIdentifierResponse<DataIdentifier> {
pub identifier: DataIdentifier,
}
impl<DataIdentifier: Identifier> WriteDataByIdentifierResponse<DataIdentifier> {
pub fn new(identifier: DataIdentifier) -> Self {
Self { identifier }
}
}
impl<DataIdentifier: Identifier> SingleValueWireFormat
for WriteDataByIdentifierResponse<DataIdentifier>
{
}
impl<DataIdentifier: Identifier> WireFormat for WriteDataByIdentifierResponse<DataIdentifier> {
fn decode<R: std::io::Read>(reader: &mut R) -> Result<Option<Self>, Error> {
let identifier = DataIdentifier::decode(reader)?.unwrap();
Ok(Some(Self::new(identifier)))
}
fn required_size(&self) -> usize {
self.identifier.required_size()
}
fn encode<T: std::io::Write>(&self, writer: &mut T) -> Result<usize, Error> {
self.identifier.encode(writer)
}
}
#[cfg(test)]
mod test {
use super::*;
use byteorder::WriteBytesExt;
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Copy, Debug, Identifier, PartialEq)]
pub enum TestIdentifier {
Abracadabra = 0xBEEF,
}
impl From<u16> for TestIdentifier {
fn from(value: u16) -> Self {
match value {
0xBEEF => TestIdentifier::Abracadabra,
_ => panic!("Invalid test identifier: {value}"),
}
}
}
impl From<TestIdentifier> for u16 {
fn from(value: TestIdentifier) -> Self {
match value {
TestIdentifier::Abracadabra => 0xBEEF,
}
}
}
impl PartialEq<u16> for TestIdentifier {
fn eq(&self, other: &u16) -> bool {
match self {
TestIdentifier::Abracadabra => *other == 0xBEEF,
}
}
}
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Copy, Debug, PartialEq)]
enum TestPayload {
Abracadabra(u8),
}
impl WireFormat for TestPayload {
fn decode<T: std::io::Read>(reader: &mut T) -> Result<Option<Self>, Error> {
let mut buf = [0u8; 2];
reader.read_exact(&mut buf)?;
let value = u16::from_be_bytes(buf);
if value == TestIdentifier::Abracadabra as u16 {
let mut byte = [0u8; 1];
reader.read_exact(&mut byte)?;
Ok(Some(TestPayload::Abracadabra(byte[0])))
} else {
Err(Error::NoDataAvailable)
}
}
fn encode<T: std::io::Write>(&self, writer: &mut T) -> Result<usize, Error> {
let id_bytes: u16 = match self {
TestPayload::Abracadabra(_) => 0xBEEF,
};
writer.write_all(&id_bytes.to_be_bytes())?;
match self {
TestPayload::Abracadabra(value) => {
writer.write_u8(*value)?;
Ok(self.required_size())
}
}
}
fn required_size(&self) -> usize {
3
}
}
impl IterableWireFormat for TestPayload {}
#[test]
fn test_write_request() {
let request = WriteDataByIdentifierRequest::new(TestPayload::Abracadabra(42));
let mut written_bytes = Vec::new();
let written = request.encode(&mut written_bytes).unwrap();
assert_eq!(written, request.required_size());
assert_eq!(written, written_bytes.len());
let request2 =
WriteDataByIdentifierRequest::<TestPayload>::decode(&mut written_bytes.as_slice())
.unwrap()
.unwrap();
assert_eq!(request, request2);
}
#[test]
fn test_write_response() {
let response = WriteDataByIdentifierResponse::new(TestIdentifier::Abracadabra);
let mut written_bytes = Vec::new();
let written = response.encode(&mut written_bytes).unwrap();
assert_eq!(written, written_bytes.len());
assert_eq!(written, response.required_size());
}
}