lib: general cleanup and added some convenience methods for Value

- split out the kbin wrapper from node_types.rs
This commit is contained in:
Matt Bilker
2018-08-28 00:46:26 -04:00
parent d99ff0aef8
commit b204d3e19e
7 changed files with 212 additions and 152 deletions

View File

@@ -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<V>(self, visitor: V) -> Result<V::Value>

145
src/kbin_wrapper.rs Normal file
View File

@@ -0,0 +1,145 @@
use std::fmt::Write;
use byteorder::WriteBytesExt;
use failure::ResultExt;
use error::{KbinError, KbinErrorKind};
pub(crate) trait KbinWrapperType<T> {
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError>;
fn to_kbin_bytes(output: &mut Vec<u8>, 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<u8>, 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<u8>, 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<bool> for bool {
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> {
trace!("KbinWrapperType<bool> 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<u8>, input: &str) -> Result<(), KbinError> {
let value = match input {
"0" => 0x00,
"1" => 0x01,
v => panic!("Unsupported value for boolean: {}", v),
};
trace!("KbinWrapperType<bool> 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<Ip4> for Ip4 {
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> {
trace!("KbinWrapperType<Ip4> 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<u8>, input: &str) -> Result<(), KbinError> {
trace!("KbinWrapperType<Ip4> to bytes => input: '{}'", input);
for part in input.split('.') {
let num = part.parse::<u8>().context(KbinErrorKind::StringParse("ip4 segment"))?;
output.write_u8(num).context(KbinErrorKind::DataWrite("ip4"))?;
}
Ok(())
}
}
impl KbinWrapperType<DummyConverter> for DummyConverter {
fn from_kbin_bytes(_output: &mut String, _input: &[u8]) -> Result<(), KbinError> { Ok(()) }
fn to_kbin_bytes(_output: &mut Vec<u8>, _input: &str) -> Result<(), KbinError> { Ok(()) }
}
impl KbinWrapperType<InvalidConverter> 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<u8>, input: &str) -> Result<(), KbinError> {
panic!("Invalid kbin type converter called for input: {}", input);
}
}

View File

@@ -28,6 +28,7 @@ mod compression;
mod encoding_type;
mod error;
mod ip4;
mod kbin_wrapper;
mod node;
mod node_types;
mod options;

View File

@@ -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<IndexMap<String, String>>,
@@ -16,6 +18,25 @@ pub struct Node {
value: Option<Value>,
}
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<Value>) -> Self {
Self {

View File

@@ -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<T> {
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError>;
fn to_kbin_bytes(output: &mut Vec<u8>, 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<u8>, 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<u8>, 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<bool> for bool {
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> {
trace!("KbinWrapperType<bool> 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<u8>, input: &str) -> Result<(), KbinError> {
let value = match input {
"0" => 0x00,
"1" => 0x01,
v => panic!("Unsupported value for boolean: {}", v),
};
trace!("KbinWrapperType<bool> to bytes => input: '{}', output: {}", input, value);
output.write_u8(value).context(KbinErrorKind::DataWrite("bool"))?;
Ok(())
}
}
struct Ip4;
struct DummyConverter;
struct InvalidConverter;
impl KbinWrapperType<Ip4> for Ip4 {
fn from_kbin_bytes(output: &mut String, input: &[u8]) -> Result<(), KbinError> {
trace!("KbinWrapperType<Ip4> 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<u8>, input: &str) -> Result<(), KbinError> {
trace!("KbinWrapperType<Ip4> to bytes => input: '{}'", input);
for part in input.split('.') {
let num = part.parse::<u8>().context(KbinErrorKind::StringParse("ip4 segment"))?;
output.write_u8(num).context(KbinErrorKind::DataWrite("ip4"))?;
}
Ok(())
}
}
impl KbinWrapperType<DummyConverter> for DummyConverter {
fn from_kbin_bytes(_output: &mut String, _input: &[u8]) -> Result<(), KbinError> { Ok(()) }
fn to_kbin_bytes(_output: &mut Vec<u8>, _input: &str) -> Result<(), KbinError> { Ok(()) }
}
impl KbinWrapperType<InvalidConverter> 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<u8>, 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 {

View File

@@ -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<E>(self, value: String) -> Result<Self::Value, E>
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]

View File

@@ -47,6 +47,20 @@ macro_rules! construct_types {
Value::Node(_) => StandardType::NodeStart,
}
}
pub fn as_i8(&self) -> Option<i8> {
match self {
Value::S8(ref n) => Some(*n),
_ => None,
}
}
pub fn as_u8(&self) -> Option<u8> {
match self {
Value::U8(ref n) => Some(*n),
_ => None,
}
}
}
impl<'de> DeserializeSeed<'de> for StandardType {