| 1 | //! The various iterators this crate provides. |
| 2 | //! |
| 3 | //! These iterators are not a very stable interface and you really should |
| 4 | //! avoid considering them to be concrete types. A lot of the iterators in |
| 5 | //! this crate use `impl Iterator` for this reason but restrictions in the |
| 6 | //! language don't allow this to be used in all places on the versions of |
| 7 | //! rust this crate wants to compile for. |
| 8 | use std::marker::PhantomData; |
| 9 | use std::ops::{Index, Range}; |
| 10 | |
| 11 | use crate::{Change, ChangeTag, DiffOp, DiffTag}; |
| 12 | |
| 13 | /// Iterator for [`DiffOp::iter_changes`]. |
| 14 | pub 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 | |
| 27 | impl<'lookup, Old, New, T> ChangesIter<'lookup, Old, New, T> |
| 28 | where |
| 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: DiffTag, old_range: Range, new_range: Range) = op.as_tag_tuple(); |
| 34 | let old_index: usize = old_range.start; |
| 35 | let new_index: usize = new_range.start; |
| 36 | let old_i: usize = old_range.start; |
| 37 | let new_i: usize = 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 | |
| 53 | impl<'lookup, Old, New, T> Iterator for ChangesIter<'lookup, Old, New, T> |
| 54 | where |
| 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" )] |
| 139 | mod text { |
| 140 | use super::*; |
| 141 | |
| 142 | /// Iterator for [`TextDiff::iter_all_changes`](crate::TextDiff::iter_all_changes). |
| 143 | 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" )] |
| 195 | pub use self::text::*; |
| 196 | |