diff --git a/.travis.yml b/.travis.yml index f6f871376..e9366fcc1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,11 +36,11 @@ script: - rustc -Vv - cargo -V - cargo check --verbose - - cargo check --verbose --features "cli" - - cargo check --verbose --features "cli serde_yaml serde_json" + - cargo check --verbose --no-default-features + - cargo check --verbose --features "cli serde_json object_sorted" - cargo clean - - cargo test --verbose --features "cli serde_yaml serde_json" - - cargo when --channel nightly bench --features "cli serde_yaml serde_json" + - cargo test --verbose --features "cli serde_json" + - cargo when --channel nightly bench --features "cli serde_json" - cargo when --channel stable doc --no-deps --all-features after_success: diff --git a/Cargo.toml b/Cargo.toml index 1ec59ef6f..3b1e54bc6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,8 @@ default = ["extra-filters", "serde"] cli = ["clap", "error-chain", "serde_yaml"] extra-filters = [] dev = [] +# Ensure keys in `Value`s `Object`s to be sorted. +object_sorted = [] [dependencies] regex = "0.2" diff --git a/appveyor.yml b/appveyor.yml index 1672f7c3f..20734cda4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,10 +27,10 @@ test_script: - rustc -Vv - cargo -V - cargo check --verbose - - cargo check --verbose --features "cli" - - cargo check --verbose --features "cli serde serde_yaml serde_json" + - cargo check --verbose --no-default-features + - cargo check --verbose --features "cli serde_json object_sorted" - cargo clean - - cargo test --verbose --features "cli serde serde_yaml serde_json" + - cargo test --verbose --features "cli serde_json" cache: - C:\Users\appveyor\.cargo\registry diff --git a/src/filters/date.rs b/src/filters/date.rs index 61f209a10..6d3adec24 100644 --- a/src/filters/date.rs +++ b/src/filters/date.rs @@ -1,12 +1,14 @@ -#[cfg(feature = "extra-filters")] -use chrono::FixedOffset; - use value::Value; use value::Scalar; -use interpreter::{FilterError, FilterResult}; +use interpreter::FilterResult; use super::check_args_len; +#[cfg(feature = "extra-filters")] +use chrono::FixedOffset; +#[cfg(feature = "extra-filters")] +use interpreter::FilterError; + pub fn date(input: &Value, args: &[Value]) -> FilterResult { check_args_len(args, 1, 0)?; diff --git a/src/filters/mod.rs b/src/filters/mod.rs index 6be1188de..4fda1bd4c 100644 --- a/src/filters/mod.rs +++ b/src/filters/mod.rs @@ -598,7 +598,7 @@ pub fn pluralize(input: &Value, args: &[Value]) -> FilterResult { #[cfg(test)] mod tests { - use std::collections::HashMap; + use value::Object; use super::*; macro_rules! unit { @@ -1371,7 +1371,7 @@ mod tests { &[Value::scalar(1_f32)]), Value::Array(vec![tos!("")])); assert_eq!(unit!(default, - Value::Object(HashMap::new()), + Value::Object(Object::new()), &[Value::scalar(1_f32)]), Value::scalar(1_f32)); assert_eq!(unit!(default, Value::scalar(false), &[Value::scalar(1_f32)]), diff --git a/src/tags/for_block.rs b/src/tags/for_block.rs index 5141e7610..f959122d5 100644 --- a/src/tags/for_block.rs +++ b/src/tags/for_block.rs @@ -1,4 +1,3 @@ -use std::collections::HashMap; use std::slice::Iter; use error::{Error, Result}; @@ -11,7 +10,7 @@ use compiler::Element; use compiler::LiquidOptions; use compiler::Token; use compiler::{parse, expect, split_block}; -use value::Value; +use value::{Value, Object}; #[derive(Clone, Debug)] enum Range { @@ -95,7 +94,7 @@ impl Renderable for For { range_len => { let mut ret = String::default(); context.run_in_scope(|mut scope| { - let mut helper_vars: HashMap = HashMap::new(); + let mut helper_vars = Object::new(); helper_vars.insert("length".to_owned(), Value::scalar(range_len as i32)); for (i, v) in slice.iter().enumerate() { diff --git a/src/tags/if_block.rs b/src/tags/if_block.rs index d7fd7c19d..6c248ce2d 100644 --- a/src/tags/if_block.rs +++ b/src/tags/if_block.rs @@ -155,9 +155,9 @@ pub fn if_block(_tag_name: &str, #[cfg(test)] mod test { - use std::collections::HashMap; use super::*; use value::Value; + use value::Object; use compiler; use interpreter; @@ -418,7 +418,7 @@ mod test { .unwrap(); let mut context = Context::new(); - let mut obj = HashMap::new(); + let mut obj = Object::new(); obj.insert("Star Wars".to_owned(), Value::scalar("1977")); context.set_global_val("movies", Value::Object(obj)); let output = template.render(&mut context).unwrap(); @@ -434,7 +434,7 @@ mod test { .unwrap(); let mut context = Context::new(); - let obj = HashMap::new(); + let obj = Object::new(); context.set_global_val("movies", Value::Object(obj)); let output = template.render(&mut context).unwrap(); assert_eq!(output, Some("if false".to_owned())); diff --git a/src/value/values.rs b/src/value/values.rs index 9b4e8edf7..249bb9fc9 100644 --- a/src/value/values.rs +++ b/src/value/values.rs @@ -1,11 +1,22 @@ -use std::collections::HashMap; use std::cmp::Ordering; use std::fmt; use std::borrow; +#[cfg(feature = "object_sorted")] +use std::collections::BTreeMap; + +#[cfg(not(any(feature = "object_sorted")))] +use std::collections::HashMap; + use super::Index; use super::Scalar; +#[cfg(feature = "object_sorted")] +type MapImpl = BTreeMap; + +#[cfg(not(any(feature = "object_sorted")))] +type MapImpl = HashMap; + /// An enum to represent different value types #[derive(Clone, Debug)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] @@ -21,7 +32,7 @@ pub enum Value { pub type Array = Vec; /// Type representing a Liquid object, payload of the `Value::Object` variant -pub type Object = HashMap; +pub type Object = MapImpl; impl Value { pub fn scalar>(value: T) -> Self {