1use std::fmt::{Display, Formatter, Error};
2use std::iter::FromIterator;
3use std::slice::Iter;
4
5use repeat::is_repeating_with_predicate;
6
7#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
9pub enum PatternElem {
10 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#[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 pub fn new(elems: Vec<PatternElem>) -> Self {
113 Pattern(elems)
114 }
115
116 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 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}