From a045f3e152875b1867ebf490b733d6720ad2ec88 Mon Sep 17 00:00:00 2001 From: Stuart Harris Date: Thu, 24 Jul 2025 10:58:46 +0100 Subject: [PATCH 1/2] chore: update CI and fix clippy etc --- .github/workflows/ci.yaml | 29 +++++++++++++++++++---------- Cargo.lock | 30 +++++++++++++++--------------- difficient-macros/Cargo.toml | 12 ++++++------ examples/visitor.rs | 12 +++++------- src/serde_visit.rs | 15 ++++++++++----- src/vec.rs | 27 ++++++++++++++++++--------- 6 files changed, 73 insertions(+), 52 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d08b190..a2d97a4 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,7 +1,11 @@ -on: [push, pull_request] - name: CI +on: + push: + branches: + - main + pull_request: + jobs: build: name: Tests @@ -11,17 +15,22 @@ jobs: - name: Checkout uses: actions/checkout@v2 - - name: Test - run: cargo test --workspace + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy, rustfmt - - name: Test with serde - run: cargo test --workspace --features serde + - name: Format check + shell: bash + run: cargo fmt --all --check - - name: Test with features - run: cargo test --workspace --features uuid,chrono,visitor + - name: Clippy (pedantic) + shell: bash + run: cargo clippy -- --no-deps -Dclippy::pedantic -Dwarnings - - name: Test with myers diff algo - run: cargo test --workspace --no-default-features --features vec_diff_myers + - uses: taiki-e/install-action@cargo-hack + + - name: Test + run: cargo hack --each-feature test --workspace - name: Run example run: cargo run --example visitor --features visitor diff --git a/Cargo.lock b/Cargo.lock index b8f72e7..cb1abe0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "android-tzdata" @@ -72,9 +72,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "darling" -version = "0.20.10" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +checksum = "a79c4acb1fd5fa3d9304be4c76e031c54d2e92d172a393e24b19a14fe8532fe9" dependencies = [ "darling_core", "darling_macro", @@ -82,9 +82,9 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.10" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +checksum = "74875de90daf30eb59609910b84d4d368103aaec4c924824c6799b28f77d6a1d" dependencies = [ "fnv", "ident_case", @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "darling_macro" -version = "0.20.10" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +checksum = "e79f8e61677d5df9167cd85265f8e5f64b215cdea3fb55eebc3e622e44c7a146" dependencies = [ "darling_core", "quote", @@ -260,9 +260,9 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.25" +version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +checksum = "ff24dfcda44452b9816fff4cd4227e1bb73ff5a2f1bc1105aa92fb8565ce44d2" dependencies = [ "proc-macro2", "syn", @@ -270,18 +270,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] @@ -374,9 +374,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.86" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89275301d38033efb81a6e60e3497e734dfcc62571f2854bf4b16690398824c" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", diff --git a/difficient-macros/Cargo.toml b/difficient-macros/Cargo.toml index aef2b94..b8625fe 100644 --- a/difficient-macros/Cargo.toml +++ b/difficient-macros/Cargo.toml @@ -7,16 +7,16 @@ version = "0.1.0" edition = "2024" [dependencies] -darling = "0.20.10" +darling = "0.21.0" heck = "0.5.0" -proc-macro2 = "1.0.86" -quote = "1.0.36" -syn = "2.0.72" +proc-macro2 = "1.0.95" +quote = "1.0.40" +syn = "2.0.104" [features] serde_impl = [] visitor_impl = ["serde_impl"] [dev-dependencies] -pretty_assertions = "1.4.0" -prettyplease = "0.2.20" +pretty_assertions = "1.4.1" +prettyplease = "0.2.36" diff --git a/examples/visitor.rs b/examples/visitor.rs index 32deed5..8d9a8f6 100644 --- a/examples/visitor.rs +++ b/examples/visitor.rs @@ -16,15 +16,13 @@ impl difficient::Visitor for ChangeEmitter { self.location.pop().unwrap(); } fn replaced(&mut self, val: T) { - use Enter::*; let mut path = String::new(); for (ix, loc) in self.location.iter().enumerate() { match loc { - NamedField { name, .. } => path.push_str(name), - PositionalField(p) => path.push_str(&p.to_string()), - Variant { name, .. } => path.push_str(name), - MapKey(key) => path.push_str(&key), - Index(key) => path.push_str(&key.to_string()), + Enter::NamedField { name, .. } | Enter::Variant { name, .. } => path.push_str(name), + Enter::PositionalField(p) => path.push_str(&p.to_string()), + Enter::MapKey(key) => path.push_str(key), + Enter::Index(key) => path.push_str(&key.to_string()), } if ix != self.location.len() - 1 { path.push('.'); @@ -83,6 +81,6 @@ fn main() { println!("Changed paths:"); for (path, val) in emitter.changes { - println!("{path}: {val}") + println!("{path}: {val}"); } } diff --git a/src/serde_visit.rs b/src/serde_visit.rs index 9a00d86..569a0ab 100644 --- a/src/serde_visit.rs +++ b/src/serde_visit.rs @@ -162,6 +162,10 @@ tuple_impl!(A 0); macro_rules! kv_map_impl { ($typ: ident, $bounds: ident) => { + #[allow( + clippy::implicit_hasher, + reason = "Implementation is shared among HashMap and BTreeMap" + )] impl<'a, K, V, U> AcceptVisitor for $typ> where K: $bounds + ToString + 'a, @@ -200,7 +204,7 @@ pub mod tests { use serde::Serialize; use super::*; - use crate::{Diffable, Replace, tests::*}; + use crate::{tests::*, Diffable, Replace}; impl AcceptVisitor for ParentDiff<'_> { fn accept(&self, visitor: &mut V) { @@ -337,7 +341,7 @@ pub mod tests { let loc = self.location.join("."); if let Ok(val) = serde_json::to_string(&val) { self.replaced_locs.push((loc, val)); - }; + } } fn splice(&mut self, from_index: usize, replace: usize, values: &[T]) { @@ -355,14 +359,15 @@ pub mod tests { values, }, )); - }; + } } fn enter(&mut self, val: Enter) { match val { - Enter::NamedField { name, .. } => self.location.push(name.into()), Enter::PositionalField(p) => self.location.push(p.to_string()), - Enter::Variant { name, .. } => self.location.push(name.into()), + Enter::NamedField { name, .. } | Enter::Variant { name, .. } => { + self.location.push(name.into()); + } Enter::MapKey(k) => self.location.push(k), Enter::Index(ix) => self.location.push(ix.to_string()), } diff --git a/src/vec.rs b/src/vec.rs index ab6c4a0..d31af1e 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -1,9 +1,3 @@ -#[cfg(feature = "vec_diff_lcs")] -use similar::algorithms::lcs as diff_algo; - -#[cfg(feature = "vec_diff_myers")] -use similar::algorithms::lcs as diff_algo; - use similar::algorithms::{Capture, Compact, Replace as SimilarReplace}; use crate::{Apply, ApplyError, Diffable, Replace}; @@ -75,7 +69,7 @@ mod visitor_impls { Self::Unchanged => {} Self::Changed { changes } => { for chg in changes { - chg.accept(visitor) + chg.accept(visitor); } } Self::Replaced(r) => visitor.replaced(r), @@ -90,7 +84,7 @@ mod visitor_impls { fn accept(&self, visitor: &mut V) { match self { VecChange::Remove { at_index, count } => { - visitor.splice::(*at_index, *count, &[]) + visitor.splice::(*at_index, *count, &[]); } VecChange::Insert { at_index, values } => visitor.splice(*at_index, 0, values), VecChange::Splice { @@ -188,6 +182,7 @@ where { type Diff = VecDiff<'a, T, T::Diff>; + #[allow(clippy::too_many_lines)] fn diff(&self, other: &'a Self) -> Self::Diff { if self.is_empty() && other.is_empty() { // short circuit @@ -205,7 +200,21 @@ where )] let rkeys: Vec<_> = other.iter().map(|v| v.key()).collect(); let mut d = Compact::new(SimilarReplace::new(Capture::new()), &lkeys, &rkeys); - diff_algo::diff(&mut d, &lkeys, 0..lkeys.len(), &rkeys, 0..rkeys.len()).unwrap(); + + if cfg!(feature = "vec_diff_myers") { + similar::algorithms::myers::diff( + &mut d, + &lkeys, + 0..lkeys.len(), + &rkeys, + 0..rkeys.len(), + ) + .unwrap(); + } else { + similar::algorithms::lcs::diff(&mut d, &lkeys, 0..lkeys.len(), &rkeys, 0..rkeys.len()) + .unwrap(); + } + let ops = d.into_inner().into_inner().into_ops(); let n_ops = ops.len(); let mut offset = 0isize; From cb1a99dfa01eabe8897c38850602f38940d618e5 Mon Sep 17 00:00:00 2001 From: Stuart Harris Date: Thu, 24 Jul 2025 11:21:22 +0100 Subject: [PATCH 2/2] chore: remove redundant lcs feature --- Cargo.toml | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0c18dff..2949033 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,16 +21,23 @@ thiserror = "1.0" uuid = { version = "1.11", optional = true } [features] -chrono = ["dep:chrono"] # impl Diffable on `chrono::DateTime` -uuid = ["dep:uuid"] # impl Diffable on `uuid::Uuid` -serde = ["dep:serde", "difficient-macros/serde_impl"] # add serde derives to derived structs -visitor = ["serde", "difficient-macros/visitor_impl"] # add AcceptVisitor impl +# impl Diffable on `chrono::DateTime` +chrono = ["dep:chrono"] -# choose your vec diff algo -vec_diff_myers = [] # is generally more efficient -vec_diff_lcs = [] # can result in smaller diffs in certain circumstances +# impl Diffable on `uuid::Uuid` +uuid = ["dep:uuid"] + +# add serde derives to derived structs +serde = ["dep:serde", "difficient-macros/serde_impl"] + +# add AcceptVisitor impl +visitor = ["serde", "difficient-macros/visitor_impl"] + +# choose your vec diff algorithm: +# the default is lcs, which can result in smaller diffs in certain circumstances, +# but you can choose myers instead, which may be more efficient +vec_diff_myers = [] -default = ["vec_diff_lcs"] [dev-dependencies] pretty_assertions = "1.4.0"