Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ jobs:
- uses: actions/checkout@v6
- run: rustup toolchain install ${{ matrix.rust }} --profile minimal
- run: cargo +${{ matrix.rust }} check --all-targets --all-features
- run: cargo +${{ matrix.rust }} test
- run: cargo +${{ matrix.rust }} test -F binary
- run: cargo +${{ matrix.rust }} test --all-features

lint:
runs-on: ubuntu-latest
Expand All @@ -43,6 +42,29 @@ jobs:
- run: cargo clippy --all-targets --all-features
- run: cargo doc --no-deps --all-features

check-features:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: rust version
run: |
rustc --version
cargo --version
- uses: taiki-e/install-action@cargo-hack
- run: cargo hack check --feature-powerset --no-dev-deps

no-std:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- run: rustup toolchain install stable --profile minimal
- run: rustup target add aarch64-unknown-none
# Build against a bare-metal target that has no `std` crate,
# so any accidental reliance on `std` fails to link.
- run: cargo build --target aarch64-unknown-none --no-default-features
- run: cargo build --target aarch64-unknown-none --no-default-features --features color

semver:
runs-on: ubuntu-latest
steps:
Expand Down
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 19 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,28 @@ categories = ["text-processing"]
rust-version = "1.75.0"
edition = "2021"

[package.metadata.docs.rs]
# To build locally:
# RUSTDOCFLAGS="--cfg=docsrs -Zunstable-options --generate-link-to-definition" RUSTC_BOOTSTRAP=1 cargo doc --all-features --no-deps --open
all-features = true
rustdoc-args = [
# Enable doc_cfg showing the required features.
"--cfg=docsrs",

# Generate links to definition in rustdoc source code pages
# https://github.com/rust-lang/rust/pull/84176
"-Zunstable-options", "--generate-link-to-definition"
]

[features]
binary = ["dep:flate2"]
default = []
std = []
binary = ["dep:flate2", "std"]
color = ["dep:anstyle"]

[dependencies]
anstyle = { version = "1.0.13", optional = true }
hashbrown = { version = "0.16.1", default-features = false, features = ["default-hasher"] }
anstyle = { version = "1.0.13", default-features = false, optional = true }
flate2 = { version = "1.1.9", optional = true, default-features = false, features = ["zlib-rs"] }

[dev-dependencies]
Expand All @@ -26,7 +42,7 @@ snapbox = { version = "0.6.24", features = ["dir"] }

[[example]]
name = "patch_formatter"
required-features = ["color"]
required-features = ["std", "color"]

[[test]]
name = "compat"
Expand Down
10 changes: 8 additions & 2 deletions src/apply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ use crate::{
patch::{Hunk, Line, Patch},
utils::LineIter,
};
use std::{fmt, iter};
use alloc::string::String;
use alloc::vec::Vec;
use core::cmp;
use core::fmt;
use core::iter;

/// An error returned when [`apply`]ing a `Patch` fails
///
Expand All @@ -16,6 +20,8 @@ impl fmt::Display for ApplyError {
}
}

#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl std::error::Error for ApplyError {}

#[derive(Debug)]
Expand Down Expand Up @@ -145,7 +151,7 @@ fn find_position<T: PartialEq + ?Sized>(
) -> Option<usize> {
// In order to avoid searching through positions which are out of bounds of the image,
// clamp the starting position based on the length of the image
let pos = std::cmp::min(hunk.new_range().start().saturating_sub(1), image.len());
let pos = cmp::min(hunk.new_range().start().saturating_sub(1), image.len());

// Create an iterator that starts with 'pos' and then interleaves
// moving pos backward/foward by one.
Expand Down
6 changes: 5 additions & 1 deletion src/binary/base85.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//!
//! [RFC 1924]: https://datatracker.ietf.org/doc/html/rfc1924

use std::fmt;
use core::fmt;

/// Base85 character set (RFC 1924).
const ALPHABET: &[u8; 85] = b"0123456789\
Expand Down Expand Up @@ -46,6 +46,8 @@ impl fmt::Display for Base85Error {
}
}

#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl std::error::Error for Base85Error {}

/// Decodes a Base85 string to the provided output.
Expand Down Expand Up @@ -115,6 +117,8 @@ pub fn encode_into(input: &[u8], output: &mut impl Extend<char>) -> Result<(), B
#[cfg(test)]
mod tests {
use super::*;
use alloc::string::String;
use alloc::vec::Vec;

fn decode(input: &str) -> Result<Vec<u8>, Base85Error> {
let mut result = Vec::with_capacity((input.len() / 5) * 4);
Expand Down
6 changes: 5 additions & 1 deletion src/binary/delta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
//!
//! Based on Diffx's [Git Delta Binary Diffs](https://diffx.org/spec/binary-diffs.html#git-delta-binary-diffs)

use std::fmt;
use alloc::vec::Vec;
use core::fmt;

/// Applies delta instructions to an original file, producing the modified file.
pub fn apply(original: &[u8], delta: &[u8]) -> Result<Vec<u8>, DeltaError> {
Expand Down Expand Up @@ -220,11 +221,14 @@ impl fmt::Display for DeltaError {
}
}

#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl std::error::Error for DeltaError {}

#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;

#[test]
fn read_size_single_byte() {
Expand Down
14 changes: 12 additions & 2 deletions src/binary/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ mod base85;
#[cfg(feature = "binary")]
mod delta;

use std::{fmt, ops::Range};
#[cfg(feature = "binary")]
use alloc::string::String;
#[cfg(feature = "binary")]
use alloc::vec::Vec;
use core::{fmt, ops::Range};

/// Cap preallocation when the size comes from untrusted input.
///
Expand Down Expand Up @@ -79,6 +83,7 @@ impl<'a> BinaryPatch<'a> {
///
/// Unlike `git apply`, this doesn't validate the original content hash.
#[cfg(feature = "binary")]
#[cfg_attr(docsrs, doc(cfg(feature = "binary")))]
pub fn apply(&self, original: &[u8]) -> Result<Vec<u8>, BinaryPatchParseError> {
match self {
BinaryPatch::Full { forward, .. } => Self::apply_block(forward, original),
Expand All @@ -93,6 +98,7 @@ impl<'a> BinaryPatch<'a> {
///
/// Unlike `git apply`, this doesn't validate the modified content hash.
#[cfg(feature = "binary")]
#[cfg_attr(docsrs, doc(cfg(feature = "binary")))]
pub fn apply_reverse(&self, modified: &[u8]) -> Result<Vec<u8>, BinaryPatchParseError> {
match self {
BinaryPatch::Full { reverse, .. } => Self::apply_block(reverse, modified),
Expand All @@ -115,6 +121,7 @@ impl<'a> BinaryPatch<'a> {
/// See [Decoding Logic](https://diffx.org/spec/binary-diffs.html#decoding-logic)
#[cfg(feature = "binary")]
fn decode_data(binary_data: &BinaryData<'_>) -> Result<Vec<u8>, BinaryPatchParseError> {
use alloc::string::ToString;
use std::io::Read;

let compressed = decode_base85_lines(binary_data.data)?;
Expand Down Expand Up @@ -193,6 +200,8 @@ impl fmt::Display for BinaryPatchParseError {
}
}

#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl std::error::Error for BinaryPatchParseError {}

#[cfg(feature = "binary")]
Expand Down Expand Up @@ -358,7 +367,7 @@ fn parse_binary_block<'a>(parser: &mut BinaryParser<'a>) -> Option<BinaryBlock<'
let format_line = parser.next_line()?;
let space = format_line.iter().position(|&b| b == b' ')?;
let (patch_type, rest) = format_line.split_at(space);
let size_str = std::str::from_utf8(&rest[1..]).ok()?;
let size_str = core::str::from_utf8(&rest[1..]).ok()?;
let size: u64 = size_str.parse().ok()?;

let kind = match patch_type {
Expand Down Expand Up @@ -527,6 +536,7 @@ mod tests {
#[cfg(feature = "binary")]
mod apply_tests {
use super::*;
use alloc::vec;

#[test]
fn decode_line_length_uppercase() {
Expand Down
1 change: 1 addition & 0 deletions src/diff/cleanup.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::range::{DiffRange, SliceLike};
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
Expand Down
6 changes: 5 additions & 1 deletion src/diff/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ use crate::{
range::{DiffRange, SliceLike},
utils::Classifier,
};
use std::{borrow::Cow, cmp, ops};
use alloc::borrow::Cow;
use alloc::vec::Vec;
use core::cmp;
use core::ops;

mod cleanup;
mod myers;
Expand Down Expand Up @@ -405,6 +408,7 @@ fn build_edit_script<T>(solution: &[DiffRange<[T]>]) -> Vec<EditRange> {
#[cfg(test)]
mod test {
use super::DiffOptions;
use alloc::string::ToString;

#[test]
fn set_original_and_modified_filenames() {
Expand Down
9 changes: 6 additions & 3 deletions src/diff/myers.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::range::{DiffRange, Range};
use std::ops::{Index, IndexMut};
use alloc::vec;
use alloc::vec::Vec;
use core::fmt;
use core::ops::{Index, IndexMut};

// A D-path is a path which starts at (0,0) that has exactly D non-diagonal edges. All D-paths
// consist of a (D - 1)-path followed by a non-diagonal edge and then a possibly empty sequence of
Expand Down Expand Up @@ -57,8 +60,8 @@ struct Snake {
y_end: usize,
}

impl ::std::fmt::Display for Snake {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
impl fmt::Display for Snake {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"({}, {}) -> ({}, {})",
Expand Down
11 changes: 9 additions & 2 deletions src/diff/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ use crate::{
range::Range,
PatchFormatter,
};
use alloc::format;
use alloc::string::ToString;
use alloc::vec;
use alloc::vec::Vec;

// Helper macros are based off of the ones used in [dissimilar](https://docs.rs/dissimilar)
macro_rules! diff_range_list {
Expand Down Expand Up @@ -764,8 +768,11 @@ Second:

let elapsed = now.elapsed();

println!("{:?}", elapsed);
assert!(elapsed < std::time::Duration::from_micros(200));
assert!(
elapsed < core::time::Duration::from_micros(200),
"{:?}",
elapsed
);

assert_eq!(result, expected);
}
Expand Down
12 changes: 12 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,18 @@
//! [`create_patch`]: fn.create_patch.html
//! [`create_patch_bytes`]: fn.create_patch_bytes.html

// unconditionally define as no_std to have consistency on the prelude that is auto imported.
#![no_std]
#![warn(clippy::std_instead_of_core)]
#![warn(clippy::std_instead_of_alloc)]
#![warn(clippy::alloc_instead_of_core)]
#![cfg_attr(docsrs, feature(doc_cfg))]

extern crate alloc;

#[cfg(feature = "std")]
extern crate std;

mod apply;
pub mod binary;
mod diff;
Expand Down
5 changes: 4 additions & 1 deletion src/merge/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ use crate::{
range::{DiffRange, Range, SliceLike},
utils::Classifier,
};
use std::{cmp, fmt};
use alloc::fmt;
use alloc::string::String;
use alloc::vec::Vec;
use core::cmp;

#[cfg(test)]
mod tests;
Expand Down
6 changes: 4 additions & 2 deletions src/patch/error.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Error types for patch parsing.

use std::fmt;
use std::ops::Range;
use core::fmt;
use core::ops::Range;

/// An error returned when parsing a `Patch` using [`Patch::from_str`] fails.
///
Expand Down Expand Up @@ -36,6 +36,8 @@ impl fmt::Display for ParsePatchError {
}
}

#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl std::error::Error for ParsePatchError {}

impl From<ParsePatchErrorKind> for ParsePatchError {
Expand Down
Loading
Loading