use std::fmt; use serde::{ de::{Error, MapAccess, SeqAccess, Visitor}, Deserialize, Deserializer, }; use crate::error::SpannedResult; use crate::value::{Map, Number, Value}; impl std::str::FromStr for Value { type Err = crate::error::SpannedError; /// Creates a value from a string reference. fn from_str(s: &str) -> SpannedResult { let mut de = super::Deserializer::from_str(s)?; let val = Value::deserialize(&mut de).map_err(|e| de.span_error(e))?; de.end().map_err(|e| de.span_error(e))?; Ok(val) } } 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, { Ok(Value::Number(Number::new(v))) } #[cfg(feature = "integer128")] fn visit_i128(self, v: i128) -> Result where E: Error, { self.visit_f64(v as f64) } fn visit_u64(self, v: u64) -> Result where E: Error, { Ok(Value::Number(Number::new(v))) } #[cfg(feature = "integer128")] fn visit_u128(self, v: u128) -> Result where E: Error, { self.visit_f64(v as f64) } fn visit_f64(self, v: f64) -> Result where E: Error, { Ok(Value::Number(Number::new(v))) } 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: Map = Map::new(); while let Some(entry) = map.next_entry()? { res.insert(entry.0, entry.1); } Ok(Value::Map(res)) } } #[cfg(test)] mod tests { use super::*; use std::str::FromStr; fn eval(s: &str) -> Value { s.parse().expect("Failed to parse") } #[test] 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_tuples_basic() { assert_eq!( eval("(3, 4.0, 5.0)"), Value::Seq(vec![ Value::Number(Number::new(3)), Value::Number(Number::new(4.0)), Value::Number(Number::new(5.0)), ],), ); } #[test] fn test_tuples_ident() { assert_eq!( eval("(true, 3, 4, 5.0)"), Value::Seq(vec![ Value::Bool(true), Value::Number(Number::new(3)), Value::Number(Number::new(4)), Value::Number(Number::new(5.0)), ]), ); } #[test] fn test_tuples_error() { use crate::de::{Error, Position, SpannedError}; assert_eq!( Value::from_str("Foo:").unwrap_err(), SpannedError { code: Error::TrailingCharacters, position: Position { col: 4, line: 1 } }, ); } #[test] fn test_floats() { assert_eq!( eval("(inf, -inf, NaN)"), Value::Seq(vec![ Value::Number(Number::new(std::f64::INFINITY)), Value::Number(Number::new(std::f64::NEG_INFINITY)), Value::Number(Number::new(std::f64::NAN)), ]), ); } #[test] fn test_complex() { assert_eq!( eval( "Some([ Room ( width: 20, height: 5, name: \"The Room\" ), ( width: 10.0, height: 10.0, 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)), ), ( Value::String("height".to_owned()), Value::Number(Number::new(5)), ), ( 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)), ), ( Value::String("Enemy2".to_owned()), Value::Number(Number::new(5)), ), ( Value::String("Enemy3".to_owned()), Value::Number(Number::new(7)), ), ] .into_iter() .collect(), ), ), ] .into_iter() .collect(), ), ])))) ); } }