liquid_value/
values.rs

1use std::borrow;
2use std::cmp::Ordering;
3use std::fmt;
4
5use itertools;
6
7use super::map;
8use super::Scalar;
9use super::ScalarCow;
10
11/// An enum to represent different value types
12#[derive(Clone, Debug, Serialize, Deserialize)]
13#[serde(untagged)]
14pub enum Value {
15    /// A scalar value.
16    Scalar(Scalar),
17    /// A sequence of `Value`s.
18    Array(Array),
19    /// A sequence of key/`Value` pairs.
20    Object(Object),
21    /// Nothing.
22    Nil,
23    /// No content.
24    Empty,
25    /// Evaluates to empty string.
26    Blank,
27}
28
29/// Type representing a Liquid array, payload of the `Value::Array` variant
30pub type Array = Vec<Value>;
31
32/// Type representing a Liquid object, payload of the `Value::Object` variant
33pub type Object = map::Map;
34
35impl Value {
36    /// Create as a `Scalar`.
37    pub fn scalar<T: Into<Scalar>>(value: T) -> Self {
38        Value::Scalar(Scalar::new(value))
39    }
40
41    /// Create as an `Array`.
42    pub fn array<I: IntoIterator<Item = Self>>(iter: I) -> Self {
43        let v: Array = iter.into_iter().collect();
44        Value::Array(v)
45    }
46
47    /// Create as nothing.
48    pub fn nil() -> Self {
49        Value::Nil
50    }
51
52    /// A `Display` for a `Scalar` as source code.
53    pub fn source(&self) -> ValueSource<'_> {
54        ValueSource(&self)
55    }
56
57    /// A `Display` for a `Value` rendered for the user.
58    pub fn render(&self) -> ValueRendered<'_> {
59        ValueRendered(&self)
60    }
61
62    /// Interpret as a string.
63    pub fn to_str(&self) -> borrow::Cow<'_, str> {
64        match *self {
65            Value::Scalar(ref x) => x.to_str(),
66            Value::Array(ref x) => {
67                let arr: Vec<_> = x.iter().map(|v| v.render()).collect();
68                borrow::Cow::Owned(itertools::join(arr, ""))
69            }
70            Value::Object(ref x) => {
71                let arr: Vec<_> = x
72                    .iter()
73                    .map(|(k, v)| format!("{}{}", k, v.render()))
74                    .collect();
75                borrow::Cow::Owned(itertools::join(arr, ""))
76            }
77            Value::Nil | Value::Empty | Value::Blank => borrow::Cow::Borrowed(""),
78        }
79    }
80
81    /// Extracts the scalar value if it is a scalar.
82    pub fn as_scalar(&self) -> Option<&Scalar> {
83        match *self {
84            Value::Scalar(ref s) => Some(s),
85            _ => None,
86        }
87    }
88
89    /// Extracts the scalar value if it is a scalar.
90    pub fn into_scalar(self) -> Option<Scalar> {
91        match self {
92            Value::Scalar(s) => Some(s),
93            _ => None,
94        }
95    }
96
97    /// Tests whether this value is a scalar
98    pub fn is_scalar(&self) -> bool {
99        self.as_scalar().is_some()
100    }
101
102    /// Extracts the array value if it is an array.
103    pub fn as_array(&self) -> Option<&Array> {
104        match *self {
105            Value::Array(ref s) => Some(s),
106            _ => None,
107        }
108    }
109
110    /// Extracts the array value if it is an array.
111    pub fn as_array_mut(&mut self) -> Option<&mut Array> {
112        match *self {
113            Value::Array(ref mut s) => Some(s),
114            _ => None,
115        }
116    }
117
118    /// Extracts the array value if it is an array.
119    pub fn into_array(self) -> Option<Array> {
120        match self {
121            Value::Array(s) => Some(s),
122            _ => None,
123        }
124    }
125
126    /// Tests whether this value is an array
127    pub fn is_array(&self) -> bool {
128        self.as_array().is_some()
129    }
130
131    /// Extracts the object value if it is a object.
132    pub fn as_object(&self) -> Option<&Object> {
133        match *self {
134            Value::Object(ref s) => Some(s),
135            _ => None,
136        }
137    }
138
139    /// Extracts the object value if it is a object.
140    pub fn as_object_mut(&mut self) -> Option<&mut Object> {
141        match *self {
142            Value::Object(ref mut s) => Some(s),
143            _ => None,
144        }
145    }
146
147    /// Extracts the object value if it is a object.
148    pub fn into_object(self) -> Option<Object> {
149        match self {
150            Value::Object(s) => Some(s),
151            _ => None,
152        }
153    }
154
155    /// Tests whether this value is an object
156    pub fn is_object(&self) -> bool {
157        self.as_object().is_some()
158    }
159
160    /// Extracts the nil value if it is nil
161    pub fn as_nil(&self) -> Option<()> {
162        match *self {
163            Value::Nil => Some(()),
164            _ => None,
165        }
166    }
167
168    /// Tests whether this value is nil
169    pub fn is_nil(&self) -> bool {
170        match *self {
171            Value::Nil => true,
172            _ => false,
173        }
174    }
175
176    /// Extracts the empty value if it is empty
177    pub fn as_empty(&self) -> Option<()> {
178        match *self {
179            Value::Empty => Some(()),
180            _ => None,
181        }
182    }
183
184    /// Tests whether this value is empty
185    pub fn is_empty(&self) -> bool {
186        match *self {
187            Value::Empty => true,
188            _ => false,
189        }
190    }
191
192    /// Extracts the blank value if it is blank
193    pub fn as_blank(&self) -> Option<()> {
194        match *self {
195            Value::Blank => Some(()),
196            _ => None,
197        }
198    }
199
200    /// Tests whether this value is blank
201    pub fn is_blank(&self) -> bool {
202        match *self {
203            Value::Blank => true,
204            _ => false,
205        }
206    }
207
208    /// Evaluate using Liquid "truthiness"
209    pub fn is_truthy(&self) -> bool {
210        // encode Ruby truthiness: all values except false and nil are true
211        match *self {
212            Value::Scalar(ref x) => x.is_truthy(),
213            Value::Nil | Value::Empty | Value::Blank => false,
214            _ => true,
215        }
216    }
217
218    /// Whether a default constructed value.
219    pub fn is_default(&self) -> bool {
220        match *self {
221            Value::Scalar(ref x) => x.is_default(),
222            Value::Nil => true,
223            Value::Empty => true,
224            Value::Blank => true,
225            Value::Array(ref x) => x.is_empty(),
226            Value::Object(ref x) => x.is_empty(),
227        }
228    }
229
230    /// Report the data type (generally for error reporting).
231    pub fn type_name(&self) -> &'static str {
232        match *self {
233            Value::Scalar(ref x) => x.type_name(),
234            Value::Nil => "nil",
235            Value::Empty => "empty",
236            Value::Blank => "blank",
237            Value::Array(_) => "array",
238            Value::Object(_) => "object",
239        }
240    }
241
242    /// Access a contained `Value`.
243    pub fn contains_key(&self, index: &Scalar) -> bool {
244        match *self {
245            Value::Array(ref x) => {
246                if let Some(index) = index.to_integer() {
247                    let index = convert_index(index, x.len());
248                    index < x.len()
249                } else {
250                    match &*index.to_str() {
251                        "first" | "last" => true,
252                        _ => false,
253                    }
254                }
255            }
256            Value::Object(ref x) => x.contains_key(index.to_str().as_ref()),
257            _ => false,
258        }
259    }
260
261    /// Keys available for lookup.
262    pub fn keys(&self) -> Keys {
263        let v = match *self {
264            Value::Array(ref x) => {
265                let start: i32 = 0;
266                let end = x.len() as i32;
267                let mut keys: Vec<_> = (start..end).map(Scalar::new).collect();
268                keys.push(Scalar::new("first"));
269                keys.push(Scalar::new("last"));
270                keys
271            }
272            Value::Object(ref x) => x
273                .keys()
274                .map(|s| match *s {
275                    borrow::Cow::Borrowed(s) => Scalar::new(s),
276                    borrow::Cow::Owned(ref s) => Scalar::new(s.to_owned()),
277                })
278                .collect(),
279            _ => vec![],
280        };
281        Keys(v.into_iter())
282    }
283
284    /// Access a contained `Value`.
285    pub fn get<'s>(&'s self, index: &ScalarCow<'_>) -> Option<&'s Self> {
286        match *self {
287            Value::Array(ref x) => {
288                if let Some(index) = index.to_integer() {
289                    let index = convert_index(index, x.len());
290                    x.get(index as usize)
291                } else {
292                    match &*index.to_str() {
293                        "first" => x.get(0),
294                        "last" => x.get(x.len() - 1),
295                        _ => None,
296                    }
297                }
298            }
299            Value::Object(ref x) => x.get(index.to_str().as_ref()),
300            _ => None,
301        }
302    }
303}
304
305/// Iterator over a `Value`s keys.
306#[derive(Debug)]
307pub struct Keys(::std::vec::IntoIter<Scalar>);
308
309impl Iterator for Keys {
310    type Item = Scalar;
311
312    #[inline]
313    fn next(&mut self) -> Option<Scalar> {
314        self.0.next()
315    }
316
317    #[inline]
318    fn size_hint(&self) -> (usize, Option<usize>) {
319        self.0.size_hint()
320    }
321
322    #[inline]
323    fn count(self) -> usize {
324        self.0.count()
325    }
326}
327
328impl ExactSizeIterator for Keys {
329    #[inline]
330    fn len(&self) -> usize {
331        self.0.len()
332    }
333}
334
335fn convert_index(index: i32, max_size: usize) -> usize {
336    let index = index as isize;
337    let max_size = max_size as isize;
338    let index = if 0 <= index { index } else { max_size + index };
339    index as usize
340}
341
342impl Default for Value {
343    fn default() -> Self {
344        Self::nil()
345    }
346}
347
348impl PartialEq<Value> for Value {
349    fn eq(&self, other: &Self) -> bool {
350        value_eq(self, other)
351    }
352}
353
354impl Eq for Value {}
355
356impl PartialOrd<Value> for Value {
357    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
358        value_cmp(self, other)
359    }
360}
361
362/// A `Display` for a `Scalar` as source code.
363#[derive(Debug)]
364pub struct ValueSource<'s>(&'s Value);
365
366impl<'s> fmt::Display for ValueSource<'s> {
367    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
368        match self.0 {
369            Value::Scalar(ref x) => write!(f, "{}", x.render())?,
370            Value::Array(ref x) => {
371                write!(f, "[")?;
372                for item in x {
373                    write!(f, "{}, ", item.render())?;
374                }
375                write!(f, "]")?;
376            }
377            Value::Object(ref x) => {
378                write!(f, "{{")?;
379                for (k, v) in x {
380                    write!(f, r#""{}": {}, "#, k, v.render())?;
381                }
382                write!(f, "}}")?;
383            }
384            Value::Nil => write!(f, "nil")?,
385            Value::Empty => write!(f, "empty")?,
386            Value::Blank => write!(f, "blank")?,
387        }
388        Ok(())
389    }
390}
391
392/// A `Display` for a `Value` rendered for the user.
393#[derive(Debug)]
394pub struct ValueRendered<'s>(&'s Value);
395
396impl<'s> fmt::Display for ValueRendered<'s> {
397    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
398        // Must match `Value::to_str`
399        match self.0 {
400            Value::Scalar(ref x) => write!(f, "{}", x.render())?,
401            Value::Array(ref x) => {
402                for item in x {
403                    write!(f, "{}", item.render())?;
404                }
405            }
406            Value::Object(ref x) => {
407                for (k, v) in x {
408                    write!(f, "{}{}", k, v.render())?;
409                }
410            }
411            Value::Nil | Value::Empty | Value::Blank => (),
412        }
413        Ok(())
414    }
415}
416
417fn value_eq(lhs: &Value, rhs: &Value) -> bool {
418    match (lhs, rhs) {
419        (&Value::Scalar(ref x), &Value::Scalar(ref y)) => x == y,
420        (&Value::Array(ref x), &Value::Array(ref y)) => x == y,
421        (&Value::Object(ref x), &Value::Object(ref y)) => x == y,
422        (&Value::Nil, &Value::Nil)
423        | (&Value::Empty, &Value::Empty)
424        | (&Value::Blank, &Value::Blank)
425        | (&Value::Empty, &Value::Blank)
426        | (&Value::Blank, &Value::Empty) => true,
427
428        // encode a best-guess of empty rules
429        // See tables in https://stackoverflow.com/questions/885414/a-concise-explanation-of-nil-v-empty-v-blank-in-ruby-on-rails
430        (&Value::Empty, &Value::Scalar(ref s)) | (&Value::Scalar(ref s), &Value::Empty) => {
431            s.to_str().is_empty()
432        }
433        (&Value::Empty, &Value::Array(ref s)) | (&Value::Array(ref s), &Value::Empty) => {
434            s.is_empty()
435        }
436        (&Value::Empty, &Value::Object(ref s)) | (&Value::Object(ref s), &Value::Empty) => {
437            s.is_empty()
438        }
439
440        // encode a best-guess of blank rules
441        // See tables in https://stackoverflow.com/questions/885414/a-concise-explanation-of-nil-v-empty-v-blank-in-ruby-on-rails
442        (&Value::Nil, &Value::Blank) | (&Value::Blank, &Value::Nil) => true,
443        (&Value::Blank, &Value::Scalar(ref s)) | (&Value::Scalar(ref s), &Value::Blank) => {
444            s.to_str().trim().is_empty() || !s.to_bool().unwrap_or(true)
445        }
446        (&Value::Blank, &Value::Array(ref s)) | (&Value::Array(ref s), &Value::Blank) => {
447            s.is_empty()
448        }
449        (&Value::Blank, &Value::Object(ref s)) | (&Value::Object(ref s), &Value::Blank) => {
450            s.is_empty()
451        }
452
453        // encode Ruby truthiness: all values except false and nil are true
454        (&Value::Nil, &Value::Scalar(ref b)) | (&Value::Scalar(ref b), &Value::Nil) => {
455            !b.to_bool().unwrap_or(true)
456        }
457        (_, &Value::Scalar(ref b)) | (&Value::Scalar(ref b), _) => b.to_bool().unwrap_or(false),
458
459        _ => false,
460    }
461}
462
463fn value_cmp(lhs: &Value, rhs: &Value) -> Option<Ordering> {
464    match (lhs, rhs) {
465        (&Value::Scalar(ref x), &Value::Scalar(ref y)) => x.partial_cmp(y),
466        (&Value::Array(ref x), &Value::Array(ref y)) => x.iter().partial_cmp(y.iter()),
467        (&Value::Object(ref x), &Value::Object(ref y)) => x.iter().partial_cmp(y.iter()),
468        _ => None,
469    }
470}
471
472#[cfg(test)]
473mod test {
474    use super::*;
475
476    #[test]
477    fn test_to_string_scalar() {
478        let val = Value::scalar(42f64);
479        assert_eq!(&val.render().to_string(), "42");
480        assert_eq!(&val.to_str(), "42");
481    }
482
483    #[test]
484    fn test_to_string_array() {
485        let val = Value::Array(vec![
486            Value::scalar(3f64),
487            Value::scalar("test"),
488            Value::scalar(5.3),
489        ]);
490        assert_eq!(&val.render().to_string(), "3test5.3");
491        assert_eq!(&val.to_str(), "3test5.3");
492    }
493
494    // TODO make a test for object, remember values are in arbitrary orders in HashMaps
495
496    #[test]
497    fn test_to_string_nil() {
498        assert_eq!(&Value::nil().render().to_string(), "");
499        assert_eq!(&Value::nil().to_str(), "");
500    }
501
502    #[test]
503    fn scalar_equality() {
504        assert_eq!(Value::scalar("alpha"), Value::scalar("alpha"));
505        assert_eq!(Value::scalar(""), Value::scalar(""));
506        assert!(Value::scalar("alpha") != Value::scalar("beta"));
507        assert!(Value::scalar("beta") != Value::scalar("alpha"));
508    }
509
510    #[test]
511    fn scalars_have_ruby_truthiness() {
512        // all strings in ruby are true
513        assert_eq!(Value::scalar(true), Value::scalar("All strings are truthy"));
514        assert_eq!(Value::scalar(true), Value::scalar(""));
515        assert!(Value::scalar("").is_truthy());
516
517        assert_eq!(Value::scalar(true), Value::scalar(true));
518        assert!(Value::scalar(true) != Value::scalar(false));
519    }
520
521    #[test]
522    fn array_equality() {
523        let a = Value::Array(vec![Value::scalar("one"), Value::scalar("two")]);
524        let b = Value::Array(vec![Value::scalar("alpha"), Value::scalar("beta")]);
525
526        assert_eq!(a, a);
527        assert!(a != b);
528        assert!(b != a);
529    }
530
531    #[test]
532    fn arrays_have_ruby_truthiness() {
533        assert_eq!(Value::scalar(true), Value::Array(Vec::new()));
534        assert!(Value::Array(Vec::new()).is_truthy());
535    }
536
537    #[test]
538    fn object_equality() {
539        let a: Object = [
540            ("alpha".into(), Value::scalar("1")),
541            ("beta".into(), Value::scalar(2f64)),
542        ]
543        .iter()
544        .cloned()
545        .collect();
546        let a = Value::Object(a);
547
548        let b: Object = [
549            ("alpha".into(), Value::scalar("1")),
550            ("beta".into(), Value::scalar(2f64)),
551            ("gamma".into(), Value::Array(vec![])),
552        ]
553        .iter()
554        .cloned()
555        .collect();
556        let b = Value::Object(b);
557
558        assert_eq!(a, a);
559        assert!(a != b);
560        assert!(b != a);
561    }
562
563    #[test]
564    fn objects_have_ruby_truthiness() {
565        assert_eq!(Value::scalar(true), Value::Object(Object::new()));
566        assert!(Value::Object(Object::new()).is_truthy());
567    }
568
569    #[test]
570    fn nil_equality() {
571        assert_eq!(Value::Nil, Value::Nil);
572    }
573
574    #[test]
575    fn nils_have_ruby_truthiness() {
576        assert_eq!(Value::scalar(false), Value::Nil);
577        assert!(!Value::Nil.is_truthy());
578
579        assert_eq!(Value::scalar(false), Value::Nil);
580        assert!(Value::scalar(true) != Value::Nil);
581        assert!(Value::scalar("") != Value::Nil);
582    }
583
584    #[test]
585    fn empty_equality() {
586        // Truth table from https://stackoverflow.com/questions/885414/a-concise-explanation-of-nil-v-empty-v-blank-in-ruby-on-rails
587        assert_eq!(Value::Empty, Value::Empty);
588        assert_eq!(Value::Empty, Value::Blank);
589        assert_eq!(Value::Empty, liquid_value!(""));
590        assert_ne!(Value::Empty, liquid_value!(" "));
591        assert_eq!(Value::Empty, liquid_value!([]));
592        assert_ne!(Value::Empty, liquid_value!([nil]));
593        assert_eq!(Value::Empty, liquid_value!({}));
594        assert_ne!(Value::Empty, liquid_value!({ "a": nil }));
595    }
596
597    #[test]
598    fn blank_equality() {
599        // Truth table from https://stackoverflow.com/questions/885414/a-concise-explanation-of-nil-v-empty-v-blank-in-ruby-on-rails
600        assert_eq!(Value::Blank, Value::Blank);
601        assert_eq!(Value::Blank, Value::Empty);
602        assert_eq!(Value::Blank, liquid_value!(nil));
603        assert_eq!(Value::Blank, liquid_value!(false));
604        assert_ne!(Value::Blank, liquid_value!(true));
605        assert_ne!(Value::Blank, liquid_value!(0));
606        assert_ne!(Value::Blank, liquid_value!(1));
607        assert_eq!(Value::Blank, liquid_value!(""));
608        assert_eq!(Value::Blank, liquid_value!(" "));
609        assert_eq!(Value::Blank, liquid_value!([]));
610        assert_ne!(Value::Blank, liquid_value!([nil]));
611        assert_eq!(Value::Blank, liquid_value!({}));
612        assert_ne!(Value::Blank, liquid_value!({ "a": nil }));
613    }
614}