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
This commit is contained in:
Matt Bilker
2019-07-08 09:00:33 +00:00
parent 288a89b01a
commit b9e81f0582
7 changed files with 315 additions and 369 deletions

View File

@@ -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"

View File

@@ -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,

View File

@@ -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;

213
src/types/bytes.rs Normal file
View File

@@ -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<B: BufMut>(self, buf: &mut B);
}
pub trait FromKbinBytes: Sized {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError>;
}
impl IntoKbinBytes for i8 {
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
buf.put_i8(self);
}
}
impl FromKbinBytes for i8 {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
input.read_i8().context(KbinErrorKind::DataConvert).map_err(Into::into)
}
}
impl IntoKbinBytes for u8 {
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
buf.put_u8(self);
}
}
impl FromKbinBytes for u8 {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
input.read_u8().context(KbinErrorKind::DataConvert).map_err(Into::into)
}
}
impl IntoKbinBytes for bool {
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
buf.put_u8(if self { 0x01 } else { 0x00 })
}
}
impl FromKbinBytes for bool {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
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<B: BufMut>(self, buf: &mut B) {
buf.put(self);
}
}
impl IntoKbinBytes for Ipv4Addr {
fn write_kbin_bytes<B: BufMut>(self, buf: &mut B) {
let octets = self.octets();
buf.put(&octets[..])
}
}
impl FromKbinBytes for Ipv4Addr {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
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<B: BufMut>(self, buf: &mut B) {
buf.$write_method(self);
}
}
impl FromKbinBytes for $type {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
input.$read_method::<BigEndian>().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<B: BufMut>(self, buf: &mut B) {
for value in self.into_iter() {
buf.put_i8(*value);
}
}
}
impl FromKbinBytes for [i8; $i8_count] {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
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<B: BufMut>(self, buf: &mut B) {
buf.put_slice(&self[..]);
}
}
impl FromKbinBytes for [u8; $u8_count] {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
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<B: BufMut>(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<R: Read>(input: &mut R) -> Result<Self, KbinError> {
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<B: BufMut>(self, buf: &mut B) {
for value in self.into_iter() {
buf.$write_method(*value);
}
}
}
impl FromKbinBytes for [$type; $count] {
fn from_kbin_bytes<R: Read>(input: &mut R) -> Result<Self, KbinError> {
let mut values = Self::default();
input.$read_method::<BigEndian>(&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),
]
}

3
src/types/mod.rs Normal file
View File

@@ -0,0 +1,3 @@
mod bytes;
pub use self::bytes::{FromKbinBytes, IntoKbinBytes};

View File

@@ -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<Option<ValueArray>, 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<u8>) -> 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::<BigEndian>(*n).context(gen_error!(S16))?;
}
},
ValueArray::U16(ref values) => {
output.reserve(values.len() * node_size);
for n in values {
output.write_u16::<BigEndian>(*n).context(gen_error!(U16))?;
}
},
ValueArray::S32(ref values) => {
output.reserve(values.len() * node_size);
for n in values {
output.write_i32::<BigEndian>(*n).context(gen_error!(S32))?;
}
},
ValueArray::U32(ref values) => {
output.reserve(values.len() * node_size);
for n in values {
output.write_u32::<BigEndian>(*n).context(gen_error!(U32))?;
}
},
ValueArray::S64(ref values) => {
output.reserve(values.len() * node_size);
for n in values {
output.write_i64::<BigEndian>(*n).context(gen_error!(S64))?;
}
},
ValueArray::U64(ref values) => {
output.reserve(values.len() * node_size);
for n in values {
output.write_u64::<BigEndian>(*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::<BigEndian>(*n).context(gen_error!(Float))?;
}
},
ValueArray::Double(ref values) => {
output.reserve(values.len() * node_size);
for n in values {
output.write_f64::<BigEndian>(*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::<BigEndian>(*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 {

View File

@@ -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<Option<Value>, 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::<i8>(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::<u8>(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<u8>) -> 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::<BigEndian>(*n).context(gen_error!(S16))?,
Value::U16(ref n) => output.write_u16::<BigEndian>(*n).context(gen_error!(U16))?,
Value::S32(ref n) => output.write_i32::<BigEndian>(*n).context(gen_error!(S32))?,
Value::U32(ref n) => output.write_u32::<BigEndian>(*n).context(gen_error!(U32))?,
Value::S64(ref n) => output.write_i64::<BigEndian>(*n).context(gen_error!(S64))?,
Value::U64(ref n) => output.write_u64::<BigEndian>(*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::<BigEndian>(*n).context(gen_error!(Time))?,
Value::Ip4(addr) => output.extend_from_slice(&addr.octets()),
Value::Float(ref n) => output.write_f32::<BigEndian>(*n).context(gen_error!(Float))?,
Value::Double(ref n) => output.write_f64::<BigEndian>(*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::<BigEndian>(*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]
]
}