query_range/range/
utility.rs1use std::ops::Range;
2use num::{PrimInt};
3
4pub fn to_title_case(content: &str) -> String {
8 if content.len() > 1 {
9 format!("{}{}", &content[0..1].to_uppercase(), &content[1..].to_lowercase())
10 } else if content.len() == 1 {
11 content[0..1].to_uppercase()
12 } else {
13 String::new()
14 }
15}
16
17pub fn get_range(query: &str, content: &str) -> Option<Range<usize>> {
19 let possible_start = content.find(query);
20 if let Some(start) = possible_start {
21 let end: usize = start + query.len();
22 if end > content.len() {
23 None
24 } else {
25 Some(start..end)
26 }
27 } else {
28 None
29 }
30}
31
32pub enum Shift<T> where T: PrimInt {
34 Up(T),
36 Down(T),
38}
39
40impl<T> Shift<T> where T: PrimInt {
41
42 fn apply_to_number(&self, number: T) -> Option<T> {
45 match self {
46 Shift::Up(amount) => number.checked_add(amount),
47 Shift::Down(amount) => number.checked_sub(amount),
48 }
49 }
50
51 fn apply_to_range(&self, range: Range<T>) -> Option<Range<T>> {
54 let Range { start, end } = range;
55 let (new_start, new_end) = match self {
56 Shift::Up(amount) => (start.checked_add(amount), end.checked_add(amount)),
57 Shift::Down(amount) => (start.checked_sub(amount), end.checked_sub(amount)),
58 };
59 if let (Some(new_start), Some(new_end)) = (new_start, new_end) {
60 Some(new_start..new_end)
61 } else {
62 None
63 }
64 }
65}
66
67pub fn shift_range<T>(range: Range<T>, shift: Shift<T>) -> Option<Range<T>> where T: PrimInt {
82 shift.apply_to_range(range)
83}
84
85pub fn shift_range_in_content<T>(range: Range<T>, shift: Shift<T>, content: &str) -> Option<Range<T>> where T: PrimInt {
102 let new_range = shift_range(range, shift);
103 if let Some(new_range) = new_range {
104 if is_within(content, &new_range) {
105 Some(new_range)
106 } else {
107 None
108 }
109 } else {
110 None
111 }
112}
113
114pub fn is_within<T>(content: &str, range: &Range<T>) -> bool where T: PrimInt {
129 let range_end = range.end.to_usize();
130 if let Some(range_end) = range_end {
131 if range_end > content.len() {
132 false
133 } else {
134 true
135 }
136 } else {
137 false
138 }
139}
140
141#[cfg(test)]
144mod test {
145 use super::*;
146
147 #[test]
148 fn can_convert_to_title_case() {
149 assert_eq!(to_title_case("fooBarBaz"), "Foobarbaz");
150 assert_eq!(to_title_case("f"), "F");
151 assert_eq!(to_title_case(""), "");
152 }
153
154 #[test]
155 fn can_apply_a_shift_to_a_number() {
156 let number = 5;
157 let shift = Shift::Up(2);
158 assert_eq!(shift.apply_to_number(number), Some(7));
159 let number = 8;
160 let shift = Shift::Down(3);
161 assert_eq!(shift.apply_to_number(number), Some(5));
162 }
163
164 #[test]
165 fn can_apply_a_shift_to_a_range() {
166 let range = 0..5;
167 let shift = Shift::Up(2);
168 assert_eq!(shift.apply_to_range(range), Some(2..7));
169 let range = 4..7;
170 let shift = Shift::Down(3);
171 assert_eq!(shift.apply_to_range(range), Some(1..4));
172 }
173
174 #[test]
175 fn can_shift_a_range() {
176 let range = 0..5;
177 let new_range = shift_range(range, Shift::Up(2));
178 assert_eq!(new_range, Some(2..7));
179 assert_ne!(shift_range(new_range.unwrap(), Shift::Down(3)), Some(0..1));
180 }
181
182 #[test]
183 fn is_within_is_true_when_range_is_within() {
184 let test_str = "012345";
185 let range = 0..2;
186 assert_eq!(is_within(test_str, &range), true);
187 }
188
189 #[test]
190 fn is_within_is_false_when_range_end_is_longer_than_string() {
191 let test_str = "012345";
192 let range = 2..7;
193 assert_eq!(is_within(test_str, &range), false);
194 }
195}