use crate::{Error, Identifier, RoutineControlSubFunction, SingleValueWireFormat, WireFormat};
use byteorder::{ReadBytesExt, WriteBytesExt};
use std::io::{Read, Write};
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub struct RoutineControlRequest<RoutineIdentifier, RoutinePayload> {
pub sub_function: RoutineControlSubFunction,
pub routine_id: RoutineIdentifier,
pub data: Option<RoutinePayload>,
}
impl<RoutineIdentifier: Identifier, RoutinePayload: WireFormat>
RoutineControlRequest<RoutineIdentifier, RoutinePayload>
{
pub(crate) fn new(
sub_function: RoutineControlSubFunction,
routine_id: RoutineIdentifier,
data: Option<RoutinePayload>,
) -> Self {
Self {
sub_function,
routine_id,
data,
}
}
}
impl<RoutineIdentifier: Identifier, RoutinePayload: WireFormat> WireFormat
for RoutineControlRequest<RoutineIdentifier, RoutinePayload>
{
fn decode<T: Read>(reader: &mut T) -> Result<Option<Self>, Error> {
let sub_function = RoutineControlSubFunction::from(reader.read_u8()?);
let routine_id = RoutineIdentifier::decode(reader)?.unwrap();
let data = RoutinePayload::decode(reader)?;
Ok(Some(Self {
sub_function,
routine_id,
data,
}))
}
fn required_size(&self) -> usize {
3 + match &self.data {
Some(record) => record.required_size(),
None => 0,
}
}
fn encode<T: Write>(&self, writer: &mut T) -> Result<usize, Error> {
writer.write_u8(u8::from(self.sub_function))?;
self.routine_id.encode(writer)?;
if let Some(record) = &self.data {
record.encode(writer)?;
}
Ok(self.required_size())
}
}
impl<RoutineIdentifier: Identifier, RoutinePayload: WireFormat> SingleValueWireFormat
for RoutineControlRequest<RoutineIdentifier, RoutinePayload>
{
}
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub struct RoutineControlResponse<RoutineInfoStatusRecord> {
pub routine_control_type: RoutineControlSubFunction,
pub routine_status_record: RoutineInfoStatusRecord,
}
impl<RoutineStatusRecord: WireFormat> RoutineControlResponse<RoutineStatusRecord> {
pub(crate) fn new(
routine_control_type: RoutineControlSubFunction,
data: RoutineStatusRecord,
) -> Self {
Self {
routine_control_type,
routine_status_record: data,
}
}
pub fn status_record_data(&self) -> Result<Vec<u8>, Error> {
let mut writer: Vec<u8> = Vec::new();
self.routine_status_record.encode(&mut writer)?;
Ok(writer)
}
}
impl<RoutineStatusRecord: WireFormat> WireFormat for RoutineControlResponse<RoutineStatusRecord> {
fn decode<T: Read>(reader: &mut T) -> Result<Option<Self>, Error> {
let routine_control_type = RoutineControlSubFunction::from(reader.read_u8()?);
let routine_status_record = RoutineStatusRecord::decode(reader)?.unwrap();
Ok(Some(Self {
routine_control_type,
routine_status_record,
}))
}
fn required_size(&self) -> usize {
1 + self.routine_status_record.required_size()
}
fn encode<T: Write>(&self, writer: &mut T) -> Result<usize, Error> {
writer.write_u8(self.routine_control_type.into())?;
self.routine_status_record.encode(writer)?;
Ok(self.required_size())
}
}
impl<RoutineStatusRecord: WireFormat> SingleValueWireFormat
for RoutineControlResponse<RoutineStatusRecord>
{
}
#[cfg(test)]
mod request {
use super::*;
use crate::Identifier;
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[derive(Clone, Copy, Debug, Eq, Identifier, PartialEq)]
struct TestIdentifier(pub u16);
impl From<u16> for TestIdentifier {
fn from(value: u16) -> Self {
TestIdentifier(value)
}
}
impl From<TestIdentifier> for u16 {
fn from(val: TestIdentifier) -> Self {
val.0
}
}
type RoutineControlRequestType = RoutineControlRequest<TestIdentifier, Vec<u8>>;
#[test]
fn simple_request() {
let bytes: [u8; 6] = [0x01, 0x00, 0x01, 0x02, 0x03, 0x04];
let req: RoutineControlRequestType =
RoutineControlRequest::decode_single_value(&mut bytes.as_slice()).unwrap();
assert_eq!(u8::from(req.sub_function), 0x01);
assert_eq!(req.routine_id, TestIdentifier::from(0x0001));
let data = req.data.clone().unwrap();
assert_eq!(data, vec![0x02, 0x03, 0x04]);
let mut buf = Vec::new();
let written = req.encode(&mut buf).unwrap();
assert_eq!(written, bytes.len());
assert_eq!(written, req.required_size());
let new_req: RoutineControlRequestType = RoutineControlRequest::new(
RoutineControlSubFunction::StopRoutine,
TestIdentifier::from(0x0002),
Some(vec![]),
);
assert_eq!(new_req.sub_function, RoutineControlSubFunction::StopRoutine);
assert_eq!(new_req.routine_id, TestIdentifier::from(0x0002));
}
#[test]
fn simple_response() {
let bytes: [u8; 6] = [0x01, 0x00, 0x01, 0x02, 0x03, 0x04];
let resp: RoutineControlResponse<Vec<u8>> =
RoutineControlResponse::decode_single_value(&mut bytes.as_slice()).unwrap();
assert_eq!(
resp.routine_control_type,
RoutineControlSubFunction::StartRoutine
);
assert_eq!(
resp.routine_status_record,
vec![0x00, 0x01, 0x02, 0x03, 0x04]
);
let mut buf = Vec::new();
let written = resp.encode(&mut buf).unwrap();
assert_eq!(written, bytes.len());
assert_eq!(written, resp.required_size());
let new_resp: RoutineControlResponse<Vec<u8>> =
RoutineControlResponse::new(RoutineControlSubFunction::StopRoutine, buf);
assert_eq!(
new_resp.routine_control_type,
RoutineControlSubFunction::StopRoutine
);
}
}