1use std::marker::PhantomData;
9use std::ops::{Index, Range};
10
11use crate::{Change, ChangeTag, DiffOp, DiffTag};
12
13pub struct ChangesIter<'lookup, Old: ?Sized, New: ?Sized, T> {
15 old: &'lookup Old,
16 new: &'lookup New,
17 old_range: Range<usize>,
18 new_range: Range<usize>,
19 old_index: usize,
20 new_index: usize,
21 old_i: usize,
22 new_i: usize,
23 tag: DiffTag,
24 _marker: PhantomData<T>,
25}
26
27impl<'lookup, Old, New, T> ChangesIter<'lookup, Old, New, T>
28where
29 Old: Index<usize, Output = T> + ?Sized,
30 New: Index<usize, Output = T> + ?Sized,
31{
32 pub(crate) fn new(old: &'lookup Old, new: &'lookup New, op: DiffOp) -> Self {
33 let (tag, old_range, new_range) = op.as_tag_tuple();
34 let old_index = old_range.start;
35 let new_index = new_range.start;
36 let old_i = old_range.start;
37 let new_i = new_range.start;
38 ChangesIter {
39 old,
40 new,
41 old_range,
42 new_range,
43 old_index,
44 new_index,
45 old_i,
46 new_i,
47 tag,
48 _marker: PhantomData,
49 }
50 }
51}
52
53impl<Old, New, T> Iterator for ChangesIter<'_, Old, New, T>
54where
55 Old: Index<usize, Output = T> + ?Sized,
56 New: Index<usize, Output = T> + ?Sized,
57 T: Clone,
58{
59 type Item = Change<T>;
60
61 fn next(&mut self) -> Option<Self::Item> {
62 match self.tag {
63 DiffTag::Equal => {
64 if self.old_i < self.old_range.end {
65 let value = self.old[self.old_i].clone();
66 self.old_i += 1;
67 self.old_index += 1;
68 self.new_index += 1;
69 Some(Change {
70 tag: ChangeTag::Equal,
71 old_index: Some(self.old_index - 1),
72 new_index: Some(self.new_index - 1),
73 value,
74 })
75 } else {
76 None
77 }
78 }
79 DiffTag::Delete => {
80 if self.old_i < self.old_range.end {
81 let value = self.old[self.old_i].clone();
82 self.old_i += 1;
83 self.old_index += 1;
84 Some(Change {
85 tag: ChangeTag::Delete,
86 old_index: Some(self.old_index - 1),
87 new_index: None,
88 value,
89 })
90 } else {
91 None
92 }
93 }
94 DiffTag::Insert => {
95 if self.new_i < self.new_range.end {
96 let value = self.new[self.new_i].clone();
97 self.new_i += 1;
98 self.new_index += 1;
99 Some(Change {
100 tag: ChangeTag::Insert,
101 old_index: None,
102 new_index: Some(self.new_index - 1),
103 value,
104 })
105 } else {
106 None
107 }
108 }
109 DiffTag::Replace => {
110 if self.old_i < self.old_range.end {
111 let value = self.old[self.old_i].clone();
112 self.old_i += 1;
113 self.old_index += 1;
114 Some(Change {
115 tag: ChangeTag::Delete,
116 old_index: Some(self.old_index - 1),
117 new_index: None,
118 value,
119 })
120 } else if self.new_i < self.new_range.end {
121 let value = self.new[self.new_i].clone();
122 self.new_i += 1;
123 self.new_index += 1;
124 Some(Change {
125 tag: ChangeTag::Insert,
126 old_index: None,
127 new_index: Some(self.new_index - 1),
128 value,
129 })
130 } else {
131 None
132 }
133 }
134 }
135 }
136}
137
138#[cfg(feature = "text")]
139mod text {
140 use super::*;
141
142 pub struct AllChangesIter<'slf, 'data, T: ?Sized> {
144 old: &'slf [&'data T],
145 new: &'slf [&'data T],
146 ops: &'slf [DiffOp],
147 current_iter: Option<ChangesIter<'slf, [&'data T], [&'data T], &'data T>>,
148 }
149
150 impl<'slf, 'data, T> AllChangesIter<'slf, 'data, T>
151 where
152 T: 'data + ?Sized + PartialEq,
153 {
154 pub(crate) fn new(
155 old: &'slf [&'data T],
156 new: &'slf [&'data T],
157 ops: &'slf [DiffOp],
158 ) -> Self {
159 AllChangesIter {
160 old,
161 new,
162 ops,
163 current_iter: None,
164 }
165 }
166 }
167
168 impl<'slf, 'data, T> Iterator for AllChangesIter<'slf, 'data, T>
169 where
170 T: PartialEq + 'data + ?Sized,
171 'data: 'slf,
172 {
173 type Item = Change<&'data T>;
174
175 fn next(&mut self) -> Option<Self::Item> {
176 loop {
177 if let Some(ref mut iter) = self.current_iter {
178 if let Some(rv) = iter.next() {
179 return Some(rv);
180 }
181 self.current_iter.take();
182 }
183 if let Some((&first, rest)) = self.ops.split_first() {
184 self.current_iter = Some(ChangesIter::new(self.old, self.new, first));
185 self.ops = rest;
186 } else {
187 return None;
188 }
189 }
190 }
191 }
192}
193
194#[cfg(feature = "text")]
195pub use self::text::*;