mirror of
https://github.com/mbilker/kbinxml-rs.git
synced 2026-09-08 10:35:32 -05:00
ser(map): override serialize_entry to handle key and value at the same time
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
use error::{KbinError, KbinErrorKind};
|
||||
|
||||
use std::fmt::{self, Write};
|
||||
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>;
|
||||
@@ -100,6 +100,9 @@ impl KbinWrapperType<bool> for bool {
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -126,13 +129,11 @@ impl KbinWrapperType<Ip4> for Ip4 {
|
||||
}
|
||||
}
|
||||
|
||||
struct DummyConverter;
|
||||
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(()) }
|
||||
}
|
||||
|
||||
struct InvalidConverter;
|
||||
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);
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
use std::io::{Seek, SeekFrom};
|
||||
|
||||
use byteorder::WriteBytesExt;
|
||||
use failure::ResultExt;
|
||||
use serde::ser::{Serialize, SerializeMap};
|
||||
@@ -7,27 +5,34 @@ use serde::ser::{Serialize, SerializeMap};
|
||||
use error::{Error, KbinErrorKind};
|
||||
use node_types::StandardType;
|
||||
use ser::{Result, Serializer, TypeHint, WriteMode, ARRAY_MASK};
|
||||
use sixbit::pack_sixbit;
|
||||
|
||||
pub struct Map<'a> {
|
||||
ser: &'a mut Serializer,
|
||||
|
||||
current_node_index: u64,
|
||||
|
||||
key_node_type: StandardType,
|
||||
}
|
||||
|
||||
impl<'a> Map<'a> {
|
||||
pub fn new(ser: &'a mut Serializer) -> Result<Self> {
|
||||
debug!("Map::new()");
|
||||
|
||||
ser.write_node(TypeHint::from_type(StandardType::NodeStart))?;
|
||||
ser.write_identifier("something")?;
|
||||
// Restrict bounds of immutable borrow from `hierarchy` Vec
|
||||
{
|
||||
// The key name would have been pushed to the stack in
|
||||
// `<Struct as SerializeStruct>::serialize_field` before calling
|
||||
// `serialize` on the value
|
||||
let name = if let Some(key) = ser.hierarchy.last() {
|
||||
trace!("Map::new() => found key name: {}", key);
|
||||
key
|
||||
} else {
|
||||
return Err(KbinErrorKind::InvalidState.into());
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
ser,
|
||||
current_node_index: 0,
|
||||
key_node_type: StandardType::NodeStart,
|
||||
})
|
||||
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)?;
|
||||
}
|
||||
|
||||
Ok(Self { ser })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,61 +40,60 @@ impl<'a> SerializeMap for Map<'a> {
|
||||
type Ok = Option<TypeHint>;
|
||||
type Error = Error;
|
||||
|
||||
fn serialize_entry<K, V>(&mut self, key: &K, value: &V) -> Result<()>
|
||||
where K: ?Sized + Serialize,
|
||||
V: ?Sized + Serialize
|
||||
{
|
||||
trace!("--> <Map as SerializeMap>::serialize_entry()");
|
||||
|
||||
// Serialize methods that return `None` will not be written
|
||||
if let Some(hint) = value.serialize(&mut *self.ser)? {
|
||||
let node_type = hint.node_type;
|
||||
debug!("SerializeMap::serialize_entry() => hint: {:?}", hint);
|
||||
|
||||
// Struct handler outputs `NodeStart` event by itself. Avoid repeating it.
|
||||
if node_type != StandardType::NodeStart {
|
||||
self.ser.write_node(hint)?;
|
||||
self.serialize_key(key)?;
|
||||
|
||||
if node_type != StandardType::Attribute {
|
||||
self.ser.node_buf.write_u8(StandardType::NodeEnd.id | ARRAY_MASK).context(KbinErrorKind::DataWrite("node end"))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_key<T>(&mut self, key: &T) -> Result<()>
|
||||
where T: ?Sized + Serialize
|
||||
{
|
||||
trace!("--> <Map as SerializeMap>::serialize_key()");
|
||||
|
||||
self.current_node_index = self.ser.node_buf.position();
|
||||
self.ser.node_buf.write_u8(0).context(KbinErrorKind::DataWrite("placeholder"))?;
|
||||
|
||||
self.ser.write_mode = WriteMode::Identifier;
|
||||
let hint = key.serialize(&mut *self.ser)?.ok_or(KbinErrorKind::MissingTypeHint)?;
|
||||
debug!("<Map as SerializeMap>::serialize_key() => hint: {:?}", hint);
|
||||
|
||||
self.ser.write_mode = WriteMode::Single;
|
||||
|
||||
self.key_node_type = hint.node_type;
|
||||
match hint.node_type {
|
||||
StandardType::Attribute |
|
||||
StandardType::String => Ok(()),
|
||||
node_type => return Err(KbinErrorKind::TypeMismatch(*StandardType::String, *node_type).into()),
|
||||
node_type => Err(KbinErrorKind::TypeMismatch(*StandardType::String, *node_type).into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_value<T>(&mut self, value: &T) -> Result<()>
|
||||
fn serialize_value<T>(&mut self, _value: &T) -> Result<()>
|
||||
where T: ?Sized + Serialize
|
||||
{
|
||||
trace!("--> <Map as SerializeMap>::serialize_value()");
|
||||
|
||||
let mut hint = value.serialize(&mut *self.ser)?.ok_or(KbinErrorKind::MissingTypeHint)?;
|
||||
debug!("<Map as SerializeMap>::serialize_value() => hint: {:?}", hint);
|
||||
|
||||
// Attributes must have a string body
|
||||
if self.key_node_type == StandardType::Attribute {
|
||||
if hint.node_type == StandardType::String {
|
||||
hint = TypeHint::from_type(StandardType::Attribute);
|
||||
} else {
|
||||
return Err(KbinErrorKind::TypeMismatch(*StandardType::Attribute, *hint.node_type).into());
|
||||
}
|
||||
}
|
||||
|
||||
let new_pos = self.ser.node_buf.position();
|
||||
self.ser.node_buf.seek(SeekFrom::Start(self.current_node_index)).context(KbinErrorKind::Seek)?;
|
||||
self.ser.write_node(hint)?;
|
||||
self.ser.node_buf.seek(SeekFrom::Start(new_pos)).context(KbinErrorKind::Seek)?;
|
||||
|
||||
if self.key_node_type != StandardType::Attribute {
|
||||
self.ser.node_buf.write_u8(StandardType::NodeEnd.id | ARRAY_MASK).context(KbinErrorKind::DataWrite("node end"))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok> {
|
||||
trace!("<Map as SerializeMap>::end()");
|
||||
self.ser.node_buf.write_u8(StandardType::NodeEnd.id | ARRAY_MASK).context(KbinErrorKind::DataWrite("node end"))?;
|
||||
|
||||
Ok(None)
|
||||
Ok(Some(TypeHint::from_type(StandardType::NodeStart)))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user