diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 341fe99..7071f41 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -1,5 +1,4 @@ use std::io::{Cursor, Write}; -use std::mem; use std::result::Result as StdResult; use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; @@ -9,13 +8,14 @@ use serde::ser::{self, Impossible, Serialize}; use byte_buffer::ByteBufferWrite; use encoding_type::EncodingType; use node_types::StandardType; -use sixbit::pack_sixbit; use super::error::{KbinError, KbinErrorKind}; mod error; +mod structure; mod tuple; use self::error::Error; +use self::structure::Struct; use self::tuple::Tuple; const SIGNATURE: u8 = 0xA0; @@ -37,10 +37,11 @@ pub(crate) enum WriteMode { pub struct Serializer { encoding: EncodingType, - pub(crate) write_mode: WriteMode, + hierarchy: Vec<&'static str>, + write_mode: WriteMode, - pub(crate) node_buf: ByteBufferWrite, - pub(crate) data_buf: ByteBufferWrite, + node_buf: ByteBufferWrite, + data_buf: ByteBufferWrite, } #[derive(Debug)] @@ -65,6 +66,7 @@ pub fn to_bytes(value: &T) -> Result> { let mut serializer = Serializer { encoding: EncodingType::SHIFT_JIS, + hierarchy: Vec::new(), write_mode: WriteMode::Single, node_buf: ByteBufferWrite::new(Vec::new()), data_buf: ByteBufferWrite::new(Vec::new()), @@ -157,7 +159,7 @@ impl<'a> ser::Serializer for &'a mut Serializer { type SerializeTupleStruct = Impossible; type SerializeTupleVariant = Impossible; type SerializeMap = Self; - type SerializeStruct = Self; + type SerializeStruct = Struct<'a>; type SerializeStructVariant = Impossible; byte_impl!(bool, serialize_bool, Boolean as u8); @@ -280,11 +282,7 @@ impl<'a> ser::Serializer for &'a mut Serializer { fn serialize_struct(self, name: &'static str, len: usize) -> Result { debug!("serialize_struct => name: {}, len: {}", name, len); - let node_type = StandardType::NodeStart; - self.node_buf.write_u8(node_type.id).context(KbinErrorKind::DataWrite(node_type.name))?; - pack_sixbit(&mut *self.node_buf, name)?; - - Ok(self) + Struct::new(self, name, len) } fn serialize_struct_variant(self, name: &'static str, variant_index: u32, variant: &'static str, len: usize) -> Result { @@ -320,36 +318,3 @@ impl<'a> ser::SerializeMap for &'a mut Serializer { Ok(None) } } - -impl<'a> ser::SerializeStruct for &'a mut Serializer { - type Ok = Option; - type Error = Error; - - fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> - where T: ?Sized + Serialize - { - let size = mem::size_of_val(value); - debug!("SerializeStruct: serialize_field, key: {}, value size: {}", key, size); - - let hint = value.serialize(&mut **self)?.ok_or(KbinErrorKind::MissingTypeHint)?; - let array_mask = if hint.is_array { ARRAY_MASK } else { 0 }; - debug!("SerializeStruct: serialize_field, key: {}, hint: {:?}", key, hint); - - self.node_buf.write_u8(hint.node_type.id | array_mask).context(KbinErrorKind::DataWrite(hint.node_type.name))?; - pack_sixbit(&mut *self.node_buf, key)?; - - // TODO: Make sure this does not prematurely end nodes - self.node_buf.write_u8(StandardType::NodeEnd.id | ARRAY_MASK).context(KbinErrorKind::DataWrite("node end"))?; - - Ok(()) - } - - fn end(self) -> Result { - debug!("SerializeStruct: end"); - self.node_buf.write_u8(StandardType::NodeEnd.id | ARRAY_MASK).context(KbinErrorKind::DataWrite("node end"))?; - - trace!("SerializeStruct::end() => node_buf: {:02x?}", self.node_buf.get_ref()); - - Ok(Some(TypeHint::from_type(StandardType::NodeStart))) - } -} diff --git a/src/ser/structure.rs b/src/ser/structure.rs new file mode 100644 index 0000000..5541947 --- /dev/null +++ b/src/ser/structure.rs @@ -0,0 +1,94 @@ +use byteorder::WriteBytesExt; +use failure::ResultExt; +use serde::ser::{Serialize, SerializeStruct}; + +use node_types::StandardType; +use error::KbinErrorKind; +use ser::{Error, Result, Serializer, TypeHint, ARRAY_MASK}; +use sixbit::pack_sixbit; + +pub struct Struct<'a> { + ser: &'a mut Serializer, + name: &'static str, +} + +impl<'a> Struct<'a> { + pub fn new(ser: &'a mut Serializer, name: &'static str, len: usize) -> Result { + debug!("Struct::new(name: {}, len: {}) => hierarchy: {:?}", name, len, ser.hierarchy); + + // Restrict bounds of immutable borrow from `hierarchy` Vec + { + // The key name would have been pushed to the stack in `serialize_field` + // before calling `serialize` on the value + let name = if let Some(key) = ser.hierarchy.last() { + trace!("Struct::new(name: {}) => found key name: {}", name, key); + key + } else { + name + }; + + let node_type = StandardType::NodeStart; + ser.node_buf.write_u8(node_type.id).context(KbinErrorKind::DataWrite(node_type.name))?; + pack_sixbit(&mut *ser.node_buf, name)?; + } + + // The `Vec` cannot be borrowed as mutable in an `else` condition because + // of the immutable borrow made in the previous if statement, so this is a + // workaround + //if ser.hierarchy.is_empty() { + ser.hierarchy.push(name); + trace!("Struct::new(name: {}) => hierarchy: {:?}", name, ser.hierarchy); + //} + + Ok(Self { + ser, + name, + }) + } +} + +impl<'a> SerializeStruct for Struct<'a> { + type Ok = Option; + type Error = Error; + + fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> + where T: ?Sized + Serialize + { + // Push key name onto stack so if the value is a struct, it will pick up + // the correct name + self.ser.hierarchy.push(key); + debug!("SerializeStruct(name: {}): serialize_field, key: {}, hierarchy: {:?}", self.name, key, self.ser.hierarchy); + + let hint = value.serialize(&mut *self.ser)?.ok_or(KbinErrorKind::MissingTypeHint)?; + let node_type = hint.node_type; + let array_mask = if hint.is_array { ARRAY_MASK } else { 0 }; + debug!("SerializeStruct(name: {}): serialize_field, key: {}, hint: {:?}", self.name, key, hint); + + // Struct handler outputs the `NodeStart` event by itself. Avoid repeating it. + if node_type != StandardType::NodeStart { + self.ser.node_buf.write_u8(node_type.id | array_mask).context(KbinErrorKind::DataWrite(node_type.name))?; + pack_sixbit(&mut *self.ser.node_buf, key)?; + + // TODO: Make sure this does not prematurely end nodes + if node_type != StandardType::Attribute { + self.ser.node_buf.write_u8(StandardType::NodeEnd.id | ARRAY_MASK).context(KbinErrorKind::DataWrite("node end"))?; + } + } + + // Pop the name off the stack that was added earlier + let val = self.ser.hierarchy.pop(); + debug!("SerializeStruct(name: {})::serialize_field() => popped: {:?}", self.name, val); + + Ok(()) + } + + fn end(self) -> Result { + debug!("SerializeStruct(name: {})::end()", self.name); + self.ser.node_buf.write_u8(StandardType::NodeEnd.id | ARRAY_MASK).context(KbinErrorKind::DataWrite("node end"))?; + + let val = self.ser.hierarchy.pop(); + trace!("SerializeStruct(name: {})::end() => popped: {:?}, hierarchy: {:?}, node_buf: {:02x?}", self.name, val, self.ser.hierarchy, self.ser.node_buf.get_ref()); + + Ok(Some(TypeHint::from_type(StandardType::NodeStart))) + } +}