Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serde byte/int/long array serialization (Issue #27 / #32) #51

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 124 additions & 25 deletions src/ser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ impl<'a, 'b, W> ser::SerializeSeq for Compound<'a, 'b, W>
where T: serde::Serialize
{
if !self.sigil {
value.serialize(&mut TagEncoder::from_outer(self.outer, Option::<String>::None))?;
value.serialize(&mut TagEncoder::<W, String>::for_seq_sigil(self.outer))?;
raw::write_bare_int(&mut self.outer.writer, self.length)?;
self.sigil = true;
}
Expand All @@ -141,7 +141,7 @@ impl<'a, 'b, W> ser::SerializeStruct for Compound<'a, 'b, W>
-> Result<()>
where T: serde::Serialize
{
value.serialize(&mut TagEncoder::from_outer(self.outer, Some(key)))?;
value.serialize(&mut TagEncoder::from_outer(self.outer, key))?;
value.serialize(&mut InnerEncoder::from_outer(self.outer))
}

Expand Down Expand Up @@ -172,7 +172,7 @@ impl<'a, 'b, W> ser::SerializeMap for Compound<'a, 'b, W>
where K: serde::Serialize,
V: serde::Serialize,
{
value.serialize(&mut TagEncoder::from_outer(self.outer, Some(key)))?;
value.serialize(&mut TagEncoder::from_outer(self.outer, key))?;
value.serialize(&mut InnerEncoder::from_outer(self.outer))
}

Expand Down Expand Up @@ -350,18 +350,18 @@ impl<'a, 'b, W> serde::Serializer for &'a mut InnerEncoder<'a, 'b, W> where W: i
}
}

/// A serializer for valid map keys, i.e. strings.
struct MapKeyEncoder<'a, 'b: 'a, W: 'a> {
/// A serializer for valid tag names, i.e. strings.
struct TagNameEncoder<'a, 'b: 'a, W: 'a> {
outer: &'a mut Encoder<'b, W>,
}

impl<'a, 'b: 'a, W: 'a> MapKeyEncoder<'a, 'b, W> where W: io::Write {
impl<'a, 'b: 'a, W: 'a> TagNameEncoder<'a, 'b, W> where W: io::Write {
pub fn from_outer(outer: &'a mut Encoder<'b, W>) -> Self {
MapKeyEncoder { outer: outer }
TagNameEncoder { outer: outer }
}
}

impl<'a, 'b: 'a, W: 'a> serde::Serializer for &'a mut MapKeyEncoder<'a, 'b, W>
impl<'a, 'b: 'a, W: 'a> serde::Serializer for &'a mut TagNameEncoder<'a, 'b, W>
where W: io::Write
{
type Ok = ();
Expand Down Expand Up @@ -395,26 +395,76 @@ impl<'a, 'b: 'a, W: 'a> serde::Serializer for &'a mut MapKeyEncoder<'a, 'b, W>
}
}

/// A serializer for valid map keys.
enum TagType<K> {
Normal(Option<K>),
SeqTag(Option<K>),
SeqSigil,
}

impl<K> TagType<K> {
fn take_key(&mut self) -> Option<K> {
match self {
TagType::Normal(key)
| TagType::SeqTag(key) => key.take(),
TagType::SeqSigil => None,
}
}
}

/// A serializer for valid tags.
struct TagEncoder<'a, 'b: 'a, W: 'a, K> {
outer: &'a mut Encoder<'b, W>,
key: Option<K>,
tag_type: TagType<K>,
}

impl<'a, 'b: 'a, W: 'a, K> TagEncoder<'a, 'b, W, K>
where W: io::Write,
K: serde::Serialize
{
fn from_outer(outer: &'a mut Encoder<'b, W>, key: Option<K>) -> Self {
TagEncoder {
outer: outer, key: key
fn from_outer(outer: &'a mut Encoder<'b, W>, key: K) -> Self {
Self {
outer,
tag_type: TagType::Normal(Some(key)),
}
}

fn for_seq_tag(outer: &'a mut Encoder<'b, W>, key: Option<K>) -> Self {
Self {
outer,
tag_type: TagType::SeqTag(key),
}
}

fn for_seq_sigil(outer: &'a mut Encoder<'b, W>) -> Self {
Self {
outer,
tag_type: TagType::SeqSigil,
}
}

fn write_header(&mut self, tag: i8) -> Result<()> {
use serde::Serialize;
let tag = match self.tag_type {
TagType::Normal( .. ) => tag,
TagType::SeqTag( .. ) => match tag {
0x01 => 0x07, // Byte array
0x03 => 0x0b, // Integer array
0x04 => 0x0c, // Long array
_ => 0x09, // List
},
TagType::SeqSigil => match tag {
// Don't write headers in byte/integer/long arrays
0x01 | 0x03 | 0x04 => return Ok(()),
_ => tag,
},
};

raw::write_bare_byte(&mut self.outer.writer, tag)?;
self.key.serialize(&mut MapKeyEncoder::from_outer(self.outer))

if let Some(key) = self.tag_type.take_key() {
key.serialize(&mut TagNameEncoder::from_outer(self.outer))?;
}

Ok(())
}
}

Expand All @@ -424,7 +474,7 @@ where W: io::Write,
{
type Ok = ();
type Error = Error;
type SerializeSeq = NoOp;
type SerializeSeq = SequenceTagEncoder<'a, 'b, W, K>;
type SerializeTuple = ser::Impossible<(), Error>;
type SerializeTupleStruct = ser::Impossible<(), Error>;
type SerializeTupleVariant = ser::Impossible<(), Error>;
Expand Down Expand Up @@ -509,9 +559,18 @@ where W: io::Write,

#[inline]
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq> {
if len.is_some() {
self.write_header(0x09)?;
Ok(NoOp)
if let Some(len) = len {
let key = match (&mut self.tag_type, len) {
(TagType::SeqTag( .. ), _)
| (TagType::Normal( .. ), 0) => {
self.write_header(0x09)?;
return Ok(SequenceTagEncoder::for_empty_sequence());
},
(TagType::SeqSigil, _) => None,
| (TagType::Normal(key), _) => key.take(),
};

Ok(SequenceTagEncoder::for_non_empty_sequence(self.outer, key))
} else {
Err(Error::UnrepresentableType("unsized list"))
}
Expand All @@ -532,17 +591,53 @@ where W: io::Write,
}
}

/// This empty serializer provides a way to serialize only headers/tags for
/// sequences, maps, and structs.
struct NoOp;
/// This serializer writes the tag (list/array tag, (key)) for non-empty sequences.
/// This infers the sequence element type from the first element written to the sequence
/// to serialize i8, i32 or i64 sequences as ByteArray, IntegerArray or LongArray
/// NBT types respectively.
/// For every other sequence element type a normal NBT List tag is written.
struct SequenceTagEncoder<'a, 'b: 'a, W: 'a, K> {
encoder: Option<&'a mut Encoder<'b, W>>,
key: Option<K>,
}

impl<'a, 'b: 'a, W: 'a, K> SequenceTagEncoder<'a, 'b, W, K>
where
W: io::Write,
K: serde::Serialize,
{
fn for_empty_sequence() -> Self {
Self {
encoder: None,
key: None,
}
}

fn for_non_empty_sequence(encoder: &'a mut Encoder<'b, W>, key: Option<K>) -> Self {
Self {
encoder: Some(encoder),
key,
}
}
}

impl ser::SerializeSeq for NoOp {
impl<'a, 'b: 'a, W: 'a, K> ser::SerializeSeq for SequenceTagEncoder<'a, 'b, W, K>
where
W: io::Write,
K: serde::Serialize,
{
type Ok = ();
type Error = Error;

fn serialize_element<T: ?Sized>(&mut self, _value: &T) -> Result<()>
where T: serde::Serialize
fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<()>
where
T: serde::Serialize,
{
if let Some(encoder) = self.encoder.take() {
// Write type-dependant sequence tag
value.serialize(&mut TagEncoder::for_seq_tag(encoder, self.key.take()))?;
}

Ok(())
}

Expand All @@ -551,6 +646,10 @@ impl ser::SerializeSeq for NoOp {
}
}

/// This empty serializer provides a way to serialize only headers/tags for
/// sequences, maps, and structs.
struct NoOp;

impl ser::SerializeStruct for NoOp {
type Ok = ();
type Error = Error;
Expand Down
27 changes: 14 additions & 13 deletions tests/serde_basics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ struct NestedArrayNbt {
}

#[test]
fn deserialize_nested_array() {
fn roundtrip_nested_array() {
let nbt = NestedArrayNbt { data: vec!(vec!(1, 2), vec!(3, 4)) };

let bytes = vec![
Expand All @@ -191,13 +191,17 @@ fn deserialize_nested_array() {
0x00
];

let read: NestedArrayNbt = from_reader(&bytes[..]).unwrap();
assert_eq!(read, nbt)
assert_roundtrip_eq(nbt, &bytes, None);
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct ByteArrayNbt {
data: Vec<i8>,
}

#[test]
fn deserialize_byte_array() {
let nbt = BasicListNbt { data: vec![1, 2, 3] };
fn roundtrip_byte_array() {
let nbt = ByteArrayNbt { data: vec![1, 2, 3] };

let bytes = vec![
0x0a,
Expand All @@ -210,8 +214,7 @@ fn deserialize_byte_array() {
0x00
];

let read: BasicListNbt = from_reader(&bytes[..]).unwrap();
assert_eq!(read, nbt)
assert_roundtrip_eq(nbt, &bytes, None);
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
Expand All @@ -238,7 +241,7 @@ fn deserialize_empty_array() {
}

#[test]
fn deserialize_int_array() {
fn roundtrip_int_array() {
let nbt = IntListNbt { data: vec![1, 2, 3] };

let bytes = vec![
Expand All @@ -255,8 +258,7 @@ fn deserialize_int_array() {
0x00
];

let read: IntListNbt = from_reader(&bytes[..]).unwrap();
assert_eq!(read, nbt)
assert_roundtrip_eq(nbt, &bytes, None);
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
Expand All @@ -265,7 +267,7 @@ struct LongListNbt {
}

#[test]
fn deserialize_long_array() {
fn roundtrip_long_array() {
let nbt = LongListNbt { data: vec![1, 2, 3] };

let bytes = vec![
Expand All @@ -282,8 +284,7 @@ fn deserialize_long_array() {
0x00
];

let read: LongListNbt = from_reader(&bytes[..]).unwrap();
assert_eq!(read, nbt)
assert_roundtrip_eq(nbt, &bytes, None);
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
Expand Down