More generic lifetimes for iter_changes and added iter_all_changes

This commit is contained in:
Armin Ronacher 2021-02-04 12:15:20 +01:00
parent b98be24027
commit 12e7d5e4b0
5 changed files with 67 additions and 11 deletions

View file

@ -174,12 +174,15 @@ impl<'s, T: DiffableStr + ?Sized> fmt::Display for InlineChange<'s, T> {
}
}
pub(crate) fn iter_inline_changes<'diff, T>(
diff: &'diff TextDiff<'_, '_, '_, T>,
pub(crate) fn iter_inline_changes<'x, 'diff, 'old, 'new, 'bufs, T>(
diff: &'diff TextDiff<'old, 'new, 'bufs, T>,
op: &DiffOp,
) -> impl Iterator<Item = InlineChange<'diff, T>>
) -> impl Iterator<Item = InlineChange<'x, T>> + 'diff
where
T: DiffableStr + ?Sized,
'x: 'diff,
'old: 'x,
'new: 'x,
{
let (tag, old_range, new_range) = op.as_tag_tuple();

View file

@ -294,7 +294,15 @@ impl<'old, 'new, 'bufs, T: DiffableStr + ?Sized + 'old + 'new> TextDiff<'old, 'n
/// ways in which a change could be encoded (insert/delete vs replace), look
/// up the value from the appropriate slice and also handle correct index
/// handling.
pub fn iter_changes(&self, op: &DiffOp) -> impl Iterator<Item = Change<'_, T>> {
pub fn iter_changes<'x, 'slf>(
&'slf self,
op: &DiffOp,
) -> impl Iterator<Item = Change<'x, T>> + 'slf
where
'x: 'slf,
'old: 'x,
'new: 'x,
{
op.iter_changes(self.old_slices(), self.new_slices())
}
@ -310,6 +318,22 @@ impl<'old, 'new, 'bufs, T: DiffableStr + ?Sized + 'old + 'new> TextDiff<'old, 'n
group_diff_ops(self.ops().to_vec(), n)
}
/// Flattens out the diff into all changes.
///
/// This is a shortcut for combining [`TextDiff::ops`] with
/// [`TextDiff::iter_changes`].
pub fn iter_all_changes<'x, 'slf>(&'slf self) -> impl Iterator<Item = Change<'x, T>> + 'slf
where
'x: 'slf,
'old: 'x,
'new: 'x,
{
// unclear why this needs Box::new here. It seems to infer some really
// odd lifetimes I can't figure out how to work with.
Box::new(self.ops().iter().flat_map(move |op| self.iter_changes(&op)))
as Box<dyn Iterator<Item = _>>
}
/// Utility to return a unified diff formatter.
pub fn unified_diff<'diff>(&'diff self) -> UnifiedDiff<'diff, 'old, 'new, 'bufs, T> {
UnifiedDiff::from_text_diff(self)
@ -322,7 +346,15 @@ impl<'old, 'new, 'bufs, T: DiffableStr + ?Sized + 'old + 'new> TextDiff<'old, 'n
/// this function with regards to how it detects those inline changes
/// is currently not defined and will likely change over time.
#[cfg(feature = "inline")]
pub fn iter_inline_changes(&self, op: &DiffOp) -> impl Iterator<Item = InlineChange<'_, T>> {
pub fn iter_inline_changes<'x, 'slf>(
&'slf self,
op: &DiffOp,
) -> impl Iterator<Item = InlineChange<'x, T>> + 'slf
where
'x: 'slf,
'old: 'x,
'new: 'x,
{
inline::iter_inline_changes(self, op)
}
}
@ -492,3 +524,18 @@ fn test_get_close_matches() {
);
assert_eq!(matches, vec!["aulo", "hulu", "uulo", "zulo"]);
}
#[test]
fn test_lifetimes_on_iter() {
fn diff_lines<'x, T>(old: &'x T, new: &'x T) -> Vec<Change<'x, T::Output>>
where
T: DiffableStrRef + ?Sized,
{
TextDiff::from_lines(old, new).iter_all_changes().collect()
}
let a = "1\n2\n3\n".to_string();
let b = "1\n99\n3\n".to_string();
let changes = diff_lines(&a, &b);
insta::assert_debug_snapshot!(&changes);
}