use byteorder::{ReadBytesExt, WriteBytesExt};
use std::io::{Read, Write};
use base::{ErrorCode,HasErrorCode};
use {io, Endian, ErrorCodeReaderExt, ErrorCodeWriterExt,
ErrorKind, HasFixedCommandId, IsRequest, IsResponse,
IsValidResponseFor, MessageExt, ReadFromPayload, Result,
TryFromResponse, WithFixedPayloadLength};
#[derive(Clone, Debug, PartialEq)]
pub struct Request {
pub values: Vec<u16>,
}
impl IsRequest for Request {
type Response = Response;
}
impl From<Request> for super::Request {
fn from(m: Request) -> Self {
super::Request::UploadJob(m)
}
}
impl Request {
const ADDITIONAL_FIXED_PAYLOAD_LENGTH: u16 = u16::FIXED_PAYLOAD_LENGTH;
fn verify_payload_length(
received: u16,
required: u16,
) -> io::Result<()> {
if required != received {
Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"Invalid upload_job_request payload length. \
Received {}, required {}.",
received, required
),
))
} else {
Ok(())
}
}
}
impl HasFixedCommandId for Request {
const COMMAND_ID: u16 = 0x2808;
}
impl MessageExt for Request {
fn payload_length(&self) -> u16 {
Self::ADDITIONAL_FIXED_PAYLOAD_LENGTH
+ u16::FIXED_PAYLOAD_LENGTH * self.values.len() as u16
}
fn write_payload(&self, w: &mut Write) -> io::Result<()> {
w.write_u16::<Endian>(self.values.len() as u16)?;
for value in &self.values {
w.write_u16::<Endian>(*value)?;
}
Ok(())
}
}
impl ReadFromPayload for Request {
fn read_from_payload<R: Read>(
r: &mut R,
payload_length: u16,
) -> io::Result<Self> {
let count = r.read_u16::<Endian>()?;
let required_payload_length = Self::ADDITIONAL_FIXED_PAYLOAD_LENGTH
+ count as u16 * u16::FIXED_PAYLOAD_LENGTH;
Self::verify_payload_length(
payload_length,
required_payload_length,
)?;
let mut values = Vec::new();
for _ in 0..count {
values.push(r.read_u16::<Endian>()?);
}
Ok(Self { values })
}
}
#[cfg(test)]
mod test_request {
use super::*;
#[test]
fn write_to_empty() {
let mut buffer = Vec::new();
let options: u8 = 0x45;
let sequence: u8 = 0x93;
let values = Vec::new();
let message = Request { values };
message
.write_to(&mut buffer, options, sequence)
.unwrap();
assert_eq!(
buffer,
[
0x45, 0x93, 0x08, 0x28, 0x02, 0x00, 0x00, 0x00, ]
);
}
#[test]
fn write_to_single_item() {
let mut buffer = Vec::new();
let options: u8 = 0x45;
let sequence: u8 = 0x93;
let values = vec![0x7542];
let length = {
let fixed = 4u16;
let per_value = 9u16;
let value_count = 1u16;
fixed + per_value * value_count
};
assert_eq!(length, 0x000D);
assert_eq!(0x000D, 13);
let message = Request { values };
message
.write_to(&mut buffer, options, sequence)
.unwrap();
assert_eq!(
buffer,
vec![
0x45, 0x93, 0x08, 0x28, 0x04, 0x00, 0x01, 0x00, 0x42, 0x75, ]
);
}
#[test]
fn write_to_three_items() {
let mut buffer = Vec::new();
let options: u8 = 0x45;
let sequence: u8 = 0x93;
let values = vec![0x1122, 0x3344, 0x5566];
let length = {
let fixed = 4u16;
let per_value = 9u16;
let value_count = 3u16;
fixed + per_value * value_count
};
assert_eq!(length, 0x001F);
assert_eq!(0x001F, 31);
let message = Request { values };
message
.write_to(&mut buffer, options, sequence)
.unwrap();
assert_eq!(
buffer,
vec![
0x45, 0x93, 0x08, 0x28, 0x08, 0x00, 0x03, 0x00, 0x22, 0x11, 0x44, 0x33, 0x66, 0x55, ]
);
}
#[test]
fn from_payload_empty() {
let buffer = vec![
0x00, 0x00, ];
let len = buffer.len() as u16;
let message =
Request::read_from_payload(&mut buffer.as_slice(), len)
.unwrap();
let values = Vec::new();
assert_eq!(message, Request { values });
}
#[test]
fn from_payload_single_item() {
let buffer = vec![
0x01, 0x00, 0x26, 0x94, ];
let len = buffer.len() as u16;
let message =
Request::read_from_payload(&mut buffer.as_slice(), len)
.unwrap();
let values = vec![0x9426];
assert_eq!(message, Request { values });
}
#[test]
fn read_from_three_items() {
let buffer = vec![
0x03, 0x00, 0x22, 0x11, 0x44, 0x33, 0x66, 0x55, ];
let len = buffer.len() as u16;
let message =
Request::read_from_payload(&mut buffer.as_slice(), len)
.unwrap();
let values = vec![0x1122, 0x3344, 0x5566];
assert_eq!(message, Request { values });
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Response {
pub error: ErrorCode,
pub job_slot_index: u16,
}
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::UploadJob(r) = r {
Ok(r)
} else {
Err(ErrorKind::UnexpectedResponseType.into())
}
}
}
impl From<Response> for super::Response {
fn from(m: Response) -> Self {
super::Response::UploadJob(m)
}
}
impl WithFixedPayloadLength for Response {
const FIXED_PAYLOAD_LENGTH: u16 =
ErrorCode::FIXED_PAYLOAD_LENGTH + u16::FIXED_PAYLOAD_LENGTH;
}
impl HasFixedCommandId for Response {
const COMMAND_ID: u16 = 0x2809;
}
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_u16::<Endian>(self.job_slot_index)?;
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,
"upload_job_response",
)?;
let error = r.read_error_code()?;
let job_slot_index = r.read_u16::<Endian>()?;
Ok(Self {
error,
job_slot_index,
})
}
}
#[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, job_slot_index: 0x6413,
};
message
.write_to(&mut buffer, options, sequence)
.unwrap();
assert_eq!(
buffer,
[
0x45, 0x93, 0x09, 0x28, 0x04, 0x00, 0x07, 0x01, 0x13, 0x64, ]
);
}
#[test]
fn read_from_payload() {
let buffer = vec![0x07, 0x01, 0x13, 0x64];
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,
job_slot_index: 0x6413
}
);
}
}