mirror of
https://github.com/mbilker/kbinxml-rs.git
synced 2026-09-08 18:45:18 -05:00
ser(structure): separate struct handling to separate class
This commit is contained in:
@@ -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<T>(value: &T) -> Result<Vec<u8>>
|
||||
{
|
||||
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<Self::Ok, Self::Error>;
|
||||
type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
|
||||
type SerializeMap = Self;
|
||||
type SerializeStruct = Self;
|
||||
type SerializeStruct = Struct<'a>;
|
||||
type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
|
||||
|
||||
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<Self::SerializeStruct> {
|
||||
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<Self::SerializeStructVariant> {
|
||||
@@ -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<TypeHint>;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T>(&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<Self::Ok> {
|
||||
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)))
|
||||
}
|
||||
}
|
||||
|
||||
94
src/ser/structure.rs
Normal file
94
src/ser/structure.rs
Normal file
@@ -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<Self> {
|
||||
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<TypeHint>;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_field<T>(&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<Self::Ok> {
|
||||
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)))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user