When decoding maps, leave fields that weren't processed
Fixes an XXX
This commit is contained in:
parent
4987b47a92
commit
39d77b6d79
|
@ -1,5 +1,7 @@
|
||||||
use std::error;
|
use std::error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::collections::{btree_map, BTreeMap};
|
||||||
|
use std::iter::Peekable;
|
||||||
|
|
||||||
use Value;
|
use Value;
|
||||||
use self::DecodeErrorKind::*;
|
use self::DecodeErrorKind::*;
|
||||||
|
@ -17,6 +19,8 @@ pub struct Decoder {
|
||||||
/// whether fields were decoded or not.
|
/// whether fields were decoded or not.
|
||||||
pub toml: Option<Value>,
|
pub toml: Option<Value>,
|
||||||
cur_field: Option<String>,
|
cur_field: Option<String>,
|
||||||
|
cur_map: Peekable<btree_map::IntoIter<String, Value>>,
|
||||||
|
leftover_map: ::Table,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Description for errors which can occur while decoding a type.
|
/// Description for errors which can occur while decoding a type.
|
||||||
|
@ -105,7 +109,12 @@ impl Decoder {
|
||||||
/// This decoder can be passed to the `Decodable` methods or driven
|
/// This decoder can be passed to the `Decodable` methods or driven
|
||||||
/// manually.
|
/// manually.
|
||||||
pub fn new(toml: Value) -> Decoder {
|
pub fn new(toml: Value) -> Decoder {
|
||||||
Decoder { toml: Some(toml), cur_field: None }
|
Decoder {
|
||||||
|
toml: Some(toml),
|
||||||
|
cur_field: None,
|
||||||
|
leftover_map: BTreeMap::new(),
|
||||||
|
cur_map: BTreeMap::new().into_iter().peekable(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sub_decoder(&self, toml: Option<Value>, field: &str) -> Decoder {
|
fn sub_decoder(&self, toml: Option<Value>, field: &str) -> Decoder {
|
||||||
|
@ -118,7 +127,9 @@ impl Decoder {
|
||||||
None => Some(format!("{}", field)),
|
None => Some(format!("{}", field)),
|
||||||
Some(ref s) => Some(format!("{}.{}", s, field))
|
Some(ref s) => Some(format!("{}.{}", s, field))
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
leftover_map: BTreeMap::new(),
|
||||||
|
cur_map: BTreeMap::new().into_iter().peekable(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use rustc_serialize;
|
use rustc_serialize;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use super::{Decoder, DecodeError};
|
use super::{Decoder, DecodeError};
|
||||||
use super::DecodeErrorKind::*;
|
use super::DecodeErrorKind::*;
|
||||||
|
@ -275,46 +276,50 @@ impl rustc_serialize::Decoder for Decoder {
|
||||||
-> Result<T, DecodeError>
|
-> Result<T, DecodeError>
|
||||||
where F: FnOnce(&mut Decoder, usize) -> Result<T, DecodeError>
|
where F: FnOnce(&mut Decoder, usize) -> Result<T, DecodeError>
|
||||||
{
|
{
|
||||||
let len = match self.toml {
|
let map = match self.toml.take() {
|
||||||
Some(Value::Table(ref table)) => table.len(),
|
Some(Value::Table(table)) => table,
|
||||||
ref found => return Err(self.mismatch("table", found)),
|
found => {
|
||||||
|
self.toml = found;
|
||||||
|
return Err(self.mismatch("table", &self.toml))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let ret = try!(f(self, len));
|
let amt = map.len();
|
||||||
self.toml.take();
|
let prev_iter = mem::replace(&mut self.cur_map,
|
||||||
|
map.into_iter().peekable());
|
||||||
|
let prev_map = mem::replace(&mut self.leftover_map, BTreeMap::new());
|
||||||
|
let ret = try!(f(self, amt));
|
||||||
|
let leftover = mem::replace(&mut self.leftover_map, prev_map);
|
||||||
|
self.cur_map = prev_iter;
|
||||||
|
if leftover.len() > 0 {
|
||||||
|
self.toml = Some(Value::Table(leftover));
|
||||||
|
}
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F)
|
fn read_map_elt_key<T, F>(&mut self, idx: usize, f: F)
|
||||||
-> Result<T, DecodeError>
|
-> Result<T, DecodeError>
|
||||||
where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
|
where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
|
||||||
{
|
{
|
||||||
match self.toml {
|
let key = match self.cur_map.peek().map(|p| p.0.clone()) {
|
||||||
Some(Value::Table(ref table)) => {
|
Some(k) => k,
|
||||||
match table.iter().skip(idx).next() {
|
None => return Err(self.err(ExpectedMapKey(idx))),
|
||||||
Some((key, _)) => {
|
};
|
||||||
let val = Value::String(key.to_string());
|
let val = Value::String(key.clone());
|
||||||
f(&mut self.sub_decoder(Some(val), key))
|
f(&mut self.sub_decoder(Some(val), &key))
|
||||||
}
|
|
||||||
None => Err(self.err(ExpectedMapKey(idx))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ref found => Err(self.mismatch("table", found)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F)
|
fn read_map_elt_val<T, F>(&mut self, idx: usize, f: F)
|
||||||
-> Result<T, DecodeError>
|
-> Result<T, DecodeError>
|
||||||
where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
|
where F: FnOnce(&mut Decoder) -> Result<T, DecodeError>
|
||||||
{
|
{
|
||||||
match self.toml {
|
match self.cur_map.next() {
|
||||||
Some(Value::Table(ref table)) => {
|
Some((key, value)) => {
|
||||||
match table.iter().skip(idx).next() {
|
let mut d = self.sub_decoder(Some(value), &key);
|
||||||
Some((key, value)) => {
|
let ret = f(&mut d);
|
||||||
// XXX: this shouldn't clone
|
if let Some(toml) = d.toml.take() {
|
||||||
f(&mut self.sub_decoder(Some(value.clone()), key))
|
self.leftover_map.insert(key, toml);
|
||||||
}
|
|
||||||
None => Err(self.err(ExpectedMapElement(idx))),
|
|
||||||
}
|
}
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
ref found => Err(self.mismatch("table", found)),
|
None => return Err(self.err(ExpectedMapElement(idx))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -639,6 +639,33 @@ mod tests {
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unused_fields8() {
|
||||||
|
#[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)]
|
||||||
|
struct Foo { a: BTreeMap<String, Bar> }
|
||||||
|
#[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)]
|
||||||
|
struct Bar { a: isize }
|
||||||
|
|
||||||
|
let v = Foo { a: map! { a, Bar { a: 2 } } };
|
||||||
|
let mut d = Decoder::new(Table(map! {
|
||||||
|
a, Table(map! {
|
||||||
|
a, Table(map! {
|
||||||
|
a, Integer(2),
|
||||||
|
b, Integer(2)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
assert_eq!(v, Decodable::decode(&mut d).unwrap());
|
||||||
|
|
||||||
|
assert_eq!(d.toml, Some(Table(map! {
|
||||||
|
a, Table(map! {
|
||||||
|
a, Table(map! {
|
||||||
|
b, Integer(2)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_arrays() {
|
fn empty_arrays() {
|
||||||
#[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)]
|
#[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)]
|
||||||
|
|
Loading…
Reference in a new issue