Add support for Rust 1.41.0 (#14)

This commit is contained in:
Armin Ronacher 2021-02-15 22:50:12 +01:00 committed by GitHub
parent d056522da4
commit b6e2894f21
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 230 additions and 96 deletions

View file

@ -18,14 +18,14 @@ jobs:
run: make test
build-stable:
name: Test on 1.43.0
name: Test on 1.41.0
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.43.0
toolchain: 1.41.0
profile: minimal
override: true
- name: Test

View file

@ -2,7 +2,11 @@
All notable changes to similar are documented here.
## 1.3.0
## 1.2.2
* Added support for Rust 1.41.0 for better compatibility.
## 1.2.1
* Added support for Rust 1.43.0 for better compatibility.

View file

@ -1 +1 @@
msrv = "1.42.0"
msrv = "1.41.0"

198
src/iter.rs Normal file
View file

@ -0,0 +1,198 @@
//! 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, 'data, Old: ?Sized, New: ?Sized, T: ?Sized> {
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<&'data T>,
}
impl<'lookup, 'data, Old, New, T> ChangesIter<'lookup, 'data, Old, New, T>
where
Old: Index<usize, Output = &'data T> + ?Sized,
New: Index<usize, Output = &'data T> + ?Sized,
T: 'data + ?Sized,
'data: 'lookup,
{
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, 'data, Old, New, T> Iterator for ChangesIter<'lookup, 'data, Old, New, T>
where
Old: Index<usize, Output = &'data T> + ?Sized,
New: Index<usize, Output = &'data T> + ?Sized,
T: 'data + ?Sized,
'data: 'lookup,
{
type Item = Change<'data, 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];
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];
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];
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];
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];
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, [&'data T], [&'data T], 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::*;

View file

@ -128,6 +128,7 @@
//! in a line diff. This currently also enables the `unicode` feature.
#![warn(missing_docs)]
pub mod algorithms;
pub mod iter;
#[cfg(feature = "text")]
pub mod udiff;
#[cfg(feature = "text")]

View file

@ -318,7 +318,11 @@ mod bytes_support {
}
fn ends_with_newline(&self) -> bool {
matches!(self.last_byte(), Some(b'\r') | Some(b'\n'))
if let Some(b'\r') | Some(b'\n') = self.last_byte() {
true
} else {
false
}
}
fn len(&self) -> usize {

View file

@ -13,8 +13,9 @@ pub use self::abstraction::{DiffableStr, DiffableStrRef};
pub use self::inline::InlineChange;
use self::utils::{upper_seq_ratio, QuickSeqRatio};
use crate::iter::{AllChangesIter, ChangesIter};
use crate::udiff::UnifiedDiff;
use crate::{capture_diff_slices, get_diff_ratio, group_diff_ops, Algorithm, Change, DiffOp};
use crate::{capture_diff_slices, get_diff_ratio, group_diff_ops, Algorithm, DiffOp};
/// A builder type config for more complex uses of [`TextDiff`].
///
@ -437,7 +438,7 @@ impl<'old, 'new, 'bufs, T: DiffableStr + ?Sized + 'old + 'new> TextDiff<'old, 'n
pub fn iter_changes<'x, 'slf>(
&'slf self,
op: &DiffOp,
) -> impl Iterator<Item = Change<'x, T>> + '_
) -> ChangesIter<'slf, 'x, [&'x T], [&'x T], T>
where
'x: 'slf,
'old: 'x,
@ -462,13 +463,13 @@ impl<'old, 'new, 'bufs, T: DiffableStr + ?Sized + 'old + 'new> TextDiff<'old, 'n
///
/// 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>> + '_
pub fn iter_all_changes<'x, 'slf>(&'slf self) -> AllChangesIter<'slf, 'x, T>
where
'x: 'slf + 'old + 'new,
'old: 'x,
'new: 'x,
{
self.ops().iter().flat_map(move |op| self.iter_changes(&op))
AllChangesIter::new(&self.old[..], &self.new[..], self.ops())
}
/// Utility to return a unified diff formatter.
@ -539,7 +540,7 @@ pub fn get_close_matches<'a, T: DiffableStr + ?Sized>(
if ratio >= cutoff {
// we're putting the word itself in reverse in so that matches with
// the same ratio are ordered lexicographically.
matches.push(((ratio * u32::MAX as f32) as u32, Reverse(possibility)));
matches.push(((ratio * std::u32::MAX as f32) as u32, Reverse(possibility)));
}
}
@ -668,6 +669,8 @@ fn test_get_close_matches() {
#[test]
fn test_lifetimes_on_iter() {
use crate::Change;
fn diff_lines<'x, T>(old: &'x T, new: &'x T) -> Vec<Change<'x, T::Output>>
where
T: DiffableStrRef + ?Sized,

View file

@ -2,6 +2,7 @@ use std::fmt;
use std::ops::{Index, Range};
use crate::algorithms::DiffHook;
use crate::iter::ChangesIter;
/// An enum representing a diffing algorithm.
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
@ -272,92 +273,14 @@ impl DiffOp {
&self,
old: &'lookup Old,
new: &'lookup New,
) -> impl Iterator<Item = Change<'x, T>> + 'lookup
) -> ChangesIter<'lookup, 'x, Old, New, T>
where
Old: Index<usize, Output = &'x T> + ?Sized,
New: Index<usize, Output = &'x T> + ?Sized,
T: 'x + ?Sized,
'x: 'lookup,
{
let (tag, old_range, new_range) = self.as_tag_tuple();
let mut old_index = old_range.start;
let mut new_index = new_range.start;
let mut old_i = old_range.start;
let mut new_i = new_range.start;
std::iter::from_fn(move || match tag {
DiffTag::Equal => {
if old_i < old_range.end {
let value = old[old_i];
old_i += 1;
old_index += 1;
new_index += 1;
Some(Change {
tag: ChangeTag::Equal,
old_index: Some(old_index - 1),
new_index: Some(new_index - 1),
value,
})
} else {
None
}
}
DiffTag::Delete => {
if old_i < old_range.end {
let value = old[old_i];
old_i += 1;
old_index += 1;
Some(Change {
tag: ChangeTag::Delete,
old_index: Some(old_index - 1),
new_index: None,
value,
})
} else {
None
}
}
DiffTag::Insert => {
if new_i < new_range.end {
let value = new[new_i];
new_i += 1;
new_index += 1;
Some(Change {
tag: ChangeTag::Insert,
old_index: None,
new_index: Some(new_index - 1),
value,
})
} else {
None
}
}
DiffTag::Replace => {
if old_i < old_range.end {
let value = old[old_i];
old_i += 1;
old_index += 1;
Some(Change {
tag: ChangeTag::Delete,
old_index: Some(old_index - 1),
new_index: None,
value,
})
} else if new_i < new_range.end {
let value = new[new_i];
new_i += 1;
new_index += 1;
Some(Change {
tag: ChangeTag::Insert,
old_index: None,
new_index: Some(new_index - 1),
value,
})
} else {
None
}
}
})
ChangesIter::new(old, new, *self)
}
/// Given a diffop yields the changes it encodes against the given slices.

View file

@ -27,8 +27,9 @@
use std::ops::Range;
use std::{fmt, io};
use crate::iter::AllChangesIter;
use crate::text::{DiffableStr, TextDiff};
use crate::types::{Algorithm, Change, DiffOp};
use crate::types::{Algorithm, DiffOp};
struct MissingNewlineHint(bool);
@ -240,13 +241,13 @@ impl<'diff, 'old, 'new, 'bufs, T: DiffableStr + ?Sized>
}
/// Iterates over all changes in a hunk.
pub fn iter_changes(&self) -> impl Iterator<Item = Change<'diff, T>> + '_
pub fn iter_changes<'x, 'slf>(&'slf self) -> AllChangesIter<'slf, 'x, T>
where
'diff: 'old + 'new + 'bufs,
'x: 'slf + 'old + 'new,
'old: 'x,
'new: 'x,
{
self.ops()
.iter()
.flat_map(move |op| self.diff.iter_changes(op))
AllChangesIter::new(self.diff.old_slices(), self.diff.new_slices(), self.ops())
}
/// Write the hunk as bytes to the output stream.