From f66d8bcf33530c858a502bfa170f2383a8cbc204 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 29 Jan 2017 16:53:20 -0800 Subject: Rewrite crate with serde support from ground up This commit completely rewrites this crate from the ground up, supporting serde at the lowest levels as I believe serde support was intended to do. This is a major change from the previous versions of this crate, with a summary of changes being: * Serialization directly to TOML is now supported without going through a `Value` first. * Deserialization directly from TOML is now supported without going through a `Value`. Note that due to the TOML format some values still are buffered in intermediate memory, but overall this should be at a minimum now. * The API of `Value` was overhauled to match the API of `serde_json::Value`. The changes here were to: * Add `is_*` accessors * Add `get` and `get_mut` for one-field lookups. * Implement panicking lookups through `Index` The old `index` methods are now gone in favor of `get` and `Index` implementations. * A `Datetime` type has been added to represent a TOML datetime in a first-class fashion. Currently this type provides no accessors other than a `Display` implementation, but the idea is that this will grow support over time for decomposing the date. * Support for the `rustc-serialize` crate has been dropped, that'll stay on the 0.2 and 0.1 release trains. * This crate no longer supports the detection of unused fields, for that though you can use the `serde_ignored` crate on crates.io --- src/decoder/rustc_serialize.rs | 371 ----------------------------------------- 1 file changed, 371 deletions(-) delete mode 100644 src/decoder/rustc_serialize.rs (limited to 'src/decoder/rustc_serialize.rs') diff --git a/src/decoder/rustc_serialize.rs b/src/decoder/rustc_serialize.rs deleted file mode 100644 index f850663..0000000 --- a/src/decoder/rustc_serialize.rs +++ /dev/null @@ -1,371 +0,0 @@ -use rustc_serialize; -use std::mem; -use std::collections::BTreeMap; - -use super::{Decoder, DecodeError}; -use super::DecodeErrorKind::*; -use Value; - -impl rustc_serialize::Decoder for Decoder { - type Error = DecodeError; - fn read_nil(&mut self) -> Result<(), DecodeError> { - match self.toml { - Some(Value::String(ref s)) if s.is_empty() => {} - Some(Value::String(..)) => return Err(self.err(NilTooLong)), - ref found => return Err(self.mismatch("string", found)), - } - self.toml.take(); - Ok(()) - } - fn read_usize(&mut self) -> Result { - self.read_i64().map(|i| i as usize) - } - fn read_u64(&mut self) -> Result { - self.read_i64().map(|i| i as u64) - } - fn read_u32(&mut self) -> Result { - self.read_i64().map(|i| i as u32) - } - fn read_u16(&mut self) -> Result { - self.read_i64().map(|i| i as u16) - } - fn read_u8(&mut self) -> Result { - self.read_i64().map(|i| i as u8) - } - fn read_isize(&mut self) -> Result { - self.read_i64().map(|i| i as isize) - } - fn read_i64(&mut self) -> Result { - match self.toml { - Some(Value::Integer(i)) => { self.toml.take(); Ok(i) } - ref found => Err(self.mismatch("integer", found)), - } - } - fn read_i32(&mut self) -> Result { - self.read_i64().map(|i| i as i32) - } - fn read_i16(&mut self) -> Result { - self.read_i64().map(|i| i as i16) - } - fn read_i8(&mut self) -> Result { - self.read_i64().map(|i| i as i8) - } - fn read_bool(&mut self) -> Result { - match self.toml { - Some(Value::Boolean(b)) => { self.toml.take(); Ok(b) } - ref found => Err(self.mismatch("bool", found)), - } - } - fn read_f64(&mut self) -> Result { - match self.toml { - Some(Value::Float(f)) => { self.toml.take(); Ok(f) }, - ref found => Err(self.mismatch("float", found)), - } - } - fn read_f32(&mut self) -> Result { - self.read_f64().map(|f| f as f32) - } - fn read_char(&mut self) -> Result { - let ch = match self.toml { - Some(Value::String(ref s)) if s.chars().count() == 1 => - s.chars().next().unwrap(), - ref found => return Err(self.mismatch("string", found)), - }; - self.toml.take(); - Ok(ch) - } - fn read_str(&mut self) -> Result { - match self.toml.take() { - Some(Value::String(s)) => Ok(s), - found => { - let err = Err(self.mismatch("string", &found)); - self.toml = found; - err - } - } - } - - // Compound types: - fn read_enum(&mut self, _name: &str, f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - f(self) - } - - fn read_enum_variant(&mut self, names: &[&str], mut f: F) - -> Result - where F: FnMut(&mut Decoder, usize) -> Result - { - // When decoding enums, this crate takes the strategy of trying to - // decode the current TOML as all of the possible variants, returning - // success on the first one that succeeds. - // - // Note that fidelity of the errors returned here is a little nebulous, - // but we try to return the error that had the relevant field as the - // longest field. This way we hopefully match an error against what was - // most likely being written down without losing too much info. - let mut first_error = None::; - for i in 0..names.len() { - let mut d = self.sub_decoder(self.toml.clone(), ""); - match f(&mut d, i) { - Ok(t) => { - self.toml = d.toml; - return Ok(t) - } - Err(e) => { - if let Some(ref first) = first_error { - let my_len = e.field.as_ref().map(|s| s.len()); - let first_len = first.field.as_ref().map(|s| s.len()); - if my_len <= first_len { - continue - } - } - first_error = Some(e); - } - } - } - Err(first_error.unwrap_or_else(|| self.err(NoEnumVariants))) - } - fn read_enum_variant_arg(&mut self, _a_idx: usize, f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - f(self) - } - - fn read_enum_struct_variant(&mut self, _names: &[&str], _f: F) - -> Result - where F: FnMut(&mut Decoder, usize) -> Result - { - panic!() - } - fn read_enum_struct_variant_field(&mut self, - _f_name: &str, - _f_idx: usize, - _f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - panic!() - } - - fn read_struct(&mut self, _s_name: &str, _len: usize, f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - match self.toml { - Some(Value::Table(..)) => { - let ret = try!(f(self)); - match self.toml { - Some(Value::Table(ref t)) if t.is_empty() => {} - _ => return Ok(ret) - } - self.toml.take(); - Ok(ret) - } - ref found => Err(self.mismatch("table", found)), - } - } - fn read_struct_field(&mut self, f_name: &str, _f_idx: usize, f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - let field = f_name.to_string(); - let toml = match self.toml { - Some(Value::Table(ref mut table)) => { - table.remove(&field) - .or_else(|| table.remove(&f_name.replace("_", "-"))) - }, - ref found => return Err(self.mismatch("table", found)), - }; - let mut d = self.sub_decoder(toml, f_name); - let ret = try!(f(&mut d)); - if let Some(value) = d.toml { - if let Some(Value::Table(ref mut table)) = self.toml { - table.insert(field, value); - } - } - Ok(ret) - } - - fn read_tuple(&mut self, tuple_len: usize, f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - self.read_seq(move |d, len| { - assert!(len == tuple_len, - "expected tuple of length `{}`, found tuple \ - of length `{}`", tuple_len, len); - f(d) - }) - } - fn read_tuple_arg(&mut self, a_idx: usize, f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - self.read_seq_elt(a_idx, f) - } - - fn read_tuple_struct(&mut self, _s_name: &str, _len: usize, _f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - panic!() - } - fn read_tuple_struct_arg(&mut self, _a_idx: usize, _f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - panic!() - } - - // Specialized types: - fn read_option(&mut self, mut f: F) - -> Result - where F: FnMut(&mut Decoder, bool) -> Result - { - match self.toml { - Some(..) => f(self, true), - None => f(self, false), - } - } - - fn read_seq(&mut self, f: F) -> Result - where F: FnOnce(&mut Decoder, usize) -> Result - { - let len = match self.toml { - Some(Value::Array(ref arr)) => arr.len(), - None => 0, - ref found => return Err(self.mismatch("array", found)), - }; - let ret = try!(f(self, len)); - match self.toml { - Some(Value::Array(ref mut arr)) => { - arr.retain(|slot| slot.as_integer() != Some(0)); - if !arr.is_empty() { return Ok(ret) } - } - _ => return Ok(ret) - } - self.toml.take(); - Ok(ret) - } - fn read_seq_elt(&mut self, idx: usize, f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - let toml = match self.toml { - Some(Value::Array(ref mut arr)) => { - mem::replace(&mut arr[idx], Value::Integer(0)) - } - ref found => return Err(self.mismatch("array", found)), - }; - let mut d = self.sub_decoder(Some(toml), ""); - let ret = try!(f(&mut d)); - if let Some(toml) = d.toml { - if let Some(Value::Array(ref mut arr)) = self.toml { - arr[idx] = toml; - } - } - Ok(ret) - } - - fn read_map(&mut self, f: F) - -> Result - where F: FnOnce(&mut Decoder, usize) -> Result - { - let map = match self.toml.take() { - Some(Value::Table(table)) => table, - found => { - self.toml = found; - return Err(self.mismatch("table", &self.toml)) - } - }; - let amt = map.len(); - 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.is_empty() { - self.toml = Some(Value::Table(leftover)); - } - Ok(ret) - } - fn read_map_elt_key(&mut self, idx: usize, f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - let key = match self.cur_map.peek().map(|p| p.0.clone()) { - Some(k) => k, - None => return Err(self.err(ExpectedMapKey(idx))), - }; - let val = Value::String(key.clone()); - f(&mut self.sub_decoder(Some(val), &key)) - } - fn read_map_elt_val(&mut self, idx: usize, f: F) - -> Result - where F: FnOnce(&mut Decoder) -> Result - { - match self.cur_map.next() { - Some((key, value)) => { - let mut d = self.sub_decoder(Some(value), &key); - let ret = f(&mut d); - if let Some(toml) = d.toml.take() { - self.leftover_map.insert(key, toml); - } - ret - } - None => Err(self.err(ExpectedMapElement(idx))), - } - } - - fn error(&mut self, err: &str) -> DecodeError { - DecodeError { - field: self.cur_field.clone(), - kind: ApplicationError(err.to_string()) - } - } -} - -#[cfg(test)] -mod tests { - use rustc_serialize::Decodable; - use std::collections::HashMap; - - use {Parser, Decoder, Value}; - - #[test] - fn bad_enum_chooses_longest_error() { - #[derive(RustcDecodable)] - #[allow(dead_code)] - struct Foo { - wut: HashMap, - } - - #[derive(RustcDecodable)] - enum Bar { - Simple(String), - Detailed(Baz), - } - - #[derive(RustcDecodable, Debug)] - struct Baz { - features: Vec, - } - - let s = r#" - [wut] - a = { features = "" } - "#; - let v = Parser::new(s).parse().unwrap(); - let mut d = Decoder::new(Value::Table(v)); - let err = match Foo::decode(&mut d) { - Ok(_) => panic!("expected error"), - Err(e) => e, - }; - assert_eq!(err.field.as_ref().unwrap(), "wut.a.features"); - - } -} -- cgit v1.2.3