1#[inline]
3pub(crate) fn order_by_len_asc<'a>(s1: &'a str, s2: &'a str) -> (&'a str, &'a str) {
4 if s1.len() <= s2.len() {
5 (s1, s2)
6 } else {
7 (s2, s1)
8 }
9}
10
11#[inline]
12pub(crate) fn count_eq<S, T>(mut s1_iter: S, mut s2_iter: T) -> usize
13where
14 S: Iterator,
15 T: Iterator,
16 <S as Iterator>::Item: PartialEq<<T as Iterator>::Item>,
17{
18 let mut match_ctn = 0;
19 loop {
20 let c1 = match s1_iter.next() {
21 None => {
22 break;
24 }
25 Some(val) => val,
26 };
27
28 let c2 = match s2_iter.next() {
29 None => {
30 break;
32 }
33 Some(val) => val,
34 };
35 if c1 == c2 {
36 match_ctn += 1;
37 } else {
38 break;
39 }
40 }
41 match_ctn
42}
43
44pub(crate) struct DelimDistinct<S, T>
45where
46 S: Iterator + Clone,
47 T: Iterator + Clone,
48 <S as Iterator>::Item: PartialEq<<T as Iterator>::Item>,
49{
50 pub prefix_len: usize,
52 pub distinct_s1: S,
54 pub s1_len: usize,
56 pub distinct_s2: T,
58 pub s2_len: usize,
60 pub suffix_len: usize,
62}
63
64#[allow(unused)]
65impl<S, T> DelimDistinct<S, T>
66where
67 S: Iterator + Clone,
68 T: Iterator + Clone,
69 <S as Iterator>::Item: PartialEq<<T as Iterator>::Item>,
70{
71 #[inline]
73 pub fn common(&self) -> usize {
74 self.prefix_len + self.suffix_len
75 }
76
77 #[inline]
79 pub fn remaining(&self) -> (usize, usize) {
80 (self.s1_len, self.s2_len)
81 }
82
83 #[inline]
85 pub fn is_eq(&self) -> bool {
86 self.remaining() == (0, 0)
87 }
88
89 #[inline]
90 pub fn remaining_s2(&self) -> usize {
91 self.s2_len
92 }
93
94 #[inline]
95 pub fn remaining_s1(&self) -> usize {
96 self.s1_len
97 }
98
99 #[inline]
102 pub(crate) fn new_skip_take(
103 a: S,
104 b: T,
105 ) -> DelimDistinct<std::iter::Skip<std::iter::Take<S>>, std::iter::Skip<std::iter::Take<T>>>
106 {
107 let a_vec: Vec<_> = a.clone().collect();
110 let b_vec: Vec<_> = b.clone().collect();
111
112 let a_len = a_vec.len();
113 let b_len = b_vec.len();
114
115 let suffix_len = count_eq(a_vec.into_iter().rev(), b_vec.into_iter().rev());
116
117 let a_iter = a.take(a_len - suffix_len);
118 let b_iter = b.take(b_len - suffix_len);
119
120 let prefix_len = count_eq(a_iter.clone(), b_iter.clone());
121
122 let common_len = prefix_len + suffix_len;
123 DelimDistinct {
124 suffix_len,
125 prefix_len,
126 s1_len: a_len - common_len,
127 s2_len: b_len - common_len,
128 distinct_s1: a_iter.skip(prefix_len),
129 distinct_s2: b_iter.skip(prefix_len),
130 }
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 #[test]
139 fn delim_different() {
140 let s1 = "kitten";
141 let s2 = "sitting";
142
143 let delim = DelimDistinct::new_skip_take(s1.chars(), s2.chars());
144 assert_eq!(delim.prefix_len, 0);
145 assert_eq!(delim.suffix_len, 0);
146 assert_eq!(delim.s1_len, 6);
147 assert_eq!(delim.s2_len, 7);
148 }
149
150 #[test]
151 fn delim_eq() {
152 let s1 = "kitten";
153 let s2 = "kitten";
154
155 let delim = DelimDistinct::new_skip_take(s1.chars(), s2.chars());
156 assert_eq!(delim.common(), 6);
157 assert_eq!(delim.remaining(), (0, 0));
158 assert!(delim.is_eq());
159 }
160
161 #[test]
162 fn delim_eq_suffix() {
163 let s1 = "cute kitten";
164 let s2 = "kitten";
165
166 let delim = DelimDistinct::new_skip_take(s1.chars(), s2.chars());
167 assert_eq!(delim.common(), 6);
168 assert_eq!(delim.remaining(), (5, 0));
169 assert_eq!(delim.distinct_s1.collect::<String>(), String::from("cute "));
170
171 let s1 = "k cute kitten";
172 let s2 = "kitten";
173 let delim = DelimDistinct::new_skip_take(s1.chars(), s2.chars());
174 assert_eq!(delim.common(), 6);
175 assert_eq!(delim.remaining(), (7, 0));
176 assert_eq!(
177 delim.distinct_s1.collect::<String>(),
178 String::from("k cute ")
179 );
180 }
181
182 #[test]
183 fn delim_eq_prefix() {
184 let s1 = "hungry kitten";
185 let s2 = "hungry hippo";
186
187 let delim = DelimDistinct::new_skip_take(s1.chars(), s2.chars());
188 assert_eq!(delim.common(), 7);
189 assert_eq!(delim.remaining(), (6, 5));
190 assert_eq!(
191 delim.distinct_s1.collect::<String>(),
192 String::from("kitten")
193 );
194 assert_eq!(delim.distinct_s2.collect::<String>(), String::from("hippo"));
195 }
196
197 #[test]
198 fn delim_eq_prefix_suffix() {
199 let s1 = "hungry kitten is hungry";
200 let s2 = "hungry hippo is hungry";
201
202 let delim = DelimDistinct::new_skip_take(s1.chars(), s2.chars());
203 assert_eq!(delim.common(), 17);
204 assert_eq!(delim.remaining(), (6, 5));
205 assert_eq!(
206 delim.distinct_s1.collect::<String>(),
207 String::from("kitten")
208 );
209 assert_eq!(delim.distinct_s2.collect::<String>(), String::from("hippo"));
210 }
211}