Skip to content

Commit

Permalink
Merge #64
Browse files Browse the repository at this point in the history
64: Implement `Deserializer` for `Value` r=kvark a=torkleyy

Just had this idea, so I thought I could implement it.
  • Loading branch information
bors[bot] committed Oct 27, 2017
2 parents 1d707e3 + 092aa83 commit 7e1c4c3
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ron"
version = "0.1.4"
version = "0.1.5"
license = "MIT/Apache-2.0"
keywords = ["parser", "serde", "serialization"]
authors = [
Expand Down
152 changes: 152 additions & 0 deletions src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ use std::cmp::{Eq, Ordering};
use std::collections::BTreeMap;
use std::hash::{Hash, Hasher};

use serde::de::{DeserializeSeed, Deserializer, MapAccess, SeqAccess, Visitor};

use de::{Error as RonError, Result};

/// 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)]
Expand Down Expand Up @@ -51,3 +55,151 @@ pub enum Value {
Seq(Vec<Value>),
Unit,
}

/// Deserializer implementation for RON `Value`.
/// This does not support enums (because `Value` doesn't store them).
impl<'de> Deserializer<'de> for Value {
type Error = RonError;

fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
match self {
Value::Bool(b) => visitor.visit_bool(b),
Value::Char(c) => visitor.visit_char(c),
Value::Map(m) => visitor.visit_map(Map {
keys: m.keys().cloned().rev().collect(),
values: m.values().cloned().rev().collect(),
}),
Value::Number(n) => visitor.visit_f64(n.get()),
Value::Option(Some(o)) => visitor.visit_some(*o),
Value::Option(None) => visitor.visit_none(),
Value::String(s) => visitor.visit_string(s),
Value::Seq(mut seq) => {
seq.reverse();

visitor.visit_seq(Seq { seq })
}
Value::Unit => visitor.visit_unit(),
}
}

forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes
byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
}
}

struct Map {
keys: Vec<Value>,
values: Vec<Value>,
}

impl<'de> MapAccess<'de> for Map {
type Error = RonError;

fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
where
K: DeserializeSeed<'de>,
{
// The `Vec` is reversed, so we can pop to get the originally first element
self.keys
.pop()
.map_or(Ok(None), |v| seed.deserialize(v).map(Some))
}

fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
where
V: DeserializeSeed<'de>,
{
// The `Vec` is reversed, so we can pop to get the originally first element
self.values
.pop()
.map(|v| seed.deserialize(v))
.expect("Contract violation")
}
}

struct Seq {
seq: Vec<Value>,
}

impl<'de> SeqAccess<'de> for Seq {
type Error = RonError;

fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
where
T: DeserializeSeed<'de>,
{
// The `Vec` is reversed, so we can pop to get the originally first element
self.seq
.pop()
.map_or(Ok(None), |v| seed.deserialize(v).map(Some))
}
}

#[cfg(test)]
mod tests {
use std::fmt::Debug;
use serde::Deserialize;
use super::*;

fn assert_same<'de, T>(s: &'de str)
where
T: Debug + Deserialize<'de> + PartialEq,
{
use de::from_str;

let direct: T = from_str(s).unwrap();
let value: Value = from_str(s).unwrap();
let value = T::deserialize(value).unwrap();

assert_eq!(direct, value, "Deserialization for {:?} is not the same", s);
}

#[test]
fn boolean() {
assert_same::<bool>("true");
assert_same::<bool>("false");
}

#[test]
fn float() {
assert_same::<f64>("0.123");
assert_same::<f64>("-4.19");
}

#[test]
fn char() {
assert_same::<char>("'4'");
assert_same::<char>("'c'");
}

#[test]
fn map() {
assert_same::<BTreeMap<char, String>>(
"{
'a': \"Hello\",
'b': \"Bye\",
}",
);
}

#[test]
fn option() {
assert_same::<Option<char>>("Some('a')");
assert_same::<Option<char>>("None");
}

#[test]
fn seq() {
assert_same::<Vec<f64>>("[1.0, 2.0, 3.0, 4.0]");
}

#[test]
fn unit() {
assert_same::<()>("()");
}
}

0 comments on commit 7e1c4c3

Please sign in to comment.