diff --git a/src/de/mod.rs b/src/de/mod.rs index f7da88f..f7b4111 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -55,6 +55,12 @@ impl<'de> Deserializer<'de> { }) } + #[inline] + fn node_stack_last(&self) -> Result<&(StandardType, bool)> { + self.node_stack.last() + .ok_or(KbinErrorKind::InvalidState.into()) + } + #[inline] fn set_read_mode(&mut self, read_mode: ReadMode) -> ReadMode { let old_read_mode = self.read_mode; @@ -70,11 +76,6 @@ impl<'de> Deserializer<'de> { Ok((node_type, is_array, name)) } - - fn node_stack_last(&self) -> Result<&(StandardType, bool)> { - self.node_stack.last() - .ok_or(KbinErrorKind::InvalidState.into()) - } } macro_rules! de_type { @@ -397,7 +398,8 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { where V: Visitor<'de> { trace!("Deserializer::deserialize_enum(name: {:?}, variants: {:?})", name, variants); - unimplemented!(); + + Err(Error::StaticMessage("enum deserialization not supported")) } fn deserialize_identifier(self, visitor: V) -> Result diff --git a/src/kbin_wrapper.rs b/src/kbin_wrapper.rs new file mode 100644 index 0000000..cd84cf6 --- /dev/null +++ b/src/kbin_wrapper.rs @@ -0,0 +1,145 @@ +use std::fmt::Write; + +use byteorder::WriteBytesExt; +use failure::ResultExt; + +use error::{KbinError, KbinErrorKind}; + +pub(crate) trait KbinWrapperType { + fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError>; + fn to_kbin_bytes(output: &mut Vec, input: &str) -> Result<(), KbinError>; +} + +macro_rules! number_impl { + (int; $($inner_type:ident),*) => { + $( + impl KbinWrapperType<$inner_type> for $inner_type { + fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> { + trace!("KbinWrapperType<{}> from bytes => input: {:02x?}", stringify!($inner_type), input); + + let mut data = [0; ::std::mem::size_of::<$inner_type>()]; + data.clone_from_slice(input); + write!(output, "{}", $inner_type::from_be_bytes(data)) + .context(KbinErrorKind::ByteParse(stringify!($inner_type)))?; + + Ok(()) + } + + fn to_kbin_bytes(output: &mut Vec, input: &str) -> Result<(), KbinError> { + let num = input.parse::<$inner_type>().context(KbinErrorKind::StringParse(stringify!($inner_type)))?; + trace!("KbinWrapperType<{}> to bytes => input: '{}', output: {}", stringify!($inner_type), input, num); + + let data = $inner_type::to_be_bytes(num); + output.extend_from_slice(&data); + + Ok(()) + } + } + )* + }; + (float; $($intermediate:ident => $inner_type:ident),*) => { + $( + impl KbinWrapperType<$inner_type> for $inner_type { + fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> { + trace!("KbinWrapperType<{}> from bytes => input: {:02x?}", stringify!($inner_type), input); + + let mut data = [0; ::std::mem::size_of::<$inner_type>()]; + data.clone_from_slice(input); + let bits = $intermediate::from_be_bytes(data); + + write!(output, "{:.6}", $inner_type::from_bits(bits)) + .context(KbinErrorKind::ByteParse(stringify!($inner_type)))?; + + Ok(()) + } + + fn to_kbin_bytes(output: &mut Vec, input: &str) -> Result<(), KbinError> { + let num = input.parse::<$inner_type>().context(KbinErrorKind::StringParse(stringify!($inner_type)))?; + trace!("KbinWrapperType<{}> to bytes => input: '{}', output: {}", stringify!($inner_type), input, num); + + let data = $intermediate::to_be_bytes(num.to_bits()); + output.extend_from_slice(&data); + + Ok(()) + } + } + )* + }; +} + +number_impl!(int; u8, u16, u32, u64); +number_impl!(int; i8, i16, i32, i64); +number_impl!(float; u32 => f32, u64 => f64); + +impl KbinWrapperType for bool { + fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> { + trace!("KbinWrapperType from bytes => input: {:02x?}", input); + + let value = match input[0] { + 0x00 => "0", + 0x01 => "1", + v => panic!("Unsupported value for boolean: {}", v), + }; + output.push_str(value); + + Ok(()) + } + + fn to_kbin_bytes(output: &mut Vec, input: &str) -> Result<(), KbinError> { + let value = match input { + "0" => 0x00, + "1" => 0x01, + v => panic!("Unsupported value for boolean: {}", v), + }; + + trace!("KbinWrapperType to bytes => input: '{}', output: {}", input, value); + output.write_u8(value).context(KbinErrorKind::DataWrite("bool"))?; + + Ok(()) + } +} + +pub(crate) struct Ip4; +pub(crate) struct DummyConverter; +pub(crate) struct InvalidConverter; + +impl KbinWrapperType for Ip4 { + fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> { + trace!("KbinWrapperType from bytes => input: {:02x?}", input); + + if input.len() != 4 { + panic!("Ip4 type requires exactly 4 bytes of data, input: {:02x?}", input); + } + + write!(output, "{}.{}.{}.{}", input[0], input[1], input[2], input[3]) + .context(KbinErrorKind::ByteParse("Ip4"))?; + + Ok(()) + } + + fn to_kbin_bytes(output: &mut Vec, input: &str) -> Result<(), KbinError> { + trace!("KbinWrapperType to bytes => input: '{}'", input); + + for part in input.split('.') { + let num = part.parse::().context(KbinErrorKind::StringParse("ip4 segment"))?; + output.write_u8(num).context(KbinErrorKind::DataWrite("ip4"))?; + } + + Ok(()) + } +} + +impl KbinWrapperType for DummyConverter { + fn from_kbin_bytes(_output: &mut String, _input: &[u8]) -> Result<(), KbinError> { Ok(()) } + fn to_kbin_bytes(_output: &mut Vec, _input: &str) -> Result<(), KbinError> { Ok(()) } +} + +impl KbinWrapperType for InvalidConverter { + fn from_kbin_bytes(_output: &mut String, input: &[u8]) -> Result<(), KbinError> { + panic!("Invalid kbin type converter called for input: {:02x?}", input); + } + + fn to_kbin_bytes(_output: &mut Vec, input: &str) -> Result<(), KbinError> { + panic!("Invalid kbin type converter called for input: {}", input); + } +} diff --git a/src/lib.rs b/src/lib.rs index 1496317..ee577bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,7 @@ mod compression; mod encoding_type; mod error; mod ip4; +mod kbin_wrapper; mod node; mod node_types; mod options; diff --git a/src/node/mod.rs b/src/node/mod.rs index a6cf571..4f2f4cf 100644 --- a/src/node/mod.rs +++ b/src/node/mod.rs @@ -1,3 +1,5 @@ +use std::fmt; + use indexmap::IndexMap; use value::Value; @@ -8,7 +10,7 @@ mod ser; pub use self::extra::ExtraNodes; -#[derive(Clone, Debug, Default, PartialEq)] +#[derive(Clone, Default, PartialEq)] pub struct Node { key: String, attributes: Option>, @@ -16,6 +18,25 @@ pub struct Node { value: Option, } +impl fmt::Debug for Node { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut d = f.debug_struct("Node"); + d.field("key", &self.key); + + if let Some(ref attributes) = self.attributes { + d.field("attributes", attributes); + } + + if let Some(ref children) = self.children { + d.field("children", children); + } else if let Some(ref value) = self.value { + d.field("value", value); + } + + d.finish() + } +} + impl Node { pub fn new(key: String, value: Option) -> Self { Self { diff --git a/src/node_types.rs b/src/node_types.rs index a92d43a..666309a 100644 --- a/src/node_types.rs +++ b/src/node_types.rs @@ -1,149 +1,8 @@ -use std::fmt::{self, Write}; +use std::fmt; use std::ops::Deref; -use byteorder::WriteBytesExt; -use failure::ResultExt; - use error::{KbinError, KbinErrorKind}; - -trait KbinWrapperType { - fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError>; - fn to_kbin_bytes(output: &mut Vec, input: &str) -> Result<(), KbinError>; -} - -macro_rules! number_impl { - (int; $($inner_type:ident),*) => { - $( - impl KbinWrapperType<$inner_type> for $inner_type { - fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> { - trace!("KbinWrapperType<{}> from bytes => input: {:02x?}", stringify!($inner_type), input); - - let mut data = [0; ::std::mem::size_of::<$inner_type>()]; - data.clone_from_slice(input); - write!(output, "{}", $inner_type::from_be_bytes(data)) - .context(KbinErrorKind::ByteParse(stringify!($inner_type)))?; - - Ok(()) - } - - fn to_kbin_bytes(output: &mut Vec, input: &str) -> Result<(), KbinError> { - let num = input.parse::<$inner_type>().context(KbinErrorKind::StringParse(stringify!($inner_type)))?; - trace!("KbinWrapperType<{}> to bytes => input: '{}', output: {}", stringify!($inner_type), input, num); - - let data = $inner_type::to_be_bytes(num); - output.extend_from_slice(&data); - - Ok(()) - } - } - )* - }; - (float; $($intermediate:ident => $inner_type:ident),*) => { - $( - impl KbinWrapperType<$inner_type> for $inner_type { - fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> { - trace!("KbinWrapperType<{}> from bytes => input: {:02x?}", stringify!($inner_type), input); - - let mut data = [0; ::std::mem::size_of::<$inner_type>()]; - data.clone_from_slice(input); - let bits = $intermediate::from_be_bytes(data); - - write!(output, "{:.6}", $inner_type::from_bits(bits)) - .context(KbinErrorKind::ByteParse(stringify!($inner_type)))?; - - Ok(()) - } - - fn to_kbin_bytes(output: &mut Vec, input: &str) -> Result<(), KbinError> { - let num = input.parse::<$inner_type>().context(KbinErrorKind::StringParse(stringify!($inner_type)))?; - trace!("KbinWrapperType<{}> to bytes => input: '{}', output: {}", stringify!($inner_type), input, num); - - let data = $intermediate::to_be_bytes(num.to_bits()); - output.extend_from_slice(&data); - - Ok(()) - } - } - )* - }; -} - -number_impl!(int; u8, u16, u32, u64); -number_impl!(int; i8, i16, i32, i64); -number_impl!(float; u32 => f32, u64 => f64); - -impl KbinWrapperType for bool { - fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> { - trace!("KbinWrapperType from bytes => input: {:02x?}", input); - - let value = match input[0] { - 0x00 => "0", - 0x01 => "1", - v => panic!("Unsupported value for boolean: {}", v), - }; - output.push_str(value); - - Ok(()) - } - - fn to_kbin_bytes(output: &mut Vec, input: &str) -> Result<(), KbinError> { - let value = match input { - "0" => 0x00, - "1" => 0x01, - v => panic!("Unsupported value for boolean: {}", v), - }; - - trace!("KbinWrapperType to bytes => input: '{}', output: {}", input, value); - output.write_u8(value).context(KbinErrorKind::DataWrite("bool"))?; - - Ok(()) - } -} - -struct Ip4; -struct DummyConverter; -struct InvalidConverter; - -impl KbinWrapperType for Ip4 { - fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> { - trace!("KbinWrapperType from bytes => input: {:02x?}", input); - - if input.len() != 4 { - panic!("Ip4 type requires exactly 4 bytes of data, input: {:02x?}", input); - } - - write!(output, "{}.{}.{}.{}", input[0], input[1], input[2], input[3]) - .context(KbinErrorKind::ByteParse("Ip4"))?; - - Ok(()) - } - - fn to_kbin_bytes(output: &mut Vec, input: &str) -> Result<(), KbinError> { - trace!("KbinWrapperType to bytes => input: '{}'", input); - - for part in input.split('.') { - let num = part.parse::().context(KbinErrorKind::StringParse("ip4 segment"))?; - output.write_u8(num).context(KbinErrorKind::DataWrite("ip4"))?; - } - - Ok(()) - } -} - -impl KbinWrapperType for DummyConverter { - fn from_kbin_bytes(_output: &mut String, _input: &[u8]) -> Result<(), KbinError> { Ok(()) } - fn to_kbin_bytes(_output: &mut Vec, _input: &str) -> Result<(), KbinError> { Ok(()) } -} - -impl KbinWrapperType for InvalidConverter { - fn from_kbin_bytes(_output: &mut String, input: &[u8]) -> Result<(), KbinError> { - panic!("Invalid kbin type converter called for input: {:02x?}", input); - } - - fn to_kbin_bytes(_output: &mut Vec, input: &str) -> Result<(), KbinError> { - panic!("Invalid kbin type converter called for input: {}", input); - } -} +use kbin_wrapper::*; #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct KbinType { diff --git a/src/value/de.rs b/src/value/de.rs index f8334fe..689ba7e 100644 --- a/src/value/de.rs +++ b/src/value/de.rs @@ -30,7 +30,20 @@ impl<'de> Deserialize<'de> for Value { type Value = Value; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("any valid kbin value") + formatter.write_str("any valid kbin value (for Value)") + } + + #[inline] + fn visit_string(self, value: String) -> Result + where E: de::Error + { + trace!("ValueVisitor::visit_string(value: {:?})", value); + + if value.starts_with("attr_") { + Ok(Value::Attribute(String::from(&value["attr_".len()..]))) + } else { + Ok(Value::String(value)) + } } #[inline] @@ -38,7 +51,12 @@ impl<'de> Deserialize<'de> for Value { where E: de::Error { trace!("ValueVisitor::visit_str(value: {:?})", value); - self.visit_string(String::from(value)) + + if value.starts_with("attr_") { + Ok(Value::Attribute(String::from(&value["attr_".len()..]))) + } else { + Ok(Value::String(String::from(value))) + } } #[inline] diff --git a/src/value/mod.rs b/src/value/mod.rs index a45c7a6..e22eda8 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -47,6 +47,20 @@ macro_rules! construct_types { Value::Node(_) => StandardType::NodeStart, } } + + pub fn as_i8(&self) -> Option { + match self { + Value::S8(ref n) => Some(*n), + _ => None, + } + } + + pub fn as_u8(&self) -> Option { + match self { + Value::U8(ref n) => Some(*n), + _ => None, + } + } } impl<'de> DeserializeSeed<'de> for StandardType {