Skip to content

Commit

Permalink
feat(Value): Add serde support
Browse files Browse the repository at this point in the history
This should open it up for clients to easily serialize to/from the formats
they care about.
  • Loading branch information
epage committed May 2, 2017
1 parent 280c6d9 commit 8ae7f5a
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 27 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ lazy_static = "0.2"
chrono = "0.3"
unicode-segmentation = "1.1"
itertools = "0.6.0"
serde = "1.0"
serde_derive = "1.0"

[build-dependencies]
skeptic = "0.9"

[dev-dependencies]
difference = "1.0"
skeptic = "0.9"
serde_yaml = "0.7"

[features]
default = ["extra-filters"]
Expand Down
9 changes: 7 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,18 @@
#![allow(unknown_lints)]
#![allow(zero_ptr)]

#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate chrono;
extern crate unicode_segmentation;
extern crate itertools;

#[macro_use]
extern crate lazy_static;

extern crate serde;
#[macro_use]
extern crate serde_derive;

use std::collections::HashMap;
use lexer::Element;
use tags::{assign_tag, cycle_tag, include_tag, break_tag, continue_tag, comment_block, raw_block,
Expand Down
52 changes: 27 additions & 25 deletions src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ use token::Token::*;

/// An enum to represent different value types
#[derive(Clone, Debug)]
#[derive(Serialize, Deserialize)]
#[serde(untagged)]
pub enum Value {
Str(String),
Num(f32),
Bool(bool),
Str(String),
Array(Array),
Object(Object),
}
Expand Down Expand Up @@ -40,19 +42,6 @@ impl<'a> Value {
}
}

/// Extracts the str value if it is a str.
pub fn as_str(&'a self) -> Option<&'a str> {
match *self {
Value::Str(ref v) => Some(v),
_ => None,
}
}

/// Tests whether this value is a str
pub fn is_str(&self) -> bool {
self.as_str().is_some()
}

/// Extracts the float value if it is a float.
pub fn as_float(&self) -> Option<f32> {
match *self {
Expand All @@ -79,6 +68,19 @@ impl<'a> Value {
self.as_bool().is_some()
}

/// Extracts the str value if it is a str.
pub fn as_str(&'a self) -> Option<&'a str> {
match *self {
Value::Str(ref v) => Some(v),
_ => None,
}
}

/// Tests whether this value is a str
pub fn is_str(&self) -> bool {
self.as_str().is_some()
}

/// Extracts the array value if it is an array.
pub fn as_array(&self) -> Option<&Vec<Value>> {
match *self {
Expand Down Expand Up @@ -125,9 +127,9 @@ impl<'a> Value {
impl PartialEq<Value> for Value {
fn eq(&self, other: &Value) -> bool {
match (self, other) {
(&Value::Str(ref x), &Value::Str(ref y)) => x == y,
(&Value::Num(x), &Value::Num(y)) => x == y,
(&Value::Bool(x), &Value::Bool(y)) => x == y,
(&Value::Str(ref x), &Value::Str(ref y)) => x == y,
(&Value::Array(ref x), &Value::Array(ref y)) => x == y,
(&Value::Object(ref x), &Value::Object(ref y)) => x == y,

Expand All @@ -146,9 +148,9 @@ impl Eq for Value {}
impl PartialOrd<Value> for Value {
fn partial_cmp(&self, other: &Value) -> Option<Ordering> {
match (self, other) {
(&Value::Str(ref x), &Value::Str(ref y)) => x.partial_cmp(y),
(&Value::Num(x), &Value::Num(y)) => x.partial_cmp(&y),
(&Value::Bool(x), &Value::Bool(y)) => x.partial_cmp(&y),
(&Value::Str(ref x), &Value::Str(ref y)) => x.partial_cmp(y),
(&Value::Array(ref x), &Value::Array(ref y)) => x.iter().partial_cmp(y.iter()),
(&Value::Object(ref x), &Value::Object(ref y)) => x.iter().partial_cmp(y.iter()),
_ => None,
Expand All @@ -159,9 +161,9 @@ impl PartialOrd<Value> for Value {
impl ToString for Value {
fn to_string(&self) -> String {
match *self {
Value::Str(ref x) => x.to_owned(),
Value::Num(ref x) => x.to_string(),
Value::Bool(ref x) => x.to_string(),
Value::Str(ref x) => x.to_owned(),
Value::Array(ref x) => {
let arr: Vec<String> = x.iter().map(|v| v.to_string()).collect();
arr.join(", ")
Expand Down Expand Up @@ -190,21 +192,21 @@ mod test {
static FALSE: Value = Value::Bool(false);

#[test]
fn test_as_str() {
fn test_num_to_string() {
let val = Value::Num(42f32);
assert_eq!(val.as_str(), None);
assert_eq!(&val.to_string(), "42");

let val = Value::str("test");
assert_eq!(val.as_str(), Some("test"));
let val = Value::Num(42.34);
assert_eq!(&val.to_string(), "42.34");
}

#[test]
fn test_num_to_string() {
fn test_as_str() {
let val = Value::Num(42f32);
assert_eq!(&val.to_string(), "42");
assert_eq!(val.as_str(), None);

let val = Value::Num(42.34);
assert_eq!(&val.to_string(), "42.34");
let val = Value::str("test");
assert_eq!(val.as_str(), Some("test"));
}

#[test]
Expand Down
131 changes: 131 additions & 0 deletions tests/value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
extern crate liquid;
extern crate serde_yaml;

#[macro_use]
extern crate difference;

use std::f32;

#[test]
pub fn serialize_num() {
let actual = liquid::Value::Num(1f32);
let actual = serde_yaml::to_string(&actual).unwrap();
assert_diff!(&actual, "---\n1", "", 0);

let actual = liquid::Value::Num(-100f32);
let actual = serde_yaml::to_string(&actual).unwrap();
assert_diff!(&actual, "---\n-100", "", 0);

let actual = liquid::Value::Num(3.14e10f32);
let actual = serde_yaml::to_string(&actual).unwrap();
assert_diff!(&actual, "---\n31399999488", "", 0);

let actual = liquid::Value::Num(f32::NAN);
let actual = serde_yaml::to_string(&actual).unwrap();
assert_diff!(&actual, "---\nNaN", "", 0);

let actual = liquid::Value::Num(f32::INFINITY);
let actual = serde_yaml::to_string(&actual).unwrap();
assert_diff!(&actual, "---\ninf", "", 0);
}

#[test]
pub fn deserialize_num() {
let actual: liquid::Value = serde_yaml::from_str("---\n1").unwrap();
assert_eq!(actual, liquid::Value::Num(1f32));

let actual: liquid::Value = serde_yaml::from_str("---\n-100").unwrap();
assert_eq!(actual, liquid::Value::Num(-100f32));

let actual: liquid::Value = serde_yaml::from_str("---\n31399999488").unwrap();
assert_eq!(actual, liquid::Value::Num(3.14e10f32));

// Skipping NaN since equality fails

let actual: liquid::Value = serde_yaml::from_str("---\ninf").unwrap();
assert_eq!(actual, liquid::Value::Num(f32::INFINITY));
}

#[test]
pub fn serialize_bool() {
let actual = liquid::Value::Bool(true);
let actual = serde_yaml::to_string(&actual).unwrap();
assert_diff!(&actual, "---\ntrue", "", 0);

let actual = liquid::Value::Bool(false);
let actual = serde_yaml::to_string(&actual).unwrap();
assert_diff!(&actual, "---\nfalse", "", 0);
}

#[test]
pub fn deserialize_bool() {
let actual: liquid::Value = serde_yaml::from_str("---\ntrue").unwrap();
assert_eq!(actual, liquid::Value::Bool(true));

let actual: liquid::Value = serde_yaml::from_str("---\nfalse").unwrap();
assert_eq!(actual, liquid::Value::Bool(false));
}

#[test]
pub fn serialize_str() {
let actual = liquid::Value::str("Hello");
let actual = serde_yaml::to_string(&actual).unwrap();
assert_diff!(&actual, "---\nHello", "", 0);

let actual = liquid::Value::str("10");
let actual = serde_yaml::to_string(&actual).unwrap();
assert_diff!(&actual, "---\n\"10\"", "", 0);

let actual = liquid::Value::str("false");
let actual = serde_yaml::to_string(&actual).unwrap();
assert_diff!(&actual, "---\n\"false\"", "", 0);
}

#[test]
pub fn deserialize_str() {
let actual: liquid::Value = serde_yaml::from_str("---\nHello").unwrap();
assert_eq!(actual, liquid::Value::str("Hello"));

let actual: liquid::Value = serde_yaml::from_str("\"10\"\n").unwrap();
assert_eq!(actual, liquid::Value::str("10"));

let actual: liquid::Value = serde_yaml::from_str("---\n\"false\"").unwrap();
assert_eq!(actual, liquid::Value::str("false"));
}

#[test]
pub fn serialize_array() {
let actual =
vec![liquid::Value::Num(1f32), liquid::Value::Bool(true), liquid::Value::str("true")];
let actual = liquid::Value::Array(actual);
let actual = serde_yaml::to_string(&actual).unwrap();
assert_diff!(&actual, "---\n- 1\n- true\n- \"true\"", "", 0);
}

#[test]
pub fn deserialize_array() {
let actual: liquid::Value = serde_yaml::from_str("---\n- 1\n- true\n- \"true\"").unwrap();
let expected =
vec![liquid::Value::Num(1f32), liquid::Value::Bool(true), liquid::Value::str("true")];
let expected = liquid::Value::Array(expected);
assert_eq!(actual, expected);
}

#[test]
pub fn serialize_object() {
// Skipping due to HashMap ordering issues
}

#[test]
pub fn deserialize_object() {
let actual: liquid::Value = serde_yaml::from_str("---\nNum: 1\nBool: true\nStr: \"true\"")
.unwrap();
let expected: liquid::Object = [("Num".to_owned(), liquid::Value::Num(1f32)),
("Bool".to_owned(), liquid::Value::Bool(true)),
("Str".to_owned(), liquid::Value::str("true"))]
.iter()
.cloned()
.collect();
let expected = liquid::Value::Object(expected);
assert_eq!(actual, expected);
}

0 comments on commit 8ae7f5a

Please sign in to comment.