From a639d1ddc7405bb96dad96cd77e6b8bde7d77500 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Tue, 21 Apr 2026 09:32:24 -0500 Subject: [PATCH 1/7] meta: bump MSRV to 1.85 Updates the minimum supported Rust version from 1.75.0 to 1.85.0. This unlocks the 2024 edition, `Error` in `core`, `#[expect(...)]`, and other improvements that will be taken advantage of in subsequent commits. --- .github/workflows/ci.yml | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ffffc6e..995e0f7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - rust: [stable, beta, nightly, 1.75.0] + rust: [stable, beta, nightly, 1.85.0] steps: - uses: actions/checkout@v6 diff --git a/Cargo.toml b/Cargo.toml index 7833ce9..8b58e29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/bmwill/diffy" readme = "README.md" keywords = ["diff", "patch", "merge"] categories = ["text-processing"] -rust-version = "1.75.0" +rust-version = "1.85.0" edition = "2021" [package.metadata.docs.rs] From 397a5dac58471e0024961e1a94fde5a191f02fc2 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Tue, 21 Apr 2026 09:40:20 -0500 Subject: [PATCH 2/7] refactor: use `core::error::Error` instead of `std::error::Error` The `Error` trait has been available in `core` since Rust 1.81, which is below our new MSRV of 1.85. Previously, `Error` impls were gated behind the `std` feature so that the crate could build in a no_std environment. Now that the trait lives in `core`, these impls are unconditional and available even without the `std` feature enabled. --- src/apply.rs | 4 +--- src/binary/base85.rs | 4 +--- src/binary/delta.rs | 4 +--- src/binary/mod.rs | 4 +--- src/lib.rs | 2 +- src/patch/error.rs | 4 +--- src/patch_set/error.rs | 4 +--- 7 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/apply.rs b/src/apply.rs index 779cb2b..975a898 100644 --- a/src/apply.rs +++ b/src/apply.rs @@ -20,9 +20,7 @@ impl fmt::Display for ApplyError { } } -#[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl std::error::Error for ApplyError {} +impl core::error::Error for ApplyError {} #[derive(Debug)] enum ImageLine<'a, T: ?Sized> { diff --git a/src/binary/base85.rs b/src/binary/base85.rs index 600adf6..0968d89 100644 --- a/src/binary/base85.rs +++ b/src/binary/base85.rs @@ -46,9 +46,7 @@ impl fmt::Display for Base85Error { } } -#[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl std::error::Error for Base85Error {} +impl core::error::Error for Base85Error {} /// Decodes a Base85 string to the provided output. /// diff --git a/src/binary/delta.rs b/src/binary/delta.rs index fb6f2fe..48e4452 100644 --- a/src/binary/delta.rs +++ b/src/binary/delta.rs @@ -221,9 +221,7 @@ impl fmt::Display for DeltaError { } } -#[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl std::error::Error for DeltaError {} +impl core::error::Error for DeltaError {} #[cfg(test)] mod tests { diff --git a/src/binary/mod.rs b/src/binary/mod.rs index 07b9f4f..60e3d66 100644 --- a/src/binary/mod.rs +++ b/src/binary/mod.rs @@ -291,9 +291,7 @@ impl fmt::Display for BinaryPatchParseError { } } -#[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl std::error::Error for BinaryPatchParseError {} +impl core::error::Error for BinaryPatchParseError {} #[cfg(feature = "binary")] impl From for BinaryPatchParseError { diff --git a/src/lib.rs b/src/lib.rs index 6504856..f25305e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,7 @@ //! This crate is `no_std` by default. //! Enable [Cargo features] as needed: //! -//! - `std` for writer-based formatting and `std::error::Error` impls +//! - `std` for std::io::Write-based formatting impls //! - `color` for ANSI-colored patch formatting //! - `binary` for applying parsed git binary patches //! diff --git a/src/patch/error.rs b/src/patch/error.rs index be3ffa9..33767ec 100644 --- a/src/patch/error.rs +++ b/src/patch/error.rs @@ -36,9 +36,7 @@ impl fmt::Display for ParsePatchError { } } -#[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl std::error::Error for ParsePatchError {} +impl core::error::Error for ParsePatchError {} impl From for ParsePatchError { fn from(kind: ParsePatchErrorKind) -> Self { diff --git a/src/patch_set/error.rs b/src/patch_set/error.rs index 6a16944..798c3d7 100644 --- a/src/patch_set/error.rs +++ b/src/patch_set/error.rs @@ -43,9 +43,7 @@ impl fmt::Display for PatchSetParseError { } } -#[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl std::error::Error for PatchSetParseError {} +impl core::error::Error for PatchSetParseError {} impl From for PatchSetParseError { fn from(kind: PatchSetParseErrorKind) -> Self { From 3cb0b047bcbe0aa6ebbe31a1ee99e97b6965afec Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Tue, 21 Apr 2026 09:41:51 -0500 Subject: [PATCH 3/7] deps: update hashbrown to 0.17.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, we depended on hashbrown 0.16.1. With this commit, we bump to 0.17.0, which requires Rust 1.85.0 — the same as our MSRV. --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f1bb3c0..415abbc 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 = "anstream" @@ -174,9 +174,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.16.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" dependencies = [ "foldhash", ] diff --git a/Cargo.toml b/Cargo.toml index 8b58e29..46c2c16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ binary = ["dep:zlib-rs"] color = ["dep:anstyle"] [dependencies] -hashbrown = { version = "0.16.1", default-features = false, features = ["default-hasher"] } +hashbrown = { version = "0.17.0", default-features = false, features = ["default-hasher"] } anstyle = { version = "1.0.13", default-features = false, optional = true } zlib-rs = { version = "0.6.3", optional = true, default-features = false, features = ["c-allocator"] } From 5820968915d0bedb30b713391dffa2c4ed2b181b Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Tue, 21 Apr 2026 10:05:02 -0500 Subject: [PATCH 4/7] meta: update to 2024 edition Migrate the crate from the 2021 edition to the 2024 edition. The bulk of the diff is mechanical: - `cargo fix --edition` renames the `expr` macro fragment specifier to `expr_2021` to preserve the 2021 matching behavior. The 2024 `expr` specifier also accepts `const` blocks and `_`, which isn't wanted in these macros. - `cargo fix --edition` adds an extra `&` in a closure pattern to match the new match ergonomics rules. - `cargo fmt` rewrites `use` blocks because rustfmt's 2024 style uses case-sensitive ordering (uppercase before lowercase), whereas the 2021 style was case-insensitive. --- Cargo.toml | 2 +- examples/patch_formatter.rs | 2 +- src/apply.rs | 4 ++-- src/diff/tests.rs | 8 ++++---- src/lib.rs | 10 +++++----- src/merge/tests.rs | 10 +++++----- src/patch/format.rs | 8 ++++---- src/patch/parse.rs | 6 +++--- src/patch/tests.rs | 2 +- src/patch_set/mod.rs | 2 +- src/patch_set/parse.rs | 10 +++++----- src/patch_set/tests.rs | 2 +- src/utils.rs | 4 ++-- 13 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 46c2c16..e0d116c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ readme = "README.md" keywords = ["diff", "patch", "merge"] categories = ["text-processing"] rust-version = "1.85.0" -edition = "2021" +edition = "2024" [package.metadata.docs.rs] # To build locally: diff --git a/examples/patch_formatter.rs b/examples/patch_formatter.rs index 4a1a90c..76d3dc7 100644 --- a/examples/patch_formatter.rs +++ b/examples/patch_formatter.rs @@ -1,5 +1,5 @@ -use diffy::create_patch; use diffy::PatchFormatter; +use diffy::create_patch; fn main() { let original = "first line\nlast line"; diff --git a/src/apply.rs b/src/apply.rs index 975a898..ad8adaf 100644 --- a/src/apply.rs +++ b/src/apply.rs @@ -58,8 +58,8 @@ impl Clone for ImageLine<'_, T> { /// Apply a `Patch` to a base image /// /// ``` -/// use diffy::apply; /// use diffy::Patch; +/// use diffy::apply; /// /// let s = "\ /// --- a/ideals @@ -110,8 +110,8 @@ pub fn apply(base_image: &str, patch: &Patch<'_, str>) -> Result { + ([$($kind:ident($text:literal)),* $(,)?], $solution:ident, $msg:expr_2021 $(,)?) => { let expected = &[$(Diff::$kind($text)),*]; assert!( same_diffs(expected, &$solution), @@ -91,7 +91,7 @@ macro_rules! assert_diff { expected, $solution, ); }; - ([$($kind:ident($text:literal)),* $(,)?], $solution:ident, $msg:expr $(,)?) => { + ([$($kind:ident($text:literal)),* $(,)?], $solution:ident, $msg:expr_2021 $(,)?) => { let expected: &[_] = &[$(Diff::$kind($text)),*]; assert_eq!( expected, @@ -328,7 +328,7 @@ fn test_compact() { } macro_rules! assert_patch { - ($diff_options:expr, $old:ident, $new:ident, $expected:ident $(,)?) => { + ($diff_options:expr_2021, $old:ident, $new:ident, $expected:ident $(,)?) => { let patch = $diff_options.create_patch($old, $new); let bpatch = $diff_options.create_patch_bytes($old.as_bytes(), $new.as_bytes()); let patch_str = patch.to_string(); diff --git a/src/lib.rs b/src/lib.rs index f25305e..162484a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -112,8 +112,8 @@ //! image. //! //! ``` -//! use diffy::apply; //! use diffy::Patch; +//! use diffy::apply; //! //! let s = "\ //! --- a/skybreaker-ideals @@ -323,16 +323,16 @@ pub mod patch_set; mod range; mod utils; +pub use apply::ApplyError; pub use apply::apply; pub use apply::apply_bytes; -pub use apply::ApplyError; +pub use diff::DiffOptions; pub use diff::create_patch; pub use diff::create_patch_bytes; -pub use diff::DiffOptions; -pub use merge::merge; -pub use merge::merge_bytes; pub use merge::ConflictStyle; pub use merge::MergeOptions; +pub use merge::merge; +pub use merge::merge_bytes; pub use patch::Hunk; pub use patch::HunkRange; pub use patch::Line; diff --git a/src/merge/tests.rs b/src/merge/tests.rs index ff40860..99188df 100644 --- a/src/merge/tests.rs +++ b/src/merge/tests.rs @@ -1,14 +1,14 @@ use super::*; macro_rules! assert_merge { - ($original:ident, $ours:ident, $theirs:ident, $kind:ident($expected:expr), $msg:literal $(,)?) => { + ($original:ident, $ours:ident, $theirs:ident, $kind:ident($expected:expr_2021), $msg:literal $(,)?) => { let solution = merge($original, $ours, $theirs); macro_rules! result { - (Ok, $s:expr) => { + (Ok, $s:expr_2021) => { Result::<&str, &str>::Ok($s) }; - (Err, $s:expr) => { + (Err, $s:expr_2021) => { Result::<&str, &str>::Err($s) }; } @@ -23,10 +23,10 @@ macro_rules! assert_merge { merge_bytes($original.as_bytes(), $ours.as_bytes(), $theirs.as_bytes()); macro_rules! result_bytes { - (Ok, $s:expr) => { + (Ok, $s:expr_2021) => { Result::<&[u8], &[u8]>::Ok($s.as_bytes()) }; - (Err, $s:expr) => { + (Err, $s:expr_2021) => { Result::<&[u8], &[u8]>::Err($s.as_bytes()) }; } diff --git a/src/patch/format.rs b/src/patch/format.rs index 4cb8e43..8f172d3 100644 --- a/src/patch/format.rs +++ b/src/patch/format.rs @@ -6,20 +6,20 @@ use core::fmt::Result; #[cfg(feature = "std")] use std::io; -#[cfg(feature = "color")] -use super::style; use super::Hunk; use super::Line; -use super::Patch; use super::NO_NEWLINE_AT_EOF; +use super::Patch; +#[cfg(feature = "color")] +use super::style; /// Formats patches for display or writing into byte streams. /// /// # Examples /// /// ``` -/// use diffy::create_patch; /// use diffy::PatchFormatter; +/// use diffy::create_patch; /// /// let patch = create_patch("alpha\nbeta\n", "ALPHA\nbeta\n"); /// let formatter = PatchFormatter::new().missing_newline_message(false); diff --git a/src/patch/parse.rs b/src/patch/parse.rs index c730da0..d784e2e 100644 --- a/src/patch/parse.rs +++ b/src/patch/parse.rs @@ -1,15 +1,15 @@ //! Parse a Patch -use super::error::ParsePatchError; -use super::error::ParsePatchErrorKind; use super::Hunk; use super::HunkRange; use super::Line; use super::NO_NEWLINE_AT_EOF; +use super::error::ParsePatchError; +use super::error::ParsePatchErrorKind; use crate::patch::Patch; -use crate::utils::escaped_filename; use crate::utils::LineIter; use crate::utils::Text; +use crate::utils::escaped_filename; use alloc::borrow::Cow; use alloc::vec::Vec; diff --git a/src/patch/tests.rs b/src/patch/tests.rs index c61c37c..6fe864d 100644 --- a/src/patch/tests.rs +++ b/src/patch/tests.rs @@ -644,8 +644,8 @@ fn non_utf8_escaped_filename_returns_error_on_str_parse() { mod error_display { use alloc::string::ToString; - use crate::patch::error::ParsePatchErrorKind; use crate::Patch; + use crate::patch::error::ParsePatchErrorKind; use snapbox::assert_data_eq; use snapbox::str; diff --git a/src/patch_set/mod.rs b/src/patch_set/mod.rs index 2b341c2..15f94d5 100644 --- a/src/patch_set/mod.rs +++ b/src/patch_set/mod.rs @@ -12,9 +12,9 @@ use alloc::borrow::Cow; use alloc::borrow::ToOwned; use core::fmt; +use crate::Patch; use crate::binary::BinaryPatch; use crate::utils::Text; -use crate::Patch; pub use error::PatchSetParseError; use error::PatchSetParseErrorKind; diff --git a/src/patch_set/parse.rs b/src/patch_set/parse.rs index 1440955..8facc78 100644 --- a/src/patch_set/parse.rs +++ b/src/patch_set/parse.rs @@ -1,18 +1,18 @@ //! Parse multiple file patches from a unified diff. -use super::error::PatchSetParseErrorKind; use super::FileMode; use super::FileOperation; use super::FilePatch; use super::Format; use super::ParseOptions; use super::PatchSetParseError; -use crate::binary::parse_binary_patch; +use super::error::PatchSetParseErrorKind; +use crate::Patch; use crate::binary::BinaryPatch; +use crate::binary::parse_binary_patch; use crate::patch::parse::parse_one; -use crate::utils::escaped_filename; use crate::utils::Text; -use crate::Patch; +use crate::utils::escaped_filename; use alloc::borrow::Cow; use alloc::string::String; @@ -610,7 +610,7 @@ fn parse_unquoted_diff_git_path<'a, T: Text + ?Sized>( let mut best_match = None; let mut longest_path_len = 0; - for (i, _) in bytes.iter().enumerate().filter(|(_, &b)| b == b' ') { + for (i, _) in bytes.iter().enumerate().filter(|&(_, &b)| b == b' ') { let (left, right_with_space) = line.split_at(i); // skip the space let (_, right) = right_with_space.split_at(1); diff --git a/src/patch_set/tests.rs b/src/patch_set/tests.rs index 0ab01fe..8d35809 100644 --- a/src/patch_set/tests.rs +++ b/src/patch_set/tests.rs @@ -4,10 +4,10 @@ use alloc::borrow::ToOwned; use alloc::string::ToString; use alloc::vec::Vec; -use super::error::PatchSetParseErrorKind; use super::FileOperation; use super::ParseOptions; use super::PatchSet; +use super::error::PatchSetParseErrorKind; mod file_operation { use super::*; diff --git a/src/utils.rs b/src/utils.rs index bfbd16e..6491856 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -5,11 +5,11 @@ use alloc::borrow::ToOwned; use alloc::string::String; use alloc::vec::Vec; use core::hash::Hash; -use hashbrown::hash_map::Entry; use hashbrown::HashMap; +use hashbrown::hash_map::Entry; -use crate::patch::error::ParsePatchErrorKind; use crate::ParsePatchError; +use crate::patch::error::ParsePatchErrorKind; /// Returns `true` if a byte must be quoted in a diff filename. /// From a3c0147f8d8c68e330991aa17a25b90ecca68a0d Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Tue, 21 Apr 2026 10:08:00 -0500 Subject: [PATCH 5/7] refactor(binary): switch to `#[expect(dead_code)]` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `expect` attribute was stabilized in Rust 1.81, which is below the new MSRV of 1.85. Switch the three `allow(dead_code)` attributes on `BinaryPatchParseErrorKind` variants to `expect(dead_code)` so the attribute itself becomes a maintenance signal: if a variant becomes reachable when the `binary` feature is disabled, the compiler will flag the now-unfulfilled expectation. In the process, also drop the `allow(dead_code)` from `InvalidHeader`. That variant was never actually dead when the `binary` feature was disabled — `parse_binary_patch` is called unconditionally from `patch_set::parse`, and it produces `InvalidHeader` when the header line is missing. The pre-existing `allow` silently hid this; `expect` surfaces it and lets us remove the attribute entirely. --- src/binary/mod.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/binary/mod.rs b/src/binary/mod.rs index 60e3d66..49f084e 100644 --- a/src/binary/mod.rs +++ b/src/binary/mod.rs @@ -318,8 +318,6 @@ impl From for BinaryPatchParseError { #[non_exhaustive] pub(crate) enum BinaryPatchParseErrorKind { /// Missing or invalid "GIT binary patch" header. - // TODO: Switch to #[expect(dead_code)] when MSRV >= 1.81 - #[cfg_attr(not(feature = "binary"), allow(dead_code))] InvalidHeader, /// First binary block (forward) not found. @@ -329,13 +327,11 @@ pub(crate) enum BinaryPatchParseErrorKind { MissingReverseBlock, /// No binary data available (marker-only patch). - // TODO: Switch to #[expect(dead_code)] when MSRV >= 1.81 - #[cfg_attr(not(feature = "binary"), allow(dead_code))] + #[cfg_attr(not(feature = "binary"), expect(dead_code))] NoBinaryData, /// Invalid line length indicator in Base85 data. - // TODO: Switch to #[expect(dead_code)] when MSRV >= 1.81 - #[cfg_attr(not(feature = "binary"), allow(dead_code))] + #[cfg_attr(not(feature = "binary"), expect(dead_code))] InvalidLineLengthIndicator, /// Base85 decoding failed. From afd2faae66650c627fd9d49573f7aec6295f4b31 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Tue, 21 Apr 2026 10:08:05 -0500 Subject: [PATCH 6/7] refactor(merge): use `Option::is_none_or` `Option::is_none_or` was stabilized in Rust 1.82, which is below the new MSRV of 1.85. Use it in place of `map_or(true, ...)` to match clippy's `unnecessary_map_or` lint and read closer to the intent: "none, or the predicate holds." --- src/merge/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/merge/mod.rs b/src/merge/mod.rs index 15744df..e518704 100644 --- a/src/merge/mod.rs +++ b/src/merge/mod.rs @@ -424,10 +424,10 @@ fn merge_solutions<'ancestor, 'ours, 'theirs, T: ?Sized + SliceLike>( solution.push(merge_range); - if ours.map_or(true, |range| range.is_empty()) { + if ours.is_none_or(|range| range.is_empty()) { ours = our_solution.next(); } - if theirs.map_or(true, |range| range.is_empty()) { + if theirs.is_none_or(|range| range.is_empty()) { theirs = their_solution.next(); } } From f7cc1be1e55beee84474dd31e607cd8c25db4874 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Tue, 21 Apr 2026 10:43:05 -0500 Subject: [PATCH 7/7] refactor: replace `allow(...)` with `expect(...)` or drop when unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `expect` attribute, stabilized in Rust 1.81, is stricter than `allow`: it verifies that the suppressed lint actually fires. This surfaces stale suppressions and prevents silently hiding new issues. Convert remaining `allow(...)` attributes to `expect(...)` across the codebase where the suppression is genuinely load-bearing. For items that are dead in non-test builds but used by tests, use `#[cfg_attr(not(test), expect(dead_code))]` so the expectation holds under every configuration. Several `allow(...)` attributes turned out to be suppressing nothing at all — drop them. Examples: - `Range::range` and `Range::empty` are called from the merge path. - `ParseOpts::no_skip_preamble` is called from the patch set parser. - `Text::ends_with` and `Text::lines` are called through the trait. - The `Diff` enum and `DiffOptions::diff` are reachable through the free `diff` fn, which is the only real anchor in that chain. - A number of `needless_lifetimes` annotations as the lint was relaxed upstream. These were all silently wrong under `allow`; `expect` caught them. --- src/binary/base85.rs | 3 ++- src/diff/cleanup.rs | 3 --- src/diff/mod.rs | 6 ++---- src/merge/mod.rs | 1 - src/patch/mod.rs | 2 +- src/patch/parse.rs | 3 +-- src/range.rs | 8 +++----- src/utils.rs | 2 -- 8 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/binary/base85.rs b/src/binary/base85.rs index 0968d89..2eb6ea8 100644 --- a/src/binary/base85.rs +++ b/src/binary/base85.rs @@ -90,7 +90,8 @@ pub fn decode_into(input: &[u8], output: &mut impl Extend) -> Result<(), Bas /// Callers encoding data where the byte count isn't a multiple of 4 /// must handle padding at a higher level. /// For example, via a length indicator in Git binary patch format. -#[allow(dead_code)] // will be used for patch formatting +// will be used for patch formatting +#[cfg_attr(not(test), expect(dead_code))] pub fn encode_into(input: &[u8], output: &mut impl Extend) -> Result<(), Base85Error> { if input.len() % 4 != 0 { return Err(Base85Error::InvalidLength); diff --git a/src/diff/cleanup.rs b/src/diff/cleanup.rs index 3b1b6dc..f323dcc 100644 --- a/src/diff/cleanup.rs +++ b/src/diff/cleanup.rs @@ -4,7 +4,6 @@ use alloc::vec::Vec; // Walks through all edits and shifts them up and then down, trying to see if they run into similar // edits which can be merged -#[allow(clippy::needless_lifetimes)] pub fn compact<'a, 'b, T: ?Sized + SliceLike>(diffs: &mut Vec>) { // First attempt to compact all Deletions let mut pointer = 0; @@ -29,7 +28,6 @@ pub fn compact<'a, 'b, T: ?Sized + SliceLike>(diffs: &mut Vec( diffs: &mut Vec>, mut pointer: usize, @@ -131,7 +129,6 @@ fn shift_diff_up<'a, 'b, T: ?Sized + SliceLike>( } // Attempts to shift the Insertion or Deletion at location `pointer` as far downwards as possible. -#[allow(clippy::needless_lifetimes)] fn shift_diff_down<'a, 'b, T: ?Sized + SliceLike>( diffs: &mut Vec>, mut pointer: usize, diff --git a/src/diff/mod.rs b/src/diff/mod.rs index 861f638..b62e440 100644 --- a/src/diff/mod.rs +++ b/src/diff/mod.rs @@ -17,7 +17,6 @@ mod myers; mod tests; // TODO determine if this should be exposed in the public API -#[allow(dead_code)] #[derive(Debug, PartialEq, Eq)] enum Diff<'a, T: ?Sized> { Equal(&'a T), @@ -117,7 +116,7 @@ impl DiffOptions { /// produce a prettier diff by reducing the number of edited blocks by shifting and merging /// edit blocks. // TODO determine if this should be exposed in the public API - #[allow(dead_code)] + #[expect(dead_code)] fn set_compact(&mut self, compact: bool) -> &mut Self { self.compact = compact; self @@ -146,7 +145,6 @@ impl DiffOptions { } // TODO determine if this should be exposed in the public API - #[allow(dead_code)] fn diff<'a>(&self, original: &'a str, modified: &'a str) -> Vec> { let solution = myers::diff(original.as_bytes(), modified.as_bytes()); @@ -229,7 +227,7 @@ impl Default for DiffOptions { } // TODO determine if this should be exposed in the public API -#[allow(dead_code)] +#[cfg_attr(not(test), expect(dead_code))] fn diff<'a>(original: &'a str, modified: &'a str) -> Vec> { DiffOptions::default().diff(original, modified) } diff --git a/src/merge/mod.rs b/src/merge/mod.rs index e518704..21f9197 100644 --- a/src/merge/mod.rs +++ b/src/merge/mod.rs @@ -524,7 +524,6 @@ fn create_merge_range<'ancestor, 'ours, 'theirs, T: ?Sized + SliceLike>( } } -#[allow(clippy::needless_lifetimes)] fn cleanup_conflicts<'ancestor, 'ours, 'theirs, T: ?Sized + SliceLike + PartialEq>( solution: &mut [MergeRange<'ancestor, 'ours, 'theirs, T>], ) { diff --git a/src/patch/mod.rs b/src/patch/mod.rs index c17634a..f75f6e9 100644 --- a/src/patch/mod.rs +++ b/src/patch/mod.rs @@ -146,7 +146,7 @@ impl<'a> Patch<'a, str> { /// /// let patch = Patch::from_str(s).unwrap(); /// ``` - #[allow(clippy::should_implement_trait)] + #[expect(clippy::should_implement_trait)] pub fn from_str(s: &'a str) -> Result, ParsePatchError> { parse::parse(s) } diff --git a/src/patch/parse.rs b/src/patch/parse.rs index d784e2e..849e912 100644 --- a/src/patch/parse.rs +++ b/src/patch/parse.rs @@ -38,7 +38,6 @@ impl ParseOpts { /// /// Useful when the caller has already positioned the input /// at the start of the patch content. - #[allow(dead_code)] // will be used by patch_set parser pub(crate) fn no_skip_preamble(mut self) -> Self { self.skip_preamble = false; self @@ -145,7 +144,7 @@ pub(crate) fn parse_one( (Ok(Patch::new(header.0, header.1, hunks)), parser.offset()) } -#[allow(clippy::type_complexity)] +#[expect(clippy::type_complexity)] fn patch_header<'a, T: Text + ?Sized>( parser: &mut Parser<'a, T>, opts: &ParseOpts, diff --git a/src/range.rs b/src/range.rs index 5e454c9..cb9c22c 100644 --- a/src/range.rs +++ b/src/range.rs @@ -35,7 +35,6 @@ impl<'a, T: ?Sized> Range<'a, T> { self.offset } - #[allow(dead_code)] pub fn range(&self) -> ops::Range { self.offset..self.offset + self.len } @@ -98,7 +97,6 @@ where Range { inner, offset, len } } - #[allow(dead_code)] pub fn empty() -> Range<'a, T> { Range { inner: T::empty(), @@ -119,17 +117,17 @@ where self.as_slice().common_suffix_len(other.as_slice()) } - #[allow(dead_code)] + #[cfg_attr(not(test), expect(dead_code))] pub fn common_overlap_len(&self, other: Range<'_, T>) -> usize { self.as_slice().common_overlap_len(other.as_slice()) } - #[allow(dead_code)] + #[expect(dead_code)] pub fn starts_with(&self, prefix: Range<'_, T>) -> bool { self.as_slice().starts_with(prefix.as_slice()) } - #[allow(dead_code)] + #[expect(dead_code)] pub fn ends_with(&self, suffix: Range<'_, T>) -> bool { self.as_slice().ends_with(suffix.as_slice()) } diff --git a/src/utils.rs b/src/utils.rs index 6491856..d94d56b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -140,7 +140,6 @@ pub trait Text: Eq + Hash + ToOwned { fn is_empty(&self) -> bool; fn len(&self) -> usize; fn starts_with(&self, prefix: &str) -> bool; - #[allow(unused)] fn ends_with(&self, suffix: &str) -> bool; fn strip_prefix(&self, prefix: &str) -> Option<&Self>; fn strip_suffix(&self, suffix: &str) -> Option<&Self>; @@ -149,7 +148,6 @@ pub trait Text: Eq + Hash + ToOwned { fn split_at(&self, mid: usize) -> (&Self, &Self); fn as_str(&self) -> Option<&str>; fn as_bytes(&self) -> &[u8]; - #[allow(unused)] fn lines(&self) -> LineIter<'_, Self>; /// Converts raw bytes into `Self::Owned`.