xio_common 0.12.0

XIO commonly used functionality
Documentation
use crate::base::{ErrorCode, JobStoppedReason};
use crate::{
    Endian, ErrorCodeReaderExt, ErrorCodeWriterExt, HasFixedCommandId,
    JobStoppedReasonReaderExt, JobStoppedReasonWriterExt, MessageExt,
    ReadExt, ReadFromPayload, Result, WithFixedPayloadLength, WriteExt,
};
use std::io::{Read, Write};

#[derive(Clone, Debug, PartialEq)]
pub struct Notification {
    pub reason: JobStoppedReason,
    pub error: ErrorCode,
    pub last_command_position: u16,
    pub last_condition_position: u16,
}

impl From<Notification> for super::Notification {
    fn from(m: Notification) -> Self {
        super::Notification::JobStopped(m)
    }
}

impl WithFixedPayloadLength for Notification {
    const FIXED_PAYLOAD_LENGTH: u16 =
        JobStoppedReason::FIXED_PAYLOAD_LENGTH
            + ErrorCode::FIXED_PAYLOAD_LENGTH
            + u16::FIXED_PAYLOAD_LENGTH
            + u16::FIXED_PAYLOAD_LENGTH;
}

impl HasFixedCommandId for Notification {
    const COMMAND_ID: u16 = 0x8803;
}

impl MessageExt for Notification {
    fn payload_length(&self) -> u16 {
        Self::FIXED_PAYLOAD_LENGTH
    }

    fn write_payload(&self, w: &mut dyn Write) -> Result<()> {
        w.write_job_stopped_reason(self.reason)?;
        w.write_error_code(self.error)?;
        w.write_u16::<Endian>(self.last_command_position)?;
        w.write_u16::<Endian>(self.last_condition_position)?;
        Ok(())
    }
}

impl ReadFromPayload for Notification {
    fn read_from_payload<R: Read>(
        r: &mut R,
        payload_length: u16,
    ) -> Result<Self> {
        Self::verify_payload_length(
            payload_length,
            "job_stopped_notification",
        )?;
        let reason = r.read_job_stopped_reason()?;
        let error = r.read_error_code()?;
        let last_command_position = r.read_u16::<Endian>()?;
        let last_condition_position = r.read_u16::<Endian>()?;
        Ok(Self {
            reason,
            error,
            last_command_position,
            last_condition_position,
        })
    }
}

#[cfg(test)]
mod test_notification {
    use super::*;

    #[test]
    fn write_to() {
        let mut buffer = Vec::new();
        let options: u8 = 0x45;
        let sequence: u8 = 0x93;

        let reason = JobStoppedReason::ExitCriterionMatched;
        let error = ErrorCode::InvalidState;
        let last_command_position = 0x4321;
        let last_condition_position = 0x8765;

        let message = Notification {
            reason,
            error,
            last_command_position,
            last_condition_position,
        };
        message.write_to(&mut buffer, options, sequence).unwrap();
        assert_eq!(
            buffer,
            [
                0x45, // options
                0x93, // sequence
                0x03, // command lower byte
                0x88, // command upper byte
                0x07, // length lower byte
                0x00, // length upper byte
                0x02, // reason
                0x07, // error lower byte
                0x01, // error upper byte
                0x21, // last_command_position lower byte
                0x43, // last_command_position upper byte
                0x65, // last_condition_position lower byte
                0x87, // last_condition_position upper byte
            ]
        );
    }
    #[test]
    fn read_from_payload() {
        let buffer = vec![
            0x02, // reason
            0x07, // error lower byte
            0x01, // error upper byte
            0x21, // last_command_position lower byte
            0x43, // last_command_position upper byte
            0x65, // last_condition_position lower byte
            0x87, // last_condition_position upper byte
        ];
        let len = buffer.len() as u16;
        let message =
            Notification::read_from_payload(&mut buffer.as_slice(), len)
                .unwrap();

        let reason = JobStoppedReason::ExitCriterionMatched;
        let error = ErrorCode::InvalidState;
        let last_command_position = 0x4321;
        let last_condition_position = 0x8765;

        assert_eq!(
            message,
            Notification {
                reason,
                error,
                last_command_position,
                last_condition_position,
            }
        );
    }
}