libserialize: tuple-arity should be provided to Decoder::read_tuple
Currently `Decoder` implementations are not provided the tuple arity as a parameter to `read_tuple`. This forces all encoder/decoder combos to serialize the arity along with the elements. Tuple-arity is always known statically at the decode site, because it is part of the type of the tuple, so it could instead be provided as an argument to `read_tuple`, as it is to `read_struct`. The upside to this is that serialized tuples could become smaller in encoder/decoder implementations which choose not to serialize type (arity) information. For example, @TyOverby's [binary-encode](https://github.com/TyOverby/binary-encode) format is currently forced to serialize the tuple-arity along with every tuple, despite the information being statically known at the decode site. A downside to this change is that the tuple-arity of serialized tuples can no longer be automatically checked during deserialization. However, for formats which do serialize the tuple-arity, either explicitly (rbml) or implicitly (json), this check can be added to the `read_tuple` method. The signature of `Deserialize::read_tuple` and `Deserialize::read_tuple_struct` are changed, and thus binary backwards-compatibility is broken. This change does *not* force serialization formats to change, and thus does not break decoding values serialized prior to this change. [breaking-change]
This commit is contained in:
parent
0547a407aa
commit
ca6b082c05
3 changed files with 52 additions and 14 deletions
|
@ -558,9 +558,15 @@ pub mod reader {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_tuple<T>(&mut self,
|
fn read_tuple<T>(&mut self,
|
||||||
f: |&mut Decoder<'doc>, uint| -> DecodeResult<T>) -> DecodeResult<T> {
|
tuple_len: uint,
|
||||||
|
f: |&mut Decoder<'doc>| -> DecodeResult<T>) -> DecodeResult<T> {
|
||||||
debug!("read_tuple()");
|
debug!("read_tuple()");
|
||||||
self.read_seq(f)
|
self.read_seq(|d, len| {
|
||||||
|
assert!(len == tuple_len,
|
||||||
|
"expected tuple of length `{}`, found tuple \
|
||||||
|
of length `{}`", tuple_len, len);
|
||||||
|
f(d)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_tuple_arg<T>(&mut self, idx: uint, f: |&mut Decoder<'doc>| -> DecodeResult<T>)
|
fn read_tuple_arg<T>(&mut self, idx: uint, f: |&mut Decoder<'doc>| -> DecodeResult<T>)
|
||||||
|
@ -571,10 +577,11 @@ pub mod reader {
|
||||||
|
|
||||||
fn read_tuple_struct<T>(&mut self,
|
fn read_tuple_struct<T>(&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
f: |&mut Decoder<'doc>, uint| -> DecodeResult<T>)
|
len: uint,
|
||||||
|
f: |&mut Decoder<'doc>| -> DecodeResult<T>)
|
||||||
-> DecodeResult<T> {
|
-> DecodeResult<T> {
|
||||||
debug!("read_tuple_struct(name={})", name);
|
debug!("read_tuple_struct(name={})", name);
|
||||||
self.read_tuple(f)
|
self.read_tuple(len, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_tuple_struct_arg<T>(&mut self,
|
fn read_tuple_struct_arg<T>(&mut self,
|
||||||
|
|
|
@ -2153,9 +2153,14 @@ impl ::Decoder<DecoderError> for Decoder {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_tuple<T>(&mut self, f: |&mut Decoder, uint| -> DecodeResult<T>) -> DecodeResult<T> {
|
fn read_tuple<T>(&mut self, tuple_len: uint, f: |&mut Decoder| -> DecodeResult<T>) -> DecodeResult<T> {
|
||||||
debug!("read_tuple()");
|
debug!("read_tuple()");
|
||||||
self.read_seq(f)
|
self.read_seq(|d, len| {
|
||||||
|
assert!(len == tuple_len,
|
||||||
|
"expected tuple of length `{}`, found tuple \
|
||||||
|
of length `{}`", tuple_len, len);
|
||||||
|
f(d)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_tuple_arg<T>(&mut self,
|
fn read_tuple_arg<T>(&mut self,
|
||||||
|
@ -2167,10 +2172,11 @@ impl ::Decoder<DecoderError> for Decoder {
|
||||||
|
|
||||||
fn read_tuple_struct<T>(&mut self,
|
fn read_tuple_struct<T>(&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
f: |&mut Decoder, uint| -> DecodeResult<T>)
|
len: uint,
|
||||||
|
f: |&mut Decoder| -> DecodeResult<T>)
|
||||||
-> DecodeResult<T> {
|
-> DecodeResult<T> {
|
||||||
debug!("read_tuple_struct(name={})", name);
|
debug!("read_tuple_struct(name={})", name);
|
||||||
self.read_tuple(f)
|
self.read_tuple(len, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_tuple_struct_arg<T>(&mut self,
|
fn read_tuple_struct_arg<T>(&mut self,
|
||||||
|
@ -2872,6 +2878,26 @@ mod tests {
|
||||||
assert_eq!(v, vec![vec![3], vec![1, 2]]);
|
assert_eq!(v, vec![vec![3], vec![1, 2]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_decode_tuple() {
|
||||||
|
let t: (uint, uint, uint) = super::decode("[1, 2, 3]").unwrap();
|
||||||
|
assert_eq!(t, (1u, 2, 3))
|
||||||
|
|
||||||
|
let t: (uint, string::String) = super::decode("[1, \"two\"]").unwrap();
|
||||||
|
assert_eq!(t, (1u, "two".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_decode_tuple_malformed_types() {
|
||||||
|
assert!(super::decode::<(uint, string::String)>("[1, 2]").is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_fail]
|
||||||
|
fn test_decode_tuple_malformed_length() {
|
||||||
|
let _ = super::decode::<(uint, uint)>("[1, 2, 3]");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_read_object() {
|
fn test_read_object() {
|
||||||
assert_eq!(from_str("{"), Err(SyntaxError(EOFWhileParsingObject, 1, 2)));
|
assert_eq!(from_str("{"), Err(SyntaxError(EOFWhileParsingObject, 1, 2)));
|
||||||
|
|
|
@ -142,12 +142,13 @@ pub trait Decoder<E> {
|
||||||
f: |&mut Self| -> Result<T, E>)
|
f: |&mut Self| -> Result<T, E>)
|
||||||
-> Result<T, E>;
|
-> Result<T, E>;
|
||||||
|
|
||||||
fn read_tuple<T>(&mut self, f: |&mut Self, uint| -> Result<T, E>) -> Result<T, E>;
|
fn read_tuple<T>(&mut self, len: uint, f: |&mut Self| -> Result<T, E>) -> Result<T, E>;
|
||||||
fn read_tuple_arg<T>(&mut self, a_idx: uint, f: |&mut Self| -> Result<T, E>) -> Result<T, E>;
|
fn read_tuple_arg<T>(&mut self, a_idx: uint, f: |&mut Self| -> Result<T, E>) -> Result<T, E>;
|
||||||
|
|
||||||
fn read_tuple_struct<T>(&mut self,
|
fn read_tuple_struct<T>(&mut self,
|
||||||
s_name: &str,
|
s_name: &str,
|
||||||
f: |&mut Self, uint| -> Result<T, E>)
|
len: uint,
|
||||||
|
f: |&mut Self| -> Result<T, E>)
|
||||||
-> Result<T, E>;
|
-> Result<T, E>;
|
||||||
fn read_tuple_struct_arg<T>(&mut self,
|
fn read_tuple_struct_arg<T>(&mut self,
|
||||||
a_idx: uint,
|
a_idx: uint,
|
||||||
|
@ -465,20 +466,24 @@ impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for Option<T> {
|
||||||
|
|
||||||
macro_rules! peel(($name:ident, $($other:ident,)*) => (tuple!($($other,)*)))
|
macro_rules! peel(($name:ident, $($other:ident,)*) => (tuple!($($other,)*)))
|
||||||
|
|
||||||
|
/// Evaluates to the number of identifiers passed to it, for example: `count_idents!(a, b, c) == 3
|
||||||
|
macro_rules! count_idents {
|
||||||
|
() => { 0u };
|
||||||
|
($_i:ident $(, $rest:ident)*) => { 1 + count_idents!($($rest),*) }
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! tuple (
|
macro_rules! tuple (
|
||||||
() => ();
|
() => ();
|
||||||
( $($name:ident,)+ ) => (
|
( $($name:ident,)+ ) => (
|
||||||
impl<E, D:Decoder<E>,$($name:Decodable<D, E>),*> Decodable<D,E> for ($($name,)*) {
|
impl<E, D:Decoder<E>,$($name:Decodable<D, E>),*> Decodable<D,E> for ($($name,)*) {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
fn decode(d: &mut D) -> Result<($($name,)*), E> {
|
fn decode(d: &mut D) -> Result<($($name,)*), E> {
|
||||||
d.read_tuple(|d, amt| {
|
let len: uint = count_idents!($($name),*);
|
||||||
|
d.read_tuple(len, |d| {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let ret = ($(try!(d.read_tuple_arg({ i+=1; i-1 }, |d| -> Result<$name,E> {
|
let ret = ($(try!(d.read_tuple_arg({ i+=1; i-1 }, |d| -> Result<$name,E> {
|
||||||
Decodable::decode(d)
|
Decodable::decode(d)
|
||||||
})),)*);
|
})),)*);
|
||||||
assert!(amt == i,
|
|
||||||
"expected tuple of length `{}`, found tuple \
|
|
||||||
of length `{}`", i, amt);
|
|
||||||
return Ok(ret);
|
return Ok(ret);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue