Add support for Rust 1.41.0 (#14)
This commit is contained in:
parent
d056522da4
commit
b6e2894f21
9 changed files with 230 additions and 96 deletions
4
.github/workflows/tests.yml
vendored
4
.github/workflows/tests.yml
vendored
|
|
@ -18,14 +18,14 @@ jobs:
|
||||||
run: make test
|
run: make test
|
||||||
|
|
||||||
build-stable:
|
build-stable:
|
||||||
name: Test on 1.43.0
|
name: Test on 1.41.0
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
toolchain: 1.43.0
|
toolchain: 1.41.0
|
||||||
profile: minimal
|
profile: minimal
|
||||||
override: true
|
override: true
|
||||||
- name: Test
|
- name: Test
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,11 @@
|
||||||
|
|
||||||
All notable changes to similar are documented here.
|
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.
|
* Added support for Rust 1.43.0 for better compatibility.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
msrv = "1.42.0"
|
msrv = "1.41.0"
|
||||||
|
|
|
||||||
198
src/iter.rs
Normal file
198
src/iter.rs
Normal 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::*;
|
||||||
|
|
@ -128,6 +128,7 @@
|
||||||
//! in a line diff. This currently also enables the `unicode` feature.
|
//! in a line diff. This currently also enables the `unicode` feature.
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
pub mod algorithms;
|
pub mod algorithms;
|
||||||
|
pub mod iter;
|
||||||
#[cfg(feature = "text")]
|
#[cfg(feature = "text")]
|
||||||
pub mod udiff;
|
pub mod udiff;
|
||||||
#[cfg(feature = "text")]
|
#[cfg(feature = "text")]
|
||||||
|
|
|
||||||
|
|
@ -318,7 +318,11 @@ mod bytes_support {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ends_with_newline(&self) -> bool {
|
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 {
|
fn len(&self) -> usize {
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,9 @@ pub use self::abstraction::{DiffableStr, DiffableStrRef};
|
||||||
pub use self::inline::InlineChange;
|
pub use self::inline::InlineChange;
|
||||||
|
|
||||||
use self::utils::{upper_seq_ratio, QuickSeqRatio};
|
use self::utils::{upper_seq_ratio, QuickSeqRatio};
|
||||||
|
use crate::iter::{AllChangesIter, ChangesIter};
|
||||||
use crate::udiff::UnifiedDiff;
|
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`].
|
/// 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>(
|
pub fn iter_changes<'x, 'slf>(
|
||||||
&'slf self,
|
&'slf self,
|
||||||
op: &DiffOp,
|
op: &DiffOp,
|
||||||
) -> impl Iterator<Item = Change<'x, T>> + '_
|
) -> ChangesIter<'slf, 'x, [&'x T], [&'x T], T>
|
||||||
where
|
where
|
||||||
'x: 'slf,
|
'x: 'slf,
|
||||||
'old: 'x,
|
'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
|
/// This is a shortcut for combining [`TextDiff::ops`] with
|
||||||
/// [`TextDiff::iter_changes`].
|
/// [`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
|
where
|
||||||
'x: 'slf + 'old + 'new,
|
'x: 'slf + 'old + 'new,
|
||||||
'old: 'x,
|
'old: 'x,
|
||||||
'new: '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.
|
/// Utility to return a unified diff formatter.
|
||||||
|
|
@ -539,7 +540,7 @@ pub fn get_close_matches<'a, T: DiffableStr + ?Sized>(
|
||||||
if ratio >= cutoff {
|
if ratio >= cutoff {
|
||||||
// we're putting the word itself in reverse in so that matches with
|
// we're putting the word itself in reverse in so that matches with
|
||||||
// the same ratio are ordered lexicographically.
|
// 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]
|
#[test]
|
||||||
fn test_lifetimes_on_iter() {
|
fn test_lifetimes_on_iter() {
|
||||||
|
use crate::Change;
|
||||||
|
|
||||||
fn diff_lines<'x, T>(old: &'x T, new: &'x T) -> Vec<Change<'x, T::Output>>
|
fn diff_lines<'x, T>(old: &'x T, new: &'x T) -> Vec<Change<'x, T::Output>>
|
||||||
where
|
where
|
||||||
T: DiffableStrRef + ?Sized,
|
T: DiffableStrRef + ?Sized,
|
||||||
|
|
|
||||||
83
src/types.rs
83
src/types.rs
|
|
@ -2,6 +2,7 @@ use std::fmt;
|
||||||
use std::ops::{Index, Range};
|
use std::ops::{Index, Range};
|
||||||
|
|
||||||
use crate::algorithms::DiffHook;
|
use crate::algorithms::DiffHook;
|
||||||
|
use crate::iter::ChangesIter;
|
||||||
|
|
||||||
/// An enum representing a diffing algorithm.
|
/// An enum representing a diffing algorithm.
|
||||||
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||||
|
|
@ -272,92 +273,14 @@ impl DiffOp {
|
||||||
&self,
|
&self,
|
||||||
old: &'lookup Old,
|
old: &'lookup Old,
|
||||||
new: &'lookup New,
|
new: &'lookup New,
|
||||||
) -> impl Iterator<Item = Change<'x, T>> + 'lookup
|
) -> ChangesIter<'lookup, 'x, Old, New, T>
|
||||||
where
|
where
|
||||||
Old: Index<usize, Output = &'x T> + ?Sized,
|
Old: Index<usize, Output = &'x T> + ?Sized,
|
||||||
New: Index<usize, Output = &'x T> + ?Sized,
|
New: Index<usize, Output = &'x T> + ?Sized,
|
||||||
T: 'x + ?Sized,
|
T: 'x + ?Sized,
|
||||||
'x: 'lookup,
|
'x: 'lookup,
|
||||||
{
|
{
|
||||||
let (tag, old_range, new_range) = self.as_tag_tuple();
|
ChangesIter::new(old, new, *self)
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a diffop yields the changes it encodes against the given slices.
|
/// Given a diffop yields the changes it encodes against the given slices.
|
||||||
|
|
|
||||||
13
src/udiff.rs
13
src/udiff.rs
|
|
@ -27,8 +27,9 @@
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::{fmt, io};
|
use std::{fmt, io};
|
||||||
|
|
||||||
|
use crate::iter::AllChangesIter;
|
||||||
use crate::text::{DiffableStr, TextDiff};
|
use crate::text::{DiffableStr, TextDiff};
|
||||||
use crate::types::{Algorithm, Change, DiffOp};
|
use crate::types::{Algorithm, DiffOp};
|
||||||
|
|
||||||
struct MissingNewlineHint(bool);
|
struct MissingNewlineHint(bool);
|
||||||
|
|
||||||
|
|
@ -240,13 +241,13 @@ impl<'diff, 'old, 'new, 'bufs, T: DiffableStr + ?Sized>
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterates over all changes in a hunk.
|
/// 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
|
where
|
||||||
'diff: 'old + 'new + 'bufs,
|
'x: 'slf + 'old + 'new,
|
||||||
|
'old: 'x,
|
||||||
|
'new: 'x,
|
||||||
{
|
{
|
||||||
self.ops()
|
AllChangesIter::new(self.diff.old_slices(), self.diff.new_slices(), self.ops())
|
||||||
.iter()
|
|
||||||
.flat_map(move |op| self.diff.iter_changes(op))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write the hunk as bytes to the output stream.
|
/// Write the hunk as bytes to the output stream.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue