From 3623144bbfb31020b43190479993eae7c5e96ba5 Mon Sep 17 00:00:00 2001 From: torkleyy Date: Sun, 10 Sep 2017 17:27:02 +0200 Subject: [PATCH 01/11] Replace panic in deserialize_any with error message --- src/de/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/de/mod.rs b/src/de/mod.rs index c879cff2..00fe1932 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -85,7 +85,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { fn deserialize_any(self, _visitor: V) -> Result where V: Visitor<'de> { - panic!("Give me some!"); + Err(Error::custom("RON does not support Deserializer::deserialize_any")) } fn deserialize_bool(self, visitor: V) -> Result From a7e08af5bb80af9f4d9cc8411e5471f7b8b415a5 Mon Sep 17 00:00:00 2001 From: torkleyy Date: Mon, 11 Sep 2017 17:30:32 +0200 Subject: [PATCH 02/11] Add Value and ValueVisitor --- src/de/mod.rs | 3 + src/de/value.rs | 150 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 src/de/value.rs diff --git a/src/de/mod.rs b/src/de/mod.rs index 00fe1932..cec3b8a6 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -13,6 +13,7 @@ use serde::de::{self, Deserializer as Deserializer_, DeserializeSeed, Visitor}; mod error; #[cfg(test)] mod tests; +mod value; /// The RON deserializer. /// @@ -85,6 +86,8 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { fn deserialize_any(self, _visitor: V) -> Result where V: Visitor<'de> { + use serde::de::Error; + Err(Error::custom("RON does not support Deserializer::deserialize_any")) } diff --git a/src/de/value.rs b/src/de/value.rs new file mode 100644 index 00000000..cd4c6f2c --- /dev/null +++ b/src/de/value.rs @@ -0,0 +1,150 @@ +use std::collections::BTreeMap; +use std::fmt; + +use serde::de::{EnumAccess, Error, MapAccess, SeqAccess, Visitor}; +use serde::{Deserialize, Deserializer}; + +#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub enum Value { + Bool(bool), + Char(char), + Enum(String, Box), + Map(BTreeMap), + Number(()), + Option(Option>), + String(String), + Seq(Vec), + Unit, +} + +impl<'de> Deserialize<'de> for Value { + fn deserialize(deserializer: D) -> Result + where D: Deserializer<'de> + { + deserializer.deserialize_any(ValueVisitor) + } +} + +struct ValueVisitor; + +impl<'de> Visitor<'de> for ValueVisitor { + type Value = Value; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "A RON value") + } + + fn visit_bool(self, v: bool) -> Result + where E: Error + { + Ok(Value::Bool(v)) + } + + fn visit_i64(self, v: i64) -> Result + where E: Error, + { + self.visit_f64(v as f64) + } + + fn visit_u64(self, v: u64) -> Result + where E: Error + { + self.visit_f64(v as f64) + } + + fn visit_f64(self, v: f64) -> Result + where E: Error + { + Ok(Value::Number(( /*TODO*/ ))) + } + + fn visit_char(self, v: char) -> Result + where E: Error + { + Ok(Value::Char(v)) + } + + fn visit_str(self, v: &str) -> Result + where E: Error + { + self.visit_string(v.to_owned()) + } + + fn visit_string(self, v: String) -> Result + where E: Error + { + Ok(Value::String(v)) + } + + fn visit_bytes(self, v: &[u8]) -> Result + where E: Error + { + self.visit_byte_buf(v.to_vec()) + } + + fn visit_byte_buf(self, v: Vec) -> Result + where E: Error + { + self.visit_string(String::from_utf8(v) + .map_err(|e| Error::custom(format!("{}", e)))?) + } + + fn visit_none(self) -> Result + where E: Error + { + Ok(Value::Option(None)) + } + + fn visit_some(self, deserializer: D) -> Result + where D: Deserializer<'de>, + { + Ok(Value::Option(Some(Box::new(deserializer.deserialize_any(ValueVisitor)?)))) + } + + fn visit_unit(self) -> Result + where E: Error + { + Ok(Value::Unit) + } + + fn visit_newtype_struct(self, deserializer: D) -> Result + where D: Deserializer<'de> + { + deserializer.deserialize_any(ValueVisitor) + } + + fn visit_seq(self, mut seq: A) -> Result + where A: SeqAccess<'de> + { + let mut vec = Vec::new(); + if let Some(cap) = seq.size_hint() { + vec.reserve_exact(cap); + } + + while let Some(x) = seq.next_element()? { + vec.push(x); + } + + Ok(Value::Seq(vec)) + } + + fn visit_map(self, mut map: A) -> Result + where A: MapAccess<'de> + { + let mut res: BTreeMap = BTreeMap::new(); + + while let Some(entry) = map.next_entry()? { + res.insert(entry.0, entry.1); + } + + Ok(Value::Map(res)) + } + + fn visit_enum(self, data: A) -> Result + where A: EnumAccess<'de> + { + let (value, variant) = data.variant()?; + + Ok(Value::Enum(variant, Box::new(value))) + } +} From f09dcbe8b47b492d3bcdb09fb44b952d86fa5a16 Mon Sep 17 00:00:00 2001 From: torkleyy Date: Mon, 11 Sep 2017 17:54:04 +0200 Subject: [PATCH 03/11] Remove visit_enum --- src/de/value.rs | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/de/value.rs b/src/de/value.rs index cd4c6f2c..9f80658c 100644 --- a/src/de/value.rs +++ b/src/de/value.rs @@ -1,14 +1,13 @@ use std::collections::BTreeMap; use std::fmt; -use serde::de::{EnumAccess, Error, MapAccess, SeqAccess, Visitor}; +use serde::de::{Error, MapAccess, SeqAccess, Visitor}; use serde::{Deserialize, Deserializer}; #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub enum Value { Bool(bool), Char(char), - Enum(String, Box), Map(BTreeMap), Number(()), Option(Option>), @@ -139,12 +138,4 @@ impl<'de> Visitor<'de> for ValueVisitor { Ok(Value::Map(res)) } - - fn visit_enum(self, data: A) -> Result - where A: EnumAccess<'de> - { - let (value, variant) = data.variant()?; - - Ok(Value::Enum(variant, Box::new(value))) - } } From 5d242bf35afba09c656f577f7231af5173bce2f4 Mon Sep 17 00:00:00 2001 From: torkleyy Date: Mon, 11 Sep 2017 17:54:54 +0200 Subject: [PATCH 04/11] Add Bytes::peek_or_eof --- src/de/mod.rs | 2 +- src/parse.rs | 30 ++++++++++++++++-------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/de/mod.rs b/src/de/mod.rs index cec3b8a6..e1e85f7d 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -415,7 +415,7 @@ impl<'a, 'de> CommaSeparated<'a, 'de> { self.de.bytes.skip_ws(); Ok(self.had_comma && - self.de.bytes.peek().ok_or(self.error(ParseError::Eof))? != self.terminator) + self.de.bytes.peek_or_eof()? != self.terminator) } } diff --git a/src/parse.rs b/src/parse.rs index 6f29e045..bf9ba0e9 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -39,7 +39,7 @@ impl<'a> Bytes<'a> { } pub fn advance_single(&mut self) -> Result<()> { - if self.peek().ok_or(self.error(ParseError::Eof))? == b'\n' { + if self.peek_or_eof()? == b'\n' { self.line += 1; self.column = 1; } else { @@ -114,13 +114,10 @@ impl<'a> Bytes<'a> { } pub fn eat_byte(&mut self) -> Result { - if let Some(peek) = self.peek() { - let _ = self.advance_single(); + let peek = self.peek_or_eof()?; + let _ = self.advance_single(); - Ok(peek) - } else { - self.err(ParseError::Eof) - } + Ok(peek) } pub fn err(&self, kind: ParseError) -> Result { @@ -145,7 +142,7 @@ impl<'a> Bytes<'a> { } pub fn identifier(&mut self) -> Result<&[u8]> { - if IDENT_FIRST.contains(&self.peek().ok_or(self.error(ParseError::Eof))?) { + if IDENT_FIRST.contains(&self.peek_or_eof()?) { let bytes = self.next_bytes_contained_in(IDENT_CHAR); let ident = &self.bytes[..bytes]; @@ -178,20 +175,25 @@ impl<'a> Bytes<'a> { self.bytes.get(0).map(|b| *b) } - pub fn signed_integer(&mut self) -> Result where T: FromStr + Neg { - match self.peek() { - Some(b'+') => { + pub fn peek_or_eof(&self) -> Result { + self.bytes.get(0).map(|b| *b).ok_or(self.error(ParseError::Eof)) + } + + pub fn signed_integer(&mut self) -> Result + where T: FromStr + Neg + { + match self.peek_or_eof()? { + b'+' => { let _ = self.advance_single(); self.unsigned_integer() } - Some(b'-') => { + b'-' => { let _ = self.advance_single(); self.unsigned_integer::().map(Neg::neg) } - Some(_) => self.unsigned_integer(), - None => self.err(ParseError::Eof), + _ => self.unsigned_integer(), } } From 1fa6509b8932dee9396bc70f26b5ff7b95d09f67 Mon Sep 17 00:00:00 2001 From: torkleyy Date: Mon, 11 Sep 2017 19:04:37 +0200 Subject: [PATCH 05/11] Implement deserialize_any --- src/de/mod.rs | 30 +++++++++++++++++------ src/de/value.rs | 64 +++++++++++++++++++++++++++++++++++++++++++++++-- src/parse.rs | 22 ++++++++++++++++- 3 files changed, 106 insertions(+), 10 deletions(-) diff --git a/src/de/mod.rs b/src/de/mod.rs index e1e85f7d..5f0b2420 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -83,12 +83,32 @@ impl<'de> Deserializer<'de> { impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { type Error = Error; - fn deserialize_any(self, _visitor: V) -> Result + fn deserialize_any(self, visitor: V) -> Result where V: Visitor<'de> { - use serde::de::Error; + if self.bytes.consume_ident("true") { + return visitor.visit_bool(true); + } else if self.bytes.consume_ident("false") { + return visitor.visit_bool(false); + } else if self.bytes.consume_ident("Some") { + return visitor.visit_some(self); + } else if self.bytes.consume_ident("None") { + return visitor.visit_none(); + } else if self.bytes.consume("()") { + return visitor.visit_unit(); + } + + let _identifier = self.bytes.identifier().is_ok(); - Err(Error::custom("RON does not support Deserializer::deserialize_any")) + match self.bytes.peek_or_eof()? { + b'(' => self.deserialize_struct("", &[], visitor), + b'[' => self.deserialize_seq(visitor), + b'{' => self.deserialize_map(visitor), + b'0' ... b'9' | b'+' | b'-' | b'.' => self.deserialize_f64(visitor), + b'"' => self.deserialize_string(visitor), + b'\'' => self.deserialize_char(visitor), + _ => unimplemented!("TODO"), + } } fn deserialize_bool(self, visitor: V) -> Result @@ -407,10 +427,6 @@ impl<'a, 'de> CommaSeparated<'a, 'de> { self.de.bytes.err(kind) } - fn error(&self, kind: ParseError) -> Error { - self.de.bytes.error(kind) - } - fn has_element(&mut self) -> Result { self.de.bytes.skip_ws(); diff --git a/src/de/value.rs b/src/de/value.rs index 9f80658c..e48011bc 100644 --- a/src/de/value.rs +++ b/src/de/value.rs @@ -1,21 +1,67 @@ +use std::cmp::{Eq, Ordering}; use std::collections::BTreeMap; use std::fmt; +use std::hash::{Hash, Hasher}; use serde::de::{Error, MapAccess, SeqAccess, Visitor}; use serde::{Deserialize, Deserializer}; +use de; + +/// A wrapper for `f64` which guarantees that the inner value +/// is finite and thus implements `Eq`, `Hash` and `Ord`. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub struct Number(f64); + +impl Number { + /// Panics if `v` is not a real number + /// (infinity, NaN, ..). + pub fn new(v: f64) -> Self { + if !v.is_finite() { + panic!("Tried to create Number with a NaN / infinity"); + } + + Number(v) + } + + /// Returns the wrapped float. + pub fn get(&self) -> f64 { + self.0 + } +} + +impl Eq for Number {} + +impl Hash for Number { + fn hash(&self, state: &mut H) { + state.write_u64(self.0 as u64); + } +} + +impl Ord for Number { + fn cmp(&self, other: &Self) -> Ordering { + self.partial_cmp(other).expect("Bug: Contract violation") + } +} + #[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub enum Value { Bool(bool), Char(char), Map(BTreeMap), - Number(()), + Number(Number), Option(Option>), String(String), Seq(Vec), Unit, } +impl Value { + pub fn from_str(s: &str) -> de::Result { + Self::deserialize(&mut super::Deserializer::from_str(s)) + } +} + impl<'de> Deserialize<'de> for Value { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> @@ -54,7 +100,7 @@ impl<'de> Visitor<'de> for ValueVisitor { fn visit_f64(self, v: f64) -> Result where E: Error { - Ok(Value::Number(( /*TODO*/ ))) + Ok(Value::Number(Number::new(v))) } fn visit_char(self, v: char) -> Result @@ -139,3 +185,17 @@ impl<'de> Visitor<'de> for ValueVisitor { Ok(Value::Map(res)) } } + +#[cfg(test)] +mod tests { + use super::*; + + fn eval(s: &str) -> Value { + Value::from_str(s).expect("Failed to parse") + } + + #[test] + fn test_none() { + assert_eq!(eval("None"), Value::Option(None)); + } +} diff --git a/src/parse.rs b/src/parse.rs index bf9ba0e9..6766df4b 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -103,8 +103,24 @@ impl<'a> Bytes<'a> { } } + fn check_ident_char(&self, index: usize) -> bool { + self.bytes.get(index).map(|b| IDENT_CHAR.contains(b)).unwrap_or(false) + } + + /// Only returns true if the char after `ident` cannot belong + /// to an identifier. + pub fn consume_ident(&mut self, ident: &str) -> bool { + if self.test_for(ident) && !self.check_ident_char(ident.len()) { + let _ = self.advance(ident.len()); + + true + } else { + false + } + } + pub fn consume(&mut self, s: &str) -> bool { - if s.bytes().enumerate().all(|(i, b)| self.bytes.get(i).map(|t| *t == b).unwrap_or(false)) { + if self.test_for(s) { let _ = self.advance(s.len()); true @@ -244,6 +260,10 @@ impl<'a> Bytes<'a> { } } + fn test_for(&self, s: &str) -> bool { + s.bytes().enumerate().all(|(i, b)| self.bytes.get(i).map(|t| *t == b).unwrap_or(false)) + } + pub fn unsigned_integer(&mut self) -> Result where T: FromStr { let num_bytes = self.next_bytes_contained_in(DIGITS); From 5eb4272858338efedfd05ce693becb8637e319c0 Mon Sep 17 00:00:00 2001 From: torkleyy Date: Mon, 11 Sep 2017 20:10:02 +0200 Subject: [PATCH 06/11] More tests, more fixes --- src/de/error.rs | 2 ++ src/de/mod.rs | 12 ++++++++---- src/de/value.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/parse.rs | 8 +++++++- 4 files changed, 62 insertions(+), 5 deletions(-) diff --git a/src/de/error.rs b/src/de/error.rs index f10cf3a9..9ee028df 100644 --- a/src/de/error.rs +++ b/src/de/error.rs @@ -43,6 +43,8 @@ pub enum ParseError { InvalidEscape, + UnexpectedByte(char), + Utf8Error(Utf8Error), TrailingCharacters, diff --git a/src/de/mod.rs b/src/de/mod.rs index 5f0b2420..929e1c30 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -90,15 +90,17 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { return visitor.visit_bool(true); } else if self.bytes.consume_ident("false") { return visitor.visit_bool(false); - } else if self.bytes.consume_ident("Some") { - return visitor.visit_some(self); + } else if self.bytes.check_ident("Some") { + return self.deserialize_option(visitor); } else if self.bytes.consume_ident("None") { return visitor.visit_none(); } else if self.bytes.consume("()") { return visitor.visit_unit(); } - let _identifier = self.bytes.identifier().is_ok(); + if self.bytes.identifier().is_ok() { + self.bytes.skip_ws(); + } match self.bytes.peek_or_eof()? { b'(' => self.deserialize_struct("", &[], visitor), @@ -107,7 +109,7 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { b'0' ... b'9' | b'+' | b'-' | b'.' => self.deserialize_f64(visitor), b'"' => self.deserialize_string(visitor), b'\'' => self.deserialize_char(visitor), - _ => unimplemented!("TODO"), + other => self.bytes.err(ParseError::UnexpectedByte(other as char)), } } @@ -216,6 +218,8 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { where V: Visitor<'de> { if self.bytes.consume("Some") && { self.bytes.skip_ws(); self.bytes.consume("(") } { + self.bytes.skip_ws(); + let v = visitor.visit_some(&mut *self)?; self.bytes.skip_ws(); diff --git a/src/de/value.rs b/src/de/value.rs index e48011bc..15f2590f 100644 --- a/src/de/value.rs +++ b/src/de/value.rs @@ -198,4 +198,49 @@ mod tests { fn test_none() { assert_eq!(eval("None"), Value::Option(None)); } + + #[test] + fn test_some() { + assert_eq!(eval("Some(())"), Value::Option(Some(Box::new(Value::Unit)))); + assert_eq!(eval("Some ( () )"), Value::Option(Some(Box::new(Value::Unit)))); + } + + #[test] + fn test_complex() { + assert_eq!(eval("Some([ + Room ( width: 20, height: 5, name: \"The Room\" ), + + ( + width: 10, + height: 10, + name: \"Another room\" + enemy_levels: { + \"Enemy1\": 3, + \"Enemy2\": 5, + \"Enemy3\": 7, + }, + ), +])"), + Value::Option(Some(Box::new(Value::Seq( + vec![ + Value::Map(vec![ + (Value::String("width".to_owned()), Value::Number(Number::new(20.0))), + (Value::String("height".to_owned()), Value::Number(Number::new(5.0))), + (Value::String("name".to_owned()), Value::String("The Room".to_owned())), + ].into_iter().collect()), + Value::Map(vec![ + (Value::String("width".to_owned()), Value::Number(Number::new(10.0))), + (Value::String("height".to_owned()), Value::Number(Number::new(10.0))), + (Value::String("name".to_owned()), Value::String("Another Room".to_owned())), + (Value::String("enemy_levels".to_owned()), Value::Map( + vec![ + (Value::String("Enemy1".to_owned()), Value::Number(Number::new(3.0))), + (Value::String("Enemy2".to_owned()), Value::Number(Number::new(5.0))), + (Value::String("Enemy3".to_owned()), Value::Number(Number::new(7.0))), + ].into_iter().collect() + )), + ].into_iter().collect()), + ] + ))))); + } } diff --git a/src/parse.rs b/src/parse.rs index 6766df4b..0f2596d5 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -103,6 +103,12 @@ impl<'a> Bytes<'a> { } } + /// Only returns true if the char after `ident` cannot belong + /// to an identifier. + pub fn check_ident(&mut self, ident: &str) -> bool { + self.test_for(ident) && !self.check_ident_char(ident.len()) + } + fn check_ident_char(&self, index: usize) -> bool { self.bytes.get(index).map(|b| IDENT_CHAR.contains(b)).unwrap_or(false) } @@ -110,7 +116,7 @@ impl<'a> Bytes<'a> { /// Only returns true if the char after `ident` cannot belong /// to an identifier. pub fn consume_ident(&mut self, ident: &str) -> bool { - if self.test_for(ident) && !self.check_ident_char(ident.len()) { + if self.check_ident(ident) { let _ = self.advance(ident.len()); true From 620260930731651d8fed192a252110cc10ed0545 Mon Sep 17 00:00:00 2001 From: torkleyy Date: Thu, 14 Sep 2017 18:38:58 +0200 Subject: [PATCH 07/11] Add IdDeserializer, fix bugs, better validation, export Value types --- src/de/id.rs | 228 ++++++++++++++++++++++++++++++++++++++++++++++++ src/de/mod.rs | 14 ++- src/de/value.rs | 4 +- 3 files changed, 242 insertions(+), 4 deletions(-) create mode 100644 src/de/id.rs diff --git a/src/de/id.rs b/src/de/id.rs new file mode 100644 index 00000000..597c3a9d --- /dev/null +++ b/src/de/id.rs @@ -0,0 +1,228 @@ +use serde::de::{self, Visitor}; + +use super::{Error, Result}; + +pub struct IdDeserializer { + d: D, +} + +impl IdDeserializer { + pub fn new(d: D) -> Self { + IdDeserializer { + d + } + } +} + +impl<'a, D> de::Deserializer<'a> for IdDeserializer +where D: de::Deserializer<'a, Error = Error> +{ + type Error = Error; + + fn deserialize_identifier( + self, + visitor: V + ) -> Result + where V: Visitor<'a> + { + self.d.deserialize_identifier(visitor) + } + + fn deserialize_any(self, visitor: V) -> Result + where V: Visitor<'a> + { + self.deserialize_identifier(visitor) + } + + fn deserialize_bool(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_i8(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_i16(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_i32(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_i64(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_u8(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_u16(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_u32(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_u64(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_f32(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_f64(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_char(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_str(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_string(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_bytes(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_byte_buf(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_option(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_unit(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_unit_struct( + self, + _: &'static str, + _: V + ) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_newtype_struct( + self, + _: &'static str, + _: V + ) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_seq(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_tuple( + self, + _: usize, + _: V + ) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_tuple_struct( + self, + _: &'static str, + _: usize, + _: V + ) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_map(self, _: V) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_struct( + self, + _: &'static str, + _: &'static [&'static str], + _: V + ) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_enum( + self, + _: &'static str, + _: &'static [&'static str], + _: V + ) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } + + fn deserialize_ignored_any( + self, + _: V + ) -> Result + where V: Visitor<'a> + { + unimplemented!("IdDeserializer may only be used for identifiers") + } +} diff --git a/src/de/mod.rs b/src/de/mod.rs index 929e1c30..31b8e9ae 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -2,15 +2,19 @@ /// pub use self::error::{Error, ParseError, Result}; +pub use self::value::{Number, Value}; use std::borrow::Cow; use std::io; use std::str; -use parse::Bytes; use serde::de::{self, Deserializer as Deserializer_, DeserializeSeed, Visitor}; +use parse::Bytes; +use self::id::IdDeserializer; + mod error; +mod id; #[cfg(test)] mod tests; mod value; @@ -100,6 +104,8 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> { if self.bytes.identifier().is_ok() { self.bytes.skip_ws(); + + return self.deserialize_struct("", &[], visitor); } match self.bytes.peek_or_eof()? { @@ -464,7 +470,11 @@ impl<'de, 'a> de::MapAccess<'de> for CommaSeparated<'a, 'de> { where K: DeserializeSeed<'de> { if self.has_element()? { - seed.deserialize(&mut *self.de).map(Some) + if self.terminator == b'}' { + seed.deserialize(&mut *self.de).map(Some) + } else { + seed.deserialize(IdDeserializer::new(&mut *self.de)).map(Some) + } } else { Ok(None) } diff --git a/src/de/value.rs b/src/de/value.rs index 15f2590f..c36d6ab9 100644 --- a/src/de/value.rs +++ b/src/de/value.rs @@ -213,7 +213,7 @@ mod tests { ( width: 10, height: 10, - name: \"Another room\" + name: \"Another room\", enemy_levels: { \"Enemy1\": 3, \"Enemy2\": 5, @@ -231,7 +231,7 @@ mod tests { Value::Map(vec![ (Value::String("width".to_owned()), Value::Number(Number::new(10.0))), (Value::String("height".to_owned()), Value::Number(Number::new(10.0))), - (Value::String("name".to_owned()), Value::String("Another Room".to_owned())), + (Value::String("name".to_owned()), Value::String("Another room".to_owned())), (Value::String("enemy_levels".to_owned()), Value::Map( vec![ (Value::String("Enemy1".to_owned()), Value::Number(Number::new(3.0))), From 5048eb30e78d05e4dcacfcaf4725285c4e66fd37 Mon Sep 17 00:00:00 2001 From: torkleyy Date: Thu, 14 Sep 2017 18:40:58 +0200 Subject: [PATCH 08/11] Fix several warnings in examples --- examples/decode.rs | 1 - examples/decode_file.rs | 1 - examples/encode.rs | 1 - 3 files changed, 3 deletions(-) diff --git a/examples/decode.rs b/examples/decode.rs index 7848d30d..2a6da8b6 100644 --- a/examples/decode.rs +++ b/examples/decode.rs @@ -1,5 +1,4 @@ extern crate ron; -extern crate serde; #[macro_use] extern crate serde_derive; diff --git a/examples/decode_file.rs b/examples/decode_file.rs index d21e1718..e0868482 100644 --- a/examples/decode_file.rs +++ b/examples/decode_file.rs @@ -1,5 +1,4 @@ extern crate ron; -extern crate serde; #[macro_use] extern crate serde_derive; diff --git a/examples/encode.rs b/examples/encode.rs index 95bde53e..6c3cd911 100644 --- a/examples/encode.rs +++ b/examples/encode.rs @@ -1,5 +1,4 @@ extern crate ron; -extern crate serde; #[macro_use] extern crate serde_derive; From 60c35e631f12227c5d62465577f64529d5a660cf Mon Sep 17 00:00:00 2001 From: torkleyy Date: Thu, 14 Sep 2017 19:03:08 +0200 Subject: [PATCH 09/11] Add Value serialization, restructure value module(s), add transcode example --- Cargo.toml | 1 + examples/transcode.rs | 35 ++++++++++++++++++++++++++++ src/de/mod.rs | 1 - src/de/value.rs | 52 ++---------------------------------------- src/lib.rs | 1 + src/ser/mod.rs | 2 ++ src/ser/value.rs | 22 ++++++++++++++++++ src/value.rs | 53 +++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 116 insertions(+), 51 deletions(-) create mode 100644 examples/transcode.rs create mode 100644 src/ser/value.rs create mode 100644 src/value.rs diff --git a/Cargo.toml b/Cargo.toml index 7bb9f0fe..954a4bca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,3 +22,4 @@ serde = "1" [dev-dependencies] serde_derive = "1" +serde_json = "1" diff --git a/examples/transcode.rs b/examples/transcode.rs new file mode 100644 index 00000000..9577ec8e --- /dev/null +++ b/examples/transcode.rs @@ -0,0 +1,35 @@ +extern crate ron; +extern crate serde; +extern crate serde_json; + +use ron::value::Value; +use serde::ser::Serialize; + +fn main() { + let data = r#" + Scene( // class name is optional + materials: { // this is a map + "metal": ( + reflectivity: 1.0, + ), + "plastic": ( + reflectivity: 0.5, + ), + }, + entities: [ // this is an array + ( + name: "hero", + material: "metal", + ), + ( + name: "monster", + material: "plastic", + ), + ], + ) + "#; + + let value = Value::from_str(data).expect("Failed to deserialize"); + let mut ser = serde_json::Serializer::pretty(std::io::stdout()); + value.serialize(&mut ser).expect("Failed to serialize"); +} diff --git a/src/de/mod.rs b/src/de/mod.rs index 31b8e9ae..d6c1f804 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -2,7 +2,6 @@ /// pub use self::error::{Error, ParseError, Result}; -pub use self::value::{Number, Value}; use std::borrow::Cow; use std::io; diff --git a/src/de/value.rs b/src/de/value.rs index c36d6ab9..ca01f9b0 100644 --- a/src/de/value.rs +++ b/src/de/value.rs @@ -1,62 +1,14 @@ -use std::cmp::{Eq, Ordering}; use std::collections::BTreeMap; use std::fmt; -use std::hash::{Hash, Hasher}; use serde::de::{Error, MapAccess, SeqAccess, Visitor}; use serde::{Deserialize, Deserializer}; use de; - -/// A wrapper for `f64` which guarantees that the inner value -/// is finite and thus implements `Eq`, `Hash` and `Ord`. -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] -pub struct Number(f64); - -impl Number { - /// Panics if `v` is not a real number - /// (infinity, NaN, ..). - pub fn new(v: f64) -> Self { - if !v.is_finite() { - panic!("Tried to create Number with a NaN / infinity"); - } - - Number(v) - } - - /// Returns the wrapped float. - pub fn get(&self) -> f64 { - self.0 - } -} - -impl Eq for Number {} - -impl Hash for Number { - fn hash(&self, state: &mut H) { - state.write_u64(self.0 as u64); - } -} - -impl Ord for Number { - fn cmp(&self, other: &Self) -> Ordering { - self.partial_cmp(other).expect("Bug: Contract violation") - } -} - -#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum Value { - Bool(bool), - Char(char), - Map(BTreeMap), - Number(Number), - Option(Option>), - String(String), - Seq(Vec), - Unit, -} +use value::{Number, Value}; impl Value { + /// Creates a value from a string reference. pub fn from_str(s: &str) -> de::Result { Self::deserialize(&mut super::Deserializer::from_str(s)) } diff --git a/src/lib.rs b/src/lib.rs index c59b6054..e7222e87 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,5 +64,6 @@ extern crate serde_derive; pub mod de; pub mod ser; +pub mod value; mod parse; diff --git a/src/ser/mod.rs b/src/ser/mod.rs index 18a2f503..57f24b8c 100644 --- a/src/ser/mod.rs +++ b/src/ser/mod.rs @@ -5,6 +5,8 @@ use serde::ser::{self, Serialize}; pub mod pretty; +mod value; + #[cfg(not(target_os = "windows"))] const NEWLINE: &str = "\n"; diff --git a/src/ser/value.rs b/src/ser/value.rs new file mode 100644 index 00000000..f9aeb0ba --- /dev/null +++ b/src/ser/value.rs @@ -0,0 +1,22 @@ +use serde::ser::{Serialize, Serializer}; + +use value::Value; + +impl Serialize for Value { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer + { + match *self { + Value::Bool(b) => serializer.serialize_bool(b), + Value::Char(c) => serializer.serialize_char(c), + Value::Map(ref m) => Serialize::serialize(m, serializer), + Value::Number(ref n) => serializer.serialize_f64(n.get()), + Value::Option(Some(ref o)) => serializer.serialize_some(o.as_ref()), + Value::Option(None) => serializer.serialize_none(), + Value::String(ref s) => serializer.serialize_str(s), + Value::Seq(ref s) => Serialize::serialize(s, serializer), + Value::Unit => serializer.serialize_unit(), + } + } +} diff --git a/src/value.rs b/src/value.rs new file mode 100644 index 00000000..3fca393c --- /dev/null +++ b/src/value.rs @@ -0,0 +1,53 @@ +//! Value module. + +use std::cmp::{Eq, Ordering}; +use std::collections::BTreeMap; +use std::hash::{Hash, Hasher}; + +/// A wrapper for `f64` which guarantees that the inner value +/// is finite and thus implements `Eq`, `Hash` and `Ord`. +#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)] +pub struct Number(f64); + +impl Number { + /// Panics if `v` is not a real number + /// (infinity, NaN, ..). + pub fn new(v: f64) -> Self { + if !v.is_finite() { + panic!("Tried to create Number with a NaN / infinity"); + } + + Number(v) + } + + /// Returns the wrapped float. + pub fn get(&self) -> f64 { + self.0 + } +} + +impl Eq for Number {} + +impl Hash for Number { + fn hash(&self, state: &mut H) { + state.write_u64(self.0 as u64); + } +} + +impl Ord for Number { + fn cmp(&self, other: &Self) -> Ordering { + self.partial_cmp(other).expect("Bug: Contract violation") + } +} + +#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub enum Value { + Bool(bool), + Char(char), + Map(BTreeMap), + Number(Number), + Option(Option>), + String(String), + Seq(Vec), + Unit, +} From 749ec236c4c6d50c5931d753c2fa3cd71450078c Mon Sep 17 00:00:00 2001 From: torkleyy Date: Thu, 14 Sep 2017 19:09:22 +0200 Subject: [PATCH 10/11] Add untagged test --- src/de/tests.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/de/tests.rs b/src/de/tests.rs index dd729646..65d15bb7 100644 --- a/src/de/tests.rs +++ b/src/de/tests.rs @@ -147,3 +147,15 @@ fn test_perm_ws() { assert_eq!(from_str::("\nMyStruct \t ( \n x : 3.5 , \t y\n: 4.5 \n ) \t\n"), Ok(MyStruct { x: 3.5, y: 4.5 })); } + +#[test] +fn untagged() { + #[derive(Deserialize, Debug, PartialEq)] + #[serde(untagged)] + enum Untagged { + U8(u8), + Bool(bool), + } + + assert_eq!(from_str::("true").unwrap(), Untagged::Bool(true)); +} From 4ad391b589042029b3ca7257f80c1ad14a4fd5c8 Mon Sep 17 00:00:00 2001 From: torkleyy Date: Wed, 20 Sep 2017 13:36:19 +0200 Subject: [PATCH 11/11] Remove generics for better compile times --- src/de/id.rs | 72 +++++++++++++++++++++++++-------------------------- src/de/mod.rs | 6 ++--- 2 files changed, 38 insertions(+), 40 deletions(-) diff --git a/src/de/id.rs b/src/de/id.rs index 597c3a9d..cce9fedd 100644 --- a/src/de/id.rs +++ b/src/de/id.rs @@ -1,143 +1,141 @@ use serde::de::{self, Visitor}; -use super::{Error, Result}; +use super::{Deserializer, Error, Result}; -pub struct IdDeserializer { - d: D, +pub struct IdDeserializer<'a, 'b: 'a> { + d: &'a mut Deserializer<'b>, } -impl IdDeserializer { - pub fn new(d: D) -> Self { +impl<'a, 'b: 'a> IdDeserializer<'a, 'b> { + pub fn new(d: &'a mut Deserializer<'b>) -> Self { IdDeserializer { d } } } -impl<'a, D> de::Deserializer<'a> for IdDeserializer -where D: de::Deserializer<'a, Error = Error> -{ +impl<'a, 'b: 'a, 'c> de::Deserializer<'b> for &'c mut IdDeserializer<'a, 'b> { type Error = Error; fn deserialize_identifier( self, visitor: V ) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { self.d.deserialize_identifier(visitor) } fn deserialize_any(self, visitor: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { self.deserialize_identifier(visitor) } fn deserialize_bool(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } fn deserialize_i8(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } fn deserialize_i16(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } fn deserialize_i32(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } fn deserialize_i64(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } fn deserialize_u8(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } fn deserialize_u16(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } fn deserialize_u32(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } fn deserialize_u64(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } fn deserialize_f32(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } fn deserialize_f64(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } fn deserialize_char(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } fn deserialize_str(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } fn deserialize_string(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } fn deserialize_bytes(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } fn deserialize_byte_buf(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } fn deserialize_option(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } fn deserialize_unit(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } @@ -147,7 +145,7 @@ where D: de::Deserializer<'a, Error = Error> _: &'static str, _: V ) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } @@ -157,13 +155,13 @@ where D: de::Deserializer<'a, Error = Error> _: &'static str, _: V ) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } fn deserialize_seq(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } @@ -173,7 +171,7 @@ where D: de::Deserializer<'a, Error = Error> _: usize, _: V ) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } @@ -184,13 +182,13 @@ where D: de::Deserializer<'a, Error = Error> _: usize, _: V ) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } fn deserialize_map(self, _: V) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } @@ -201,7 +199,7 @@ where D: de::Deserializer<'a, Error = Error> _: &'static [&'static str], _: V ) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } @@ -212,7 +210,7 @@ where D: de::Deserializer<'a, Error = Error> _: &'static [&'static str], _: V ) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } @@ -221,7 +219,7 @@ where D: de::Deserializer<'a, Error = Error> self, _: V ) -> Result - where V: Visitor<'a> + where V: Visitor<'b> { unimplemented!("IdDeserializer may only be used for identifiers") } diff --git a/src/de/mod.rs b/src/de/mod.rs index d6c1f804..cd174dff 100644 --- a/src/de/mod.rs +++ b/src/de/mod.rs @@ -469,10 +469,10 @@ impl<'de, 'a> de::MapAccess<'de> for CommaSeparated<'a, 'de> { where K: DeserializeSeed<'de> { if self.has_element()? { - if self.terminator == b'}' { - seed.deserialize(&mut *self.de).map(Some) + if self.terminator == b')' { + seed.deserialize(&mut IdDeserializer::new(&mut *self.de)).map(Some) } else { - seed.deserialize(IdDeserializer::new(&mut *self.de)).map(Some) + seed.deserialize(&mut *self.de).map(Some) } } else { Ok(None)