From 64edc9110eb1008f3af592aaa97ce7a541326f5a Mon Sep 17 00:00:00 2001 From: Josh Holmer Date: Sat, 30 Jul 2016 23:14:36 -0400 Subject: [PATCH] Start using quickcheck and add inline hints --- Cargo.lock | 25 +++++++++++++++++++++++++ Cargo.toml | 3 +++ src/colors.rs | 5 +++++ src/deflate/deflate.rs | 12 ++++++++++++ src/deflate/libz_stream.rs | 6 ++++++ src/deflate/miniz_stream.rs | 6 ++++++ src/filters.rs | 1 + src/headers.rs | 3 ++- src/lib.rs | 6 ++++++ src/png.rs | 3 +++ 10 files changed, 69 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 3f7348a0..6422b2f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,6 +13,7 @@ dependencies = [ "libz-sys 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "miniz-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quickcheck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)", "scoped-pool 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -112,6 +113,15 @@ dependencies = [ "num 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "env_logger" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.1.73 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "flate2" version = "0.2.14" @@ -182,6 +192,11 @@ dependencies = [ "pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "log" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "matches" version = "0.1.2" @@ -300,6 +315,16 @@ dependencies = [ "num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quickcheck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "env_logger 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quine-mc_cluskey" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index e968c309..113338c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,9 @@ version = "^0.0.79" optional = true version = "^0.1.63" +[dev-dependencies] +quickcheck = "^0.3.0" + [dev-dependencies.image] version = "^0.8.0" default-features = false diff --git a/src/colors.rs b/src/colors.rs index 40aee6ea..44eb1d2b 100644 --- a/src/colors.rs +++ b/src/colors.rs @@ -16,6 +16,7 @@ pub enum ColorType { } impl fmt::Display for ColorType { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", @@ -31,6 +32,7 @@ impl fmt::Display for ColorType { impl ColorType { /// Get the code used by the PNG specification to denote this color type + #[inline] pub fn png_header_code(&self) -> u8 { match *self { ColorType::Grayscale => 0, @@ -58,6 +60,7 @@ pub enum BitDepth { } impl fmt::Display for BitDepth { + #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", @@ -73,6 +76,7 @@ impl fmt::Display for BitDepth { impl BitDepth { /// Retrieve the number of bits per channel per pixel as a `u8` + #[inline] pub fn as_u8(&self) -> u8 { match *self { BitDepth::One => 1, @@ -83,6 +87,7 @@ impl BitDepth { } } /// Parse a number of bits per channel per pixel into a `BitDepth` + #[inline] pub fn from_u8(depth: u8) -> BitDepth { match depth { 1 => BitDepth::One, diff --git a/src/deflate/deflate.rs b/src/deflate/deflate.rs index 7452d7e8..3686051e 100644 --- a/src/deflate/deflate.rs +++ b/src/deflate/deflate.rs @@ -2,6 +2,8 @@ use libz_sys; use miniz_sys; use libc::c_int; use std::cmp::max; +#[cfg(test)] +use quickcheck::TestResult; /// Decompress a data stream using the DEFLATE algorithm pub fn inflate(data: &[u8]) -> Result, String> { @@ -58,3 +60,13 @@ pub fn deflate(data: &[u8], zc: u8, zm: u8, zs: u8, zw: u8) -> Result, S Ok(output) } + +#[cfg(test)] +quickcheck! { + fn quickcheck(data: Vec, zc: u8, zm: u8, zs: u8, zw: u8) -> TestResult { + if data.is_empty() || zc > 9 || zm == 0 || zm > 9 || zs > 3 || zw > 15 || zw < 8 { + return TestResult::discard(); + } + TestResult::from_bool(data == inflate(&deflate(&data, zc, zm, zs, zw).unwrap()).unwrap()) + } +} diff --git a/src/deflate/libz_stream.rs b/src/deflate/libz_stream.rs index 64108f26..0bf4e449 100644 --- a/src/deflate/libz_stream.rs +++ b/src/deflate/libz_stream.rs @@ -62,10 +62,12 @@ impl Stream { } impl Stream { + #[inline] pub fn total_in(&self) -> usize { self.raw.total_in as usize } + #[inline] pub fn total_out(&self) -> usize { self.raw.total_out as usize } @@ -105,23 +107,27 @@ impl Stream { } } + #[inline] pub fn reset(&mut self) -> c_int { unsafe { libz_sys::deflateReset(&mut self.raw) } } } impl Direction for Compress { + #[inline] unsafe fn destroy(stream: *mut libz_sys::z_stream) -> c_int { libz_sys::deflateEnd(stream) } } impl Direction for Decompress { + #[inline] unsafe fn destroy(stream: *mut libz_sys::z_stream) -> c_int { libz_sys::inflateEnd(stream) } } impl Drop for Stream { + #[inline] fn drop(&mut self) { unsafe { let _ = ::destroy(&mut self.raw); diff --git a/src/deflate/miniz_stream.rs b/src/deflate/miniz_stream.rs index 5ccc359c..5df4bbdc 100644 --- a/src/deflate/miniz_stream.rs +++ b/src/deflate/miniz_stream.rs @@ -57,10 +57,12 @@ impl Stream { } impl Stream { + #[inline] pub fn total_in(&self) -> usize { self.raw.total_in as usize } + #[inline] pub fn total_out(&self) -> usize { self.raw.total_out as usize } @@ -100,23 +102,27 @@ impl Stream { } } + #[inline] pub fn reset(&mut self) -> c_int { unsafe { miniz_sys::mz_deflateReset(&mut self.raw) } } } impl Direction for Compress { + #[inline] unsafe fn destroy(stream: *mut miniz_sys::mz_stream) -> c_int { miniz_sys::mz_deflateEnd(stream) } } impl Direction for Decompress { + #[inline] unsafe fn destroy(stream: *mut miniz_sys::mz_stream) -> c_int { miniz_sys::mz_inflateEnd(stream) } } impl Drop for Stream { + #[inline] fn drop(&mut self) { unsafe { let _ = ::destroy(&mut self.raw); diff --git a/src/filters.rs b/src/filters.rs index 7bc06fe4..8396eead 100644 --- a/src/filters.rs +++ b/src/filters.rs @@ -147,6 +147,7 @@ pub fn unfilter_line(filter: u8, bpp: usize, data: &[u8], last_line: &[u8]) -> V unfiltered } +#[inline] fn paeth_predictor(a: u8, b: u8, c: u8) -> u8 { let p = a as i32 + b as i32 - c as i32; let pa = (p - a as i32).abs(); diff --git a/src/headers.rs b/src/headers.rs index 9e870ca2..9f01de5e 100644 --- a/src/headers.rs +++ b/src/headers.rs @@ -35,10 +35,11 @@ pub enum Headers { All, } +#[inline] pub fn file_header_is_valid(bytes: &[u8]) -> bool { let expected_header: [u8; 8] = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]; - bytes.iter().zip(expected_header.iter()).all(|x| x.0 == x.1) + *bytes == expected_header } pub fn parse_next_header(byte_data: &[u8], diff --git a/src/lib.rs b/src/lib.rs index d522be34..505d8949 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,10 @@ extern crate miniz_sys; extern crate num_cpus; extern crate scoped_pool; +#[cfg(test)] +#[macro_use] +extern crate quickcheck; + use headers::Headers; use scoped_pool::Pool; use std::collections::{HashMap, HashSet}; @@ -536,6 +540,7 @@ fn perform_reductions(png: &mut png::PngData, opts: &Options) -> bool { } /// Display the status of the image data after a reduction has taken place +#[inline] fn report_reduction(png: &png::PngData) { if let Some(palette) = png.palette.clone() { writeln!(&mut stderr(), @@ -581,6 +586,7 @@ fn perform_strip(png: &mut png::PngData, opts: &Options) { } /// Check if an image was already optimized prior to oxipng's operations +#[inline] fn is_fully_optimized(original_size: usize, optimized_size: usize, opts: &Options) -> bool { original_size <= optimized_size && !opts.force && opts.interlace.is_none() } diff --git a/src/png.rs b/src/png.rs index 00927e8a..6acb207e 100644 --- a/src/png.rs +++ b/src/png.rs @@ -272,6 +272,7 @@ impl PngData { } /// Return the number of channels in the image, based on color type + #[inline] pub fn channels_per_pixel(&self) -> u8 { match self.ihdr_data.color_type { ColorType::Grayscale | ColorType::Indexed => 1, @@ -733,6 +734,7 @@ impl PngData { /// Returns true if the interlacing was changed, false otherwise /// The `interlace` parameter specifies the *new* interlacing mode /// Assumes that the data has already been de-filtered + #[inline] pub fn change_interlacing(&mut self, interlace: u8) -> bool { if interlace == self.ihdr_data.interlaced { return false; @@ -749,6 +751,7 @@ impl PngData { } } +#[inline] fn write_png_block(key: &[u8], header: &[u8], output: &mut Vec) { let mut header_data = Vec::with_capacity(header.len() + 4); header_data.extend_from_slice(key);