pub struct FibIter { f0: u32, f1: u32, } impl FibIter { pub fn new() -> FibIter { FibIter { f0: 1, f1: 1, } } pub fn next(&mut self) -> u32 { let f0 = self.f0; // 1 2 |-> 2 3 self.f0 = self.f1; self.f1 += f0; f0 } pub fn rev(self) -> RevFibIter { RevFibIter { f0: self.f1 - self.f0, f1: self.f0 } } fn inc(&mut self) -> Option { Option::Some(self.next() as usize) } } struct Split { start: usize, end: usize, count: u32, fib: Option, rfib: Option, n: u32, symmetric: bool, } impl Split { fn new(n: u32, symmetric: bool) -> Split { let mut fib = FibIter::new(); Split { start: 0, end: fib.inc().unwrap(), count: 0, fib: Option::Some(fib), rfib: Option::None, n: n, symmetric: symmetric } } fn inc(&mut self) { if self.symmetric && self.n == self.count { self.rfib = Option::Some(self.fib.take().unwrap().rev()); } self.start = self.end; self.end += match self.fib { Some(_) => self. fib.as_mut().unwrap().inc().unwrap(), None => self.rfib.as_mut().unwrap().inc().unwrap() }; self.count += 1; } } fn _fib_split(text: &str, n: u32, panic: bool, symmetric: bool) -> (Vec, &str) { let mut out: Vec = Vec::new(); let mut sp = Split::new(n, symmetric); // ( panic -> sp.count < n) while sp.end <= text.len() && (!panic || sp.count < n) { out.push(text[sp.start..sp.end].to_string()); sp.inc(); } if panic && sp.count < n { panic!("Split into {} our of {} words!", sp.count, n); } (out, &text[sp.start..]) } pub fn fib_split(text: &str) -> Vec { let (mut init, last) = _fib_split(text, 0, false, false); init.push(last.to_string()); init } pub fn fib_split_n(text: &str, n: u32) -> (Vec, &str) { _fib_split(text, n, true, false) } pub struct RevFibIter { f0: u32, f1: u32, } impl RevFibIter { pub fn next(&mut self) -> Option { if self.f1 == 1 { return Option::None; } // 2 3 |-> 1 2 let f0 = self.f0; self.f0 = self.f1 - self.f0; self.f1 = f0; Option::Some(self.f1) } fn inc(&mut self) -> Option { let val = self.next(); match val { Option::Some(_) => Option::Some(val.unwrap() as usize), Option::None => Option::None, } } } pub fn fib_split_n_symmetric(text: &str, n: u32) -> (Vec, &str) { _fib_split(text, n, true, true) } use std::panic::catch_unwind; #[test] fn fib_iter() { let mut fib_iter = FibIter::new(); assert_eq!(fib_iter.next(), 1); assert_eq!(fib_iter.next(), 1); assert_eq!(fib_iter.next(), 2); assert_eq!(fib_iter.next(), 3); assert_eq!(fib_iter.next(), 5); assert_eq!(fib_iter.next(), 8); assert_eq!(fib_iter.next(), 13); } #[test] fn rev_fib_iter() { let mut fib_iter = FibIter::new(); for _ in 0..7 { fib_iter.next(); } let mut rev_fib_iter = fib_iter.rev(); assert_eq!(rev_fib_iter.next(), Some(13)); assert_eq!(rev_fib_iter.next(), Some(8)); assert_eq!(rev_fib_iter.next(), Some(5)); assert_eq!(rev_fib_iter.next(), Some(3)); assert_eq!(rev_fib_iter.next(), Some(2)); assert_eq!(rev_fib_iter.next(), Some(1)); assert_eq!(rev_fib_iter.next(), Some(1)); assert_eq!(rev_fib_iter.next(), None); assert_eq!(rev_fib_iter.next(), None); } #[test] fn rev_fib_iter_empty() { let fib_iter = FibIter::new(); let mut rev_fib_iter = fib_iter.rev(); assert_eq!(rev_fib_iter.next(), None); } #[test] fn fib_split_empty() { let words = fib_split(""); assert!(words == Vec::<&str>::new() || words == &[""]); } #[test] fn fib_split_ascii() { let words = fib_split("abcd123456"); assert_eq!(words, &["a", "b", "cd", "123", "456"]); } #[test] fn fib_split_cyrillic() { let words = fib_split("манджа с грозде"); assert_eq!(words, &["м", "а", "нд", "жа ", "с гро", "зде"]); } #[test] fn fib_split_n_zero() { let (words, rest) = fib_split_n("", 0); assert_eq!(words, Vec::<&str>::new()); assert_eq!(rest, ""); let (words, rest) = fib_split_n("abcdгрозде", 0); assert_eq!(words, Vec::<&str>::new()); assert_eq!(rest, "abcdгрозде"); } #[test] fn fib_split_n_ascii() { let (words, rest) = fib_split_n("abcd_123", 1); assert_eq!(words, &["a"]); assert_eq!(rest, "bcd_123"); let (words, rest) = fib_split_n("abcd_123", 4); assert_eq!(words, &["a", "b", "cd", "_12"]); assert_eq!(rest, "3"); } #[test] fn fib_split_n_ascii_exact() { let (words, rest) = fib_split_n("abcd_12_3456", 5); assert_eq!(words, &["a", "b", "cd", "_12", "_3456"]); assert_eq!(rest, ""); } #[test] fn fib_split_n_ascii_panic() { assert!(catch_unwind(|| fib_split_n("", 1)).is_err()); assert!(catch_unwind(|| fib_split_n("abcd_123", 5)).is_err()); } #[test] fn fib_split_n_cyrillic() { let (words, rest) = fib_split_n("манджа_with_грозде", 1); assert_eq!(words, &["м"]); assert_eq!(rest, "анджа_with_грозде"); let (words, rest) = fib_split_n("манджа_with_грозде", 5); assert_eq!(words, &["м", "а", "нд", "жа_", "with_"]); assert_eq!(rest, "грозде"); } #[test] fn fib_split_n_cyrillic_exact() { let (words, rest) = fib_split_n("манджа_with_", 5); assert_eq!(words, &["м", "а", "нд", "жа_", "with_"]); assert_eq!(rest, ""); } #[test] fn fib_split_n_cyrillic_panic() { assert!(catch_unwind(|| fib_split_n("манджа_with_грозде", 6)).is_err()); } #[test] fn fib_split_n_symmetric_zero() { let (words, rest) = fib_split_n_symmetric("", 0); assert_eq!(words, Vec::<&str>::new()); assert_eq!(rest, ""); let (words, rest) = fib_split_n_symmetric("abcdгрозде", 0); assert_eq!(words, Vec::<&str>::new()); assert_eq!(rest, "abcdгрозде"); } #[test] fn fib_split_n_symmetric_ascii() { let (words, rest) = fib_split_n_symmetric("abcd1234", 1); assert_eq!(words, &["a", "b"]); assert_eq!(rest, "cd1234"); let (words, rest) = fib_split_n_symmetric("abcd1234", 2); assert_eq!(words, &["a", "b", "c", "d"]); assert_eq!(rest, "1234"); } #[test] fn fib_split_n_symmetric_ascii_exact() { let (words, rest) = fib_split_n_symmetric("abcd1234", 3); assert_eq!(words, &["a", "b", "cd", "12", "3", "4"]); assert_eq!(rest, ""); } #[test] fn fib_split_n_symmetric_ascii_panic() { assert!(catch_unwind(|| fib_split_n_symmetric("", 1)).is_err()); assert!(catch_unwind(|| fib_split_n_symmetric("abcd_1234", 4)).is_err()); } #[test] fn fib_split_n_symmetric_cyrillic() { let (words, rest) = fib_split_n_symmetric("манджа_with_грозде", 1); assert_eq!(words, &["м", "а"]); assert_eq!(rest, "нджа_with_грозде"); let (words, rest) = fib_split_n_symmetric("манджа_with_грозде", 4); assert_eq!(words, &["м", "а", "нд", "жа_", "wit", "h_", "г", "р"]); assert_eq!(rest, "озде"); } #[test] fn fib_split_n_symmetric_cyrillic_exact() { let (words, rest) = fib_split_n_symmetric("манджа_with_гр", 4); assert_eq!(words, &["м", "а", "нд", "жа_", "wit", "h_", "г", "р"]); assert_eq!(rest, ""); } #[test] fn fib_split_n_symmetric_cyrillic_panic() { assert!(catch_unwind(|| fib_split_n_symmetric("манджа_with_грозде", 5)).is_err()); }