From e896960b426b4ae72cdb1529dec13c3d5e6e1778 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Lauzier?= Date: Sun, 25 Jul 2021 20:38:26 -0400 Subject: [PATCH] Fix some warnings --- Cargo.lock | 8 ++-- benches/filters.rs | 1 + build.rs | 2 +- clippy.toml | 4 ++ src/atomicmin.rs | 3 +- src/colors.rs | 4 ++ src/deflate/cfzlib.rs | 3 +- src/deflate/miniz_stream.rs | 4 +- src/error.rs | 1 + src/evaluate.rs | 4 +- src/headers.rs | 1 + src/lib.rs | 94 ++++++++++++++++++++++++------------- src/main.rs | 77 ++++++++++++++++++++---------- src/png/mod.rs | 10 ++-- src/reduction/alpha.rs | 7 +-- src/reduction/color.rs | 41 ++++++++-------- src/reduction/mod.rs | 31 +++++++----- tests/flags.rs | 8 ++-- 18 files changed, 193 insertions(+), 110 deletions(-) create mode 100644 clippy.toml diff --git a/Cargo.lock b/Cargo.lock index 698b9550..56cdeb54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,9 +60,9 @@ checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" [[package]] name = "bytemuck" -version = "1.7.0" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9966d2ab714d0f785dbac0a0396251a35280aeb42413281617d0209ab4898435" +checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b" [[package]] name = "byteorder" @@ -72,9 +72,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" +checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" [[package]] name = "cfg-if" diff --git a/benches/filters.rs b/benches/filters.rs index 27a330b8..2c5aeef3 100644 --- a/benches/filters.rs +++ b/benches/filters.rs @@ -1,4 +1,5 @@ #![feature(test)] +#![allow(unused_must_use)] extern crate oxipng; extern crate test; diff --git a/build.rs b/build.rs index e9f6cf5a..abe3e4f1 100644 --- a/build.rs +++ b/build.rs @@ -2,7 +2,7 @@ use rustc_version::{version, Version}; use std::process::exit; fn main() { - // This should match the version in Github Actions scripts and the Readme + // This should match the version in GitHub Actions scripts and the Readme const REQUIRED_VERSION: &str = "1.46.0"; if version().unwrap() < Version::parse(REQUIRED_VERSION).unwrap() { eprintln!("oxipng requires rustc >= {}.", REQUIRED_VERSION); diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 00000000..761dfcc6 --- /dev/null +++ b/clippy.toml @@ -0,0 +1,4 @@ +msrv = "1.46" +too-many-arguments-threshold = 9 +max-struct-bools = 11 +too-many-lines-threshold = 249 diff --git a/src/atomicmin.rs b/src/atomicmin.rs index 73c3d997..56943d7e 100644 --- a/src/atomicmin.rs +++ b/src/atomicmin.rs @@ -7,6 +7,7 @@ pub struct AtomicMin { } impl AtomicMin { + #[must_use] pub fn new(init: Option) -> Self { Self { val: AtomicUsize::new(init.unwrap_or(usize::MAX)), @@ -22,7 +23,7 @@ impl AtomicMin { } } - /// Unset value is usize_max + /// Unset value is `usize_max` pub fn as_atomic_usize(&self) -> &AtomicUsize { &self.val } diff --git a/src/colors.rs b/src/colors.rs index ae698dca..8b647410 100644 --- a/src/colors.rs +++ b/src/colors.rs @@ -35,6 +35,7 @@ impl fmt::Display for ColorType { impl ColorType { /// Get the code used by the PNG specification to denote this color type #[inline] + #[must_use] pub fn png_header_code(self) -> u8 { match self { ColorType::Grayscale => 0, @@ -46,6 +47,7 @@ impl ColorType { } #[inline] + #[must_use] pub fn channels_per_pixel(self) -> u8 { match self { ColorType::Grayscale | ColorType::Indexed => 1, @@ -91,6 +93,7 @@ impl fmt::Display for BitDepth { impl BitDepth { /// Retrieve the number of bits per channel per pixel as a `u8` #[inline] + #[must_use] pub fn as_u8(self) -> u8 { match self { BitDepth::One => 1, @@ -106,6 +109,7 @@ impl BitDepth { /// /// If depth is unsupported #[inline] + #[must_use] pub fn from_u8(depth: u8) -> BitDepth { match depth { 1 => BitDepth::One, diff --git a/src/deflate/cfzlib.rs b/src/deflate/cfzlib.rs index bad4da6f..a069221b 100644 --- a/src/deflate/cfzlib.rs +++ b/src/deflate/cfzlib.rs @@ -3,7 +3,7 @@ use crate::Deadline; use crate::PngError; use crate::PngResult; pub use cloudflare_zlib::is_supported; -use cloudflare_zlib::*; +use cloudflare_zlib::{Deflate, ZError}; impl From for PngError { fn from(err: ZError) -> Self { @@ -40,6 +40,7 @@ pub(crate) fn cfzlib_deflate( #[test] fn compress_test() { + use cloudflare_zlib::{Z_BEST_COMPRESSION, Z_DEFAULT_STRATEGY}; let vec = cfzlib_deflate( b"azxcvbnm", Z_BEST_COMPRESSION as u8, diff --git a/src/deflate/miniz_stream.rs b/src/deflate/miniz_stream.rs index b44ed212..b72b8706 100644 --- a/src/deflate/miniz_stream.rs +++ b/src/deflate/miniz_stream.rs @@ -1,7 +1,9 @@ use crate::atomicmin::AtomicMin; use crate::error::PngError; use crate::PngResult; -use miniz_oxide::deflate::core::*; +use miniz_oxide::deflate::core::{ + compress, create_comp_flags_from_zip_params, CompressorOxide, TDEFLFlush, TDEFLStatus, +}; pub(crate) fn compress_to_vec_oxipng( input: &[u8], diff --git a/src/error.rs b/src/error.rs index 0f099d5d..eaeb14c4 100644 --- a/src/error.rs +++ b/src/error.rs @@ -37,6 +37,7 @@ impl fmt::Display for PngError { impl PngError { #[cold] + #[must_use] pub fn new(description: &str) -> PngError { PngError::Other(description.into()) } diff --git a/src/evaluate.rs b/src/evaluate.rs index 0e07d308..c609481f 100644 --- a/src/evaluate.rs +++ b/src/evaluate.rs @@ -88,12 +88,12 @@ impl Evaluator { /// Set baseline image. It will be used only to measure minimum compression level required pub fn set_baseline(&self, image: Arc) { - self.try_image_inner(image, false) + self.try_image_inner(image, false); } /// Check if the image is smaller than others pub fn try_image(&self, image: Arc) { - self.try_image_inner(image, true) + self.try_image_inner(image, true); } fn try_image_inner(&self, image: Arc, is_reduction: bool) { diff --git a/src/headers.rs b/src/headers.rs index 318d4cdb..5421858e 100644 --- a/src/headers.rs +++ b/src/headers.rs @@ -80,6 +80,7 @@ pub enum Headers { } #[inline] +#[must_use] pub fn file_header_is_valid(bytes: &[u8]) -> bool { let expected_header: [u8; 8] = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]; diff --git a/src/lib.rs b/src/lib.rs index a4620cef..a7e2371a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,18 +1,41 @@ -#![warn(trivial_casts, trivial_numeric_casts, unused_import_braces)] -#![deny(missing_debug_implementations, missing_copy_implementations)] -#![warn(clippy::expl_impl_clone_on_copy)] -#![warn(clippy::float_cmp_const)] -#![warn(clippy::linkedlist)] -#![warn(clippy::map_flatten)] -#![warn(clippy::match_same_arms)] -#![warn(clippy::mem_forget)] -#![warn(clippy::mut_mut)] -#![warn(clippy::mutex_integer)] -#![warn(clippy::needless_continue)] -#![warn(clippy::path_buf_push_overwrite)] -#![warn(clippy::range_plus_one)] -#![allow(clippy::cognitive_complexity)] -#![allow(clippy::upper_case_acronyms)] +#![deny( + trivial_casts, + trivial_numeric_casts, + unused_import_braces, + missing_debug_implementations, + missing_copy_implementations, + rust_2018_idioms, + rust_2018_compatibility, + future_incompatible, + unused, + nonstandard_style +)] +#![warn( + clippy::all, + clippy::doc_markdown, + clippy::wildcard_imports, + clippy::unreadable_literal, + clippy::unnested_or_patterns, + clippy::must_use_candidate, + clippy::map_unwrap_or, + clippy::large_types_passed_by_value, + clippy::float_cmp_const, + clippy::lossy_float_literal, + clippy::float_equality_without_abs, + clippy::suboptimal_flops, + clippy::imprecise_flops, + clippy::mem_forget, + clippy::mutex_integer, + clippy::path_buf_push_overwrite, + clippy::expl_impl_clone_on_copy, + clippy::linkedlist, + clippy::map_flatten, + clippy::match_same_arms, + clippy::mut_mut, + clippy::needless_continue, + clippy::range_plus_one, + clippy::range_minus_one +)] #![cfg_attr( not(any(feature = "libdeflater", feature = "zopfli")), allow(irrefutable_let_patterns), @@ -30,7 +53,10 @@ use crate::deflate::inflate; use crate::evaluate::Evaluator; use crate::png::PngData; use crate::png::PngImage; -use crate::reduction::*; +use crate::reduction::{ + alpha, bit_depth, color, reduce_bit_depth, reduce_color_type, reduced_palette, + try_alpha_reductions, +}; use crc::{Crc, CRC_32_ISO_HDLC}; use image::{DynamicImage, GenericImageView, ImageFormat, Pixel}; use log::{debug, error, info, warn}; @@ -79,6 +105,7 @@ pub enum OutFile { } impl OutFile { + #[must_use] pub fn path(&self) -> Option<&Path> { match *self { OutFile::Path(Some(ref p)) => Some(p.as_path()), @@ -95,6 +122,7 @@ pub enum InFile { } impl InFile { + #[must_use] pub fn path(&self) -> Option<&Path> { match *self { InFile::Path(ref p) => Some(p.as_path()), @@ -201,6 +229,7 @@ pub struct Options { } impl Options { + #[must_use] pub fn from_preset(level: u8) -> Options { let opts = Options::default(); match level { @@ -221,6 +250,7 @@ impl Options { } } + #[must_use] pub fn max_compression() -> Options { Options::from_preset(6) } @@ -364,7 +394,7 @@ pub fn optimize(input: &InFile, output: &OutFile, opts: &Options) -> PngResult<( let mut png = PngData::from_slice(&in_data, opts.fix_errors)?; // Run the optimizer on the decoded PNG. - let mut optimized_output = optimize_png(&mut png, &in_data, opts, deadline)?; + let mut optimized_output = optimize_png(&mut png, &in_data, opts, &deadline)?; if is_fully_optimized(in_data.len(), optimized_output.len(), opts) { info!("File already optimized"); @@ -396,8 +426,7 @@ pub fn optimize(input: &InFile, output: &OutFile, opts: &Options) -> PngResult<( (&OutFile::Path(ref output_path), _) => { let output_path = output_path .as_ref() - .map(|p| p.as_path()) - .unwrap_or_else(|| input.path().unwrap()); + .map_or_else(|| input.path().unwrap(), PathBuf::as_path); if opts.backup { perform_backup(output_path)?; } @@ -447,7 +476,7 @@ pub fn optimize_from_memory(data: &[u8], opts: &Options) -> PngResult> { let mut png = PngData::from_slice(data, opts.fix_errors)?; // Run the optimizer on the decoded PNG. - let optimized_output = optimize_png(&mut png, data, opts, deadline)?; + let optimized_output = optimize_png(&mut png, data, opts, &deadline)?; if is_fully_optimized(original_size, optimized_output.len(), opts) { info!("Image already optimized"); @@ -470,7 +499,7 @@ fn optimize_png( png: &mut PngData, original_data: &[u8], opts: &Options, - deadline: Arc, + deadline: &Arc, ) -> PngResult> { type TrialWithData = (TrialOptions, Vec); @@ -532,13 +561,11 @@ fn optimize_png( if opts.interlace.is_none() { eval.set_baseline(png.raw.clone()); } - perform_reductions(png.raw.clone(), opts, &deadline, &eval); - let reduction_occurred = if let Some(result) = eval.get_result() { + perform_reductions(png.raw.clone(), opts, deadline, &eval); + let reduction_occurred = eval.get_result().map_or(false, |result| { *png = result; true - } else { - false - }; + }); if opts.idat_recoding || reduction_occurred { // Go through selected permutations and determine the best @@ -605,7 +632,7 @@ fn optimize_png( trial.strategy, window, &best_size, - &deadline, + deadline, ), #[cfg(feature = "zopfli")] Deflaters::Zopfli => deflate::zopfli_deflate(filtered), @@ -783,7 +810,7 @@ fn perform_reductions( } } - try_alpha_reductions(png, &opts.alphas, eval); + try_alpha_reductions(&png, &opts.alphas, eval); } #[derive(Debug)] @@ -801,6 +828,7 @@ pub struct Deadline { } impl Deadline { + #[must_use] pub fn new(timeout: Option) -> Self { Self { imp: timeout.map(|timeout| DeadlineImp { @@ -872,7 +900,7 @@ fn perform_strip(png: &mut PngData, opts: &Options) { *b"cHRM", *b"gAMA", *b"iCCP", *b"sBIT", *b"sRGB", *b"bKGD", *b"hIST", *b"pHYs", *b"sPLT", ]; - let keys: Vec<[u8; 4]> = raw.aux_headers.keys().cloned().collect(); + let keys: Vec<[u8; 4]> = raw.aux_headers.keys().copied().collect(); for hdr in &keys { if !PRESERVED_HEADERS.contains(hdr) { raw.aux_headers.remove(hdr); @@ -908,7 +936,7 @@ fn perform_strip(png: &mut PngData, opts: &Options) { } } -/// If the profile is sRGB, extracts the rendering intent value from it +/// If the profile is `sRGB`, extracts the rendering intent value from it fn srgb_rendering_intent(mut iccp: &[u8]) -> Option { // Skip (useless) profile name loop { @@ -1032,14 +1060,14 @@ fn copy_permissions(metadata_input: &Metadata, out_file: &File) -> PngResult<()> )) }) .and_then(|out_meta_reread| { - if out_meta_reread.permissions().mode() != permissions { + if out_meta_reread.permissions().mode() == permissions { + Ok(()) + } else { Err(PngError::new(&format!( "failed to set permissions, expected: {:04o}, found: {:04o}", permissions, out_meta_reread.permissions().mode() ))) - } else { - Ok(()) } }) }) diff --git a/src/main.rs b/src/main.rs index 1a269dd4..85f28d1b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,41 @@ -#![warn(trivial_casts, trivial_numeric_casts, unused_import_braces)] -#![deny(missing_debug_implementations, missing_copy_implementations)] -#![warn(clippy::expl_impl_clone_on_copy)] -#![warn(clippy::float_cmp_const)] -#![warn(clippy::linkedlist)] -#![warn(clippy::map_flatten)] -#![warn(clippy::match_same_arms)] -#![warn(clippy::mem_forget)] -#![warn(clippy::mut_mut)] -#![warn(clippy::mutex_integer)] -#![warn(clippy::needless_continue)] -#![warn(clippy::path_buf_push_overwrite)] -#![warn(clippy::range_plus_one)] -#![allow(clippy::cognitive_complexity)] +#![deny( + trivial_casts, + trivial_numeric_casts, + unused_import_braces, + missing_debug_implementations, + missing_copy_implementations, + rust_2018_idioms, + rust_2018_compatibility, + future_incompatible, + unused, + nonstandard_style +)] +#![warn( + clippy::all, + clippy::doc_markdown, + clippy::wildcard_imports, + clippy::unreadable_literal, + clippy::unnested_or_patterns, + clippy::must_use_candidate, + clippy::map_unwrap_or, + clippy::large_types_passed_by_value, + clippy::float_cmp_const, + clippy::lossy_float_literal, + clippy::float_equality_without_abs, + clippy::suboptimal_flops, + clippy::imprecise_flops, + clippy::mem_forget, + clippy::mutex_integer, + clippy::path_buf_push_overwrite, + clippy::expl_impl_clone_on_copy, + clippy::linkedlist, + clippy::map_flatten, + clippy::match_same_arms, + clippy::mut_mut, + clippy::needless_continue, + clippy::range_plus_one, + clippy::range_minus_one +)] use clap::{App, AppSettings, Arg, ArgMatches}; use indexmap::IndexSet; @@ -318,12 +342,13 @@ fn collect_files( } continue; }; - let out_file = if let Some(ref out_dir) = *out_dir { - let out_path = Some(out_dir.join(input.file_name().unwrap())); - OutFile::Path(out_path) - } else { - (*out_file).clone() - }; + let out_file = out_dir.as_ref().map_or_else( + || (*out_file).clone(), + |out_dir| { + let out_path = Some(out_dir.join(input.file_name().unwrap())); + OutFile::Path(out_path) + }, + ); let in_file = if using_stdin { InFile::StdIn } else { @@ -335,7 +360,7 @@ fn collect_files( } fn parse_opts_into_struct( - matches: &ArgMatches, + matches: &ArgMatches<'_>, ) -> Result<(OutFile, Option, Options), String> { stderrlog::new() .module(module_path!()) @@ -389,10 +414,12 @@ fn parse_opts_into_struct( let out_file = if matches.is_present("stdout") { OutFile::StdOut - } else if let Some(x) = matches.value_of("output_file") { - OutFile::Path(Some(PathBuf::from(x))) } else { - OutFile::Path(None) + matches + .value_of("output_file") + .map_or(OutFile::Path(None), |x| { + OutFile::Path(Some(PathBuf::from(x))) + }) }; if matches.is_present("alpha") { @@ -452,7 +479,7 @@ fn parse_opts_into_struct( } if let Some(hdrs) = matches.value_of("keep") { - opts.strip = Headers::Keep(hdrs.split(',').map(|x| x.trim().to_owned()).collect()) + opts.strip = Headers::Keep(hdrs.split(',').map(|x| x.trim().to_owned()).collect()); } if let Some(hdrs) = matches.value_of("strip") { diff --git a/src/png/mod.rs b/src/png/mod.rs index eea89b14..c4686aab 100644 --- a/src/png/mod.rs +++ b/src/png/mod.rs @@ -1,8 +1,8 @@ use crate::colors::ColorType; use crate::deflate; use crate::error::PngError; -use crate::filters::*; -use crate::headers::*; +use crate::filters::{filter_line, unfilter_line}; +use crate::headers::{file_header_is_valid, parse_ihdr_header, parse_next_header, IhdrData}; use crate::interlace::{deinterlace_image, interlace_image}; use byteorder::{BigEndian, WriteBytesExt}; use crc::{Crc, CRC_32_ISO_HDLC}; @@ -170,6 +170,7 @@ impl PngData { } /// Format the `PngData` struct into a valid PNG bytestream + #[must_use] pub fn output(&self) -> Vec { // PNG header let mut output = vec![0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]; @@ -264,12 +265,14 @@ impl PngImage { /// Return the number of channels in the image, based on color type #[inline] + #[must_use] pub fn channels_per_pixel(&self) -> u8 { self.ihdr.color_type.channels_per_pixel() } /// Return an iterator over the scanlines of the image #[inline] + #[must_use] pub fn scan_lines(&self) -> ScanLines<'_> { ScanLines::new(self) } @@ -309,6 +312,7 @@ impl PngImage { /// 3: Average /// 4: Paeth /// 5: All (heuristically pick the best filter for each line) + #[must_use] pub fn filter_image(&self, filter: u8) -> Vec { let mut filtered = Vec::with_capacity(self.data.len()); let bpp = ((self.ihdr.bit_depth.as_u8() * self.channels_per_pixel() + 7) / 8) as usize; @@ -351,7 +355,7 @@ impl PngImage { best_filter = filter; std::mem::swap(&mut best_line, &mut f_buf); } - f_buf.clear() //discard buffer, and start again + f_buf.clear(); //discard buffer, and start again } filtered.push(best_filter); filtered.extend_from_slice(&best_line); diff --git a/src/reduction/alpha.rs b/src/reduction/alpha.rs index 9190672b..fc5993fe 100644 --- a/src/reduction/alpha.rs +++ b/src/reduction/alpha.rs @@ -12,7 +12,7 @@ use rayon::prelude::*; use std::sync::Arc; pub(crate) fn try_alpha_reductions( - png: Arc, + png: &Arc, alphas: &IndexSet, eval: &Evaluator, ) { @@ -23,10 +23,11 @@ pub(crate) fn try_alpha_reductions( alphas .par_iter() .with_max_len(1) - .filter_map(|&alpha| filtered_alpha_channel(&png, alpha)) + .filter_map(|&alpha| filtered_alpha_channel(png, alpha)) .for_each(|image| eval.try_image(Arc::new(image))); } +#[must_use] pub fn filtered_alpha_channel(png: &PngImage, optim: AlphaOptim) -> Option { let (bpc, bpp) = match png.ihdr.color_type { ColorType::RGBA | ColorType::GrayscaleAlpha => { @@ -214,7 +215,7 @@ pub fn reduced_alpha_channel(png: &PngImage) -> Option { // and alpha has just been removed if let Some(sbit_header) = png.aux_headers.get(b"sBIT") { // Some programs save the sBIT header as RGB even if the image is RGBA. - aux_headers.insert(*b"sBIT", sbit_header.iter().cloned().take(3).collect()); + aux_headers.insert(*b"sBIT", sbit_header.iter().copied().take(3).collect()); } Some(PngImage { diff --git a/src/reduction/color.rs b/src/reduction/color.rs index 11686fc6..489d19ad 100644 --- a/src/reduction/color.rs +++ b/src/reduction/color.rs @@ -117,11 +117,11 @@ pub fn reduced_color_to_palette(png: &PngImage) -> Option { raw_data.push(line.filter); let ok = if png.ihdr.color_type == ColorType::RGB { reduce_scanline_to_palette( - line.data.as_rgb().iter().cloned().map(|px| { - px.alpha(if Some(px) != transparency_pixel { - 255 - } else { + line.data.as_rgb().iter().copied().map(|px| { + px.alpha(if Some(px) == transparency_pixel { 0 + } else { + 255 }) }), &mut palette, @@ -130,7 +130,7 @@ pub fn reduced_color_to_palette(png: &PngImage) -> Option { } else { debug_assert_eq!(png.ihdr.color_type, ColorType::RGBA); reduce_scanline_to_palette( - line.data.as_rgba().iter().cloned(), + line.data.as_rgba().iter().copied(), &mut palette, &mut raw_data, ) @@ -143,10 +143,10 @@ pub fn reduced_color_to_palette(png: &PngImage) -> Option { let num_transparent = palette .iter() .filter_map(|(px, &idx)| { - if px.a != 255 { - Some(idx as usize + 1) - } else { + if px.a == 255 { None + } else { + Some(idx as usize + 1) } }) .max(); @@ -180,7 +180,7 @@ pub fn reduced_color_to_palette(png: &PngImage) -> Option { if let Some(sbit_header) = png.aux_headers.get(b"sBIT") { // Some programs save the sBIT header as RGB even if the image is RGBA. - aux_headers.insert(*b"sBIT", sbit_header.iter().cloned().take(3).collect()); + aux_headers.insert(*b"sBIT", sbit_header.iter().copied().take(3).collect()); } let mut palette_vec = vec![RGBA8::new(0, 0, 0, 0); palette.len()]; @@ -220,8 +220,8 @@ pub fn reduce_rgb_to_grayscale(png: &PngImage) -> Option { let pixel_bytes = cur_pixel .iter() .step_by(2) - .cloned() - .zip(cur_pixel.iter().skip(1).step_by(2).cloned()) + .copied() + .zip(cur_pixel.iter().skip(1).step_by(2).copied()) .unique() .collect::>(); if pixel_bytes.len() > 1 { @@ -235,15 +235,16 @@ pub fn reduce_rgb_to_grayscale(png: &PngImage) -> Option { } } - let transparency_pixel = if let Some(ref trns) = png.transparency_pixel { - if trns.len() != 6 || trns[0..2] != trns[2..4] || trns[2..4] != trns[4..6] { - None - } else { - Some(trns[0..2].to_owned()) - } - } else { - png.transparency_pixel.clone() - }; + let transparency_pixel = png.transparency_pixel.as_ref().map_or_else( + || png.transparency_pixel.clone(), + |trns| { + if trns.len() != 6 || trns[0..2] != trns[2..4] || trns[2..4] != trns[4..6] { + None + } else { + Some(trns[0..2].to_owned()) + } + }, + ); let mut aux_headers = png.aux_headers.clone(); if let Some(sbit_header) = png.aux_headers.get(b"sBIT") { diff --git a/src/reduction/mod.rs b/src/reduction/mod.rs index 6b89b839..484d612b 100644 --- a/src/reduction/mod.rs +++ b/src/reduction/mod.rs @@ -1,7 +1,10 @@ use crate::colors::{BitDepth, ColorType}; use crate::headers::IhdrData; use crate::png::PngImage; -use indexmap::map::{Entry::*, IndexMap}; +use indexmap::map::{ + Entry::{Occupied, Vacant}, + IndexMap, +}; use rgb::RGBA8; use std::borrow::Cow; @@ -10,13 +13,16 @@ use crate::alpha::reduced_alpha_channel; pub mod bit_depth; use crate::bit_depth::reduce_bit_depth_8_or_less; pub mod color; -use crate::color::*; +use crate::color::{ + reduce_rgb_to_grayscale, reduce_rgba_to_grayscale_alpha, reduced_color_to_palette, +}; pub(crate) use crate::alpha::try_alpha_reductions; pub(crate) use crate::bit_depth::reduce_bit_depth; /// Attempt to reduce the number of colors in the palette /// Returns `None` if palette hasn't changed +#[must_use] pub fn reduced_palette(png: &PngImage) -> Option { if png.ihdr.color_type != ColorType::Indexed { // Can't reduce if there is no palette @@ -67,7 +73,7 @@ pub fn reduced_palette(png: &PngImage) -> Option { .get(i) .copied() .unwrap_or_else(|| RGBA8::new(0, 0, 0, 255)); - ((color.a as i32) << 18) + ((i32::from(color.a)) << 18) // These are coefficients for standard sRGB to luma conversion - i32::from(color.r) * 299 - i32::from(color.g) * 587 @@ -78,14 +84,14 @@ pub fn reduced_palette(png: &PngImage) -> Option { let mut next_index = 0_u16; let mut seen = IndexMap::with_capacity(palette.len()); - for (i, used) in used_enumerated.iter().cloned() { + for (i, used) in used_enumerated.iter().copied() { if !used { continue; } // There are invalid files that use pixel indices beyond palette size let color = palette .get(i) - .cloned() + .copied() .unwrap_or_else(|| RGBA8::new(0, 0, 0, 255)); match seen.entry(color) { Vacant(new) => { @@ -137,7 +143,7 @@ fn do_palette_reduction(png: &PngImage, palette_map: &[Option; 256]) -> Opti } fn palette_map_to_byte_map(png: &PngImage, palette_map: &[Option; 256]) -> Option<[u8; 256]> { - let len = png.palette.as_ref().map_or(0, |p| p.len()); + let len = png.palette.as_ref().map_or(0, Vec::len); if (0..len).all(|i| palette_map[i].map_or(true, |to| to == i as u8)) { // No reduction necessary return None; @@ -148,18 +154,18 @@ fn palette_map_to_byte_map(png: &PngImage, palette_map: &[Option; 256]) -> O // low bit-depths can be pre-computed for every byte value match png.ihdr.bit_depth { BitDepth::Eight => { - for byte in 0..=255usize { - byte_map[byte] = palette_map[byte].unwrap_or(0) + for byte in 0..=255_usize { + byte_map[byte] = palette_map[byte].unwrap_or(0); } } BitDepth::Four => { - for byte in 0..=255usize { + for byte in 0..=255_usize { byte_map[byte] = palette_map[(byte & 0x0F)].unwrap_or(0) | (palette_map[(byte >> 4)].unwrap_or(0) << 4); } } BitDepth::Two => { - for byte in 0..=255usize { + for byte in 0..=255_usize { byte_map[byte] = palette_map[(byte & 0x03)].unwrap_or(0) | (palette_map[((byte >> 2) & 0x03)].unwrap_or(0) << 2) | (palette_map[((byte >> 4) & 0x03)].unwrap_or(0) << 4) @@ -173,7 +179,7 @@ fn palette_map_to_byte_map(png: &PngImage, palette_map: &[Option; 256]) -> O } fn reordered_palette(palette: &[RGBA8], palette_map: &[Option; 256]) -> Vec { - let max_index = palette_map.iter().cloned().flatten().max().unwrap_or(0) as usize; + let max_index = palette_map.iter().copied().flatten().max().unwrap_or(0) as usize; let mut new_palette = vec![RGBA8::new(0, 0, 0, 255); max_index + 1]; for (&color, &map_to) in palette.iter().zip(palette_map.iter()) { if let Some(map_to) = map_to { @@ -185,6 +191,7 @@ fn reordered_palette(palette: &[RGBA8], palette_map: &[Option; 256]) -> Vec< /// Attempt to reduce the color type of the image /// Returns true if the color type was reduced, false otherwise +#[must_use] pub fn reduce_color_type(png: &PngImage, grayscale_reduction: bool) -> Option { let mut should_reduce_bit_depth = false; let mut reduced = Cow::Borrowed(png); @@ -244,6 +251,6 @@ pub fn reduce_color_type(png: &PngImage, grayscale_reduction: bool) -> Option Some(r), - _ => None, + Cow::Borrowed(_) => None, } } diff --git a/tests/flags.rs b/tests/flags.rs index 07f29d19..27aeb50a 100644 --- a/tests/flags.rs +++ b/tests/flags.rs @@ -36,8 +36,8 @@ fn test_it_converts_callbacks( mut callback_pre: CBPRE, mut callback_post: CBPOST, ) where - CBPOST: FnMut(&Path) -> (), - CBPRE: FnMut(&Path) -> (), + CBPOST: FnMut(&Path), + CBPRE: FnMut(&Path), { let png = PngData::new(&input, opts.fix_errors).unwrap(); @@ -46,14 +46,14 @@ fn test_it_converts_callbacks( callback_pre(&input); - match oxipng::optimize(&InFile::Path(input), &output, &opts) { + match oxipng::optimize(&InFile::Path(input), output, opts) { Ok(_) => (), Err(x) => panic!("{}", x), }; let output = output.path().unwrap(); assert!(output.exists()); - callback_post(&output); + callback_post(output); let png = match PngData::new(output, opts.fix_errors) { Ok(x) => x,