//! 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, new_range: Range, old_index: usize, new_index: usize, old_i: usize, new_i: usize, tag: DiffTag, _marker: PhantomData, } impl<'lookup, Old, New, T> ChangesIter<'lookup, Old, New, T> where Old: Index + ?Sized, New: Index + ?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 + ?Sized, New: Index + ?Sized, T: Clone, { type Item = Change; fn next(&mut self) -> Option { 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>, } 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 { 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::*;