Update rust and fix issues

This commit is contained in:
Andrew 2025-08-10 17:05:48 +12:00
parent 13d9eceb4b
commit b453b7c3f8
19 changed files with 39 additions and 48 deletions

View file

@ -161,7 +161,7 @@ jobs:
- name: Install MSRV Rust toolchain - name: Install MSRV Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1 uses: actions-rust-lang/setup-rust-toolchain@v1
with: with:
toolchain: 1.74.0 toolchain: 1.85.1
cache-bin: false cache-bin: false
cache-shared-key: cache cache-shared-key: cache

View file

@ -4,7 +4,7 @@ categories = ["command-line-utilities", "compression"]
description = "A lossless PNG compression optimizer" description = "A lossless PNG compression optimizer"
keywords = ["png", "image-compression", "optimization", "multi-threading", "lossless"] keywords = ["png", "image-compression", "optimization", "multi-threading", "lossless"]
documentation = "https://docs.rs/oxipng" documentation = "https://docs.rs/oxipng"
edition = "2021" edition = "2024"
exclude = [ exclude = [
".editorconfig", ".editorconfig",
".gitattributes", ".gitattributes",
@ -21,7 +21,7 @@ license = "MIT"
name = "oxipng" name = "oxipng"
repository = "https://github.com/oxipng/oxipng" repository = "https://github.com/oxipng/oxipng"
version = "9.1.5" version = "9.1.5"
rust-version = "1.74.0" rust-version = "1.85.1"
[badges] [badges]
travis-ci = { repository = "oxipng/oxipng", branch = "master" } travis-ci = { repository = "oxipng/oxipng", branch = "master" }

View file

@ -2,7 +2,7 @@
# check=error=true # check=error=true
FROM --platform=$BUILDPLATFORM tonistiigi/xx AS xx FROM --platform=$BUILDPLATFORM tonistiigi/xx AS xx
FROM --platform=$BUILDPLATFORM rust:1.74-alpine AS base FROM --platform=$BUILDPLATFORM rust:1.85.1-alpine AS base
RUN apk update && \ RUN apk update && \
apk add \ apk add \

View file

@ -40,7 +40,7 @@ cargo build --release
cp target/release/oxipng /usr/local/bin cp target/release/oxipng /usr/local/bin
``` ```
The current minimum supported Rust version is **1.74.0**. The current minimum supported Rust version is **1.85.1**.
Oxipng follows Semantic Versioning. Oxipng follows Semantic Versioning.

View file

@ -8,8 +8,7 @@ use std::{num::NonZeroU8, path::PathBuf};
use oxipng::{internal_tests::*, *}; use oxipng::{internal_tests::*, *};
use test::Bencher; use test::Bencher;
// SAFETY: trivially safe. Stopgap solution until const unwrap is stabilized. const DEFAULT_ZOPFLI_ITERATIONS: NonZeroU8 = NonZeroU8::new(15).unwrap();
const DEFAULT_ZOPFLI_ITERATIONS: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(15) };
#[bench] #[bench]
fn zopfli_16_bits_strategy_0(b: &mut Bencher) { fn zopfli_16_bits_strategy_0(b: &mut Bencher) {

View file

@ -1,9 +1,9 @@
use std::io::Write; use std::io::Write;
use crate::{ use crate::{
PngResult,
error::PngError, error::PngError,
headers::{read_be_u16, read_be_u32}, headers::{read_be_u16, read_be_u32},
PngResult,
}; };
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View file

@ -15,11 +15,7 @@ impl AtomicMin {
pub fn get(&self) -> Option<usize> { pub fn get(&self) -> Option<usize> {
let val = self.val.load(SeqCst); let val = self.val.load(SeqCst);
if val == usize::MAX { if val == usize::MAX { None } else { Some(val) }
None
} else {
Some(val)
}
} }
/// Try a new value, returning true if it is the new minimum /// Try a new value, returning true if it is the new minimum

View file

@ -1,6 +1,6 @@
use std::path::PathBuf; use std::path::PathBuf;
use clap::{value_parser, Arg, ArgAction, Command}; use clap::{Arg, ArgAction, Command, value_parser};
include!("display_chunks.rs"); include!("display_chunks.rs");

View file

@ -4,12 +4,12 @@
#[cfg(not(feature = "parallel"))] #[cfg(not(feature = "parallel"))]
use std::cell::RefCell; use std::cell::RefCell;
use std::sync::{ use std::sync::{
atomic::{AtomicUsize, Ordering::*},
Arc, Arc,
atomic::{AtomicUsize, Ordering::*},
}; };
#[cfg(feature = "parallel")] #[cfg(feature = "parallel")]
use crossbeam_channel::{unbounded, Receiver, Sender}; use crossbeam_channel::{Receiver, Sender, unbounded};
use deflate::Deflaters; use deflate::Deflaters;
use indexmap::IndexSet; use indexmap::IndexSet;
use log::trace; use log::trace;
@ -17,7 +17,7 @@ use rayon::prelude::*;
#[cfg(not(feature = "parallel"))] #[cfg(not(feature = "parallel"))]
use crate::rayon; use crate::rayon;
use crate::{atomicmin::AtomicMin, deflate, filters::RowFilter, png::PngImage, Deadline, PngError}; use crate::{Deadline, PngError, atomicmin::AtomicMin, deflate, filters::RowFilter, png::PngImage};
pub(crate) struct Candidate { pub(crate) struct Candidate {
pub image: Arc<PngImage>, pub image: Arc<PngImage>,
@ -30,7 +30,7 @@ pub(crate) struct Candidate {
} }
impl Candidate { impl Candidate {
fn cmp_key(&self) -> impl Ord { fn cmp_key(&self) -> impl Ord + use<> {
( (
self.estimated_output_size, self.estimated_output_size,
self.image.data.len(), self.image.data.len(),
@ -161,10 +161,7 @@ impl Evaluator {
best_candidate_size.set_min(estimated_output_size); best_candidate_size.set_min(estimated_output_size);
trace!( trace!(
"Eval: {}-bit {:23} {:8} {} bytes", "Eval: {}-bit {:23} {:8} {} bytes",
image.ihdr.bit_depth, image.ihdr.bit_depth, description, filter, estimated_output_size
description,
filter,
estimated_output_size
); );
#[cfg(feature = "parallel")] #[cfg(feature = "parallel")]
@ -182,10 +179,7 @@ impl Evaluator {
} else if let Err(PngError::DeflatedDataTooLong(size)) = idat_data { } else if let Err(PngError::DeflatedDataTooLong(size)) = idat_data {
trace!( trace!(
"Eval: {}-bit {:23} {:8} >{} bytes", "Eval: {}-bit {:23} {:8} >{} bytes",
image.ihdr.bit_depth, image.ihdr.bit_depth, description, filter, size
description,
filter,
size
); );
} }
}); });

View file

@ -3,12 +3,12 @@ use log::{debug, trace, warn};
use rgb::{RGB16, RGBA8}; use rgb::{RGB16, RGBA8};
use crate::{ use crate::{
Deflaters, Options, PngResult,
colors::{BitDepth, ColorType}, colors::{BitDepth, ColorType},
deflate::{crc32, inflate}, deflate::{crc32, inflate},
display_chunks::DISPLAY_CHUNKS, display_chunks::DISPLAY_CHUNKS,
error::PngError, error::PngError,
interlace::Interlacing, interlace::Interlacing,
Deflaters, Options, PngResult,
}; };
#[derive(Debug, Clone)] #[derive(Debug, Clone)]

View file

@ -2,7 +2,7 @@ use std::{fmt, fmt::Display};
use bitvec::prelude::*; use bitvec::prelude::*;
use crate::{headers::IhdrData, png::PngImage, PngError}; use crate::{PngError, headers::IhdrData, png::PngImage};
/// Whether to enable progressive rendering. See [`Options`][crate::Options]) /// Whether to enable progressive rendering. See [`Options`][crate::Options])
#[repr(u8)] #[repr(u8)]

View file

@ -27,16 +27,16 @@ mod rayon;
use std::{ use std::{
fs::{File, Metadata}, fs::{File, Metadata},
io::{stdin, stdout, BufWriter, Read, Write}, io::{BufWriter, Read, Write, stdin, stdout},
path::Path, path::Path,
sync::{ sync::{
atomic::{AtomicBool, Ordering},
Arc, Arc,
atomic::{AtomicBool, Ordering},
}, },
time::{Duration, Instant}, time::{Duration, Instant},
}; };
pub use indexmap::{indexset, IndexSet}; pub use indexmap::{IndexSet, indexset};
use log::{debug, info, trace, warn}; use log::{debug, info, trace, warn};
use rayon::prelude::*; use rayon::prelude::*;
pub use rgb::{RGB16, RGBA8}; pub use rgb::{RGB16, RGBA8};
@ -232,9 +232,9 @@ pub fn optimize(input: &InFile, output: &OutFile, opts: &Options) -> PngResult<(
if is_fully_optimized(in_data.len(), optimized_output.len(), opts) { if is_fully_optimized(in_data.len(), optimized_output.len(), opts) {
match (output, input) { match (output, input) {
// if p is None, it also means same as the input path // If output path is None, it also means same as the input path
(OutFile::Path { path, .. }, InFile::Path(ref input_path)) (OutFile::Path { path, .. }, InFile::Path(input_path))
if path.as_ref().map_or(true, |p| p == input_path) => if path.as_ref().is_none_or(|p| p == input_path) =>
{ {
info!("{input}: Could not optimize further, no change written"); info!("{input}: Could not optimize further, no change written");
return Ok(()); return Ok(());
@ -396,7 +396,9 @@ fn optimize_png(
} }
if opts.interlace == Some(Interlacing::Adam7) && png.raw.ihdr.interlaced != Interlacing::Adam7 { if opts.interlace == Some(Interlacing::Adam7) && png.raw.ihdr.interlaced != Interlacing::Adam7 {
warn!("Interlacing was not enabled as it would result in a larger file. To override this, use `--force`."); warn!(
"Interlacing was not enabled as it would result in a larger file. To override this, use `--force`."
);
} }
#[cfg(feature = "sanity-checks")] #[cfg(feature = "sanity-checks")]
@ -471,7 +473,7 @@ fn optimize_raw(
}; };
if result.data_is_compressed if result.data_is_compressed
&& max_size.map_or(true, |max_size| result.estimated_output_size < max_size) && max_size.is_none_or(|max_size| result.estimated_output_size < max_size)
{ {
debug!("Found better result:"); debug!("Found better result:");
debug!(" {}, f = {}", deflater, result.filter); debug!(" {}, f = {}", deflater, result.filter);

View file

@ -25,7 +25,7 @@ use std::{
use clap::ArgMatches; use clap::ArgMatches;
mod cli; mod cli;
use indexmap::IndexSet; use indexmap::IndexSet;
use log::{error, warn, Level, LevelFilter}; use log::{Level, LevelFilter, error, warn};
use oxipng::{Deflaters, InFile, Options, OutFile, PngError, RowFilter, StripChunks}; use oxipng::{Deflaters, InFile, Options, OutFile, PngError, RowFilter, StripChunks};
use rayon::prelude::*; use rayon::prelude::*;

View file

@ -4,7 +4,7 @@ use std::{
time::Duration, time::Duration,
}; };
use indexmap::{indexset, IndexSet}; use indexmap::{IndexSet, indexset};
use log::warn; use log::warn;
use crate::{deflate::Deflaters, filters::RowFilter, headers::StripChunks, interlace::Interlacing}; use crate::{deflate::Deflaters, filters::RowFilter, headers::StripChunks, interlace::Interlacing};

View file

@ -12,14 +12,14 @@ use rgb::ComponentSlice;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use crate::{ use crate::{
Options,
apng::*, apng::*,
colors::{BitDepth, ColorType}, colors::{BitDepth, ColorType},
deflate, deflate,
error::PngError, error::PngError,
filters::*, filters::*,
headers::*, headers::*,
interlace::{deinterlace_image, interlace_image, Interlacing}, interlace::{Interlacing, deinterlace_image, interlace_image},
Options,
}; };
pub(crate) mod scan_lines; pub(crate) mod scan_lines;

View file

@ -1,7 +1,7 @@
use std::hash::{BuildHasherDefault, Hash}; use std::hash::{BuildHasherDefault, Hash};
use indexmap::IndexSet; use indexmap::IndexSet;
use rgb::{alt::Gray, ComponentMap, ComponentSlice, FromSlice, RGB, RGBA}; use rgb::{ComponentMap, ComponentSlice, FromSlice, RGB, RGBA, alt::Gray};
use rustc_hash::FxHasher; use rustc_hash::FxHasher;
use crate::{ use crate::{

View file

@ -1,6 +1,6 @@
use std::sync::Arc; use std::sync::Arc;
use crate::{evaluate::Evaluator, png::PngImage, ColorType, Deadline, Deflaters, Options}; use crate::{ColorType, Deadline, Deflaters, Options, evaluate::Evaluator, png::PngImage};
pub mod alpha; pub mod alpha;
use crate::alpha::*; use crate::alpha::*;
@ -183,7 +183,7 @@ pub(crate) fn perform_reductions(
if (!cheap || reduced.is_none()) && !deadline.passed() { if (!cheap || reduced.is_none()) && !deadline.passed() {
if let Some(indexed) = indexed.and_then(|png| reduced_bit_depth_8_or_less(&png)) { if let Some(indexed) = indexed.and_then(|png| reduced_bit_depth_8_or_less(&png)) {
// Only evaluate this if it's different from the first result (which must be grayscale if it exists) // Only evaluate this if it's different from the first result (which must be grayscale if it exists)
if reduced.as_ref().map_or(true, |r| r.data != indexed.data) { if reduced.as_ref().is_none_or(|r| r.data != indexed.data) {
eval.try_image(Arc::new(indexed)); eval.try_image(Arc::new(indexed));
evaluation_added = true; evaluation_added = true;
} }

View file

@ -2,10 +2,10 @@ use indexmap::IndexSet;
use rgb::RGBA8; use rgb::RGBA8;
use crate::{ use crate::{
Interlacing,
colors::{BitDepth, ColorType}, colors::{BitDepth, ColorType},
headers::IhdrData, headers::IhdrData,
png::{scan_lines::ScanLine, PngImage}, png::{PngImage, scan_lines::ScanLine},
Interlacing,
}; };
/// Attempt to reduce the number of colors in the palette, returning the reduced image if successful /// Attempt to reduce the number of colors in the palette, returning the reduced image if successful

View file

@ -99,11 +99,11 @@ fn test_it_converts(
fn verbose_mode() { fn verbose_mode() {
use std::cell::RefCell; use std::cell::RefCell;
#[cfg(not(feature = "parallel"))] #[cfg(not(feature = "parallel"))]
use std::sync::mpsc::{channel as unbounded, Sender}; use std::sync::mpsc::{Sender, channel as unbounded};
#[cfg(feature = "parallel")] #[cfg(feature = "parallel")]
use crossbeam_channel::{unbounded, Sender}; use crossbeam_channel::{Sender, unbounded};
use log::{set_logger, set_max_level, Level, LevelFilter, Log, Metadata, Record}; use log::{Level, LevelFilter, Log, Metadata, Record, set_logger, set_max_level};
// Rust runs tests in parallel by default. // Rust runs tests in parallel by default.
// We want to make sure that we verify only logs from our test. // We want to make sure that we verify only logs from our test.