ser(tuple): separate tuple and sequence processing to handle tuple types

This commit is contained in:
Matt Bilker
2018-08-17 19:05:03 -04:00
parent 1b5253112f
commit 284dda9606
6 changed files with 354 additions and 83 deletions

View File

@@ -98,6 +98,9 @@ pub enum KbinErrorKind {
#[fail(display = "Unable to convert from hexadecimal")]
HexError,
#[fail(display = "Missing base kbin type where one is required")]
MissingBaseType,
#[fail(display = "Missing type hint where one is required")]
MissingTypeHint,
@@ -153,6 +156,7 @@ impl From<FromUtf8Error> for KbinError {
#[derive(Clone, Debug)]
pub enum Error {
Message(String),
StaticMessage(&'static str),
Wrapped(Compat<KbinError>),
}
@@ -179,6 +183,7 @@ impl StdError for Error {
fn description(&self) -> &str {
match *self {
Error::Message(ref msg) => msg,
Error::StaticMessage(ref msg) => msg,
Error::Wrapped(ref err) => err.description(),
}
}

View File

@@ -287,6 +287,25 @@ impl fmt::Display for KbinType {
}
}
macro_rules! find_type {
($($base:ident => [$($size:tt $alternate:ident)+])+) => {
pub fn find_type(base: StandardType, len: usize) -> StandardType {
match base {
$(
StandardType::$base => match len {
1 => StandardType::$base,
$(
$size => StandardType::$alternate,
)+
_ => panic!("Unsupported len, base: {:?}, len: {}", base, len),
},
)*
_ => panic!("Unsupported base, base: {:?}, len: {}", base, len),
}
}
};
}
macro_rules! construct_types {
(
$(
@@ -345,6 +364,18 @@ macro_rules! construct_types {
)+
}
}
find_type! {
S8 => [ 2 S8_2 3 S8_3 4 S8_4 ]
U8 => [ 2 U8_2 3 U8_3 4 U8_4 ]
S16 => [ 2 S16_2 3 S16_3 4 S16_4 ]
U16 => [ 2 U16_2 3 U16_3 4 U16_4 ]
S32 => [ 2 S32_2 3 S32_3 4 S32_4 ]
U32 => [ 2 U32_2 3 U32_3 4 U32_4 ]
Float => [ 2 Float2 3 Float3 4 Float4 ]
Double => [ 2 Double2 3 Double3 4 Double4 ]
Boolean => [ 2 Boolean2 3 Boolean3 4 Boolean4 ]
}
}
impl Deref for StandardType {

174
src/ser/buffer.rs Normal file
View File

@@ -0,0 +1,174 @@
use byteorder::{BigEndian, WriteBytesExt};
use failure::ResultExt;
use serde::ser::{self, Impossible, Serialize};
use error::{Error, KbinErrorKind};
use node_types::StandardType;
pub struct BufferSerializer {
buffer: Vec<u8>,
}
impl BufferSerializer {
pub fn new() -> Self {
Self {
buffer: Vec::new(),
}
}
#[inline]
pub fn get_ref(&self) -> &[u8] {
&self.buffer
}
#[inline]
pub fn into_inner(self) -> Vec<u8> {
self.buffer
}
}
macro_rules! ser_type {
(byte; $inner_type:ident, $method:ident, $standard_type:ident $($cast:tt)*) => {
fn $method(self, value: $inner_type) -> Result<Self::Ok, Self::Error> {
let node_type = StandardType::$standard_type;
trace!("BufferSerializer::{}(node_type: {}, value: {})", stringify!($method), stringify!($standard_type), value);
self.buffer.write_u8(value $($cast)*).context(KbinErrorKind::DataWrite(node_type.name))?;
Ok(node_type)
}
};
(large; $inner_type:ident, $method:ident, $write_method:ident, $standard_type:ident $($cast:tt)*) => {
fn $method(self, value: $inner_type) -> Result<Self::Ok, Self::Error> {
trace!(concat!("BufferSerializer::{}(node_type: {}, value: {})"), stringify!($method), stringify!($standard_type), value);
//self.buffer.push(Value::$standard_type(value));
let node_type = StandardType::$standard_type;
self.buffer.$write_method::<BigEndian>(value $($cast)*).context(KbinErrorKind::DataWrite(node_type.name))?;
Ok(node_type)
}
}
}
impl<'a> ser::Serializer for &'a mut BufferSerializer {
type Ok = StandardType;
type Error = Error;
type SerializeSeq = Impossible<Self::Ok, Self::Error>;
type SerializeTuple = Impossible<Self::Ok, Self::Error>;
type SerializeTupleStruct = Impossible<Self::Ok, Self::Error>;
type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
type SerializeMap = Impossible<Self::Ok, Self::Error>;
type SerializeStruct = Impossible<Self::Ok, Self::Error>;
type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
fn is_human_readable(&self) -> bool {
false
}
ser_type!(byte; bool, serialize_bool, Boolean as u8);
ser_type!(byte; u8, serialize_u8, U8);
ser_type!(byte; i8, serialize_i8, S8 as u8);
ser_type!(large; u16, serialize_u16, write_u16, U16);
ser_type!(large; i16, serialize_i16, write_i16, S16);
ser_type!(large; u32, serialize_u32, write_u32, U32);
ser_type!(large; i32, serialize_i32, write_i32, S32);
ser_type!(large; u64, serialize_u64, write_u64, U64);
ser_type!(large; i64, serialize_i64, write_i64, S64);
ser_type!(large; f32, serialize_f32, write_f32, Float);
ser_type!(large; f64, serialize_f64, write_f64, Double);
fn serialize_char(self, value: char) -> Result<Self::Ok, Self::Error> {
trace!("BufferSerializer::serialize_char(value: {})", value);
Err(Error::StaticMessage("char not supported"))
}
fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> {
trace!("BufferSerializer::serialize_str(value: {})", value);
Err(Error::StaticMessage("str not supported"))
}
// Binary data is handled separately from other array types.
// Binary data should also be the only element of its node.
fn serialize_bytes(self, value: &[u8]) -> Result<Self::Ok, Self::Error> {
trace!("BufferSerializer::serialize_bytes(value: {:02x?})", value);
Err(Error::StaticMessage("bytes not supported"))
}
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
trace!("BufferSerializer::serialize_none()");
Err(Error::StaticMessage("option not supported"))
}
fn serialize_some<T>(self, _v: &T) -> Result<Self::Ok, Self::Error>
where T: ?Sized + Serialize
{
trace!("BufferSerializer::serialize_some()");
Err(Error::StaticMessage("option not supported"))
}
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
trace!("BufferSerializer::serialize_unit()");
Err(Error::StaticMessage("unit not supported"))
}
fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
trace!("BufferSerializer::serialize_unit_struct(name: {})", name);
Err(Error::StaticMessage("unit struct not supported"))
}
fn serialize_unit_variant(self, name: &'static str, variant_index: u32, variant: &'static str) -> Result<Self::Ok, Self::Error> {
trace!("BufferSerializer::serialize_unit_variant(name: {}, variant_index: {}, variant: {})", name, variant_index, variant);
Err(Error::StaticMessage("unit variant not supported"))
}
fn serialize_newtype_struct<T>(self, name: &'static str, _value: &T) -> Result<Self::Ok, Self::Error>
where T: ?Sized + Serialize
{
trace!("BufferSerializer::serialize_newtype_struct(name: {})", name);
Err(Error::StaticMessage("newtype struct not supported"))
}
fn serialize_newtype_variant<T>(self, name: &'static str, variant_index: u32, variant: &'static str, _value: &T) -> Result<Self::Ok, Self::Error>
where T: ?Sized + Serialize
{
trace!("BufferSerializer::serialize_newtype_variant(name: {}, variant_index: {}, variant: {})", name, variant_index, variant);
Err(Error::StaticMessage("newtype variant not supported"))
}
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
trace!("BufferSerializer::serialize_seq(len: {:?})", len);
Err(Error::StaticMessage("sequences not supported"))
}
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
trace!("BufferSerializer::serialize_tuple(len: {})", len);
Err(Error::StaticMessage("tuple not supported"))
}
fn serialize_tuple_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeTupleStruct, Self::Error> {
trace!("BufferSerializer::serialize_tuple_struct(name: {}, len: {})", name, len);
Err(Error::StaticMessage("tuple struct not supported"))
}
fn serialize_tuple_variant(self, name: &'static str, variant_index: u32, variant: &'static str, len: usize) -> Result<Self::SerializeTupleVariant, Self::Error> {
trace!("BufferSerializer::serialize_tuple_variant(name: {}, variant_index: {}, variant: {}, len: {})", name, variant_index, variant, len);
Err(Error::StaticMessage("tuple variant not supported"))
}
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
trace!("BufferSerializer::serialize_map(len: {:?})", len);
Err(Error::StaticMessage("map not supported"))
}
fn serialize_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeStruct, Self::Error> {
trace!("BufferSerializer::serialize_struct(name: {}, len: {})", name, len);
Err(Error::StaticMessage("struct not supported"))
}
fn serialize_struct_variant(self, name: &'static str, variant_index: u32, variant: &'static str, len: usize) -> Result<Self::SerializeStructVariant, Self::Error> {
trace!("BufferSerializer::serialize_struct_variant(name: {}, variant_index: {}, variant: {}, len: {})", name, variant_index, variant, len);
Err(Error::StaticMessage("struct variant not supported"))
}
}

View File

@@ -12,14 +12,17 @@ use error::{Error, KbinError, KbinErrorKind};
use sixbit::pack_sixbit;
use super::{ARRAY_MASK, SIGNATURE, SIG_COMPRESSED};
mod buffer;
mod custom;
mod map;
mod structure;
mod seq;
mod tuple;
use self::custom::Custom;
use self::map::Map;
use self::structure::Struct;
use self::seq::Seq;
use self::tuple::Tuple;
pub type Result<T> = StdResult<T, Error>;
@@ -122,7 +125,7 @@ impl Serializer {
macro_rules! ser_type {
(byte; $inner_type:ident, $method:ident, $standard_type:ident $($cast:tt)*) => {
fn $method(self, value: $inner_type) -> Result<Self::Ok> {
trace!(concat!("Serializer::", stringify!($method), " => value: {}"), value);
trace!(concat!("Serializer::", stringify!($method), "(value: {})"), value);
let node_type = StandardType::$standard_type;
match self.write_mode {
@@ -141,7 +144,7 @@ macro_rules! ser_type {
};
(large; $inner_type:ident, $method:ident, $write_method:ident, $standard_type:ident $($cast:tt)*) => {
fn $method(self, value: $inner_type) -> Result<Self::Ok> {
trace!(concat!("Serializer::", stringify!($method), " => value: {}"), value);
trace!(concat!("Serializer::", stringify!($method), "(value: {})"), value);
let node_type = StandardType::$standard_type;
match self.write_mode {
@@ -165,7 +168,7 @@ impl<'a> ser::Serializer for &'a mut Serializer {
type Ok = Option<TypeHint>;
type Error = Error;
type SerializeSeq = Tuple<'a>;
type SerializeSeq = Seq<'a>;
type SerializeTuple = Tuple<'a>;
type SerializeTupleStruct = Custom<'a>;
type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
@@ -234,45 +237,44 @@ impl<'a> ser::Serializer for &'a mut Serializer {
// TODO: Figure out a good way to serialize this
fn serialize_none(self) -> Result<Self::Ok> {
debug!("serialize_none");
trace!("Serializer::serialize_none()");
Ok(None)
}
fn serialize_some<T>(self, v: &T) -> Result<Self::Ok>
fn serialize_some<T>(self, value: &T) -> Result<Self::Ok>
where T: ?Sized + Serialize
{
trace!("Serializer::serialize_some()");
v.serialize(&mut *self)
value.serialize(&mut *self)
}
// TODO: Figure out a good way to serialize this
fn serialize_unit(self) -> Result<Self::Ok> {
debug!("serialize_unit");
unimplemented!();
trace!("Serializer::serialize_unit()");
Err(Error::StaticMessage("unit not supported"))
}
fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok> {
debug!("serialize_unit_struct => name: {}", name);
let hint = name.serialize(&mut *self)?;
Ok(hint)
trace!("Serializer::serialize_unit_struct(name: {})", name);
name.serialize(&mut *self)
}
fn serialize_unit_variant(self, name: &'static str, variant_index: u32, variant: &'static str) -> Result<Self::Ok> {
debug!("serialize_unit_variant => name: {}, variant_index: {}, variant: {}", name, variant_index, variant);
trace!("Serializer::serialize_unit_variant(name: {}, variant_index: {}, variant: {})", name, variant_index, variant);
variant.serialize(&mut *self)
}
fn serialize_newtype_struct<T>(self, name: &'static str, value: &T) -> Result<Self::Ok>
where T: ?Sized + Serialize
{
debug!("serialize_newtype_struct => name: {}", name);
trace!("Serializer::serialize_newtype_struct(name: {})", name);
value.serialize(&mut *self)
}
fn serialize_newtype_variant<T>(self, name: &'static str, variant_index: u32, variant: &'static str, value: &T) -> Result<Self::Ok>
where T: ?Sized + Serialize
{
debug!("serialize_newtype_variant => name: {}, variant_index: {}, variant: {}", name, variant_index, variant);
trace!("Serializer::serialize_newtype_variant(name: {}, variant_index: {}, variant: {})", name, variant_index, variant);
variant.serialize(&mut *self)?;
let hint = value.serialize(&mut *self)?.map(|mut hint| {
hint.is_array = false;
@@ -282,24 +284,25 @@ impl<'a> ser::Serializer for &'a mut Serializer {
}
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq> {
debug!("serialize_seq => len: {:?}", len);
let len = len.ok_or(Error::Message("unsized sequences not supported".to_string()))?;
Ok(Tuple::new(self, len))
trace!("Serializer::serialize_seq(len: {:?})", len);
let len = len.ok_or(Error::StaticMessage("unsized sequences not supported"))?;
Seq::new(self, len)
}
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
debug!("serialize_tuple => len: {}", len);
trace!("Serializer::serialize_tuple(len: {})", len);
Ok(Tuple::new(self, len))
}
fn serialize_tuple_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeTupleStruct> {
debug!("serialize_tuple_struct => name: {}, len: {}", name, len);
trace!("Serializer::serialize_tuple_struct(name: {}, len: {})", name, len);
Custom::new(self, name, len)
}
fn serialize_tuple_variant(self, name: &'static str, variant_index: u32, variant: &'static str, len: usize) -> Result<Self::SerializeTupleVariant> {
debug!("serialize_tuple_variant => name: {}, variant_index: {}, variant: {}, len: {}", name, variant_index, variant, len);
Err(Error::Message("tuple variant not supported".to_string()))
trace!("Serializer::serialize_tuple_variant(name: {}, variant_index: {}, variant: {}, len: {})", name, variant_index, variant, len);
Err(Error::StaticMessage("tuple variant not supported"))
}
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap> {
@@ -308,13 +311,12 @@ impl<'a> ser::Serializer for &'a mut Serializer {
}
fn serialize_struct(self, name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
debug!("serialize_struct => name: {}, len: {}", name, len);
trace!("Serializer::serialize_struct(name: {}, len: {})", name, len);
Struct::new(self, name, len)
}
fn serialize_struct_variant(self, name: &'static str, variant_index: u32, variant: &'static str, len: usize) -> Result<Self::SerializeStructVariant> {
debug!("serialize_struct_variant => name: {}, variant_index: {}, variant: {}, len: {}", name, variant_index, variant, len);
Err(Error::Message("struct variant not supported".to_string()))
trace!("Serializer::serialize_struct_variant(name: {}, variant_index: {}, variant: {}, len: {})", name, variant_index, variant, len);
Err(Error::StaticMessage("struct variant not supported"))
}
}

84
src/ser/seq.rs Normal file
View File

@@ -0,0 +1,84 @@
use std::io::{Seek, SeekFrom};
use byteorder::{BigEndian, WriteBytesExt};
use failure::ResultExt;
use serde::ser::{Serialize, SerializeSeq};
use error::KbinErrorKind;
use node_types::StandardType;
use ser::{Error, Result, Serializer, TypeHint, WriteMode};
pub struct Seq<'a> {
ser: &'a mut Serializer,
size_index: u64,
node_type: Option<StandardType>,
len: usize,
}
impl<'a> Seq<'a> {
pub fn new(ser: &'a mut Serializer, len: usize) -> Result<Self> {
trace!("Tuple::new(len: {})", len);
ser.write_mode = WriteMode::Array;
// Estimate u32 for the total size of the tuple
let size_index = ser.data_buf.position();
ser.data_buf.write_u32::<BigEndian>(len as u32).context(KbinErrorKind::DataWrite("size placeholder"))?;
Ok(Self {
ser,
size_index,
node_type: None,
len,
})
}
}
impl<'a> SerializeSeq for Seq<'a> {
type Ok = Option<TypeHint>;
type Error = Error;
fn serialize_element<T>(&mut self, value: &T) -> Result<()>
where T: ?Sized + Serialize
{
trace!("<Seq as SerializeSeq>::serialize_element()");
let hint = value.serialize(&mut *self.ser)?.ok_or(KbinErrorKind::MissingTypeHint)?;
debug!("<Seq as SerializeSeq>::serialize_element() => hint: {:?}", hint);
// Rust tuple types can have different types per element, this is not
// permitted by kbin
if let Some(node_type) = self.node_type {
if node_type != hint.node_type {
return Err(KbinErrorKind::TypeMismatch(*node_type, *hint.node_type).into());
}
} else {
self.node_type = Some(hint.node_type);
}
Ok(())
}
fn end(self) -> Result<Self::Ok> {
trace!("<Seq as SerializeSeq>::end()");
self.ser.write_mode = WriteMode::Single;
self.ser.data_buf.realign_writes(None)?;
let node_type = self.node_type.ok_or(KbinErrorKind::InvalidState)?;
let size = (self.len as u32) * (node_type.size as u32);
// Update the size estimate from the constructor
if size as usize != self.len {
debug!("<Seq as SerializeSeq>::end() => size correction: {}", size);
let current_pos = self.ser.data_buf.position();
self.ser.data_buf.seek(SeekFrom::Start(self.size_index)).context(KbinErrorKind::Seek)?;
self.ser.data_buf.write_u32::<BigEndian>(size).context(KbinErrorKind::DataWrite("node size"))?;
self.ser.data_buf.seek(SeekFrom::Start(current_pos)).context(KbinErrorKind::Seek)?;
}
Ok(Some(TypeHint { node_type, is_array: true, count: self.len }))
}
}

View File

@@ -1,42 +1,47 @@
use std::io::{Seek, SeekFrom};
use byteorder::{BigEndian, WriteBytesExt};
use failure::ResultExt;
use serde::ser::{Serialize, SerializeSeq, SerializeTuple};
use serde::ser::{Serialize, SerializeTuple};
use error::KbinErrorKind;
use node_types::StandardType;
use ser::{Error, Result, Serializer, TypeHint, WriteMode};
use ser::{Error, Result, Serializer, TypeHint};
use ser::buffer::BufferSerializer;
/// Tuple handler for serialization.
///
/// Kbin tuple types are monotype (all tuple elements have the same type)
/// which differs from Rust's tuples that can have different types for each
/// element.
///
/// This key difference is what makes it harder to seralize tuples, which is
/// why the `BufferSerializer` is used to serialize tuple elements to an
/// intermediate byte array before running the write logic. Kbin's write logic
/// depends on the size of the type, which is taken care of by
/// `ByteBuffer::write_aligned`.
pub struct Tuple<'a> {
ser: &'a mut Serializer,
buffer: BufferSerializer,
size_index: u64,
node_type: Option<StandardType>,
len: usize,
}
impl<'a> Tuple<'a> {
pub fn new(ser: &'a mut Serializer, len: usize) -> Self {
debug!("Tuple::new(len: {})", len);
ser.write_mode = WriteMode::Array;
// Estimate u32 for the total size of the tuple
let size_index = ser.data_buf.position();
ser.data_buf.write_u32::<BigEndian>(len as u32).expect("Unable to write size placeholder");
trace!("Tuple::new(len: {})", len);
Self {
ser,
size_index,
buffer: BufferSerializer::new(),
node_type: None,
len,
}
}
fn find_standard_type(&self) -> StandardType {
debug!("find_standard_type => len: {}", self.len);
self.node_type.unwrap_or(StandardType::String)
fn find_standard_type(&self) -> Result<StandardType> {
let base = self.node_type.ok_or(KbinErrorKind::MissingBaseType)?;
let combined = StandardType::find_type(base, self.len);
debug!("find_standard_type => StandardType::find_type(base: {:?}, len: {}) = {:?}", base, self.len, combined);
Ok(combined)
}
}
@@ -47,58 +52,28 @@ impl<'a> SerializeTuple for Tuple<'a> {
fn serialize_element<T>(&mut self, value: &T) -> Result<()>
where T: ?Sized + Serialize
{
debug!("SerializeTuple: serialize_element");
let hint = value.serialize(&mut *self.ser)?.ok_or(KbinErrorKind::MissingTypeHint)?;
debug!("SerializeTuple: serialize_element, hint: {:?}", hint);
let node_type = value.serialize(&mut self.buffer)?;
// Rust tuple types can have different types per element, this is not
// permitted by kbin
if let Some(node_type) = self.node_type {
if node_type != hint.node_type {
return Err(KbinErrorKind::TypeMismatch(*node_type, *hint.node_type).into());
if let Some(known) = self.node_type {
if known != node_type {
return Err(KbinErrorKind::TypeMismatch(*known, *node_type).into());
}
} else {
self.node_type = Some(hint.node_type);
self.node_type = Some(node_type);
}
Ok(())
}
fn end(self) -> Result<Self::Ok> {
debug!("SerializeTuple: end");
let node_type = self.find_standard_type()?;
let buffer = self.buffer.into_inner();
debug!("<Tuple as SerializeTuple>::end() => buffer: {:?}, node_type: {:?}", buffer, node_type);
self.ser.write_mode = WriteMode::Single;
self.ser.data_buf.realign_writes(None)?;
self.ser.data_buf.write_aligned(*node_type, &buffer)?;
let node_type = self.find_standard_type();
let size = (self.len as u32) * (node_type.size as u32);
// Update the size estimate from the constructor
if size as usize != self.len {
debug!("SerializeTuple: end, size correction: {}", size);
let current_pos = self.ser.data_buf.position();
self.ser.data_buf.seek(SeekFrom::Start(self.size_index)).context(KbinErrorKind::Seek)?;
self.ser.data_buf.write_u32::<BigEndian>(size).context(KbinErrorKind::DataWrite("node size"))?;
self.ser.data_buf.seek(SeekFrom::Start(current_pos)).context(KbinErrorKind::Seek)?;
}
Ok(Some(TypeHint { node_type, is_array: true, count: self.len }))
}
}
// kbin only supports sized arrays, coerce sequence types to tuple processing
impl<'a> SerializeSeq for Tuple<'a> {
type Ok = Option<TypeHint>;
type Error = Error;
fn serialize_element<T>(&mut self, value: &T) -> Result<()>
where T: ?Sized + Serialize
{
<Self as SerializeTuple>::serialize_element(self, value)
}
fn end(self) -> Result<Self::Ok> {
<Self as SerializeTuple>::end(self)
Ok(Some(TypeHint::from_type(node_type)))
}
}