sea_canal/
pattern.rs

1use std::fmt::{Display, Formatter, Error};
2use std::iter::FromIterator;
3use std::slice::Iter;
4
5use repeat::is_repeating_with_predicate;
6
7/// Operations from one integer to another.
8#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
9pub enum PatternElem {
10    // Listed alphabetically to make equality sorting intuitive.
11    Const(i32),
12    Cube,
13    CubeRoot,
14    Custom(CustomPatternElem),
15    Div(i32),
16    Meta(Pattern),
17    Mod(i32),
18    Mult(i32),
19    Plus(i32),
20    Square,
21    SquareRoot,
22}
23
24impl PatternElem {
25    pub fn get_operand(&self) -> Option<i32> {
26        match *self {
27            PatternElem::Plus(i) | PatternElem::Mult(i) |
28            PatternElem::Div(i) | PatternElem::Mod(i) => Some(i),
29            _ => None
30        }
31    }
32
33    pub fn same_operator_type(&self, other: &Self) -> bool {
34        match (self, other) {
35            (&PatternElem::Custom(ref p1), &PatternElem::Custom(ref p2)) => p1 == p2,
36            (&PatternElem::Const(_), &PatternElem::Const(_)) |
37            (&PatternElem::Cube, &PatternElem::Cube) |
38            (&PatternElem::CubeRoot, &PatternElem::CubeRoot) |
39            (&PatternElem::Div(_), &PatternElem::Div(_)) |
40            (&PatternElem::Mod(_), &PatternElem::Mod(_)) |
41            (&PatternElem::Mult(_), &PatternElem::Mult(_)) |
42            (&PatternElem::Plus(_), &PatternElem::Plus(_)) |
43            (&PatternElem::Square, &PatternElem::SquareRoot) |
44            (&PatternElem::SquareRoot, &PatternElem::SquareRoot) => true,
45            _ => false
46        }
47    }
48}
49
50#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
51pub struct CustomPatternElem {
52    check: fn(i32, i32) -> bool,
53    repr: String,
54}
55
56impl CustomPatternElem {
57    pub fn new(check: fn(i32, i32) -> bool, repr: &str) -> Self {
58        CustomPatternElem { check: check, repr: String::from(repr) }
59    }
60
61    pub fn check(&self, x: i32, y: i32) -> bool {
62        let check = self.check;
63        check(x, y)
64    }
65}
66
67impl Display for PatternElem {
68    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
69        match *self {
70            PatternElem::Const(i) => write!(fmt, "={}", i),
71            PatternElem::Plus(i) if i < 0 => write!(fmt, "-{}", i.abs()),
72            PatternElem::Plus(i) => write!(fmt, "+{}", i),
73            PatternElem::Mult(i) => write!(fmt, "*{}", i),
74            PatternElem::Div(i) => write!(fmt, "/{}", i),
75            PatternElem::Mod(i) => write!(fmt, "%{}", i),
76            PatternElem::Square => write!(fmt, "^2"),
77            PatternElem::Cube => write!(fmt, "^3"),
78            PatternElem::SquareRoot => write!(fmt, "root 2"),
79            PatternElem::CubeRoot => write!(fmt, "root 3"),
80            PatternElem::Custom(CustomPatternElem { ref repr, .. }) => write!(fmt, "{}", repr),
81            PatternElem::Meta(ref pat) => write!(fmt, "[{}...]", pat),
82        }
83    }
84}
85
86/// A sequence of operations defining a pattern.
87#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
88pub struct Pattern(Vec<PatternElem>);
89
90impl IntoIterator for Pattern {
91    type Item = PatternElem;
92    type IntoIter = ::std::vec::IntoIter<PatternElem>;
93
94    fn into_iter(self) -> Self::IntoIter {
95        self.0.into_iter()
96    }
97}
98
99impl FromIterator<PatternElem> for Pattern {
100    fn from_iter<I: IntoIterator<Item=PatternElem>>(iterator: I) -> Self {
101        Pattern(iterator.into_iter().collect())
102    }
103}
104
105#[macro_export]
106macro_rules! pat {
107    ($($elem:expr),*) => (Pattern::new(vec![$($elem),*]))
108}
109
110impl Pattern {
111    /// Constructs a new pattern given a vector of operations.
112    pub fn new(elems: Vec<PatternElem>) -> Self {
113        Pattern(elems)
114    }
115
116    /// Constructs a new empty pattern.
117    pub fn empty() -> Self {
118        Pattern::new(Vec::new())
119    }
120
121    pub fn len(&self) -> usize {
122        self.0.len()
123    }
124
125    pub fn is_empty(&self) -> bool {
126        self.0.is_empty()
127    }
128
129    /// Appends each of the items in `iter` to the pattern separately, returning a vector of
130    /// patterns.
131    ///
132    /// ```
133    /// # #[macro_use] extern crate sea_canal;
134    /// # use sea_canal::Pattern;
135    /// # use sea_canal::PatternElem::{Plus, Mult, Div};
136    /// # fn main() {
137    /// let pat = pat![Plus(3), Mult(2)];
138    /// let pats = pat.extend_each(vec![Div(2), Div(3)].into_iter());
139    /// assert_eq!(pats, vec![pat![Plus(3), Mult(2), Div(2)], pat![Plus(3), Mult(2), Div(3)]]);
140    /// # }
141    /// ```
142    pub fn extend_each<T>(&self, iter: T) -> Vec<Self> where T: Iterator<Item=PatternElem> {
143        iter.map(|elem| {
144            let mut v = self.0.clone();
145            v.push(elem);
146            Pattern::new(v)
147        }).collect()
148    }
149
150    pub fn iter(&self) -> Iter<PatternElem> {
151        self.0.iter()
152    }
153
154    pub fn has_repeating_types(&self) -> bool {
155        is_repeating_with_predicate(&self.0, |x, y| x.same_operator_type(y))
156    }
157}
158
159impl Display for Pattern {
160    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
161        for (i, elem) in self.0.iter().enumerate() {
162            if i != 0 {
163                try!(write!(fmt, ", "));
164            }
165
166            try!(write!(fmt, "{}", elem));
167        }
168
169        Ok(())
170    }
171}
172
173#[cfg(test)]
174mod tests {
175    use super::PatternElem::*;
176    use super::Pattern;
177
178    #[test]
179    fn fmt_pat_elem_plus() {
180        assert_eq!("+0", format!("{}", Plus(0)));
181        assert_eq!("+4", format!("{}", Plus(4)));
182    }
183
184    #[test]
185    fn fmt_pat_elem_minus() {
186        assert_eq!("-1", format!("{}", Plus(-1)));
187        assert_eq!("-4", format!("{}", Plus(-4)));
188    }
189
190    #[test]
191    fn fmt_pat_elem_mult() {
192        assert_eq!("*-4", format!("{}", Mult(-4)));
193        assert_eq!("*4", format!("{}", Mult(4)));
194    }
195
196    #[test]
197    fn fmt_pat_elem_div() {
198        assert_eq!("/-4", format!("{}", Div(-4)));
199        assert_eq!("/4", format!("{}", Div(4)));
200    }
201
202    #[test]
203    fn fmt_pat_elem_mod() {
204        assert_eq!("%-4", format!("{}", Mod(-4)));
205        assert_eq!("%4", format!("{}", Mod(4)));
206    }
207
208    #[test]
209    fn fmt_pat_elem_const() {
210        assert_eq!("=-4", format!("{}", Const(-4)));
211        assert_eq!("=4", format!("{}", Const(4)));
212    }
213
214    #[test]
215    fn fmt_pat_elem_square() {
216        assert_eq!("^2", format!("{}", Square));
217    }
218
219    #[test]
220    fn fmt_pat_elem_cube() {
221        assert_eq!("^3", format!("{}", Cube));
222    }
223
224    #[test]
225    fn fmt_pat_elem_square_root() {
226        assert_eq!("root 2", format!("{}", SquareRoot));
227    }
228
229    #[test]
230    fn fmt_pat_elem_cube_root() {
231        assert_eq!("root 3", format!("{}", CubeRoot));
232    }
233
234    #[test]
235    fn fmt_pat() {
236        assert_eq!("", format!("{}", Pattern::empty()));
237        assert_eq!("+4", format!("{}", pat![Plus(4)]));
238        assert_eq!("+4, %-6", format!("{}", pat![Plus(4), Mod(-6)]));
239        assert_eq!("+4, %-6, -12, *42, /3, =9", format!("{}", pat![Plus(4), Mod(-6), Plus(-12), Mult(42), Div(3), Const(9)]));
240        assert_eq!("^2, root 2, ^3, root 3", format!("{}", pat![Square, SquareRoot, Cube, CubeRoot]));
241    }
242}