by/
search.rs

1// Copyright 2018 Eduardo Sánchez Muñoz
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use ByteStr;
9
10// Matcher
11pub trait Matcher {}
12
13// IntoMatcher
14pub trait IntoMatcher {
15    type Matcher: Matcher;
16    
17    fn into_matcher(self) -> Self::Matcher;
18}
19
20// PrefixMatcher
21pub trait PrefixMatcher: Matcher {
22    fn is_prefix_of(&self, haystack: &ByteStr) -> bool;
23}
24
25// SufixMatcher
26pub trait SufixMatcher: Matcher {
27    fn is_sufix_of(&self, haystack: &ByteStr) -> bool;
28}
29
30// FullMatcher
31pub trait FullMatcher: Matcher {
32    fn matches(&self, haystack: &ByteStr) -> bool;
33}
34
35// ForwardSearcher
36pub trait ForwardSearcher: Matcher {
37    fn find(&self, haystack: &ByteStr) -> Option<(usize, usize)>;
38}
39
40// ReverseSearcher
41pub trait ReverseSearcher: Matcher {
42    fn rfind(&self, haystack: &ByteStr) -> Option<(usize, usize)>;
43}
44
45// DoubleEndedSearcher
46pub trait DoubleEndedSearcher: ForwardSearcher + ReverseSearcher {}
47
48// StrMatcher
49pub struct StrMatcher<'a> {
50    needle: &'a ByteStr,
51}
52
53impl<'a> StrMatcher<'a> {
54    #[inline]
55    pub fn new(needle: &'a ByteStr) -> Self {
56        Self { needle: needle }
57    }
58}
59
60impl<'a> Matcher for StrMatcher<'a> {}
61
62impl<'a, T: AsRef<[u8]>> IntoMatcher for &'a T {
63    type Matcher = StrMatcher<'a>;
64    
65    #[inline]
66    fn into_matcher(self) -> StrMatcher<'a> {
67        StrMatcher::new(ByteStr::from_slice(self.as_ref()))
68    }
69}
70
71impl<'a> PrefixMatcher for StrMatcher<'a> {
72    fn is_prefix_of(&self, haystack: &ByteStr) -> bool {
73        haystack.len() >= self.needle.len() && haystack[0 .. self.needle.len()] == self.needle[..]
74    }
75}
76
77impl<'a> SufixMatcher for StrMatcher<'a> {
78    fn is_sufix_of(&self, haystack: &ByteStr) -> bool {
79        haystack.len() >= self.needle.len() &&
80            haystack[haystack.len() - self.needle.len() .. haystack.len()] == self.needle[..]
81    }
82}
83
84impl<'a> FullMatcher for StrMatcher<'a> {
85    #[inline]
86    fn matches(&self, haystack: &ByteStr) -> bool {
87        haystack == self.needle
88    }
89}
90
91impl<'a> ForwardSearcher for StrMatcher<'a> {
92    fn find(&self, haystack: &ByteStr) -> Option<(usize, usize)> {
93        for (i, window) in haystack.windows(self.needle.len()).enumerate() {
94            if window == self.needle {
95                return Some((i, i + self.needle.len()));
96            }
97        }
98        None
99    }
100}
101
102impl<'a> ReverseSearcher for StrMatcher<'a> {
103    fn rfind(&self, haystack: &ByteStr) -> Option<(usize, usize)> {
104        for (i, window) in haystack.windows(self.needle.len()).enumerate().rev() {
105            if window == self.needle {
106                return Some((i, i + self.needle.len()));
107            }
108        }
109        None
110    }
111}
112
113// ByteMatcher
114pub struct ByteMatcher {
115    needle: u8,
116}
117
118impl ByteMatcher {
119    #[inline]
120    pub fn new(needle: u8) -> Self {
121        ByteMatcher { needle: needle }
122    }
123}
124
125impl Matcher for ByteMatcher {}
126
127impl IntoMatcher for u8 {
128    type Matcher = ByteMatcher;
129    
130    fn into_matcher(self) -> ByteMatcher {
131        ByteMatcher::new(self)
132    }
133}
134
135impl PrefixMatcher for ByteMatcher {
136    #[inline]
137    fn is_prefix_of(&self, haystack: &ByteStr) -> bool {
138        haystack.first().map_or(false, |&byte| byte == self.needle)
139    }
140}
141
142impl SufixMatcher for ByteMatcher {
143    #[inline]
144    fn is_sufix_of(&self, haystack: &ByteStr) -> bool {
145        haystack.last().map_or(false, |&byte| byte == self.needle)
146    }
147}
148
149impl FullMatcher for ByteMatcher {
150    #[inline]
151    fn matches(&self, haystack: &ByteStr) -> bool {
152        haystack == [self.needle]
153    }
154}
155
156impl ForwardSearcher for ByteMatcher {
157    fn find(&self, haystack: &ByteStr) -> Option<(usize, usize)> {
158        for (i, &byte) in haystack.iter().enumerate() {
159            if byte == self.needle {
160                return Some((i, i + 1));
161            }
162        }
163        None
164    }
165}
166
167impl ReverseSearcher for ByteMatcher {
168    fn rfind(&self, haystack: &ByteStr) -> Option<(usize, usize)> {
169        for (i, &byte) in haystack.iter().enumerate().rev() {
170            if byte == self.needle {
171                return Some((i, i + 1));
172            }
173        }
174        None
175    }
176}
177
178impl DoubleEndedSearcher for ByteMatcher {}