summaryrefslogtreecommitdiffstats
path: root/vendor/similar/src/iter.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/similar/src/iter.rs')
-rw-r--r--vendor/similar/src/iter.rs195
1 files changed, 195 insertions, 0 deletions
diff --git a/vendor/similar/src/iter.rs b/vendor/similar/src/iter.rs
new file mode 100644
index 0000000..0a1ae53
--- /dev/null
+++ b/vendor/similar/src/iter.rs
@@ -0,0 +1,195 @@
+//! The various iterators this crate provides.
+//!
+//! These iterators are not a very stable interface and you really should
+//! avoid considering them to be concrete types. A lot of the iterators in
+//! this crate use `impl Iterator` for this reason but restrictions in the
+//! language don't allow this to be used in all places on the versions of
+//! rust this crate wants to compile for.
+use std::marker::PhantomData;
+use std::ops::{Index, Range};
+
+use crate::{Change, ChangeTag, DiffOp, DiffTag};
+
+/// Iterator for [`DiffOp::iter_changes`].
+pub struct ChangesIter<'lookup, Old: ?Sized, New: ?Sized, T> {
+ old: &'lookup Old,
+ new: &'lookup New,
+ old_range: Range<usize>,
+ new_range: Range<usize>,
+ old_index: usize,
+ new_index: usize,
+ old_i: usize,
+ new_i: usize,
+ tag: DiffTag,
+ _marker: PhantomData<T>,
+}
+
+impl<'lookup, Old, New, T> ChangesIter<'lookup, Old, New, T>
+where
+ Old: Index<usize, Output = T> + ?Sized,
+ New: Index<usize, Output = T> + ?Sized,
+{
+ pub(crate) fn new(old: &'lookup Old, new: &'lookup New, op: DiffOp) -> Self {
+ let (tag, old_range, new_range) = op.as_tag_tuple();
+ let old_index = old_range.start;
+ let new_index = new_range.start;
+ let old_i = old_range.start;
+ let new_i = new_range.start;
+ ChangesIter {
+ old,
+ new,
+ old_range,
+ new_range,
+ old_index,
+ new_index,
+ old_i,
+ new_i,
+ tag,
+ _marker: PhantomData,
+ }
+ }
+}
+
+impl<'lookup, Old, New, T> Iterator for ChangesIter<'lookup, Old, New, T>
+where
+ Old: Index<usize, Output = T> + ?Sized,
+ New: Index<usize, Output = T> + ?Sized,
+ T: Clone,
+{
+ type Item = Change<T>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ match self.tag {
+ DiffTag::Equal => {
+ if self.old_i < self.old_range.end {
+ let value = self.old[self.old_i].clone();
+ self.old_i += 1;
+ self.old_index += 1;
+ self.new_index += 1;
+ Some(Change {
+ tag: ChangeTag::Equal,
+ old_index: Some(self.old_index - 1),
+ new_index: Some(self.new_index - 1),
+ value,
+ })
+ } else {
+ None
+ }
+ }
+ DiffTag::Delete => {
+ if self.old_i < self.old_range.end {
+ let value = self.old[self.old_i].clone();
+ self.old_i += 1;
+ self.old_index += 1;
+ Some(Change {
+ tag: ChangeTag::Delete,
+ old_index: Some(self.old_index - 1),
+ new_index: None,
+ value,
+ })
+ } else {
+ None
+ }
+ }
+ DiffTag::Insert => {
+ if self.new_i < self.new_range.end {
+ let value = self.new[self.new_i].clone();
+ self.new_i += 1;
+ self.new_index += 1;
+ Some(Change {
+ tag: ChangeTag::Insert,
+ old_index: None,
+ new_index: Some(self.new_index - 1),
+ value,
+ })
+ } else {
+ None
+ }
+ }
+ DiffTag::Replace => {
+ if self.old_i < self.old_range.end {
+ let value = self.old[self.old_i].clone();
+ self.old_i += 1;
+ self.old_index += 1;
+ Some(Change {
+ tag: ChangeTag::Delete,
+ old_index: Some(self.old_index - 1),
+ new_index: None,
+ value,
+ })
+ } else if self.new_i < self.new_range.end {
+ let value = self.new[self.new_i].clone();
+ self.new_i += 1;
+ self.new_index += 1;
+ Some(Change {
+ tag: ChangeTag::Insert,
+ old_index: None,
+ new_index: Some(self.new_index - 1),
+ value,
+ })
+ } else {
+ None
+ }
+ }
+ }
+ }
+}
+
+#[cfg(feature = "text")]
+mod text {
+ use super::*;
+
+ /// Iterator for [`TextDiff::iter_all_changes`](crate::TextDiff::iter_all_changes).
+ pub struct AllChangesIter<'slf, 'data, T: ?Sized> {
+ old: &'slf [&'data T],
+ new: &'slf [&'data T],
+ ops: &'slf [DiffOp],
+ current_iter: Option<ChangesIter<'slf, [&'data T], [&'data T], &'data T>>,
+ }
+
+ impl<'slf, 'data, T> AllChangesIter<'slf, 'data, T>
+ where
+ T: 'data + ?Sized + PartialEq,
+ {
+ pub(crate) fn new(
+ old: &'slf [&'data T],
+ new: &'slf [&'data T],
+ ops: &'slf [DiffOp],
+ ) -> Self {
+ AllChangesIter {
+ old,
+ new,
+ ops,
+ current_iter: None,
+ }
+ }
+ }
+
+ impl<'slf, 'data, T> Iterator for AllChangesIter<'slf, 'data, T>
+ where
+ T: PartialEq + 'data + ?Sized,
+ 'data: 'slf,
+ {
+ type Item = Change<&'data T>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ loop {
+ if let Some(ref mut iter) = self.current_iter {
+ if let Some(rv) = iter.next() {
+ return Some(rv);
+ }
+ self.current_iter.take();
+ }
+ if let Some((&first, rest)) = self.ops.split_first() {
+ self.current_iter = Some(ChangesIter::new(self.old, self.new, first));
+ self.ops = rest;
+ } else {
+ return None;
+ }
+ }
+ }
+ }
+}
+
+#[cfg(feature = "text")]
+pub use self::text::*;