diff --git a/qoi-bench/src/main.rs b/qoi-bench/src/main.rs index 8bda609..80b875b 100644 --- a/qoi-bench/src/main.rs +++ b/qoi-bench/src/main.rs @@ -210,8 +210,8 @@ struct BenchResult { impl BenchResult { pub fn new(codec: impl AsRef, mut decode_sec: Vec, mut encode_sec: Vec) -> Self { - decode_sec.sort_by(|a, b| a.partial_cmp(&b).unwrap_or(Ordering::Equal)); - encode_sec.sort_by(|a, b| a.partial_cmp(&b).unwrap_or(Ordering::Equal)); + decode_sec.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal)); + encode_sec.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal)); let codec = codec.as_ref().into(); Self { codec, decode_sec, encode_sec } } diff --git a/src/colorspace.rs b/src/colorspace.rs index 02d6861..57da106 100644 --- a/src/colorspace.rs +++ b/src/colorspace.rs @@ -35,7 +35,7 @@ impl Default for ColorSpace { impl From for u8 { #[inline] fn from(colorspace: ColorSpace) -> Self { - colorspace as u8 + colorspace as Self } } diff --git a/src/decode.rs b/src/decode.rs index 9f23b3d..8076272 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -10,6 +10,11 @@ use crate::header::Header; use crate::pixel::{Pixel, SupportedChannels}; use crate::utils::{cold, unlikely}; +const QOI_OP_INDEX_END: u8 = QOI_OP_INDEX | 0x3f; +const QOI_OP_RUN_END: u8 = QOI_OP_RUN | 0x3d; // <- note, 0x3d (not 0x3f) +const QOI_OP_DIFF_END: u8 = QOI_OP_DIFF | 0x3f; +const QOI_OP_LUMA_END: u8 = QOI_OP_LUMA | 0x3f; + pub fn qoi_decode_impl( data: &[u8], n_pixels: usize, ) -> Result> @@ -24,11 +29,6 @@ where }); } - const QOI_OP_INDEX_END: u8 = QOI_OP_INDEX | 0x3f; - const QOI_OP_RUN_END: u8 = QOI_OP_RUN | 0x3d; // <- note, 0x3d (not 0x3f) - const QOI_OP_DIFF_END: u8 = QOI_OP_DIFF | 0x3f; - const QOI_OP_LUMA_END: u8 = QOI_OP_LUMA | 0x3f; - let mut out = vec![0; n_pixels * N]; // unnecessary zero-init, but w/e let mut pixels = cast_slice_mut::<_, [u8; N]>(&mut out); let mut data = &data[QOI_HEADER_SIZE..]; @@ -36,65 +36,57 @@ where let mut index = [Pixel::::new(); 256]; let mut px = Pixel::::new().with_a(0xff); - loop { - match pixels { - [px_out, ptail @ ..] => { - pixels = ptail; - match data { - [b1 @ QOI_OP_INDEX..=QOI_OP_INDEX_END, dtail @ ..] => { - px = index[usize::from(*b1)]; - *px_out = px.into(); - data = dtail; - continue; - } - [QOI_OP_RGB, r, g, b, dtail @ ..] => { - px = Pixel::from_rgb(Pixel::from_array([*r, *g, *b]), px.a_or(0xff)); - data = dtail; - } - [QOI_OP_RGBA, r, g, b, a, dtail @ ..] if RGBA => { - px = Pixel::from_array([*r, *g, *b, *a]); - data = dtail; - } - [b1 @ QOI_OP_RUN..=QOI_OP_RUN_END, dtail @ ..] => { - *px_out = px.into(); - let run = usize::from(b1 & 0x3f).min(pixels.len()); - let (phead, ptail) = pixels.split_at_mut(run); // can't panic - phead.fill(px.into()); - pixels = ptail; - data = dtail; - continue; - } - [b1 @ QOI_OP_DIFF..=QOI_OP_DIFF_END, dtail @ ..] => { - px.rgb_add( - ((b1 >> 4) & 0x03).wrapping_sub(2), - ((b1 >> 2) & 0x03).wrapping_sub(2), - (b1 & 0x03).wrapping_sub(2), - ); - data = dtail; - } - [b1 @ QOI_OP_LUMA..=QOI_OP_LUMA_END, b2, dtail @ ..] => { - let vg = (b1 & 0x3f).wrapping_sub(32); - let vg_8 = vg.wrapping_sub(8); - let vr = vg_8.wrapping_add((b2 >> 4) & 0x0f); - let vb = vg_8.wrapping_add(b2 & 0x0f); - px.rgb_add(vr, vg, vb); - data = dtail; - } - _ => { - cold(); - if unlikely(data.len() < 8) { - return Err(Error::UnexpectedBufferEnd); - } - } - } - index[usize::from(px.hash_index())] = px; + while let [px_out, ptail @ ..] = pixels { + pixels = ptail; + match data { + [b1 @ QOI_OP_INDEX..=QOI_OP_INDEX_END, dtail @ ..] => { + px = index[usize::from(*b1)]; *px_out = px.into(); + data = dtail; + continue; + } + [QOI_OP_RGB, r, g, b, dtail @ ..] => { + px = Pixel::from_rgb(Pixel::from_array([*r, *g, *b]), px.a_or(0xff)); + data = dtail; + } + [QOI_OP_RGBA, r, g, b, a, dtail @ ..] if RGBA => { + px = Pixel::from_array([*r, *g, *b, *a]); + data = dtail; + } + [b1 @ QOI_OP_RUN..=QOI_OP_RUN_END, dtail @ ..] => { + *px_out = px.into(); + let run = usize::from(b1 & 0x3f).min(pixels.len()); + let (phead, ptail) = pixels.split_at_mut(run); // can't panic + phead.fill(px.into()); + pixels = ptail; + data = dtail; + continue; + } + [b1 @ QOI_OP_DIFF..=QOI_OP_DIFF_END, dtail @ ..] => { + px.rgb_add( + ((b1 >> 4) & 0x03).wrapping_sub(2), + ((b1 >> 2) & 0x03).wrapping_sub(2), + (b1 & 0x03).wrapping_sub(2), + ); + data = dtail; + } + [b1 @ QOI_OP_LUMA..=QOI_OP_LUMA_END, b2, dtail @ ..] => { + let vg = (b1 & 0x3f).wrapping_sub(32); + let vg_8 = vg.wrapping_sub(8); + let vr = vg_8.wrapping_add((b2 >> 4) & 0x0f); + let vb = vg_8.wrapping_add(b2 & 0x0f); + px.rgb_add(vr, vg, vb); + data = dtail; } _ => { cold(); - break; + if unlikely(data.len() < 8) { + return Err(Error::UnexpectedBufferEnd); + } } } + index[usize::from(px.hash_index())] = px; + *px_out = px.into(); } Ok(out) diff --git a/src/encode.rs b/src/encode.rs index 5e1efa5..67bc26e 100644 --- a/src/encode.rs +++ b/src/encode.rs @@ -38,11 +38,12 @@ impl<'a> WriteBuf<'a> { } #[inline] - pub fn len(&self) -> usize { + pub const fn len(&self) -> usize { self.buf.len() } } +#[allow(clippy::cast_possible_truncation)] fn qoi_encode_impl( out: &mut [u8], data: &[u8], width: u32, height: u32, colorspace: ColorSpace, ) -> Result diff --git a/src/header.rs b/src/header.rs index e0556f0..3caca84 100644 --- a/src/header.rs +++ b/src/header.rs @@ -26,6 +26,7 @@ impl Default for Header { } #[inline(always)] +#[allow(clippy::cast_possible_truncation)] const fn u32_to_be(v: u32) -> [u8; 4] { [ ((0xff00_0000 & v) >> 24) as u8, @@ -47,7 +48,7 @@ impl Header { } #[inline] - pub fn with_colorspace(mut self, colorspace: ColorSpace) -> Self { + pub const fn with_colorspace(mut self, colorspace: ColorSpace) -> Self { self.colorspace = colorspace; self } diff --git a/src/lib.rs b/src/lib.rs index b4dcdb0..4590249 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,13 +2,11 @@ #![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)] #![allow( clippy::inline_always, - clippy::struct_excessive_bools, - clippy::fn_params_excessive_bools, clippy::similar_names, clippy::missing_errors_doc, clippy::must_use_candidate, - clippy::never_loop, - clippy::module_name_repetitions + clippy::module_name_repetitions, + clippy::cargo_common_metadata )] mod colorspace; diff --git a/src/utils.rs b/src/utils.rs index 56209b3..fb81dc8 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -6,7 +6,7 @@ pub const fn cold() {} #[allow(unused)] pub const fn likely(b: bool) -> bool { if !b { - cold() + cold(); } b } @@ -14,7 +14,7 @@ pub const fn likely(b: bool) -> bool { #[inline(always)] pub const fn unlikely(b: bool) -> bool { if b { - cold() + cold(); } b }