shortcut/
cmp.rs

1use Row;
2use std::fmt;
3use std::borrow::Cow;
4use std::borrow::Borrow;
5
6/// A value represents something to compare against.
7#[derive(Clone, Debug)]
8pub enum Value<'a, T: Clone + 'a> {
9    /// A constant value literal.
10    Const(Cow<'a, T>),
11
12    /// A different column for the same row. Note that comparisons of this kind *cannot use an
13    /// index*, at least not in the current implementation.
14    Column(usize),
15}
16
17impl<'a, T: Clone + 'a> Value<'a, T> {
18    /// Extract the value literal for this `Value` when evaluated for the given row.
19    /// For `Const` values, this evaluates to the `Const` value itself. For `Column`, it evaluates
20    /// to the value of that column in the given row.
21    pub fn value<'b: 'a, R: Row<T> + ?Sized>(&'b self, row: &'b R) -> &'b T {
22        match *self {
23            Value::Column(i) => &row.index(i),
24            Value::Const(ref val) => val,
25        }
26    }
27
28    /// Construct a new `Value` by moving an existing value.
29    pub fn new<I: Into<T>>(t: I) -> Self {
30        Value::Const(Cow::Owned(t.into()))
31    }
32
33    /// Construct a new `Value` by using a reference to an existing value.
34    pub fn using<I: Borrow<T>>(t: &'a I) -> Self {
35        Value::Const(Cow::Borrowed(t.borrow()))
36    }
37
38    /// Construct a new `Value` that refers to the value in a particular column of a row.
39    pub fn column(c: usize) -> Self {
40        Value::Column(c)
41    }
42}
43
44/// A comparison to perform for a literal value against a `Value`.
45#[derive(Clone, Debug)]
46pub enum Comparison<'a, T: Clone + 'a> {
47    /// Is the value equal to the given `Value`?
48    Equal(Value<'a, T>),
49}
50
51impl<'a, T: Ord + Clone + 'a> Comparison<'a, T> {
52    /// Returns true if the given value compares successfully against this `Value` when evaluated
53    /// against the given row.
54    pub fn matches<R: Row<T> + ?Sized>(&self, value: &T, row: &R) -> bool {
55        match *self {
56            Comparison::Equal(ref v) => value == v.value(row),
57        }
58    }
59}
60
61/// A single condition to evaluate for a row in the dataset.
62#[derive(Clone, Debug)]
63pub struct Condition<'a, T: Clone + 'a> {
64    /// The column of the row to use as the comparison value.
65    pub column: usize,
66
67    /// The comparison to perform on the selected value.
68    pub cmp: Comparison<'a, T>,
69}
70
71impl<'a, T: Ord + Clone + 'a> Condition<'a, T> {
72    /// Returns true if this condition holds true for the given row. To determine if this is the
73    /// case, `row[self.column]` is extracted, and is evaluated using the comparison in `self.cmp`.
74    pub fn matches<R: Row<T> + ?Sized>(&self, row: &R) -> bool {
75        self.cmp.matches(&row.index(self.column), row)
76    }
77}
78
79impl<'a, T: fmt::Display + Clone + 'a> fmt::Display for Value<'a, T> {
80    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81        match *self {
82            Value::Column(i) => write!(f, "[{}]", i),
83            Value::Const(ref val) => write!(f, "{}", val),
84        }
85    }
86}
87
88impl<'a, T: fmt::Display + Clone + 'a> fmt::Display for Comparison<'a, T> {
89    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
90        match *self {
91            Comparison::Equal(ref v) => write!(f, "= {}", v),
92        }
93    }
94}
95
96impl<'a, T: fmt::Display + Clone + 'a> fmt::Display for Condition<'a, T> {
97    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98        write!(f, "[{}] {}", self.column, self.cmp)
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105
106    #[test]
107    fn value() {
108        let a = &["a"];
109        let b = &["b"];
110        assert_eq!(Value::column(0).value(&a[..]), &"a");
111        assert_eq!(Value::new("a").value(&b[..]), &"a");
112    }
113
114    #[test]
115    fn cmp_eq() {
116        let a = &["a"];
117        let b = &["b"];
118        assert!(Comparison::Equal(Value::column(0)).matches(&"a", &a[..]));
119        assert!(!Comparison::Equal(Value::column(0)).matches(&"a", &b[..]));
120        assert!(Comparison::Equal(Value::new("a")).matches(&"a", &b[..]));
121        assert!(!Comparison::Equal(Value::new("b")).matches(&"a", &a[..]));
122    }
123
124    #[test]
125    fn borrowed_values() {
126        let a = vec!["a".to_string()];
127        let b = vec!["b".to_string()];
128        assert!(Comparison::Equal(Value::column(0)).matches(&a[0], &a));
129        assert!(!Comparison::Equal(Value::column(0)).matches(&a[0], &b));
130        assert!(Comparison::Equal(Value::using(&a[0])).matches(&a[0], &b));
131        assert!(!Comparison::Equal(Value::using(&b[0])).matches(&a[0], &a));
132    }
133
134    #[test]
135    fn through_deref() {
136        let a = vec!["a".to_string()];
137        let b = vec!["b".to_string()];
138        assert!(Comparison::Equal(Value::column(0)).matches(&a[0], &a));
139        assert!(!Comparison::Equal(Value::column(0)).matches(&a[0], &b));
140        assert!(Comparison::Equal(Value::new("a")).matches(&a[0], &b));
141        assert!(!Comparison::Equal(Value::new("b")).matches(&a[0], &a));
142    }
143
144    #[test]
145    fn cond_eq() {
146        let cmpf0 = Comparison::Equal(Value::column(0));
147        let cmpca = Comparison::Equal(Value::new("a"));
148        let cmpcb = Comparison::Equal(Value::new("b"));
149
150        let cf10 = Condition {
151            column: 1,
152            cmp: cmpf0,
153        };
154        let cca = Condition {
155            column: 0,
156            cmp: cmpca,
157        };
158        let ccb = Condition {
159            column: 0,
160            cmp: cmpcb,
161        };
162
163        let a = &["a"];
164        let b = &["b"];
165        let aa = &["a", "a"];
166        let ab = &["a", "b"];
167        assert!(cf10.matches(&aa[..]));
168        assert!(!cf10.matches(&ab[..]));
169        assert!(cca.matches(&a[..]));
170        assert!(!cca.matches(&b[..]));
171        assert!(ccb.matches(&b[..]));
172        assert!(!ccb.matches(&a[..]));
173    }
174
175    #[test]
176    fn display() {
177        let cf01: Condition<String> = Condition {
178            column: 0,
179            cmp: Comparison::Equal(Value::Column(1)),
180        };
181
182        let cca = Condition {
183            column: 0,
184            cmp: Comparison::Equal::<&str>(Value::new("a")),
185        };
186
187        assert_eq!(format!("{}", cf01), "[0] = [1]");
188        assert_eq!(format!("{}", cca), "[0] = a")
189    }
190}