use crate::base::{ParameterValue, ParameterValueRaw};
use snafu::ResultExt;
use std::io::{Read, Write};
use crate::{
error, Endian, ReadExt, Result, TryInto, WithFixedPayloadLength,
WriteExt,
};
impl WithFixedPayloadLength for ParameterValueRaw {
const FIXED_PAYLOAD_LENGTH: u16 =
u8::FIXED_PAYLOAD_LENGTH + u64::FIXED_PAYLOAD_LENGTH;
}
pub(crate) enum ParameterValueWriteMode {
Type,
Value,
TypeAndValue,
}
pub(crate) trait ParameterValueWriterExt: Write {
fn write_type(
&mut self,
type_id: u8,
mode: &ParameterValueWriteMode,
) -> Result<()> {
use self::ParameterValueWriteMode::*;
match *mode {
Type | TypeAndValue => self.write_u8(type_id),
Value => Ok(()),
}
}
fn write_value_u64(
&mut self,
value: u64,
mode: &ParameterValueWriteMode,
) -> Result<()> {
use self::ParameterValueWriteMode::*;
match *mode {
Value | TypeAndValue => self.write_u64::<Endian>(value),
Type => Ok(()),
}
}
fn write_value_i64(
&mut self,
value: i64,
mode: &ParameterValueWriteMode,
) -> Result<()> {
use self::ParameterValueWriteMode::*;
match *mode {
Value | TypeAndValue => self.write_i64::<Endian>(value),
Type => Ok(()),
}
}
fn write_parameter_value(
&mut self,
r: &ParameterValueRaw,
mode: &ParameterValueWriteMode,
) -> Result<()> {
match *r {
ParameterValue::Boolean(ref v) => {
self.write_type(0x00u8, mode)?;
self.write_value_u64(*v as u64, mode)?;
}
ParameterValue::Int8(ref v) => {
self.write_type(0x01u8, mode)?;
self.write_value_u64(*v as u64, mode)?;
}
ParameterValue::Int16(ref v) => {
self.write_type(0x02u8, mode)?;
self.write_value_u64(*v as u64, mode)?;
}
ParameterValue::Int32(ref v) => {
self.write_type(0x03u8, mode)?;
self.write_value_u64(*v as u64, mode)?;
}
ParameterValue::Int64(ref v) => {
self.write_type(0x04u8, mode)?;
self.write_value_i64(*v, mode)?;
}
ParameterValue::UInt8(ref v) => {
self.write_type(0x05u8, mode)?;
self.write_value_u64(u64::from(*v), mode)?;
}
ParameterValue::UInt16(ref v) => {
self.write_type(0x06u8, mode)?;
self.write_value_u64(u64::from(*v), mode)?;
}
ParameterValue::UInt32(ref v) => {
self.write_type(0x07u8, mode)?;
self.write_value_u64(u64::from(*v), mode)?;
}
ParameterValue::UInt64(ref v) => {
self.write_type(0x08u8, mode)?;
self.write_value_u64(*v, mode)?;
}
ParameterValue::ParameterMask(ref v) => {
self.write_type(0x09u8, mode)?;
self.write_value_u64(*v, mode)?;
}
ParameterValue::BooleanChannel(ref v) => {
self.write_type(0x10u8, mode)?;
self.write_value_u64(v.into(), mode)?;
}
ParameterValue::Int8Channel(ref v) => {
self.write_type(0x11u8, mode)?;
self.write_value_u64(v.into(), mode)?;
}
ParameterValue::Int16Channel(ref v) => {
self.write_type(0x12u8, mode)?;
self.write_value_u64(v.into(), mode)?;
}
ParameterValue::Int32Channel(ref v) => {
self.write_type(0x13u8, mode)?;
self.write_value_u64(v.into(), mode)?;
}
ParameterValue::Int64Channel(ref v) => {
self.write_type(0x14u8, mode)?;
self.write_value_u64(v.into(), mode)?;
}
ParameterValue::UInt8Channel(ref v) => {
self.write_type(0x15u8, mode)?;
self.write_value_u64(v.into(), mode)?;
}
ParameterValue::UInt16Channel(ref v) => {
self.write_type(0x16u8, mode)?;
self.write_value_u64(v.into(), mode)?;
}
ParameterValue::UInt32Channel(ref v) => {
self.write_type(0x17u8, mode)?;
self.write_value_u64(v.into(), mode)?;
}
ParameterValue::UInt64Channel(ref v) => {
self.write_type(0x18u8, mode)?;
self.write_value_u64(v.into(), mode)?;
}
ParameterValue::ParameterMaskChannel(ref v) => {
self.write_type(0x19u8, mode)?;
self.write_value_u64(v.into(), mode)?;
}
}
Ok(())
}
}
impl<B: Write + ?Sized> ParameterValueWriterExt for B {}
pub(crate) trait ParameterValueReaderExt: Read {
fn read_type(&mut self) -> Result<u8> {
self.read_u8()
}
fn read_value(&mut self) -> Result<u64> {
self.read_u64::<Endian>()
}
fn read_parameter_value(&mut self) -> Result<ParameterValueRaw> {
(self.read_type()?, self.read_value()?)
.try_into()
.context(error::Io)
}
}
impl<B: Read + ?Sized> ParameterValueReaderExt for B {}