1pub mod builder {
2 use std::ops::AddAssign;
3
4 pub struct StringBuilder {
46 full_string: String,
47 current_len: usize
48 }
49
50 impl StringBuilder {
51 pub fn new() -> Self {
52 StringBuilder {
53 full_string: String::with_capacity(0),
54 current_len: 0
55 }
56 }
57
58 pub fn append<T>(
59 &mut self,
60 t: T
61 ) -> &mut Self
62 where T: ToString
63 {
64 let str = t.to_string();
65 let mut len = self.current_len;
66 len.add_assign(AsRef::<str>::as_ref(&str).len());
67 let mut buf = String::with_capacity(len);
68 buf.push_str(self.full_string.as_ref());
69 buf.push_str(str.as_ref());
70 self.current_len = len;
71 self.full_string = buf;
72 self
73 }
74
75 pub fn build(&self) -> String {
76 self.full_string.clone()
77 }
78 }
79}
80
81
82pub mod modify {
83 use std::ops::AddAssign;
84
85 pub fn append<S>(base: &mut String, append: &S)
106 where S: ToString
107 {
108 let str = append.to_string();
109 let mut len = base.len();
110 len.add_assign(AsRef::<str>::as_ref(&str).len());
111 let mut buf = String::with_capacity(len);
112 buf.push_str(base.as_ref());
113 buf.push_str(str.as_ref());
114 *base = buf;
115 }
116
117 pub fn replace<S, R>(base: &mut String, find: &S, replace: &R)
142 where S: ToString, R: ToString
143 {
144 let t = base.to_string();
145 let base_str_bytes = t.as_bytes();
146 let t = find.to_string();
147 let sub_str_bytes = t.as_bytes();
148 let t = replace.to_string();
149 let repl_len = AsRef::<str>::as_ref(&t).len();
150 assert!(base_str_bytes.len() >= sub_str_bytes.len());
151
152 let mut replaced_string = String::with_capacity(0);
153 let mut replaced_len = 0usize;
154 let mut current_base_pos = 0usize;
155 while current_base_pos < base_str_bytes.len() {
156
157 let mut current_sub_pos = 0usize;
158 let mut current_base_test = current_base_pos;
159 'inner: while current_sub_pos < sub_str_bytes.len()
160 && current_base_test < base_str_bytes.len() {
161
162 if &base_str_bytes[current_base_test] == &sub_str_bytes[current_sub_pos] {
163
164 if current_sub_pos == sub_str_bytes.len() -1 {
165 let mut temp_len = replaced_len;
166 temp_len.add_assign(repl_len);
167 let mut temp_str = String::with_capacity(temp_len);
168 temp_str.push_str(replaced_string.as_ref());
169 temp_str.push_str(t.as_ref());
170 replaced_len = temp_len;
171 replaced_string = temp_str;
172 current_base_pos = current_base_test;
173 break 'inner;
174 }
175
176 current_sub_pos = current_sub_pos + 1;
177 current_base_test = current_base_test + 1;
178 continue 'inner;
179 }
180 let mut temp_len = replaced_len;
181 temp_len.add_assign(1);
182 let mut temp_string = String::with_capacity(temp_len);
183 temp_string.push_str(replaced_string.as_ref());
184 temp_string.push_str(unsafe {
185 std::str::from_utf8_unchecked(&base_str_bytes[current_base_pos..current_base_pos +1])
186 });
187 replaced_len = temp_len;
188 replaced_string = temp_string;
189 break 'inner;
190 }
191
192 current_base_pos = current_base_pos + 1;
193 }
194
195 *base = replaced_string
196 }
197}
198
199
200pub mod compare {
201
202 pub fn find_all_exact<B, S>(
226 base: &B,
227 find: &S
228 ) -> Vec<(usize, usize)>
229 where B: ToString, S: ToString
230 {
231 let t = base.to_string();
232 let base_string_bytes = t.as_bytes();
233 let t = find.to_string();
234 let find_string_bytes = t.as_bytes();
235 assert!(base_string_bytes.len() >= find_string_bytes.len());
236 let mut matches: Vec<(usize, usize)> = vec![];
237
238 let mut current_base_pos = 0usize;
239 while current_base_pos < base_string_bytes.len() {
240
241 let mut current_find_pos = 0usize;
242 let mut current_base_test = current_base_pos;
243 'inner: while current_find_pos < find_string_bytes.len()
244 && current_base_test < base_string_bytes.len() {
245
246 if &base_string_bytes[current_base_test] == &find_string_bytes[current_find_pos] {
247
248 if current_find_pos == find_string_bytes.len() -1 {
249 matches.push((current_base_pos, current_base_test + 1));
250 break 'inner;
251 }
252
253 current_find_pos = current_find_pos + 1;
254 current_base_test = current_base_test + 1;
255 continue 'inner;
256 }
257 break 'inner;
258 }
259 current_base_pos = current_base_pos + 1;
260 }
261 matches
262 }
263
264 pub fn contains<B, S>(
286 base: &B,
287 find: &S
288 ) -> Option<(usize, usize)>
289 where B: ToString, S: ToString
290 {
291 let t = base.to_string();
292 let base_string_bytes = t.as_bytes();
293 let t = find.to_string();
294 let find_string_bytes = t.as_bytes();
295 assert!(base_string_bytes.len() >= find_string_bytes.len());
296
297 let mut current_base_pos = 0usize;
298 while current_base_pos < base_string_bytes.len() {
299
300 let mut current_find_pos = 0usize;
301 let mut base_pos_test = current_base_pos;
302 'inner: while current_find_pos < find_string_bytes.len()
303 && base_pos_test < base_string_bytes.len(){
304
305 if &base_string_bytes[base_pos_test] == &find_string_bytes[current_find_pos] {
306
307 if current_find_pos == find_string_bytes.len() -1 {
308 return Some((current_base_pos, base_pos_test + 1));
309 }
310
311 current_find_pos = current_find_pos + 1;
312 base_pos_test = base_pos_test + 1;
313 continue 'inner;
314 }
315 break 'inner;
316 }
317 current_base_pos = current_base_pos + 1;
318 }
319 return None;
320 }
321}
322
323
324#[cfg(test)]
325mod tests {
326 use std::fmt::Display;
327 use super::*;
328
329 #[test]
330 fn test_append1() {
331 let mut str1 = String::from("123");
332 let str2 = String::from("test");
333 modify::append(&mut str1, &str2);
334 assert_eq!(String::from("123test"), str1);
335 }
336
337 #[test]
338 fn test_append2() {
339 let mut str1 = String::from("123");
340 let str2 = String::from("test");
341 modify::append(&mut str1, &str2);
342 assert_eq!(String::from("123test"), str1);
343 }
344
345 #[test]
346 fn test_replace() {
347 let mut str1 = String::from("123123123test123123123test12");
348 let str2 = String::from("test");
349 let str3 = String::from("replaced");
350 modify::replace(&mut str1, &str2, &str3);
351 assert_eq!("123123123replaced123123123replaced12", str1);
352 }
353
354 #[test]
355 fn test_contains() {
356 let str1 = String::from("123123123test123123123");
357 let str2 = String::from("test");
358 let result = compare::contains(&str1, &str2);
359 assert_eq!(str2, &str1[result.unwrap().0..result.unwrap().1]);
360 }
361
362 #[test]
363 fn test_find_all_exact1() {
364 let str1 = String::from("123test113test444testtest");
365 let str2 = String::from("test");
366 let result = compare::find_all_exact(&str1, &str2);
367 let expected: Vec<(usize, usize)> = vec![(3,7), (10, 14), (17, 21), (21, 25)];
368 assert_eq!(expected, result);
369 }
370
371 #[test]
372 fn test_find_all_exact2() {
373 let str1 = String::from("bbbbbbbbbbbbbbbbbb");
374 let str2 = String::from("bbb");
375 let result = compare::find_all_exact(&str1, &str2);
376 let expected: Vec<(usize, usize)> = vec![(0, 3), (1, 4), (2, 5), (3, 6), (4, 7), (5, 8), (6, 9), (7, 10), (8, 11), (9, 12), (10, 13), (11, 14), (12, 15), (13, 16), (14, 17), (15, 18)];
377 assert_eq!(expected, result);
378 }
379
380 struct ToStringStruct {
381 a_string: String,
382 a_number: i32
383 }
384
385 impl Display for ToStringStruct {
386 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
387 write!(f, r#"{{ "a_string": "{}", "a_number": "{}" }}"#, self.a_string, self.a_number)
388 }
389 }
390
391
392 #[test]
393 fn test_stringbuilder1() {
394 let mut string_builder = builder::StringBuilder::new();
395 string_builder
396 .append("this")
397 .append("is")
398 .append("a")
399 .append("test");
400
401 assert_eq!(string_builder.build(), "thisisatest".to_string());
402 }
403
404 #[test]
405 fn test_stringbuilder2() {
406 let mut string_builder = builder::StringBuilder::new();
407 string_builder.append("this")
408 .append("is")
409 .append("another")
410 .append("test");
411 assert_eq!(string_builder.build(), "thisisanothertest".to_string());
412
413 string_builder
414 .append("this")
415 .append("is")
416 .append("another")
417 .append("test");
418 assert_eq!(string_builder.build(), "thisisanothertestthisisanothertest".to_string());
419 }
420
421 #[test]
422 fn test_stringbuilder3() {
423 let mut string_builder = builder::StringBuilder::new();
424 let to_string_struct = ToStringStruct {
425 a_string: String::from("struct_string"),
426 a_number: 4321
427 };
428 string_builder
429 .append(1234)
430 .append('c')
431 .append("test")
432 .append(55usize)
433 .append(to_string_struct);
434
435 assert_eq!(string_builder.build(), "1234ctest55{ \"a_string\": \"struct_string\", \"a_number\": \"4321\" }".to_string());
436 }
437}