use Row;
use std::fmt;
use std::borrow::Cow;
use std::borrow::Borrow;
#[derive(Clone, Debug)]
pub enum Value<'a, T: Clone + 'a> {
Const(Cow<'a, T>),
Column(usize),
}
impl<'a, T: Clone + 'a> Value<'a, T> {
pub fn value<'b: 'a, R: Row<T> + ?Sized>(&'b self, row: &'b R) -> &'b T {
match *self {
Value::Column(i) => &row.index(i),
Value::Const(ref val) => val,
}
}
pub fn new<I: Into<T>>(t: I) -> Self {
Value::Const(Cow::Owned(t.into()))
}
pub fn using<I: Borrow<T>>(t: &'a I) -> Self {
Value::Const(Cow::Borrowed(t.borrow()))
}
pub fn column(c: usize) -> Self {
Value::Column(c)
}
}
#[derive(Clone, Debug)]
pub enum Comparison<'a, T: Clone + 'a> {
Equal(Value<'a, T>),
}
impl<'a, T: Ord + Clone + 'a> Comparison<'a, T> {
pub fn matches<R: Row<T> + ?Sized>(&self, value: &T, row: &R) -> bool {
match *self {
Comparison::Equal(ref v) => value == v.value(row),
}
}
}
#[derive(Clone, Debug)]
pub struct Condition<'a, T: Clone + 'a> {
pub column: usize,
pub cmp: Comparison<'a, T>,
}
impl<'a, T: Ord + Clone + 'a> Condition<'a, T> {
pub fn matches<R: Row<T> + ?Sized>(&self, row: &R) -> bool {
self.cmp.matches(&row.index(self.column), row)
}
}
impl<'a, T: fmt::Display + Clone + 'a> fmt::Display for Value<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Value::Column(i) => write!(f, "[{}]", i),
Value::Const(ref val) => write!(f, "{}", val),
}
}
}
impl<'a, T: fmt::Display + Clone + 'a> fmt::Display for Comparison<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Comparison::Equal(ref v) => write!(f, "= {}", v),
}
}
}
impl<'a, T: fmt::Display + Clone + 'a> fmt::Display for Condition<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}] {}", self.column, self.cmp)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn value() {
let a = &["a"];
let b = &["b"];
assert_eq!(Value::column(0).value(&a[..]), &"a");
assert_eq!(Value::new("a").value(&b[..]), &"a");
}
#[test]
fn cmp_eq() {
let a = &["a"];
let b = &["b"];
assert!(Comparison::Equal(Value::column(0)).matches(&"a", &a[..]));
assert!(!Comparison::Equal(Value::column(0)).matches(&"a", &b[..]));
assert!(Comparison::Equal(Value::new("a")).matches(&"a", &b[..]));
assert!(!Comparison::Equal(Value::new("b")).matches(&"a", &a[..]));
}
#[test]
fn borrowed_values() {
let a = vec!["a".to_string()];
let b = vec!["b".to_string()];
assert!(Comparison::Equal(Value::column(0)).matches(&a[0], &a));
assert!(!Comparison::Equal(Value::column(0)).matches(&a[0], &b));
assert!(Comparison::Equal(Value::using(&a[0])).matches(&a[0], &b));
assert!(!Comparison::Equal(Value::using(&b[0])).matches(&a[0], &a));
}
#[test]
fn through_deref() {
let a = vec!["a".to_string()];
let b = vec!["b".to_string()];
assert!(Comparison::Equal(Value::column(0)).matches(&a[0], &a));
assert!(!Comparison::Equal(Value::column(0)).matches(&a[0], &b));
assert!(Comparison::Equal(Value::new("a")).matches(&a[0], &b));
assert!(!Comparison::Equal(Value::new("b")).matches(&a[0], &a));
}
#[test]
fn cond_eq() {
let cmpf0 = Comparison::Equal(Value::column(0));
let cmpca = Comparison::Equal(Value::new("a"));
let cmpcb = Comparison::Equal(Value::new("b"));
let cf10 = Condition {
column: 1,
cmp: cmpf0,
};
let cca = Condition {
column: 0,
cmp: cmpca,
};
let ccb = Condition {
column: 0,
cmp: cmpcb,
};
let a = &["a"];
let b = &["b"];
let aa = &["a", "a"];
let ab = &["a", "b"];
assert!(cf10.matches(&aa[..]));
assert!(!cf10.matches(&ab[..]));
assert!(cca.matches(&a[..]));
assert!(!cca.matches(&b[..]));
assert!(ccb.matches(&b[..]));
assert!(!ccb.matches(&a[..]));
}
#[test]
fn display() {
let cf01: Condition<String> = Condition {
column: 0,
cmp: Comparison::Equal(Value::Column(1)),
};
let cca = Condition {
column: 0,
cmp: Comparison::Equal::<&str>(Value::new("a")),
};
assert_eq!(format!("{}", cf01), "[0] = [1]");
assert_eq!(format!("{}", cca), "[0] = a")
}
}