xio_common 0.5.0

XIO commonly used functionality
Documentation
use byteorder::{ReadBytesExt, WriteBytesExt};
use std::io::{Read, Write};
use base::{ParameterValueRaw,HasErrorCode,ErrorCode};
use {io, Endian,  ErrorCodeReaderExt, ErrorCodeWriterExt,
     ErrorKind,  HasFixedCommandId, IsRequest, IsResponse,
     IsValidResponseFor, MessageExt,
     ParameterValueReaderExt, ParameterValueWriteMode,
     ParameterValueWriterExt, ReadFromPayload, Result, TryFromResponse,
     WithFixedPayloadLength};

#[derive(Clone, Debug, PartialEq)]
pub struct Request {
    pub parameter_index: u16,
}

impl IsRequest for Request {
    type Response = Response;
}

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

impl WithFixedPayloadLength for Request {
    const FIXED_PAYLOAD_LENGTH: u16 = u16::FIXED_PAYLOAD_LENGTH;
}

impl HasFixedCommandId for Request {
    const COMMAND_ID: u16 = 0x2812;
}

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

    fn write_payload(&self, w: &mut Write) -> io::Result<()> {
        w.write_u16::<Endian>(self.parameter_index)?;
        Ok(())
    }
}

impl ReadFromPayload for Request {
    fn read_from_payload<R: Read>(
        r: &mut R,
        payload_length: u16,
    ) -> io::Result<Self> {
        Self::verify_payload_length(
            payload_length,
            "read_raw_value_from_parameter_request",
        )?;
        let parameter_index = r.read_u16::<Endian>()?;
        Ok(Self {
            parameter_index,
        })
    }
}

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

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

        let message = Request {
            parameter_index: 0x1234,
        };
        message
            .write_to(&mut buffer, options, sequence)
            .unwrap();
        assert_eq!(
            buffer,
            [
                0x45, // options
                0x93, // sequence
                0x12, // command lower byte
                0x28, // command upper byte
                0x02, // length lower byte
                0x00, // length upper byte
                0x34, // parameter_index lower byte
                0x12, // parameter_index upper byte
            ]
        );
    }
    #[test]
    fn read_from_payload() {
        let buffer = vec![0x34, 0x12];
        let len = buffer.len() as u16;
        let message =
            Request::read_from_payload(&mut buffer.as_slice(), len)
                .unwrap();
        assert_eq!(
            message,
            Request {
                parameter_index: 0x1234,
            }
        );
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Response {
    pub error: ErrorCode,
    pub value: ParameterValueRaw,
}

impl IsResponse for Response {
    type Request = Request;
}

impl IsValidResponseFor for Response {
    fn is_valid_response_for(&self, _request: &Request) -> bool {
        true
    }
}

impl HasErrorCode for Response {
    fn error_code(&self) -> ErrorCode {
        self.error
    }
}

impl TryFromResponse for Response {
    fn try_from_response(r: super::Response) -> Result<Self> {
        if let super::Response::ReadRawValueFromParameter(r) = r {
            Ok(r)
        } else {
            Err(ErrorKind::UnexpectedResponseType.into())
        }
    }
}

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

impl WithFixedPayloadLength for Response {
    const FIXED_PAYLOAD_LENGTH: u16 = ErrorCode::FIXED_PAYLOAD_LENGTH
        + ParameterValueRaw::FIXED_PAYLOAD_LENGTH;
}

impl HasFixedCommandId for Response {
    const COMMAND_ID: u16 = 0x2813;
}

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

    fn write_payload(&self, w: &mut Write) -> io::Result<()> {
        w.write_error_code(&self.error)?;
        w.write_parameter_value(
            &self.value,
            &ParameterValueWriteMode::TypeAndValue,
        )?;
        Ok(())
    }
}

impl ReadFromPayload for Response {
    fn read_from_payload<R: Read>(
        r: &mut R,
        payload_length: u16,
    ) -> io::Result<Self> {
        Self::verify_payload_length(
            payload_length,
            "read_raw_value_from_parameter_response",
        )?;
        let error = r.read_error_code()?;
        let value = r.read_parameter_value()?;
        Ok(Self { error, value })
    }
}

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

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

        let message = Response {
            error: ErrorCode::InvalidState, // 0x0107
            value: 0x6543u16.into(),
        };
        message
            .write_to(&mut buffer, options, sequence)
            .unwrap();
        assert_eq!(
            buffer,
            [
                0x45, // options
                0x93, // sequence
                0x13, // command lower byte
                0x28, // command upper byte
                0x0B, // length lower byte
                0x00, // length upper byte
                0x07, // error lower byte
                0x01, // error upper byte
                0x06, // value type
                0x43, // value byte 0
                0x65, // value byte 1
                0x00, // value byte 2
                0x00, // value byte 3
                0x00, // value byte 4
                0x00, // value byte 5
                0x00, // value byte 6
                0x00, // value byte 7
            ]
        );
    }
    #[test]
    fn read_from_payload() {
        let buffer = vec![
            0x07, // error lower byte
            0x01, // error upper byte
            0x06, // value type
            0x43, // value byte 0
            0x65, // value byte 1
            0x00, // value byte 2
            0x00, // value byte 3
            0x00, // value byte 4
            0x00, // value byte 5
            0x00, // value byte 6
            0x00, // value byte 7
        ];
        let len = buffer.len() as u16;
        let message =
            Response::read_from_payload(&mut buffer.as_slice(), len)
                .unwrap();
        assert_eq!(
            message,
            Response {
                error: ErrorCode::InvalidState, // 0x0107
                value: 0x6543u16.into(),
            }
        );
    }
}