From b9e81f058241e036fbd6ed7d78c87e592f590243 Mon Sep 17 00:00:00 2001 From: Matt Bilker Date: Mon, 8 Jul 2019 09:00:33 +0000 Subject: [PATCH] types: handle kbin type conversion in separate handler - Reduces code duplication between Value and ValueArray handling - Reduces code and macro complexity for Value and ValueArray --- Cargo.toml | 2 +- src/error.rs | 3 + src/lib.rs | 3 +- src/types/bytes.rs | 213 ++++++++++++++++++++++++++++++++ src/types/mod.rs | 3 + src/value/array.rs | 299 ++++++--------------------------------------- src/value/mod.rs | 161 +++++++++--------------- 7 files changed, 315 insertions(+), 369 deletions(-) create mode 100644 src/types/bytes.rs create mode 100644 src/types/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 1d76383..747c01d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ description = "An encoder/decoder for Konami's binary XML format used in many of edition = "2018" [dependencies] -byteorder = "1.3.1" +byteorder = "1.3.2" bytes = "0.4.10" encoding_rs = "0.8.6" failure = "0.1.1" diff --git a/src/error.rs b/src/error.rs index 70d0613..a7227dc 100644 --- a/src/error.rs +++ b/src/error.rs @@ -32,6 +32,9 @@ pub enum KbinErrorKind { #[fail(display = "Unable to write a {} to data buffer", _0)] DataWrite(&'static str), + #[fail(display = "Unable to read bytes or not enough data read")] + DataConvert, + #[fail(display = "Unable to read data size")] DataReadSize, diff --git a/src/lib.rs b/src/lib.rs index bb9b729..ba6be8d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,7 @@ mod sixbit; mod text_reader; mod to_element; mod to_text_xml; +mod types; mod value; mod writer; @@ -40,7 +41,7 @@ pub use crate::node_types::StandardType; pub use crate::options::Options; pub use crate::to_element::ToElement; pub use crate::to_text_xml::ToTextXml; -pub use crate::value::Value; +pub use crate::value::{Value, ValueArray}; pub use crate::writer::{Writer, Writeable}; const SIGNATURE: u8 = 0xA0; diff --git a/src/types/bytes.rs b/src/types/bytes.rs new file mode 100644 index 0000000..b864d03 --- /dev/null +++ b/src/types/bytes.rs @@ -0,0 +1,213 @@ +use std::io::Read; +use std::net::Ipv4Addr; + +use byteorder::ReadBytesExt; +use bytes::{BigEndian, BufMut}; +use failure::ResultExt; + +use crate::error::{KbinError, KbinErrorKind}; + +pub trait IntoKbinBytes { + fn write_kbin_bytes(self, buf: &mut B); +} + +pub trait FromKbinBytes: Sized { + fn from_kbin_bytes(input: &mut R) -> Result; +} + +impl IntoKbinBytes for i8 { + fn write_kbin_bytes(self, buf: &mut B) { + buf.put_i8(self); + } +} + +impl FromKbinBytes for i8 { + fn from_kbin_bytes(input: &mut R) -> Result { + input.read_i8().context(KbinErrorKind::DataConvert).map_err(Into::into) + } +} + +impl IntoKbinBytes for u8 { + fn write_kbin_bytes(self, buf: &mut B) { + buf.put_u8(self); + } +} + +impl FromKbinBytes for u8 { + fn from_kbin_bytes(input: &mut R) -> Result { + input.read_u8().context(KbinErrorKind::DataConvert).map_err(Into::into) + } +} + +impl IntoKbinBytes for bool { + fn write_kbin_bytes(self, buf: &mut B) { + buf.put_u8(if self { 0x01 } else { 0x00 }) + } +} + +impl FromKbinBytes for bool { + fn from_kbin_bytes(input: &mut R) -> Result { + match u8::from_kbin_bytes(input)? { + 0x00 => Ok(false), + 0x01 => Ok(true), + input => Err(KbinErrorKind::InvalidBooleanInput(input).into()), + } + } +} + +impl<'a> IntoKbinBytes for &'a [u8] { + fn write_kbin_bytes(self, buf: &mut B) { + buf.put(self); + } +} + +impl IntoKbinBytes for Ipv4Addr { + fn write_kbin_bytes(self, buf: &mut B) { + let octets = self.octets(); + + buf.put(&octets[..]) + } +} + +impl FromKbinBytes for Ipv4Addr { + fn from_kbin_bytes(input: &mut R) -> Result { + let mut octets = [0; 4]; + input.read_exact(&mut octets).context(KbinErrorKind::DataConvert)?; + + Ok(Ipv4Addr::from(octets)) + } +} + +macro_rules! multibyte_impl { + ( + $(($type:ty, $write_method:ident, $read_method:ident)),*$(,)? + ) => { + $( + impl IntoKbinBytes for $type { + fn write_kbin_bytes(self, buf: &mut B) { + buf.$write_method(self); + } + } + + impl FromKbinBytes for $type { + fn from_kbin_bytes(input: &mut R) -> Result { + input.$read_method::().context(KbinErrorKind::DataConvert).map_err(Into::into) + } + } + )* + }; +} + +macro_rules! tuple_impl { + ( + i8: [$($i8_count:expr),*], + u8: [$($u8_count:expr),*], + bool: [$($bool_count:expr),*], + multi: [ + $([$type:ty ; $($count:expr),*] => ($write_method:ident, $read_method:ident)),*$(,)? + ] + ) => { + $( + impl<'a> IntoKbinBytes for &'a [i8; $i8_count] { + fn write_kbin_bytes(self, buf: &mut B) { + for value in self.into_iter() { + buf.put_i8(*value); + } + } + } + + impl FromKbinBytes for [i8; $i8_count] { + fn from_kbin_bytes(input: &mut R) -> Result { + let mut values = Self::default(); + input.read_i8_into(&mut values).context(KbinErrorKind::DataConvert)?; + + Ok(values) + } + } + )* + $( + impl<'a> IntoKbinBytes for &'a [u8; $u8_count] { + fn write_kbin_bytes(self, buf: &mut B) { + buf.put_slice(&self[..]); + } + } + + impl FromKbinBytes for [u8; $u8_count] { + fn from_kbin_bytes(input: &mut R) -> Result { + let mut values = Self::default(); + input.read_exact(&mut values).context(KbinErrorKind::DataConvert)?; + + Ok(values) + } + } + )* + $( + impl<'a> IntoKbinBytes for &'a [bool; $bool_count] { + fn write_kbin_bytes(self, buf: &mut B) { + for value in self.into_iter() { + value.write_kbin_bytes(buf); + } + } + } + + impl FromKbinBytes for [bool; $bool_count] { + fn from_kbin_bytes(input: &mut R) -> Result { + let mut values = Self::default(); + + for i in 0..$bool_count { + values[i] = bool::from_kbin_bytes(input)?; + } + + Ok(values) + } + } + )* + $( + $( + impl<'a> IntoKbinBytes for &'a [$type; $count] { + fn write_kbin_bytes(self, buf: &mut B) { + for value in self.into_iter() { + buf.$write_method(*value); + } + } + } + + impl FromKbinBytes for [$type; $count] { + fn from_kbin_bytes(input: &mut R) -> Result { + let mut values = Self::default(); + input.$read_method::(&mut values).context(KbinErrorKind::DataConvert)?; + + Ok(values) + } + } + )* + )* + }; +} + +multibyte_impl! { + (i16, put_i16_be, read_i16), + (u16, put_u16_be, read_u16), + (i32, put_i32_be, read_i32), + (u32, put_u32_be, read_u32), + (i64, put_i64_be, read_i64), + (u64, put_u64_be, read_u64), + (f32, put_f32_be, read_f32), + (f64, put_f64_be, read_f64), +} + +tuple_impl! { + i8: [2, 3, 4, 16], + u8: [2, 3, 4, 16], + bool: [2, 3, 4, 16], + multi: [ + [i16; 2, 3, 4, 8] => (put_i16_be, read_i16_into), + [u16; 2, 3, 4, 8] => (put_u16_be, read_u16_into), + [i32; 2, 3, 4] => (put_i32_be, read_i32_into), + [u32; 2, 3, 4] => (put_u32_be, read_u32_into), + [i64; 2, 3, 4] => (put_i64_be, read_i64_into), + [u64; 2, 3, 4] => (put_u64_be, read_u64_into), + [f32; 2, 3, 4] => (put_f32_be, read_f32_into), + [f64; 2, 3, 4] => (put_f64_be, read_f64_into), + ] +} diff --git a/src/types/mod.rs b/src/types/mod.rs new file mode 100644 index 0000000..61270b1 --- /dev/null +++ b/src/types/mod.rs @@ -0,0 +1,3 @@ +mod bytes; + +pub use self::bytes::{FromKbinBytes, IntoKbinBytes}; diff --git a/src/value/array.rs b/src/value/array.rs index 17e64c5..32edefc 100644 --- a/src/value/array.rs +++ b/src/value/array.rs @@ -1,14 +1,14 @@ //use std::convert::TryFrom; use std::fmt; +use std::io::Cursor; use std::net::Ipv4Addr; //use std::str::FromStr; -use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; -use failure::ResultExt; //use rustc_hex::FromHex; use crate::error::{KbinError, KbinErrorKind}; -use crate::node_types::{self, StandardType}; +use crate::node_types::StandardType; +use crate::types::{FromKbinBytes, IntoKbinBytes}; #[derive(Clone, Debug, PartialEq)] pub enum ValueArray { @@ -66,14 +66,7 @@ pub enum ValueArray { macro_rules! tuple { ( - byte: [ - s8: [$($s8_konst:ident),*], - u8: [$($u8_konst:ident),*], - bool: [$($bool_konst:ident),*] - ], - multi: [ - $($read_method:ident $write_method:ident $inner_type:ty => [$($multi_konst:ident),*]),* - ] + $($konst:ident),*$(,)? ) => { pub fn from_standard_type(node_type: StandardType, input: &[u8]) -> Result, KbinError> { let node_size = node_type.size * node_type.count; @@ -84,6 +77,8 @@ macro_rules! tuple { return Err(KbinErrorKind::SizeMismatch(*node_type, node_size, input.len()).into()); } + let mut reader = Cursor::new(input); + let value = match node_type { StandardType::NodeStart | StandardType::NodeEnd | @@ -92,266 +87,34 @@ macro_rules! tuple { StandardType::Binary | StandardType::String | StandardType::Time => return Ok(None), - StandardType::S8 => ValueArray::S8(input.iter().map(|v| *v as i8).collect()), - StandardType::U8 => ValueArray::U8(input.to_vec()), - StandardType::S16 => { - let mut values = vec![0; len]; - BigEndian::read_i16_into(input, &mut values); - ValueArray::S16(values) - }, - StandardType::U16 => { - let mut values = vec![0; len]; - BigEndian::read_u16_into(input, &mut values); - ValueArray::U16(values) - }, - StandardType::S32 => { - let mut values = vec![0; len]; - BigEndian::read_i32_into(input, &mut values); - ValueArray::S32(values) - }, - StandardType::U32 => { - let mut values = vec![0; len]; - BigEndian::read_u32_into(input, &mut values); - ValueArray::U32(values) - }, - StandardType::S64 => { - let mut values = vec![0; len]; - BigEndian::read_i64_into(input, &mut values); - ValueArray::S64(values) - }, - StandardType::U64 => { - let mut values = vec![0; len]; - BigEndian::read_u64_into(input, &mut values); - ValueArray::U64(values) - }, - StandardType::Ip4 => { - let mut values = Vec::with_capacity(len); - - for chunk in input.chunks(4) { - let mut octets = [0; 4]; - octets.copy_from_slice(chunk); - values.push(Ipv4Addr::from(octets)); - } - - ValueArray::Ip4(values) - }, - StandardType::Float => { - let mut values = vec![0.0; len]; - BigEndian::read_f32_into(input, &mut values); - ValueArray::Float(values) - }, - StandardType::Double => { - let mut values = vec![0.0; len]; - BigEndian::read_f64_into(input, &mut values); - ValueArray::Double(values) - }, - StandardType::Boolean => { - let mut values = Vec::with_capacity(len); - - for value in input { - match value { - 0x00 => values.push(false), - 0x01 => values.push(true), - input => return Err(KbinErrorKind::InvalidBooleanInput(*input).into()), - }; - } - - ValueArray::Boolean(values) - }, $( - StandardType::$s8_konst => { - const COUNT: usize = node_types::$s8_konst.count; - + StandardType::$konst => { let mut values = Vec::with_capacity(len); - for chunk in input.chunks(COUNT) { - let mut value = [0; COUNT]; - for i in 0..COUNT { - value[i] = chunk[i] as i8; - } - values.push(value); + for _ in 0..len { + values.push(FromKbinBytes::from_kbin_bytes(&mut reader)?); } - ValueArray::$s8_konst(values) + ValueArray::$konst(values) }, )* - $( - StandardType::$u8_konst => { - const COUNT: usize = node_types::$u8_konst.count; - - let mut values = Vec::with_capacity(len); - - for chunk in input.chunks(COUNT) { - let mut value = [0; COUNT]; - value[0..COUNT].copy_from_slice(&chunk[0..COUNT]); - values.push(value); - } - - ValueArray::$u8_konst(values) - }, - )* - $( - StandardType::$bool_konst => { - const COUNT: usize = node_types::$bool_konst.count; - - let mut values = Vec::with_capacity(len); - - for chunk in input.chunks(COUNT) { - let mut value: [_; COUNT] = Default::default(); - for i in 0..COUNT { - value[i] = match chunk[i] { - 0x00 => false, - 0x01 => true, - input => return Err(KbinErrorKind::InvalidBooleanInput(input).into()), - }; - } - values.push(value); - } - - ValueArray::$bool_konst(values) - }, - )* - $( - $( - StandardType::$multi_konst => { - const COUNT: usize = node_types::$multi_konst.count; - const SIZE: usize = node_types::$multi_konst.size * COUNT; - - let mut values = Vec::with_capacity(len); - - for chunk in input.chunks(SIZE) { - let mut value: [_; COUNT] = Default::default(); - BigEndian::$read_method(chunk, &mut value); - values.push(value); - } - - ValueArray::$multi_konst(values) - }, - )* - )* }; Ok(Some(value)) } pub(super) fn to_bytes_inner(&self, output: &mut Vec) -> Result<(), KbinError> { - macro_rules! gen_error { - ($konst:ident) => { - KbinErrorKind::DataWrite(StandardType::$konst.name) - }; - } - let node_size = self.standard_type().size; match self { - ValueArray::S8(ref values) => { - output.reserve(values.len()); - for n in values { - output.push(*n as u8); - } - }, - ValueArray::U8(ref values) => output.extend(values), - ValueArray::S16(ref values) => { - output.reserve(values.len() * node_size); - for n in values { - output.write_i16::(*n).context(gen_error!(S16))?; - } - }, - ValueArray::U16(ref values) => { - output.reserve(values.len() * node_size); - for n in values { - output.write_u16::(*n).context(gen_error!(U16))?; - } - }, - ValueArray::S32(ref values) => { - output.reserve(values.len() * node_size); - for n in values { - output.write_i32::(*n).context(gen_error!(S32))?; - } - }, - ValueArray::U32(ref values) => { - output.reserve(values.len() * node_size); - for n in values { - output.write_u32::(*n).context(gen_error!(U32))?; - } - }, - ValueArray::S64(ref values) => { - output.reserve(values.len() * node_size); - for n in values { - output.write_i64::(*n).context(gen_error!(S64))?; - } - }, - ValueArray::U64(ref values) => { - output.reserve(values.len() * node_size); - for n in values { - output.write_u64::(*n).context(gen_error!(U64))?; - } - }, - ValueArray::Ip4(ref values) => { - for addr in values { - output.extend_from_slice(&addr.octets()); - } - }, - ValueArray::Float(ref values) => { - output.reserve(values.len() * node_size); - for n in values { - output.write_f32::(*n).context(gen_error!(Float))?; - } - }, - ValueArray::Double(ref values) => { - output.reserve(values.len() * node_size); - for n in values { - output.write_f64::(*n).context(gen_error!(Double))?; - } - }, - ValueArray::Boolean(ref values) => { - output.reserve(values.len() * node_size); - for v in values { - output.push(if *v { 0x01 } else { 0x00 }); - } - }, $( - ValueArray::$s8_konst(values) => { + ValueArray::$konst(values) => { output.reserve(values.len() * node_size); for value in values { - for n in value.into_iter() { - output.push(*n as u8); - } + value.write_kbin_bytes(output); } }, )* - $( - ValueArray::$u8_konst(values) => { - output.reserve(values.len() * node_size); - for value in values { - for n in value.into_iter() { - output.push(*n); - } - } - }, - )* - $( - ValueArray::$bool_konst(values) => { - output.reserve(values.len() * node_size); - for value in values { - for v in value.into_iter() { - output.push(if *v { 0x01 } else { 0x00 }); - } - } - }, - )* - $( - $( - ValueArray::$multi_konst(values) => { - output.reserve(values.len() * node_size); - for value in values { - for v in value.into_iter() { - output.$write_method::(*v).context(gen_error!($multi_konst))?; - } - } - }, - )* - )* }; Ok(()) @@ -361,21 +124,29 @@ macro_rules! tuple { impl ValueArray { tuple! { - byte: [ - s8: [S8_2, S8_3, S8_4, Vs8], - u8: [U8_2, U8_3, U8_4, Vu8], - bool: [Boolean2, Boolean3, Boolean4, Vb] - ], - multi: [ - read_i16_into write_i16 i16 => [S16_2, S16_3, S16_4, Vs16], - read_i32_into write_i32 i32 => [S32_2, S32_3, S32_4], - read_i64_into write_i64 i64 => [S64_2, S64_3, S64_4], - read_u16_into write_u16 u16 => [U16_2, U16_3, U16_4, Vu16], - read_u32_into write_u32 u32 => [U32_2, U32_3, U32_4], - read_u64_into write_u64 u64 => [U64_2, U64_3, U64_4], - read_f32_into write_f32 f32 => [Float2, Float3, Float4], - read_f64_into write_f64 f64 => [Double2, Double3, Double4] - ] + S8, + U8, + S16, + U16, + S32, + U32, + S64, + U64, + Ip4, + Float, + Double, + Boolean, + S8_2, S8_3, S8_4, Vs8, + U8_2, U8_3, U8_4, Vu8, + Boolean2, Boolean3, Boolean4, Vb, + S16_2, S16_3, S16_4, Vs16, + S32_2, S32_3, S32_4, + S64_2, S64_3, S64_4, + U16_2, U16_3, U16_4, Vu16, + U32_2, U32_3, U32_4, + U64_2, U64_3, U64_4, + Float2, Float3, Float4, + Double2, Double3, Double4, } pub fn standard_type(&self) -> StandardType { diff --git a/src/value/mod.rs b/src/value/mod.rs index 7d85a3e..0b1fd71 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -1,15 +1,15 @@ use std::convert::TryFrom; use std::fmt; +use std::io::Cursor; use std::net::Ipv4Addr; use std::str::FromStr; -use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; use failure::{Fail, ResultExt}; use rustc_hex::FromHex; use crate::error::{KbinError, KbinErrorKind}; use crate::node_types::{self, StandardType}; -use crate::types::FromKbinBytes; +use crate::types::{FromKbinBytes, IntoKbinBytes}; mod array; @@ -147,12 +147,13 @@ macro_rules! construct_types { macro_rules! tuple { ( byte: [ - s8: [$($s8_konst:ident),*], - u8: [$($u8_konst:ident),*], + int: [ + $($int_konst:ident),*$(,)? + ], bool: [$($bool_konst:ident),*] ], multi: [ - $($read_method:ident $write_method:ident $inner_type:ty => [$($multi_konst:ident),*]),* + $($inner_type:ty => [$($multi_konst:ident),*]),* ] ) => { pub fn from_standard_type(node_type: StandardType, is_array: bool, input: &[u8]) -> Result, KbinError> { @@ -183,62 +184,42 @@ macro_rules! tuple { }, }; + let mut reader = Cursor::new(input); + let value = match node_type { StandardType::NodeStart | StandardType::NodeEnd | StandardType::FileEnd | StandardType::Attribute | StandardType::String => return Ok(None), - StandardType::S8 => i8::from_kbin_bytes(input).map(Value::S8)?, - StandardType::U8 => u8::from_kbin_bytes(input).map(Value::U8)?, - StandardType::S16 => i16::from_kbin_bytes(input).map(Value::S16)?, - StandardType::U16 => u16::from_kbin_bytes(input).map(Value::U16)?, - StandardType::S32 => i32::from_kbin_bytes(input).map(Value::S32)?, - StandardType::U32 => u32::from_kbin_bytes(input).map(Value::U32)?, - StandardType::S64 => i64::from_kbin_bytes(input).map(Value::S64)?, - StandardType::U64 => u64::from_kbin_bytes(input).map(Value::U64)?, + StandardType::S8 => i8::from_kbin_bytes(&mut reader).map(Value::S8)?, + StandardType::U8 => u8::from_kbin_bytes(&mut reader).map(Value::U8)?, + StandardType::S16 => i16::from_kbin_bytes(&mut reader).map(Value::S16)?, + StandardType::U16 => u16::from_kbin_bytes(&mut reader).map(Value::U16)?, + StandardType::S32 => i32::from_kbin_bytes(&mut reader).map(Value::S32)?, + StandardType::U32 => u32::from_kbin_bytes(&mut reader).map(Value::U32)?, + StandardType::S64 => i64::from_kbin_bytes(&mut reader).map(Value::S64)?, + StandardType::U64 => u64::from_kbin_bytes(&mut reader).map(Value::U64)?, StandardType::Binary => Value::Binary(input.to_vec()), - StandardType::Time => u32::from_kbin_bytes(input).map(Value::Time)?, - StandardType::Ip4 => Ipv4Addr::from_kbin_bytes(input).map(Value::Ip4)?, - StandardType::Float => f32::from_kbin_bytes(input).map(Value::Float)?, - StandardType::Double => f64::from_kbin_bytes(input).map(Value::Double)?, - StandardType::Boolean => bool::from_kbin_bytes(input).map(Value::Boolean)?, + StandardType::Time => u32::from_kbin_bytes(&mut reader).map(Value::Time)?, + StandardType::Ip4 => Ipv4Addr::from_kbin_bytes(&mut reader).map(Value::Ip4)?, + StandardType::Float => f32::from_kbin_bytes(&mut reader).map(Value::Float)?, + StandardType::Double => f64::from_kbin_bytes(&mut reader).map(Value::Double)?, + StandardType::Boolean => bool::from_kbin_bytes(&mut reader).map(Value::Boolean)?, $( - StandardType::$s8_konst => { - const COUNT: usize = node_types::$s8_konst.count; - let mut value = [0; COUNT]; - for i in 0..COUNT { - value[i] = input[i] as i8; - } - Value::$s8_konst(value) - }, - )* - $( - StandardType::$u8_konst => { - const COUNT: usize = node_types::$u8_konst.count; - let mut value = [0; COUNT]; - value[0..COUNT].copy_from_slice(&input[0..COUNT]); - Value::$u8_konst(value) + StandardType::$int_konst => { + FromKbinBytes::from_kbin_bytes(&mut reader).map(Value::$int_konst)? }, )* $( StandardType::$bool_konst => { - const COUNT: usize = node_types::$bool_konst.count; - let mut value: [_; COUNT] = Default::default(); - for i in 0..COUNT { - value[i] = bool::from_kbin_bytes(&input[i..i + 1])?; - } - Value::$bool_konst(value) + FromKbinBytes::from_kbin_bytes(&mut reader).map(Value::$bool_konst)? }, )* $( $( StandardType::$multi_konst => { - const COUNT: usize = node_types::$multi_konst.count; - const SIZE: usize = node_types::$multi_konst.size * COUNT; - let mut value: [_; COUNT] = Default::default(); - BigEndian::$read_method(&input[0..SIZE], &mut value); - Value::$multi_konst(value) + FromKbinBytes::from_kbin_bytes(&mut reader).map(Value::$multi_konst)? }, )* )* @@ -311,19 +292,11 @@ macro_rules! tuple { StandardType::FileEnd | StandardType::NodeStart => return Err(KbinErrorKind::InvalidNodeType(node_type).into()), $( - StandardType::$s8_konst => { - const COUNT: usize = node_types::$s8_konst.count; + StandardType::$int_konst => { + const COUNT: usize = node_types::$int_konst.count; let mut value = [0; COUNT]; - parse_tuple::(node_type, input, &mut value)?; - Value::$s8_konst(value) - }, - )* - $( - StandardType::$u8_konst => { - const COUNT: usize = node_types::$u8_konst.count; - let mut value = [0; COUNT]; - parse_tuple::(node_type, input, &mut value)?; - Value::$u8_konst(value) + parse_tuple(node_type, input, &mut value)?; + Value::$int_konst(value) }, )* $( @@ -366,27 +339,21 @@ macro_rules! tuple { fn to_bytes_inner(&self, output: &mut Vec) -> Result<(), KbinError> { debug!("Value::to_bytes_inner(self: {:?})", self); - macro_rules! gen_error { - ($konst:ident) => { - KbinErrorKind::DataWrite(StandardType::$konst.name) - }; - } - match self { - Value::S8(ref n) => output.push(*n as u8), - Value::U8(ref n) => output.push(*n), - Value::S16(ref n) => output.write_i16::(*n).context(gen_error!(S16))?, - Value::U16(ref n) => output.write_u16::(*n).context(gen_error!(U16))?, - Value::S32(ref n) => output.write_i32::(*n).context(gen_error!(S32))?, - Value::U32(ref n) => output.write_u32::(*n).context(gen_error!(U32))?, - Value::S64(ref n) => output.write_i64::(*n).context(gen_error!(S64))?, - Value::U64(ref n) => output.write_u64::(*n).context(gen_error!(U64))?, + Value::S8(ref n) => n.write_kbin_bytes(output), + Value::U8(ref n) => n.write_kbin_bytes(output), + Value::S16(ref n) => n.write_kbin_bytes(output), + Value::U16(ref n) => n.write_kbin_bytes(output), + Value::S32(ref n) => n.write_kbin_bytes(output), + Value::U32(ref n) => n.write_kbin_bytes(output), + Value::S64(ref n) => n.write_kbin_bytes(output), + Value::U64(ref n) => n.write_kbin_bytes(output), Value::Binary(ref data) => output.extend_from_slice(data), - Value::Time(ref n) => output.write_u32::(*n).context(gen_error!(Time))?, - Value::Ip4(addr) => output.extend_from_slice(&addr.octets()), - Value::Float(ref n) => output.write_f32::(*n).context(gen_error!(Float))?, - Value::Double(ref n) => output.write_f64::(*n).context(gen_error!(Double))?, - Value::Boolean(ref v) => output.push(if *v { 0x01 } else { 0x00 }), + Value::Time(ref n) => n.write_kbin_bytes(output), + Value::Ip4(addr) => addr.write_kbin_bytes(output), + Value::Float(ref n) => n.write_kbin_bytes(output), + Value::Double(ref n) => n.write_kbin_bytes(output), + Value::Boolean(ref v) => v.write_kbin_bytes(output), Value::Array(_, values) => { for value in values { value.to_bytes_inner(output)?; @@ -396,36 +363,22 @@ macro_rules! tuple { Value::Attribute(_) | Value::String(_) => return Err(KbinErrorKind::InvalidNodeType(self.standard_type()).into()), $( - Value::$s8_konst(value) => { + Value::$int_konst(value) => { output.reserve(value.len()); - for n in value.into_iter() { - output.push(*n as u8); - } - }, - )* - $( - Value::$u8_konst(value) => { - output.reserve(value.len()); - for n in value.into_iter() { - output.push(*n); - } + value.write_kbin_bytes(output); }, )* $( Value::$bool_konst(value) => { output.reserve(value.len()); - for v in value.into_iter() { - output.push(if *v { 0x01 } else { 0x00 }); - } + value.write_kbin_bytes(output); }, )* $( $( Value::$multi_konst(value) => { output.reserve(value.len() * StandardType::$multi_konst.size); - for v in value.into_iter() { - output.$write_method::(*v).context(gen_error!($multi_konst))?; - } + value.write_kbin_bytes(output); }, )* )* @@ -439,19 +392,21 @@ macro_rules! tuple { impl Value { tuple! { byte: [ - s8: [S8_2, S8_3, S8_4, Vs8], - u8: [U8_2, U8_3, U8_4, Vu8], + int: [ + S8_2, S8_3, S8_4, Vs8, + U8_2, U8_3, U8_4, Vu8, + ], bool: [Boolean2, Boolean3, Boolean4, Vb] ], multi: [ - read_i16_into write_i16 i16 => [S16_2, S16_3, S16_4, Vs16], - read_i32_into write_i32 i32 => [S32_2, S32_3, S32_4], - read_i64_into write_i64 i64 => [S64_2, S64_3, S64_4], - read_u16_into write_u16 u16 => [U16_2, U16_3, U16_4, Vu16], - read_u32_into write_u32 u32 => [U32_2, U32_3, U32_4], - read_u64_into write_u64 u64 => [U64_2, U64_3, U64_4], - read_f32_into write_f32 f32 => [Float2, Float3, Float4], - read_f64_into write_f64 f64 => [Double2, Double3, Double4] + i16 => [S16_2, S16_3, S16_4, Vs16], + i32 => [S32_2, S32_3, S32_4], + i64 => [S64_2, S64_3, S64_4], + u16 => [U16_2, U16_3, U16_4, Vu16], + u32 => [U32_2, U32_3, U32_4], + u64 => [U64_2, U64_3, U64_4], + f32 => [Float2, Float3, Float4], + f64 => [Double2, Double3, Double4] ] }