From 7d676d96420638dec69638740fe4b09c34baabf0 Mon Sep 17 00:00:00 2001 From: Baptiste Parmantier Date: Tue, 22 Sep 2026 08:00:17 +0200 Subject: [PATCH] style(lint): replace constant-size chunks_exact with as_chunks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A newer stable clippy adds `chunks_exact_to_as_chunks`, which fires on every `chunks_exact` call whose size is a literal. The workspace has 32 of them across 20 files, so the clippy job fails on every branch — main included. Its last run, from before this work existed, was already red for the same reason. The replacement is clippy's own suggestion, `as_chunks::().0.iter()`. It is not a pure substitution: the iterator now yields `&[T; N]` rather than `&[T]`, so two sites needed real edits — an assertion comparing against an array literal, and a predicate taking `&[u8]`. The array type is the better one anyway; it is what makes the chunk length visible to the compiler. Completeness is checkable rather than argued: no `chunks_exact` with a literal size remains in the workspace, so the lint has nothing left to fire on. The local toolchain predates this lint, so that grep is the verification, not a local clippy run. --- crates/rustmotion-components/src/badge.rs | 4 +- crates/rustmotion-components/src/callout.rs | 4 +- crates/rustmotion-components/src/counter.rs | 2 +- crates/rustmotion-components/src/kbd.rs | 4 +- crates/rustmotion-components/src/list.rs | 2 +- crates/rustmotion-components/src/lottie.rs | 2 +- crates/rustmotion-components/src/marquee.rs | 2 +- .../rustmotion-components/src/notification.rs | 4 +- crates/rustmotion-components/src/pill_nav.rs | 2 +- crates/rustmotion-components/src/table.rs | 4 +- crates/rustmotion-components/src/terminal.rs | 4 +- crates/rustmotion-components/src/tooltip.rs | 4 +- .../tests/caption_presets.rs | 6 ++- .../tests/codeblock_auto_scroll.rs | 4 +- .../tests/relative_font_size.rs | 2 +- .../src/engine/renderer/text.rs | 2 +- .../rustmotion-core/src/engine/transition.rs | 4 +- crates/rustmotion-studio/src/editor/audio.rs | 4 +- .../src/scenario/optimistic.rs | 4 +- crates/rustmotion/src/tests.rs | 49 ++++++++++++++----- 20 files changed, 80 insertions(+), 33 deletions(-) diff --git a/crates/rustmotion-components/src/badge.rs b/crates/rustmotion-components/src/badge.rs index 5e19ea9f..f4f2cdbb 100644 --- a/crates/rustmotion-components/src/badge.rs +++ b/crates/rustmotion-components/src/badge.rs @@ -441,7 +441,9 @@ mod tests { // Solid variant text is always white — probe for white ink // specifically, since the pill background paints regardless. let text_ink = buf - .chunks_exact(4) + .as_chunks::<4>() + .0 + .iter() .filter(|p| p[3] > 0 && p[0] > 200 && p[1] > 200 && p[2] > 200) .count(); assert!( diff --git a/crates/rustmotion-components/src/callout.rs b/crates/rustmotion-components/src/callout.rs index 22e8bf97..8092d4aa 100644 --- a/crates/rustmotion-components/src/callout.rs +++ b/crates/rustmotion-components/src/callout.rs @@ -267,7 +267,9 @@ mod tests { // for near-white ink specifically, since the bubble background // paints regardless of font-size. let text_ink = buf - .chunks_exact(4) + .as_chunks::<4>() + .0 + .iter() .filter(|p| p[3] > 0 && p[0] > 200 && p[1] > 200 && p[2] > 200) .count(); assert!( diff --git a/crates/rustmotion-components/src/counter.rs b/crates/rustmotion-components/src/counter.rs index ebe1108e..e67af735 100644 --- a/crates/rustmotion-components/src/counter.rs +++ b/crates/rustmotion-components/src/counter.rs @@ -403,7 +403,7 @@ mod tests { skia_safe::image::CachingHint::Disallow, ); assert!(ok, "pixel read should succeed"); - let lit = buf.chunks_exact(4).filter(|p| p[3] > 0).count(); + let lit = buf.as_chunks::<4>().0.iter().filter(|p| p[3] > 0).count(); assert!( lit > 20, "counter at font-size: 2rem must paint visible ink, got {lit} lit pixels" diff --git a/crates/rustmotion-components/src/kbd.rs b/crates/rustmotion-components/src/kbd.rs index ecc065b8..6874cbf3 100644 --- a/crates/rustmotion-components/src/kbd.rs +++ b/crates/rustmotion-components/src/kbd.rs @@ -339,7 +339,9 @@ mod tests { // face — probe for near-white ink specifically, since the face/ // border/shadow paint regardless of font-size. let text_ink = buf - .chunks_exact(4) + .as_chunks::<4>() + .0 + .iter() .filter(|p| p[3] > 0 && p[0] > 180 && p[1] > 180 && p[2] > 180) .count(); assert!( diff --git a/crates/rustmotion-components/src/list.rs b/crates/rustmotion-components/src/list.rs index d58723cd..4e7fd71e 100644 --- a/crates/rustmotion-components/src/list.rs +++ b/crates/rustmotion-components/src/list.rs @@ -333,7 +333,7 @@ mod tests { skia_safe::image::CachingHint::Disallow, ); assert!(ok, "pixel read should succeed"); - let lit = buf.chunks_exact(4).filter(|p| p[3] > 0).count(); + let lit = buf.as_chunks::<4>().0.iter().filter(|p| p[3] > 0).count(); assert!( lit > 20, "list at font-size: 2rem must paint visible ink, got {lit} lit pixels" diff --git a/crates/rustmotion-components/src/lottie.rs b/crates/rustmotion-components/src/lottie.rs index e2b08b5c..6fee0988 100644 --- a/crates/rustmotion-components/src/lottie.rs +++ b/crates/rustmotion-components/src/lottie.rs @@ -525,7 +525,7 @@ mod tests { let mut red_sum: u64 = 0; let mut blue_sum: u64 = 0; - for px in buf.chunks_exact(4) { + for px in buf.as_chunks::<4>().0.iter() { let r = px[0] as u64; let _g = px[1] as u64; let b = px[2] as u64; diff --git a/crates/rustmotion-components/src/marquee.rs b/crates/rustmotion-components/src/marquee.rs index 08e0379c..401baaa1 100644 --- a/crates/rustmotion-components/src/marquee.rs +++ b/crates/rustmotion-components/src/marquee.rs @@ -224,7 +224,7 @@ mod tests { skia_safe::image::CachingHint::Disallow, ); assert!(ok, "pixel read should succeed"); - let lit = buf.chunks_exact(4).filter(|p| p[3] > 0).count(); + let lit = buf.as_chunks::<4>().0.iter().filter(|p| p[3] > 0).count(); assert!( lit > 20, "marquee at font-size: 2rem must paint visible ink, got {lit} lit pixels" diff --git a/crates/rustmotion-components/src/notification.rs b/crates/rustmotion-components/src/notification.rs index 436f2d35..4d63a057 100644 --- a/crates/rustmotion-components/src/notification.rs +++ b/crates/rustmotion-components/src/notification.rs @@ -451,7 +451,9 @@ mod tests { // Title text is white (#FFFFFF default) on a dark #1E293B card — // probe for near-white ink specifically. let text_ink = buf - .chunks_exact(4) + .as_chunks::<4>() + .0 + .iter() .filter(|p| p[3] > 0 && p[0] > 200 && p[1] > 200 && p[2] > 200) .count(); assert!( diff --git a/crates/rustmotion-components/src/pill_nav.rs b/crates/rustmotion-components/src/pill_nav.rs index 3b3d038d..3039de35 100644 --- a/crates/rustmotion-components/src/pill_nav.rs +++ b/crates/rustmotion-components/src/pill_nav.rs @@ -328,7 +328,7 @@ mod tests { skia_safe::image::CachingHint::Disallow, ); assert!(ok, "pixel read should succeed"); - let lit = buf.chunks_exact(4).filter(|p| p[3] > 0).count(); + let lit = buf.as_chunks::<4>().0.iter().filter(|p| p[3] > 0).count(); assert!( lit > 20, "pill_nav at font-size: 2rem must paint visible ink, got {lit} lit pixels" diff --git a/crates/rustmotion-components/src/table.rs b/crates/rustmotion-components/src/table.rs index 05fbc996..527a532c 100644 --- a/crates/rustmotion-components/src/table.rs +++ b/crates/rustmotion-components/src/table.rs @@ -371,7 +371,9 @@ mod tests { // probe specifically for near-white text ink rather than any lit // pixel (the header/row backgrounds paint regardless of font-size). let text_ink = buf - .chunks_exact(4) + .as_chunks::<4>() + .0 + .iter() .filter(|p| p[3] > 0 && p[0] > 200 && p[1] > 200 && p[2] > 200) .count(); assert!( diff --git a/crates/rustmotion-components/src/terminal.rs b/crates/rustmotion-components/src/terminal.rs index 0e22037b..be6224ec 100644 --- a/crates/rustmotion-components/src/terminal.rs +++ b/crates/rustmotion-components/src/terminal.rs @@ -536,7 +536,9 @@ mod tests { // specifically: pixels that are not the dark theme background color // (#1E1E1E) and not fully transparent. let text_ink = buf - .chunks_exact(4) + .as_chunks::<4>() + .0 + .iter() .filter(|p| p[3] > 0 && !(p[0] < 40 && p[1] < 40 && p[2] < 40)) .count(); assert!( diff --git a/crates/rustmotion-components/src/tooltip.rs b/crates/rustmotion-components/src/tooltip.rs index 44cd1a54..432c1690 100644 --- a/crates/rustmotion-components/src/tooltip.rs +++ b/crates/rustmotion-components/src/tooltip.rs @@ -280,7 +280,9 @@ mod tests { // Text is near-white (#E2E8F0 default) on a dark #1E293B body — // probe for near-white ink specifically. let text_ink = buf - .chunks_exact(4) + .as_chunks::<4>() + .0 + .iter() .filter(|p| p[3] > 0 && p[0] > 180 && p[1] > 180 && p[2] > 180) .count(); assert!( diff --git a/crates/rustmotion-components/tests/caption_presets.rs b/crates/rustmotion-components/tests/caption_presets.rs index 2f074ae8..59ecf7b9 100644 --- a/crates/rustmotion-components/tests/caption_presets.rs +++ b/crates/rustmotion-components/tests/caption_presets.rs @@ -82,7 +82,11 @@ fn render_caption_at(json: serde_json::Value, time: f64, y: f32) -> Vec { } fn count_pixels(buf: &[u8], pred: impl Fn(&[u8]) -> bool) -> usize { - buf.chunks_exact(4).filter(|p| pred(p)).count() + buf.as_chunks::<4>() + .0 + .iter() + .filter(|p| pred(p.as_slice())) + .count() } fn lit_pixels(buf: &[u8]) -> usize { diff --git a/crates/rustmotion-components/tests/codeblock_auto_scroll.rs b/crates/rustmotion-components/tests/codeblock_auto_scroll.rs index 40a4f2eb..e1668a31 100644 --- a/crates/rustmotion-components/tests/codeblock_auto_scroll.rs +++ b/crates/rustmotion-components/tests/codeblock_auto_scroll.rs @@ -42,7 +42,9 @@ fn text_ink_pixels(buf: &[u8]) -> usize { // Background is #2b303b ~ (43, 48, 59). Count pixels that deviate from // that by a wide margin in any channel — syntect's theme colors are all // much brighter than the near-black background. - buf.chunks_exact(4) + buf.as_chunks::<4>() + .0 + .iter() .filter(|p| { let (r, g, b, a) = (p[0] as i32, p[1] as i32, p[2] as i32, p[3] as i32); a > 200 && ((r - 43).abs() > 40 || (g - 48).abs() > 40 || (b - 59).abs() > 40) diff --git a/crates/rustmotion-components/tests/relative_font_size.rs b/crates/rustmotion-components/tests/relative_font_size.rs index 21965697..c40e8fe0 100644 --- a/crates/rustmotion-components/tests/relative_font_size.rs +++ b/crates/rustmotion-components/tests/relative_font_size.rs @@ -77,7 +77,7 @@ fn render(json: serde_json::Value) -> Vec { } fn lit_pixels(buf: &[u8]) -> usize { - buf.chunks_exact(4).filter(|p| p[3] > 0).count() + buf.as_chunks::<4>().0.iter().filter(|p| p[3] > 0).count() } #[test] diff --git a/crates/rustmotion-core/src/engine/renderer/text.rs b/crates/rustmotion-core/src/engine/renderer/text.rs index d607dadf..6d578977 100644 --- a/crates/rustmotion-core/src/engine/renderer/text.rs +++ b/crates/rustmotion-core/src/engine/renderer/text.rs @@ -975,7 +975,7 @@ mod emoji_presentation_tests { surface.read_pixels(&info, &mut buf, (W * 4) as usize, (0, 0)); let (mut n, mut sr, mut sg, mut sb) = (0usize, 0f64, 0f64, 0f64); - for px in buf.chunks_exact(4) { + for px in buf.as_chunks::<4>().0.iter() { if px[3] > 40 { n += 1; sr += px[0] as f64; diff --git a/crates/rustmotion-core/src/engine/transition.rs b/crates/rustmotion-core/src/engine/transition.rs index b256a080..22e5923f 100644 --- a/crates/rustmotion-core/src/engine/transition.rs +++ b/crates/rustmotion-core/src/engine/transition.rs @@ -970,9 +970,9 @@ mod camera_pan_tests { ); // blend_fade(10, 200, 0.5) = (10*0.5 + 200*0.5 + 0.5) as u8 = 105. - for px in out.chunks_exact(4) { + for px in out.as_chunks::<4>().0.iter() { assert_eq!( - px, + *px, [105, 105, 105, 255], "mid-pan Static frame must be a blend of bg_a and bg_b, not a copy of either" ); diff --git a/crates/rustmotion-studio/src/editor/audio.rs b/crates/rustmotion-studio/src/editor/audio.rs index 5b015479..6a232169 100644 --- a/crates/rustmotion-studio/src/editor/audio.rs +++ b/crates/rustmotion-studio/src/editor/audio.rs @@ -165,7 +165,9 @@ pub fn prepare(scenario: Arc, total_duration: f64) { match mixed { Ok(Some(pcm_bytes)) => { let pcm: Vec = pcm_bytes - .chunks_exact(2) + .as_chunks::<2>() + .0 + .iter() .map(|b| i16::from_le_bytes([b[0], b[1]]) as f32 / 32768.0) .collect(); let _ = tx.send(Cmd::Load(Arc::new(pcm), SAMPLE_RATE)); diff --git a/crates/rustmotion-studio/src/scenario/optimistic.rs b/crates/rustmotion-studio/src/scenario/optimistic.rs index adf3ae3f..5cca75c0 100644 --- a/crates/rustmotion-studio/src/scenario/optimistic.rs +++ b/crates/rustmotion-studio/src/scenario/optimistic.rs @@ -312,7 +312,9 @@ mod tests { .expect("render") }; let count_red = |rgba: &[u8]| { - rgba.chunks_exact(4) + rgba.as_chunks::<4>() + .0 + .iter() .filter(|p| p[0] > 180 && p[1] < 90 && p[2] < 90) .count() }; diff --git a/crates/rustmotion/src/tests.rs b/crates/rustmotion/src/tests.rs index 784e3d12..661687b4 100644 --- a/crates/rustmotion/src/tests.rs +++ b/crates/rustmotion/src/tests.rs @@ -539,7 +539,7 @@ mod component_smoke { /// Counts non-transparent pixels in an RGBA buffer (alpha > 0). fn nonzero_pixels(buf: &[u8]) -> usize { - buf.chunks_exact(4).filter(|p| p[3] > 0).count() + buf.as_chunks::<4>().0.iter().filter(|p| p[3] > 0).count() } #[test] @@ -605,7 +605,8 @@ mod component_smoke { let late = render_new_at(&scene, 400, 300, 0.95, 1.0); // Total red intensity (sum of red channel) — alpha-attenuated pixels // contribute less to this sum even when premul keeps the count up. - let red_sum: fn(&[u8]) -> u64 = |buf| buf.chunks_exact(4).map(|p| p[0] as u64).sum(); + let red_sum: fn(&[u8]) -> u64 = + |buf| buf.as_chunks::<4>().0.iter().map(|p| p[0] as u64).sum(); let early_red = red_sum(&early); let late_red = red_sum(&late); assert!( @@ -638,7 +639,7 @@ mod component_smoke { } fn red_sum(buf: &[u8]) -> u64 { - buf.chunks_exact(4).map(|p| p[0] as u64).sum() + buf.as_chunks::<4>().0.iter().map(|p| p[0] as u64).sum() } #[test] @@ -718,7 +719,9 @@ mod component_smoke { } })); let count_mid = |buf: &[u8]| { - buf.chunks_exact(4) + buf.as_chunks::<4>() + .0 + .iter() .filter(|p| p[0] > 20 && p[0] < 220) .count() }; @@ -744,7 +747,9 @@ mod component_smoke { })); let buf = render_new_at(&inverted, 400, 300, 0.5, 1.0); let flipped = buf - .chunks_exact(4) + .as_chunks::<4>() + .0 + .iter() .filter(|p| p[0] < 50 && p[1] > 150) .count(); assert!( @@ -873,7 +878,8 @@ mod component_smoke { bleed: false, }; let scene = vec![child]; - let blue_sum = |buf: &[u8]| -> u64 { buf.chunks_exact(4).map(|p| p[2] as u64).sum() }; + let blue_sum = + |buf: &[u8]| -> u64 { buf.as_chunks::<4>().0.iter().map(|p| p[2] as u64).sum() }; let before = render_new_at(&scene, 400, 300, 0.5, 4.0); let mid = render_new_at(&scene, 400, 300, 1.5, 4.0); let after = render_new_at(&scene, 400, 300, 2.5, 4.0); @@ -936,7 +942,7 @@ mod component_smoke { fn red_centroid_x(buf: &[u8], width: u32) -> Option { let mut sum_wx = 0.0_f64; let mut sum_w = 0.0_f64; - for (i, p) in buf.chunks_exact(4).enumerate() { + for (i, p) in buf.as_chunks::<4>().0.iter().enumerate() { let x = (i as u32 % width) as f64; let w = p[0] as f64; sum_wx += w * x; @@ -1665,7 +1671,7 @@ mod svg_draw_on_tests { /// Count non-transparent pixels in RGBA buffer. fn lit(buf: &[u8]) -> usize { - buf.chunks_exact(4).filter(|p| p[3] > 0).count() + buf.as_chunks::<4>().0.iter().filter(|p| p[3] > 0).count() } /// Count non-transparent pixels in horizontal band [y0, y1) of a 100-wide canvas. @@ -1831,7 +1837,9 @@ mod svg_draw_on_tests { ); // resvg fills the rect red. Count red-dominant pixels. let red_pixels = buf - .chunks_exact(4) + .as_chunks::<4>() + .0 + .iter() .filter(|p| p[3] > 0 && p[0] > p[2] && p[0] > p[1]) .count(); assert!( @@ -2232,7 +2240,9 @@ mod audio_tests { let lit_at = |frame: usize| { crate::encode::video::render_frame_task(&scenario.video, &scenario, &tasks[frame]) .expect("render") - .chunks_exact(4) + .as_chunks::<4>() + .0 + .iter() .filter(|p| p[0] > 40) .count() }; @@ -2556,7 +2566,14 @@ mod audio_tests { } })) }; - let red_sum = |pixels: &[u8]| pixels.chunks_exact(4).map(|p| p[0] as u64).sum::(); + let red_sum = |pixels: &[u8]| { + pixels + .as_chunks::<4>() + .0 + .iter() + .map(|p| p[0] as u64) + .sum::() + }; let loud = paint_scene(make_child(), 200, 200, 0.0, 30); let quiet = paint_scene(make_child(), 200, 200, 0.5, 30); @@ -2658,7 +2675,13 @@ mod motion_blur_trail { /// Find the maximum red channel value across all pixels. fn max_red(pixels: &[u8]) -> u8 { - pixels.chunks_exact(4).map(|p| p[0]).max().unwrap_or(0) + pixels + .as_chunks::<4>() + .0 + .iter() + .map(|p| p[0]) + .max() + .unwrap_or(0) } /// Make a red Shape with slide_in_left + motion_blur, positioned at the center. @@ -3385,7 +3408,7 @@ mod world_view_regressions { fn avg_luma(buf: &[u8]) -> f64 { let mut sum = 0u64; let mut n = 0u64; - for px in buf.chunks_exact(4) { + for px in buf.as_chunks::<4>().0.iter() { sum += px[0] as u64 + px[1] as u64 + px[2] as u64; n += 3; }