diff --git a/src/row/arch/neon.rs b/src/row/arch/neon.rs index 2e5de6e..443b469 100644 --- a/src/row/arch/neon.rs +++ b/src/row/arch/neon.rs @@ -119,7 +119,7 @@ pub(crate) unsafe fn yuv_420_to_rgba_row( /// bytes long. #[inline] #[target_feature(enable = "neon")] -pub(crate) unsafe fn yuv_420_to_rgb_or_rgba_row( +unsafe fn yuv_420_to_rgb_or_rgba_row( y: &[u8], u_half: &[u8], v_half: &[u8], @@ -1214,10 +1214,7 @@ pub(crate) unsafe fn nv21_to_rgba_row( /// `vld2_u8`, `vst3q_u8` / `vst4q_u8`). #[inline] #[target_feature(enable = "neon")] -pub(crate) unsafe fn nv12_or_nv21_to_rgb_or_rgba_row_impl< - const SWAP_UV: bool, - const ALPHA: bool, ->( +unsafe fn nv12_or_nv21_to_rgb_or_rgba_row_impl( y: &[u8], uv_or_vu_half: &[u8], out: &mut [u8], @@ -1473,10 +1470,7 @@ pub(crate) unsafe fn nv42_to_rgba_row( /// No width parity constraint (4:4:4). #[inline] #[target_feature(enable = "neon")] -pub(crate) unsafe fn nv24_or_nv42_to_rgb_or_rgba_row_impl< - const SWAP_UV: bool, - const ALPHA: bool, ->( +unsafe fn nv24_or_nv42_to_rgb_or_rgba_row_impl( y: &[u8], uv_or_vu: &[u8], out: &mut [u8], @@ -1687,7 +1681,7 @@ pub(crate) unsafe fn yuv_444_to_rgba_row( /// No width parity constraint (4:4:4). #[inline] #[target_feature(enable = "neon")] -pub(crate) unsafe fn yuv_444_to_rgb_or_rgba_row( +unsafe fn yuv_444_to_rgb_or_rgba_row( y: &[u8], u: &[u8], v: &[u8], diff --git a/src/row/arch/wasm_simd128.rs b/src/row/arch/wasm_simd128.rs index 77e98ef..29e3f5a 100644 --- a/src/row/arch/wasm_simd128.rs +++ b/src/row/arch/wasm_simd128.rs @@ -122,7 +122,7 @@ pub(crate) unsafe fn yuv_420_to_rgba_row( /// bytes long. #[inline] #[target_feature(enable = "simd128")] -pub(crate) unsafe fn yuv_420_to_rgb_or_rgba_row( +unsafe fn yuv_420_to_rgb_or_rgba_row( y: &[u8], u_half: &[u8], v_half: &[u8], @@ -1441,10 +1441,7 @@ pub(crate) unsafe fn nv21_to_rgba_row( /// 5. `out.len() >= width * (if ALPHA { 4 } else { 3 })`. #[inline] #[target_feature(enable = "simd128")] -pub(crate) unsafe fn nv12_or_nv21_to_rgb_or_rgba_row_impl< - const SWAP_UV: bool, - const ALPHA: bool, ->( +unsafe fn nv12_or_nv21_to_rgb_or_rgba_row_impl( y: &[u8], uv_or_vu_half: &[u8], out: &mut [u8], @@ -1702,10 +1699,7 @@ pub(crate) unsafe fn nv42_to_rgba_row( /// `out.len() >= width * if ALPHA { 4 } else { 3 }`. #[inline] #[target_feature(enable = "simd128")] -pub(crate) unsafe fn nv24_or_nv42_to_rgb_or_rgba_row_impl< - const SWAP_UV: bool, - const ALPHA: bool, ->( +unsafe fn nv24_or_nv42_to_rgb_or_rgba_row_impl( y: &[u8], uv_or_vu: &[u8], out: &mut [u8], @@ -1969,7 +1963,7 @@ pub(crate) unsafe fn yuv_444_to_rgba_row( /// 3. `out.len() >= width * (if ALPHA { 4 } else { 3 })`. #[inline] #[target_feature(enable = "simd128")] -pub(crate) unsafe fn yuv_444_to_rgb_or_rgba_row( +unsafe fn yuv_444_to_rgb_or_rgba_row( y: &[u8], u: &[u8], v: &[u8], diff --git a/src/row/arch/x86_avx2.rs b/src/row/arch/x86_avx2.rs index 4530164..2882928 100644 --- a/src/row/arch/x86_avx2.rs +++ b/src/row/arch/x86_avx2.rs @@ -132,7 +132,7 @@ pub(crate) unsafe fn yuv_420_to_rgba_row( /// bytes long. #[inline] #[target_feature(enable = "avx2")] -pub(crate) unsafe fn yuv_420_to_rgb_or_rgba_row( +unsafe fn yuv_420_to_rgb_or_rgba_row( y: &[u8], u_half: &[u8], v_half: &[u8], @@ -1646,10 +1646,7 @@ pub(crate) unsafe fn nv21_to_rgba_row( /// 5. `out.len() >= width * (if ALPHA { 4 } else { 3 })`. #[inline] #[target_feature(enable = "avx2")] -pub(crate) unsafe fn nv12_or_nv21_to_rgb_or_rgba_row_impl< - const SWAP_UV: bool, - const ALPHA: bool, ->( +unsafe fn nv12_or_nv21_to_rgb_or_rgba_row_impl( y: &[u8], uv_or_vu_half: &[u8], out: &mut [u8], @@ -1898,10 +1895,7 @@ pub(crate) unsafe fn nv42_to_rgba_row( /// 4. `out.len() >= width * if ALPHA { 4 } else { 3 }`. #[inline] #[target_feature(enable = "avx2")] -pub(crate) unsafe fn nv24_or_nv42_to_rgb_or_rgba_row_impl< - const SWAP_UV: bool, - const ALPHA: bool, ->( +unsafe fn nv24_or_nv42_to_rgb_or_rgba_row_impl( y: &[u8], uv_or_vu: &[u8], out: &mut [u8], @@ -2144,7 +2138,7 @@ pub(crate) unsafe fn yuv_444_to_rgba_row( /// 3. `out.len() >= width * (if ALPHA { 4 } else { 3 })`. #[inline] #[target_feature(enable = "avx2")] -pub(crate) unsafe fn yuv_444_to_rgb_or_rgba_row( +unsafe fn yuv_444_to_rgb_or_rgba_row( y: &[u8], u: &[u8], v: &[u8], diff --git a/src/row/arch/x86_avx512.rs b/src/row/arch/x86_avx512.rs index 2a5ad81..e0385c4 100644 --- a/src/row/arch/x86_avx512.rs +++ b/src/row/arch/x86_avx512.rs @@ -146,7 +146,7 @@ pub(crate) unsafe fn yuv_420_to_rgba_row( /// bytes long. #[inline] #[target_feature(enable = "avx512f,avx512bw")] -pub(crate) unsafe fn yuv_420_to_rgb_or_rgba_row( +unsafe fn yuv_420_to_rgb_or_rgba_row( y: &[u8], u_half: &[u8], v_half: &[u8], @@ -1693,10 +1693,7 @@ pub(crate) unsafe fn nv21_to_rgba_row( /// 5. `out.len() >= width * (if ALPHA { 4 } else { 3 })`. #[inline] #[target_feature(enable = "avx512f,avx512bw")] -pub(crate) unsafe fn nv12_or_nv21_to_rgb_or_rgba_row_impl< - const SWAP_UV: bool, - const ALPHA: bool, ->( +unsafe fn nv12_or_nv21_to_rgb_or_rgba_row_impl( y: &[u8], uv_or_vu_half: &[u8], out: &mut [u8], @@ -1950,10 +1947,7 @@ pub(crate) unsafe fn nv42_to_rgba_row( /// 4. `out.len() >= width * if ALPHA { 4 } else { 3 }`. #[inline] #[target_feature(enable = "avx512f,avx512bw")] -pub(crate) unsafe fn nv24_or_nv42_to_rgb_or_rgba_row_impl< - const SWAP_UV: bool, - const ALPHA: bool, ->( +unsafe fn nv24_or_nv42_to_rgb_or_rgba_row_impl( y: &[u8], uv_or_vu: &[u8], out: &mut [u8], @@ -2209,7 +2203,7 @@ pub(crate) unsafe fn yuv_444_to_rgba_row( /// 3. `out.len() >= width * (if ALPHA { 4 } else { 3 })`. #[inline] #[target_feature(enable = "avx512f,avx512bw")] -pub(crate) unsafe fn yuv_444_to_rgb_or_rgba_row( +unsafe fn yuv_444_to_rgb_or_rgba_row( y: &[u8], u: &[u8], v: &[u8], diff --git a/src/row/arch/x86_sse41.rs b/src/row/arch/x86_sse41.rs index 84bee7d..4aaecaf 100644 --- a/src/row/arch/x86_sse41.rs +++ b/src/row/arch/x86_sse41.rs @@ -132,7 +132,7 @@ pub(crate) unsafe fn yuv_420_to_rgba_row( /// bytes long. #[inline] #[target_feature(enable = "sse4.1")] -pub(crate) unsafe fn yuv_420_to_rgb_or_rgba_row( +unsafe fn yuv_420_to_rgb_or_rgba_row( y: &[u8], u_half: &[u8], v_half: &[u8], @@ -1460,10 +1460,7 @@ pub(crate) unsafe fn nv21_to_rgba_row( /// 5. `out.len() >= width * (if ALPHA { 4 } else { 3 })`. #[inline] #[target_feature(enable = "sse4.1")] -pub(crate) unsafe fn nv12_or_nv21_to_rgb_or_rgba_row_impl< - const SWAP_UV: bool, - const ALPHA: bool, ->( +unsafe fn nv12_or_nv21_to_rgb_or_rgba_row_impl( y: &[u8], uv_or_vu_half: &[u8], out: &mut [u8], @@ -1693,10 +1690,7 @@ pub(crate) unsafe fn nv42_to_rgba_row( /// 4. `out.len() >= width * if ALPHA { 4 } else { 3 }`. #[inline] #[target_feature(enable = "sse4.1")] -pub(crate) unsafe fn nv24_or_nv42_to_rgb_or_rgba_row_impl< - const SWAP_UV: bool, - const ALPHA: bool, ->( +unsafe fn nv24_or_nv42_to_rgb_or_rgba_row_impl( y: &[u8], uv_or_vu: &[u8], out: &mut [u8], @@ -1909,7 +1903,7 @@ pub(crate) unsafe fn yuv_444_to_rgba_row( /// 3. `out.len() >= width * (if ALPHA { 4 } else { 3 })`. #[inline] #[target_feature(enable = "sse4.1")] -pub(crate) unsafe fn yuv_444_to_rgb_or_rgba_row( +unsafe fn yuv_444_to_rgb_or_rgba_row( y: &[u8], u: &[u8], v: &[u8], diff --git a/src/row/mod.rs b/src/row/mod.rs index c64403c..5974753 100644 --- a/src/row/mod.rs +++ b/src/row/mod.rs @@ -34,6 +34,12 @@ pub(crate) mod arch; pub(crate) mod scalar; +// Re-exported only when a caller is compiled. The `MixedSinker` Strategy A +// fan-out is the sole consumer, and it lives in `crate::sinker::mixed` which +// is gated on `feature = "std"` / `feature = "alloc"` (needs `Vec`). Without +// either feature both this re-export and the underlying scalar function would +// be unused, which is a hard error under `cargo clippy -- -D warnings`. +#[cfg(any(feature = "std", feature = "alloc"))] pub(crate) use scalar::expand_rgb_to_rgba_row; use crate::ColorMatrix; diff --git a/src/row/scalar.rs b/src/row/scalar.rs index ff356a3..71d1018 100644 --- a/src/row/scalar.rs +++ b/src/row/scalar.rs @@ -220,7 +220,7 @@ pub(crate) fn nv21_to_rgba_row( /// - `y.len() >= width`, `uv_or_vu_half.len() >= width`, /// `out.len() >= width * (if ALPHA { 4 } else { 3 })`. #[cfg_attr(not(tarpaulin), inline(always))] -pub(crate) fn nv12_or_nv21_to_rgb_or_rgba_row_impl( +fn nv12_or_nv21_to_rgb_or_rgba_row_impl( y: &[u8], uv_or_vu_half: &[u8], out: &mut [u8], @@ -353,7 +353,7 @@ pub(crate) fn nv42_to_rgba_row( /// - `y.len() >= width`, `uv_or_vu.len() >= 2 * width`, /// `out.len() >= width * (if ALPHA { 4 } else { 3 })`. #[cfg_attr(not(tarpaulin), inline(always))] -pub(crate) fn nv24_or_nv42_to_rgb_or_rgba_row_impl( +fn nv24_or_nv42_to_rgb_or_rgba_row_impl( y: &[u8], uv_or_vu: &[u8], out: &mut [u8], @@ -445,7 +445,7 @@ pub(crate) fn yuv_444_to_rgba_row( /// - `y.len() >= width`, `u.len() >= width`, `v.len() >= width`, /// `out.len() >= width * (if ALPHA { 4 } else { 3 })`. #[cfg_attr(not(tarpaulin), inline(always))] -pub(crate) fn yuv_444_to_rgb_or_rgba_row( +fn yuv_444_to_rgb_or_rgba_row( y: &[u8], u: &[u8], v: &[u8], @@ -509,6 +509,11 @@ fn clamp_u8(v: i32) -> u8 { /// /// - `rgb.len() >= 3 * width` /// - `rgba_out.len() >= 4 * width` +// Only the `MixedSinker` Strategy A fan-out calls this; that lives in +// `crate::sinker::mixed`, gated on `feature = "std"` / `"alloc"`. Without +// either feature the helper would be unused and `-D dead_code` (set by +// `cargo clippy -- -D warnings` on CI) would fail the build. +#[cfg(any(feature = "std", feature = "alloc"))] #[cfg_attr(not(tarpaulin), inline(always))] pub(crate) fn expand_rgb_to_rgba_row(rgb: &[u8], rgba_out: &mut [u8], width: usize) { debug_assert!(rgb.len() >= width * 3, "rgb row too short"); diff --git a/src/sinker/mixed/bayer.rs b/src/sinker/mixed/bayer.rs index 1601c71..a4afc1e 100644 --- a/src/sinker/mixed/bayer.rs +++ b/src/sinker/mixed/bayer.rs @@ -1,12 +1,10 @@ //! Bayer / Bayer16 RAW `MixedSinker` impls. -#![allow(unused_imports)] - use super::{ - HsvBuffers, HsvPlane, LumaChannel, LumaCoefficients, MixedSinker, MixedSinkerError, RowSlice, - check_dimensions_match, rgb_row_to_luma_row, + LumaCoefficients, MixedSinker, MixedSinkerError, RowSlice, check_dimensions_match, + rgb_row_buf_or_scratch, rgb_row_to_luma_row, }; -use crate::{ColorMatrix, PixelSink, SourceFormat, raw::*, row::*, yuv::*}; +use crate::{PixelSink, raw::*, row::*}; // ---- Bayer (8-bit) impl -------------------------------------------------- @@ -116,31 +114,14 @@ impl PixelSink for MixedSinker<'_, Bayer> { // 8-bit RGB scratch / output buffer. Bayer always derives every // output channel from the demosaiced RGB, so the RGB row exists // unconditionally when any of `rgb` / `luma` / `hsv` is set. - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; bayer_to_rgb_row( row.above(), @@ -336,31 +317,14 @@ impl PixelSink for MixedSinker<'_, Bayer16> { // 8-bit RGB scratch / output. Same lazy-grow pattern as the // 8-bit Bayer impl above. - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; bayer16_to_rgb_row::( row.above(), diff --git a/src/sinker/mixed/mod.rs b/src/sinker/mixed/mod.rs index 5ae8a3e..0369929 100644 --- a/src/sinker/mixed/mod.rs +++ b/src/sinker/mixed/mod.rs @@ -1093,6 +1093,78 @@ pub(super) fn check_dimensions_match( Ok(()) } +/// Slice the RGBA row out of an attached RGBA plane buffer. Returns +/// `Err(GeometryOverflow)` if `one_plane_end × 4` wraps `usize` (only +/// reachable on 32-bit targets at extreme dimensions). +/// +/// Centralises the duplicated overflow/bounds-check pattern that every +/// `MixedSinker::process` impl runs in both the standalone-RGBA +/// branch and the Strategy-A expand branch. +#[cfg_attr(not(tarpaulin), inline(always))] +pub(super) fn rgba_plane_row_slice( + buf: &mut [u8], + one_plane_start: usize, + one_plane_end: usize, + width: usize, + height: usize, +) -> Result<&mut [u8], MixedSinkerError> { + let end = one_plane_end + .checked_mul(4) + .ok_or(MixedSinkerError::GeometryOverflow { + width, + height, + channels: 4, + })?; + let start = one_plane_start * 4; // ≤ end, fits. + Ok(&mut buf[start..end]) +} + +/// Pick an RGB row buffer for the kernel to write into: caller's RGB +/// plane slice when attached, or the growing scratch buffer otherwise +/// (HSV-only callers don't allocate an RGB plane). Returns +/// `Err(GeometryOverflow)` if `width × 3` or `one_plane_end × 3` wraps +/// `usize` — see [`rgba_plane_row_slice`] for the rationale. +/// +/// `rgb_scratch` is grown via `Vec::resize` only when too small; the +/// caller keeps the existing capacity across rows so steady-state +/// processing allocates zero times. +#[cfg_attr(not(tarpaulin), inline(always))] +pub(super) fn rgb_row_buf_or_scratch<'a>( + rgb: Option<&'a mut [u8]>, + rgb_scratch: &'a mut Vec, + one_plane_start: usize, + one_plane_end: usize, + width: usize, + height: usize, +) -> Result<&'a mut [u8], MixedSinkerError> { + match rgb { + Some(buf) => { + let end = one_plane_end + .checked_mul(3) + .ok_or(MixedSinkerError::GeometryOverflow { + width, + height, + channels: 3, + })?; + let start = one_plane_start * 3; + Ok(&mut buf[start..end]) + } + None => { + let row_bytes = width + .checked_mul(3) + .ok_or(MixedSinkerError::GeometryOverflow { + width, + height, + channels: 3, + })?; + if rgb_scratch.len() < row_bytes { + rgb_scratch.resize(row_bytes, 0); + } + Ok(&mut rgb_scratch[..row_bytes]) + } + } +} + /// Configurable-coefficients luma derivation from packed /// `R, G, B` u8 row. /// diff --git a/src/sinker/mixed/planar_8bit.rs b/src/sinker/mixed/planar_8bit.rs index e26ef8d..a0d5c7e 100644 --- a/src/sinker/mixed/planar_8bit.rs +++ b/src/sinker/mixed/planar_8bit.rs @@ -1,12 +1,10 @@ //! 8-bit planar YUV `MixedSinker` impls: Yuv420p / Yuv422p / Yuv444p / Yuv440p. -#![allow(unused_imports)] - use super::{ - HsvBuffers, HsvPlane, LumaChannel, LumaCoefficients, MixedSinker, MixedSinkerError, RowSlice, - check_dimensions_match, rgb_row_to_luma_row, + MixedSinker, MixedSinkerError, RowSlice, check_dimensions_match, rgb_row_buf_or_scratch, + rgba_plane_row_slice, }; -use crate::{ColorMatrix, PixelSink, SourceFormat, raw::*, row::*, yuv::*}; +use crate::{PixelSink, row::*, yuv::*}; // ---- Yuv420p impl -------------------------------------------------------- @@ -166,20 +164,12 @@ impl PixelSink for MixedSinker<'_, Yuv420p> { if want_rgba && !need_rgb_kernel { let rgba_buf = rgba.as_deref_mut().unwrap(); - let rgba_plane_end = - one_plane_end - .checked_mul(4) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 4, - })?; - let rgba_plane_start = one_plane_start * 4; + let rgba_row = rgba_plane_row_slice(rgba_buf, one_plane_start, one_plane_end, w, h)?; yuv_420_to_rgba_row( row.y(), row.u_half(), row.v_half(), - &mut rgba_buf[rgba_plane_start..rgba_plane_end], + rgba_row, w, row.matrix(), row.full_range(), @@ -204,31 +194,14 @@ impl PixelSink for MixedSinker<'_, Yuv420p> { // through the `× 3` check at buffer attachment. Overflow here // returns `GeometryOverflow` instead of panicking inside the row // dispatcher's own checked multiplication. - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; // ≤ rgb_plane_end, fits. - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; // Fused YUV→RGB: upsample chroma in registers inside the row // primitive, no intermediate memory. @@ -256,16 +229,8 @@ impl PixelSink for MixedSinker<'_, Yuv420p> { } if let Some(buf) = rgba.as_deref_mut() { - let rgba_plane_end = - one_plane_end - .checked_mul(4) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 4, - })?; - let rgba_plane_start = one_plane_start * 4; - expand_rgb_to_rgba_row(rgb_row, &mut buf[rgba_plane_start..rgba_plane_end], w); + let rgba_row = rgba_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?; + expand_rgb_to_rgba_row(rgb_row, rgba_row, w); } Ok(()) @@ -392,20 +357,12 @@ impl PixelSink for MixedSinker<'_, Yuv422p> { if want_rgba && !need_rgb_kernel { let rgba_buf = rgba.as_deref_mut().unwrap(); - let rgba_plane_end = - one_plane_end - .checked_mul(4) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 4, - })?; - let rgba_plane_start = one_plane_start * 4; + let rgba_row = rgba_plane_row_slice(rgba_buf, one_plane_start, one_plane_end, w, h)?; yuv_420_to_rgba_row( row.y(), row.u_half(), row.v_half(), - &mut rgba_buf[rgba_plane_start..rgba_plane_end], + rgba_row, w, row.matrix(), row.full_range(), @@ -418,31 +375,14 @@ impl PixelSink for MixedSinker<'_, Yuv422p> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; // Reuses the Yuv420p dispatcher — 4:2:2's per-row contract is // identical (half-width chroma, one pair per Y pair). @@ -469,16 +409,8 @@ impl PixelSink for MixedSinker<'_, Yuv422p> { } if let Some(buf) = rgba.as_deref_mut() { - let rgba_plane_end = - one_plane_end - .checked_mul(4) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 4, - })?; - let rgba_plane_start = one_plane_start * 4; - expand_rgb_to_rgba_row(rgb_row, &mut buf[rgba_plane_start..rgba_plane_end], w); + let rgba_row = rgba_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?; + expand_rgb_to_rgba_row(rgb_row, rgba_row, w); } Ok(()) @@ -594,20 +526,12 @@ impl PixelSink for MixedSinker<'_, Yuv444p> { if want_rgba && !need_rgb_kernel { let rgba_buf = rgba.as_deref_mut().unwrap(); - let rgba_plane_end = - one_plane_end - .checked_mul(4) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 4, - })?; - let rgba_plane_start = one_plane_start * 4; + let rgba_row = rgba_plane_row_slice(rgba_buf, one_plane_start, one_plane_end, w, h)?; yuv_444_to_rgba_row( row.y(), row.u(), row.v(), - &mut rgba_buf[rgba_plane_start..rgba_plane_end], + rgba_row, w, row.matrix(), row.full_range(), @@ -620,31 +544,14 @@ impl PixelSink for MixedSinker<'_, Yuv444p> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; yuv_444_to_rgb_row( row.y(), @@ -669,16 +576,8 @@ impl PixelSink for MixedSinker<'_, Yuv444p> { } if let Some(buf) = rgba.as_deref_mut() { - let rgba_plane_end = - one_plane_end - .checked_mul(4) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 4, - })?; - let rgba_plane_start = one_plane_start * 4; - expand_rgb_to_rgba_row(rgb_row, &mut buf[rgba_plane_start..rgba_plane_end], w); + let rgba_row = rgba_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?; + expand_rgb_to_rgba_row(rgb_row, rgba_row, w); } Ok(()) @@ -796,20 +695,12 @@ impl PixelSink for MixedSinker<'_, Yuv440p> { if want_rgba && !need_rgb_kernel { let rgba_buf = rgba.as_deref_mut().unwrap(); - let rgba_plane_end = - one_plane_end - .checked_mul(4) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 4, - })?; - let rgba_plane_start = one_plane_start * 4; + let rgba_row = rgba_plane_row_slice(rgba_buf, one_plane_start, one_plane_end, w, h)?; yuv_444_to_rgba_row( row.y(), row.u(), row.v(), - &mut rgba_buf[rgba_plane_start..rgba_plane_end], + rgba_row, w, row.matrix(), row.full_range(), @@ -822,31 +713,14 @@ impl PixelSink for MixedSinker<'_, Yuv440p> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; yuv_444_to_rgb_row( row.y(), @@ -871,16 +745,8 @@ impl PixelSink for MixedSinker<'_, Yuv440p> { } if let Some(buf) = rgba.as_deref_mut() { - let rgba_plane_end = - one_plane_end - .checked_mul(4) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 4, - })?; - let rgba_plane_start = one_plane_start * 4; - expand_rgb_to_rgba_row(rgb_row, &mut buf[rgba_plane_start..rgba_plane_end], w); + let rgba_row = rgba_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?; + expand_rgb_to_rgba_row(rgb_row, rgba_row, w); } Ok(()) diff --git a/src/sinker/mixed/semi_planar_8bit.rs b/src/sinker/mixed/semi_planar_8bit.rs index 9a949eb..3961d4e 100644 --- a/src/sinker/mixed/semi_planar_8bit.rs +++ b/src/sinker/mixed/semi_planar_8bit.rs @@ -1,12 +1,10 @@ //! 8-bit semi-planar YUV `MixedSinker` impls: Nv12 / Nv16 / Nv21 / Nv24 / Nv42. -#![allow(unused_imports)] - use super::{ - HsvBuffers, HsvPlane, LumaChannel, LumaCoefficients, MixedSinker, MixedSinkerError, RowSlice, - check_dimensions_match, rgb_row_to_luma_row, + MixedSinker, MixedSinkerError, RowSlice, check_dimensions_match, rgb_row_buf_or_scratch, + rgba_plane_row_slice, }; -use crate::{ColorMatrix, PixelSink, SourceFormat, raw::*, row::*, yuv::*}; +use crate::{PixelSink, row::*, yuv::*}; // ---- Nv12 impl ---------------------------------------------------------- @@ -129,19 +127,11 @@ impl PixelSink for MixedSinker<'_, Nv12> { if want_rgba && !need_rgb_kernel { let rgba_buf = rgba.as_deref_mut().unwrap(); - let rgba_plane_end = - one_plane_end - .checked_mul(4) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 4, - })?; - let rgba_plane_start = one_plane_start * 4; + let rgba_row = rgba_plane_row_slice(rgba_buf, one_plane_start, one_plane_end, w, h)?; nv12_to_rgba_row( row.y(), row.uv_half(), - &mut rgba_buf[rgba_plane_start..rgba_plane_end], + rgba_row, w, row.matrix(), row.full_range(), @@ -154,31 +144,14 @@ impl PixelSink for MixedSinker<'_, Nv12> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; // Fused NV12 → RGB: UV deinterleave + chroma upsample both happen // in registers inside the row primitive, no intermediate memory. @@ -204,16 +177,8 @@ impl PixelSink for MixedSinker<'_, Nv12> { } if let Some(buf) = rgba.as_deref_mut() { - let rgba_plane_end = - one_plane_end - .checked_mul(4) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 4, - })?; - let rgba_plane_start = one_plane_start * 4; - expand_rgb_to_rgba_row(rgb_row, &mut buf[rgba_plane_start..rgba_plane_end], w); + let rgba_row = rgba_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?; + expand_rgb_to_rgba_row(rgb_row, rgba_row, w); } Ok(()) @@ -332,19 +297,11 @@ impl PixelSink for MixedSinker<'_, Nv16> { if want_rgba && !need_rgb_kernel { let rgba_buf = rgba.as_deref_mut().unwrap(); - let rgba_plane_end = - one_plane_end - .checked_mul(4) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 4, - })?; - let rgba_plane_start = one_plane_start * 4; + let rgba_row = rgba_plane_row_slice(rgba_buf, one_plane_start, one_plane_end, w, h)?; nv12_to_rgba_row( row.y(), row.uv(), - &mut rgba_buf[rgba_plane_start..rgba_plane_end], + rgba_row, w, row.matrix(), row.full_range(), @@ -357,31 +314,14 @@ impl PixelSink for MixedSinker<'_, Nv16> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; // Reuses the NV12 dispatcher — 4:2:2's row contract is identical. nv12_to_rgb_row( @@ -406,16 +346,8 @@ impl PixelSink for MixedSinker<'_, Nv16> { } if let Some(buf) = rgba.as_deref_mut() { - let rgba_plane_end = - one_plane_end - .checked_mul(4) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 4, - })?; - let rgba_plane_start = one_plane_start * 4; - expand_rgb_to_rgba_row(rgb_row, &mut buf[rgba_plane_start..rgba_plane_end], w); + let rgba_row = rgba_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?; + expand_rgb_to_rgba_row(rgb_row, rgba_row, w); } Ok(()) @@ -532,19 +464,11 @@ impl PixelSink for MixedSinker<'_, Nv21> { if want_rgba && !need_rgb_kernel { let rgba_buf = rgba.as_deref_mut().unwrap(); - let rgba_plane_end = - one_plane_end - .checked_mul(4) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 4, - })?; - let rgba_plane_start = one_plane_start * 4; + let rgba_row = rgba_plane_row_slice(rgba_buf, one_plane_start, one_plane_end, w, h)?; nv21_to_rgba_row( row.y(), row.vu_half(), - &mut rgba_buf[rgba_plane_start..rgba_plane_end], + rgba_row, w, row.matrix(), row.full_range(), @@ -557,31 +481,14 @@ impl PixelSink for MixedSinker<'_, Nv21> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; // Fused NV21 → RGB: VU deinterleave + chroma upsample both happen // in registers inside the row primitive, no intermediate memory. @@ -607,16 +514,8 @@ impl PixelSink for MixedSinker<'_, Nv21> { } if let Some(buf) = rgba.as_deref_mut() { - let rgba_plane_end = - one_plane_end - .checked_mul(4) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 4, - })?; - let rgba_plane_start = one_plane_start * 4; - expand_rgb_to_rgba_row(rgb_row, &mut buf[rgba_plane_start..rgba_plane_end], w); + let rgba_row = rgba_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?; + expand_rgb_to_rgba_row(rgb_row, rgba_row, w); } Ok(()) @@ -735,19 +634,11 @@ impl PixelSink for MixedSinker<'_, Nv24> { // Avoids both the scratch allocation and the expand-pad pass. if want_rgba && !need_rgb_kernel { let rgba_buf = rgba.as_deref_mut().unwrap(); - let rgba_plane_end = - one_plane_end - .checked_mul(4) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 4, - })?; - let rgba_plane_start = one_plane_start * 4; + let rgba_row = rgba_plane_row_slice(rgba_buf, one_plane_start, one_plane_end, w, h)?; nv24_to_rgba_row( row.y(), row.uv(), - &mut rgba_buf[rgba_plane_start..rgba_plane_end], + rgba_row, w, row.matrix(), row.full_range(), @@ -760,31 +651,14 @@ impl PixelSink for MixedSinker<'_, Nv24> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; nv24_to_rgb_row( row.y(), @@ -811,16 +685,8 @@ impl PixelSink for MixedSinker<'_, Nv24> { // derive RGBA from the just-computed RGB row (memory-bound copy + // 0xFF alpha pad) instead of running a second YUV→RGB kernel. if let Some(buf) = rgba.as_deref_mut() { - let rgba_plane_end = - one_plane_end - .checked_mul(4) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 4, - })?; - let rgba_plane_start = one_plane_start * 4; - expand_rgb_to_rgba_row(rgb_row, &mut buf[rgba_plane_start..rgba_plane_end], w); + let rgba_row = rgba_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?; + expand_rgb_to_rgba_row(rgb_row, rgba_row, w); } Ok(()) @@ -929,19 +795,11 @@ impl PixelSink for MixedSinker<'_, Nv42> { if want_rgba && !need_rgb_kernel { let rgba_buf = rgba.as_deref_mut().unwrap(); - let rgba_plane_end = - one_plane_end - .checked_mul(4) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 4, - })?; - let rgba_plane_start = one_plane_start * 4; + let rgba_row = rgba_plane_row_slice(rgba_buf, one_plane_start, one_plane_end, w, h)?; nv42_to_rgba_row( row.y(), row.vu(), - &mut rgba_buf[rgba_plane_start..rgba_plane_end], + rgba_row, w, row.matrix(), row.full_range(), @@ -954,31 +812,14 @@ impl PixelSink for MixedSinker<'_, Nv42> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; nv42_to_rgb_row( row.y(), @@ -1002,16 +843,8 @@ impl PixelSink for MixedSinker<'_, Nv42> { } if let Some(buf) = rgba.as_deref_mut() { - let rgba_plane_end = - one_plane_end - .checked_mul(4) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 4, - })?; - let rgba_plane_start = one_plane_start * 4; - expand_rgb_to_rgba_row(rgb_row, &mut buf[rgba_plane_start..rgba_plane_end], w); + let rgba_row = rgba_plane_row_slice(buf, one_plane_start, one_plane_end, w, h)?; + expand_rgb_to_rgba_row(rgb_row, rgba_row, w); } Ok(()) diff --git a/src/sinker/mixed/subsampled_4_2_0_high_bit.rs b/src/sinker/mixed/subsampled_4_2_0_high_bit.rs index 74427a3..9531a17 100644 --- a/src/sinker/mixed/subsampled_4_2_0_high_bit.rs +++ b/src/sinker/mixed/subsampled_4_2_0_high_bit.rs @@ -1,12 +1,9 @@ //! High-bit-depth 4:2:0 `MixedSinker` impls: Yuv420p9/10/12/14/16 + P010/P012/P016. -#![allow(unused_imports)] - use super::{ - HsvBuffers, HsvPlane, LumaChannel, LumaCoefficients, MixedSinker, MixedSinkerError, RowSlice, - check_dimensions_match, rgb_row_to_luma_row, + MixedSinker, MixedSinkerError, RowSlice, check_dimensions_match, rgb_row_buf_or_scratch, }; -use crate::{ColorMatrix, PixelSink, SourceFormat, raw::*, row::*, yuv::*}; +use crate::{PixelSink, row::*, yuv::*}; // ---- Yuv420p9 impl ----------------------------------------------------- // @@ -136,31 +133,14 @@ impl PixelSink for MixedSinker<'_, Yuv420p9> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; yuv420p9_to_rgb_row( row.y(), @@ -351,31 +331,14 @@ impl PixelSink for MixedSinker<'_, Yuv420p10> { // 8‑bit RGB path — either writes to the caller's buffer (when // `with_rgb` is set) or to the lazily‑grown scratch (when HSV is // requested without RGB). Mirrors the 8‑bit source impls' layout. - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; yuv420p10_to_rgb_row( row.y(), @@ -535,31 +498,14 @@ impl PixelSink for MixedSinker<'_, Yuv420p12> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; yuv420p12_to_rgb_row( row.y(), @@ -716,31 +662,14 @@ impl PixelSink for MixedSinker<'_, Yuv420p14> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; yuv420p14_to_rgb_row( row.y(), @@ -897,31 +826,14 @@ impl PixelSink for MixedSinker<'_, Yuv420p16> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; yuv420p16_to_rgb_row( row.y(), @@ -1081,31 +993,14 @@ impl PixelSink for MixedSinker<'_, P010> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; p010_to_rgb_row( row.y(), @@ -1255,31 +1150,14 @@ impl PixelSink for MixedSinker<'_, P012> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; p012_to_rgb_row( row.y(), @@ -1425,31 +1303,14 @@ impl PixelSink for MixedSinker<'_, P016> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; p016_to_rgb_row( row.y(), diff --git a/src/sinker/mixed/subsampled_4_2_2_high_bit.rs b/src/sinker/mixed/subsampled_4_2_2_high_bit.rs index 9fa9e2a..c63085d 100644 --- a/src/sinker/mixed/subsampled_4_2_2_high_bit.rs +++ b/src/sinker/mixed/subsampled_4_2_2_high_bit.rs @@ -1,12 +1,9 @@ //! High-bit-depth 4:2:2 / 4:4:0 `MixedSinker` impls: Yuv422p9/10/12/14/16 + Yuv440p10/12 + P210/P212/P216. -#![allow(unused_imports)] - use super::{ - HsvBuffers, HsvPlane, LumaChannel, LumaCoefficients, MixedSinker, MixedSinkerError, RowSlice, - check_dimensions_match, rgb_row_to_luma_row, + MixedSinker, MixedSinkerError, RowSlice, check_dimensions_match, rgb_row_buf_or_scratch, }; -use crate::{ColorMatrix, PixelSink, SourceFormat, raw::*, row::*, yuv::*}; +use crate::{PixelSink, row::*, yuv::*}; // ---- Yuv422p9 impl ----------------------------------------------------- // @@ -134,31 +131,14 @@ impl PixelSink for MixedSinker<'_, Yuv422p9> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; yuv420p9_to_rgb_row( row.y(), @@ -314,31 +294,14 @@ impl PixelSink for MixedSinker<'_, Yuv422p10> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; yuv420p10_to_rgb_row( row.y(), @@ -485,31 +448,14 @@ impl PixelSink for MixedSinker<'_, Yuv422p12> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; yuv420p12_to_rgb_row( row.y(), @@ -656,31 +602,14 @@ impl PixelSink for MixedSinker<'_, Yuv422p14> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; yuv420p14_to_rgb_row( row.y(), @@ -835,31 +764,14 @@ impl PixelSink for MixedSinker<'_, Yuv422p16> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; yuv420p16_to_rgb_row( row.y(), @@ -1005,31 +917,14 @@ impl PixelSink for MixedSinker<'_, Yuv440p10> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; yuv444p10_to_rgb_row( row.y(), @@ -1172,31 +1067,14 @@ impl PixelSink for MixedSinker<'_, Yuv440p12> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; yuv444p12_to_rgb_row( row.y(), @@ -1342,31 +1220,14 @@ impl PixelSink for MixedSinker<'_, P210> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; p010_to_rgb_row( row.y(), @@ -1508,31 +1369,14 @@ impl PixelSink for MixedSinker<'_, P212> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; p012_to_rgb_row( row.y(), @@ -1674,31 +1518,14 @@ impl PixelSink for MixedSinker<'_, P216> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; p016_to_rgb_row( row.y(), diff --git a/src/sinker/mixed/subsampled_4_4_4_high_bit.rs b/src/sinker/mixed/subsampled_4_4_4_high_bit.rs index 04d9db1..f1dde93 100644 --- a/src/sinker/mixed/subsampled_4_4_4_high_bit.rs +++ b/src/sinker/mixed/subsampled_4_4_4_high_bit.rs @@ -1,12 +1,9 @@ //! High-bit-depth 4:4:4 `MixedSinker` impls: Yuv444p9/10/12/14/16 + P410/P412/P416. -#![allow(unused_imports)] - use super::{ - HsvBuffers, HsvPlane, LumaChannel, LumaCoefficients, MixedSinker, MixedSinkerError, RowSlice, - check_dimensions_match, rgb_row_to_luma_row, + MixedSinker, MixedSinkerError, RowSlice, check_dimensions_match, rgb_row_buf_or_scratch, }; -use crate::{ColorMatrix, PixelSink, SourceFormat, raw::*, row::*, yuv::*}; +use crate::{PixelSink, row::*, yuv::*}; // ---- Yuv444p9 impl ----------------------------------------------------- @@ -124,31 +121,14 @@ impl PixelSink for MixedSinker<'_, Yuv444p9> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; yuv444p9_to_rgb_row( row.y(), @@ -291,31 +271,14 @@ impl PixelSink for MixedSinker<'_, Yuv444p10> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; yuv444p10_to_rgb_row( row.y(), @@ -456,31 +419,14 @@ impl PixelSink for MixedSinker<'_, Yuv444p12> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; yuv444p12_to_rgb_row( row.y(), @@ -621,31 +567,14 @@ impl PixelSink for MixedSinker<'_, Yuv444p14> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; yuv444p14_to_rgb_row( row.y(), @@ -787,31 +716,14 @@ impl PixelSink for MixedSinker<'_, Yuv444p16> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; yuv444p16_to_rgb_row( row.y(), @@ -950,31 +862,14 @@ impl PixelSink for MixedSinker<'_, P410> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; p410_to_rgb_row( row.y(), @@ -1106,31 +1001,14 @@ impl PixelSink for MixedSinker<'_, P412> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; p412_to_rgb_row( row.y(), @@ -1266,31 +1144,14 @@ impl PixelSink for MixedSinker<'_, P416> { return Ok(()); } - let rgb_row: &mut [u8] = match rgb.as_deref_mut() { - Some(buf) => { - let rgb_plane_end = - one_plane_end - .checked_mul(3) - .ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - let rgb_plane_start = one_plane_start * 3; - &mut buf[rgb_plane_start..rgb_plane_end] - } - None => { - let rgb_row_bytes = w.checked_mul(3).ok_or(MixedSinkerError::GeometryOverflow { - width: w, - height: h, - channels: 3, - })?; - if rgb_scratch.len() < rgb_row_bytes { - rgb_scratch.resize(rgb_row_bytes, 0); - } - &mut rgb_scratch[..rgb_row_bytes] - } - }; + let rgb_row = rgb_row_buf_or_scratch( + rgb.as_deref_mut(), + rgb_scratch, + one_plane_start, + one_plane_end, + w, + h, + )?; p416_to_rgb_row( row.y(),