From 1c099361541e5d40ef58b8aad4d052a50aff95d5 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Sun, 4 Oct 2026 10:39:06 -0400 Subject: [PATCH] Clippy 1.99: chunks_exact with a constant size -> as_chunks; drop a no-op Option filter Rust 1.99's clippy adds chunks_exact_to_as_chunks and some_filter, which broke the Clippy step on every CI runner (it uses the latest stable). All sites are mechanical: as_chunks drops the remainder exactly like chunks_exact. Co-Authored-By: Claude Opus 5.5 --- crates/algo/src/oil.rs | 4 +++- crates/algo/src/retouch.rs | 2 +- crates/algo/src/selection.rs | 2 +- crates/algo/src/tests.rs | 6 +++--- crates/algo/src/tests_ext.rs | 20 ++++++++++---------- crates/algo/src/warp.rs | 2 +- crates/cms/src/lutfile.rs | 8 ++++---- crates/cms/src/profile.rs | 10 +++++----- crates/cms/src/transform.rs | 12 ++++++------ crates/codecs/src/codecs/jpeg.rs | 2 +- crates/codecs/src/codecs/png.rs | 4 ++-- crates/codecs/src/codecs/pnm.rs | 2 +- crates/codecs/src/format.rs | 2 +- crates/codecs/src/image.rs | 12 ++++++------ crates/compose/src/lib.rs | 2 +- crates/engine/src/color_cmds.rs | 4 ++-- crates/engine/src/filters_ext/tests.rs | 2 +- crates/engine/src/render_cmds.rs | 4 ++-- crates/engine/src/transform_cmds.rs | 2 +- crates/engine/src/type_cmds.rs | 2 +- crates/engine/src/web_cmds.rs | 4 ++-- crates/format/src/convert.rs | 4 ++-- crates/io/src/annotations_map.rs | 2 +- crates/io/src/blocks.rs | 2 +- crates/io/src/channel_map.rs | 2 +- crates/io/src/lib.rs | 4 +++- crates/io/src/linked.rs | 2 +- crates/io/src/psd_import.rs | 6 ++++-- crates/io/tests/flat.rs | 2 +- crates/paint/src/tile.rs | 2 +- crates/psd/src/layer.rs | 2 +- crates/psd/src/path.rs | 4 +++- crates/psd/src/patterns.rs | 2 +- crates/psd/src/pixels.rs | 4 ++-- crates/psd/src/resources.rs | 2 +- crates/raster/src/lib.rs | 6 +++--- crates/text/src/engine_data.rs | 2 +- crates/text/src/psd_styles.rs | 6 +++--- crates/text/src/tests.rs | 4 ++-- crates/ui-egui/src/brush_panel.rs | 2 +- crates/ui-egui/src/gpu_canvas.rs | 2 +- crates/ui-egui/src/liquify_ui.rs | 2 +- crates/ui-egui/src/palette.rs | 4 +--- crates/ui-egui/src/tone.rs | 2 +- 44 files changed, 92 insertions(+), 86 deletions(-) diff --git a/crates/algo/src/oil.rs b/crates/algo/src/oil.rs index c96850d8..5a40b056 100644 --- a/crates/algo/src/oil.rs +++ b/crates/algo/src/oil.rs @@ -65,7 +65,9 @@ pub(crate) fn oil_paint(src: &Image, out: Rect, ctx: &Ctx, spec: &OilSpec) -> Ve gauss_blur_n(&mut efg, ww, wh, 3, tensor_sigma(spec.scale)); // 4. Stroke direction = minor eigenvector (along edges). let tangent: Vec<(f32, f32)> = efg - .chunks_exact(3) + .as_chunks::<3>() + .0 + .iter() .map(|t| { let (e, f, g) = (t[0], t[1], t[2]); let l1 = 0.5 * (e + g + ((e - g) * (e - g) + 4.0 * f * f).sqrt()); diff --git a/crates/algo/src/retouch.rs b/crates/algo/src/retouch.rs index c719bca2..12aac4c5 100644 --- a/crates/algo/src/retouch.rs +++ b/crates/algo/src/retouch.rs @@ -298,7 +298,7 @@ mod tests { let (w, h, ch) = (8, 1, 4); let data: Vec = (0..w).flat_map(|x| if x < 4 { [1.0, 0.0, 0.0, 1.0] } else { [0.0, 1.0, 0.0, 0.0] }).collect(); let b = local_blur(&data, w, h, ch, Some(3), (2, 0, 6, 1), 1.0); - for p in b.chunks_exact(4) { + for p in b.as_chunks::<4>().0 { if p[3] > 0.01 { assert!(p[0] > 0.99 && p[1] < 0.01, "{p:?}"); } diff --git a/crates/algo/src/selection.rs b/crates/algo/src/selection.rs index 9481d946..f9b719dc 100644 --- a/crates/algo/src/selection.rs +++ b/crates/algo/src/selection.rs @@ -547,7 +547,7 @@ pub fn polygon(points: &[(f32, f32)], area: Rect, anti_alias: bool) -> Vec } } xs.sort_by(|a, b| a.total_cmp(b)); - for span in xs.chunks_exact(2) { + for span in xs.as_chunks::<2>().0 { let (x0, x1) = ((span[0] - area.x0 as f32).max(0.0), (span[1] - area.x0 as f32).min(w as f32)); if x1 <= x0 { continue; diff --git a/crates/algo/src/tests.rs b/crates/algo/src/tests.rs index c1d5bb9f..9d06ef17 100644 --- a/crates/algo/src/tests.rs +++ b/crates/algo/src/tests.rs @@ -127,7 +127,7 @@ fn blur_preserves_flat_colour_and_mass() { for p in [FilterParams::GaussianBlur { radius: 2.0 }, FilterParams::BoxBlur { radius: 3.0 }] { let out = run(&small, &p); let big = Rect::new(-10, -10, 40, 40); - let sum: f32 = out.read_region(big).chunks_exact(4).map(|px| px[3]).sum(); + let sum: f32 = out.read_region(big).as_chunks::<4>().0.iter().map(|px| px[3]).sum(); assert!((sum - 100.0).abs() < 0.01, "{}: {sum}", p.label()); // No colour bleeding from transparent pixels. let edge = out.pixel(9, 15); @@ -176,7 +176,7 @@ fn unsharp_threshold_and_contrast() { let sharp = run(&s, &FilterParams::UnsharpMask { amount: 200.0, radius: 2.0, threshold: 0.0 }); let var = |surf: &Surface| { let v = surf.read_region(Rect::new(5, 5, 35, 25)); - let reds: Vec = v.chunks_exact(4).map(|p| p[0]).collect(); + let reds: Vec = v.as_chunks::<4>().0.iter().map(|p| p[0]).collect(); let m = reds.iter().sum::() / reds.len() as f32; reds.iter().map(|r| (r - m).powi(2)).sum::() }; @@ -198,7 +198,7 @@ fn noise_is_deterministic_monochrome_and_centred() { assert_eq!(a, run(&s, &p)); let v = a.read_region(R); let mut mean = 0.0; - for px in v.chunks_exact(4) { + for px in v.as_chunks::<4>().0 { assert_eq!(px[0], px[1]); assert_eq!(px[1], px[2]); assert!((px[0] - 0.5).abs() <= 0.25 + 1e-6); diff --git a/crates/algo/src/tests_ext.rs b/crates/algo/src/tests_ext.rs index fc30e087..9aa0345b 100644 --- a/crates/algo/src/tests_ext.rs +++ b/crates/algo/src/tests_ext.rs @@ -303,7 +303,7 @@ fn mezzotint_is_binary_and_tracks_brightness() { let out = run(&s, &FilterParams::Mezzotint { kind: MezzotintType::FineDots, seed: 1 }); let v = out.read_region(R); let mut mean = [0.0f32; 3]; - for px in v.chunks_exact(4) { + for px in v.as_chunks::<4>().0 { for k in 0..3 { assert!(px[k] == 0.0 || px[k] == 1.0); mean[k] += px[k] / 1200.0; @@ -318,10 +318,10 @@ fn halftone_covers_by_ink() { let w = run(&flat(SampleType::F32, R, WHITE), &FilterParams::ColorHalftone { max_radius: 4.0, angles }); assert!(w.read_region(R).iter().all(|&v| (v - 1.0).abs() < 1e-6), "white paper stays white"); let b = run(&flat(SampleType::F32, R, BLACK), &FilterParams::ColorHalftone { max_radius: 4.0, angles }); - let mean_b: f32 = b.read_region(R).chunks_exact(4).map(|p| p[0]).sum::() / 1200.0; + let mean_b: f32 = b.read_region(R).as_chunks::<4>().0.iter().map(|p| p[0]).sum::() / 1200.0; assert!(mean_b < 0.05, "black is fully inked: {mean_b}"); let g = run(&flat(SampleType::F32, R, [0.5, 0.5, 0.5, 1.0]), &FilterParams::ColorHalftone { max_radius: 4.0, angles }); - let mean_g: f32 = g.read_region(R).chunks_exact(4).map(|p| p[1]).sum::() / 1200.0; + let mean_g: f32 = g.read_region(R).as_chunks::<4>().0.iter().map(|p| p[1]).sum::() / 1200.0; assert!((mean_g - 0.5).abs() < 0.12, "mid gray ≈ half coverage: {mean_g}"); } @@ -330,8 +330,8 @@ fn pointillize_shows_canvas() { let s = flat(SampleType::F32, R, [0.0, 0.0, 1.0, 1.0]); let out = run(&s, &FilterParams::Pointillize { cell_size: 10.0, seed: 3, background: [1.0, 0.0, 0.0, 1.0] }); let v = out.read_region(R); - assert!(v.chunks_exact(4).any(|p| p[0] > 0.99 && p[2] < 0.01), "canvas visible between dots"); - assert!(v.chunks_exact(4).any(|p| p[2] > 0.9), "dots take the image colour"); + assert!(v.as_chunks::<4>().0.iter().any(|p| p[0] > 0.99 && p[2] < 0.01), "canvas visible between dots"); + assert!(v.as_chunks::<4>().0.iter().any(|p| p[2] > 0.9), "dots take the image colour"); } #[test] @@ -372,8 +372,8 @@ fn tiles_leave_gaps_with_fill() { let out = run(&s, &FilterParams::Tiles { count: 3, max_offset: 40.0, fill: TileFill::Foreground, foreground: [0.0, 1.0, 0.0, 1.0], background: WHITE, seed: 2 }); let v = out.read_region(R); - assert!(v.chunks_exact(4).any(|p| p[1] > 0.99), "foreground gaps"); - assert!(v.chunks_exact(4).filter(|p| p[2] > 0.99).count() > 600, "mostly tiles"); + assert!(v.as_chunks::<4>().0.iter().any(|p| p[1] > 0.99), "foreground gaps"); + assert!(v.as_chunks::<4>().0.iter().filter(|p| p[2] > 0.99).count() > 600, "mostly tiles"); } #[test] @@ -409,7 +409,7 @@ fn fibers_lie_between_colours_and_are_seeded() { let p = FilterParams::Fibers { variance: 16.0, strength: 4.0, seed: 1, foreground: [1.0, 0.0, 0.0, 1.0], background: [0.0, 0.0, 1.0, 1.0] }; let a = run(&s, &p); assert_eq!(a, run(&s, &p)); - for px in a.read_region(R).chunks_exact(4) { + for px in a.read_region(R).as_chunks::<4>().0 { assert!((px[0] + px[2] - 1.0).abs() < 1e-5 && px[1].abs() < 1e-6); } let b = run(&s, &FilterParams::Fibers { variance: 16.0, strength: 4.0, seed: 2, foreground: [1.0, 0.0, 0.0, 1.0], background: [0.0, 0.0, 1.0, 1.0] }); @@ -462,7 +462,7 @@ fn lighting_point_light_falls_off() { } fn variance(s: &Surface, r: Rect, c: usize) -> f32 { - let v: Vec = s.read_region(r).chunks_exact(4).map(|p| p[c]).collect(); + let v: Vec = s.read_region(r).as_chunks::<4>().0.iter().map(|p| p[c]).collect(); let m = v.iter().sum::() / v.len() as f32; v.iter().map(|x| (x - m).powi(2)).sum::() / v.len() as f32 } @@ -525,7 +525,7 @@ fn shaped_blurs_spread_a_point_into_the_shape() { }, ); // A triangle iris pointing up: the bokeh reaches farther below the point than above it... and specular boost brightens. - let sum: f32 = lb.read_region(R).chunks_exact(4).map(|p| p[0]).sum(); + let sum: f32 = lb.read_region(R).as_chunks::<4>().0.iter().map(|p| p[0]).sum(); assert!(sum > 1.5, "highlight bloomed: {sum}"); assert!(lb.pixel(20, 15 + 5)[0] != lb.pixel(20, 15 - 5)[0], "triangular, not circular"); } diff --git a/crates/algo/src/warp.rs b/crates/algo/src/warp.rs index 0740dc0d..013c21f9 100644 --- a/crates/algo/src/warp.rs +++ b/crates/algo/src/warp.rs @@ -283,7 +283,7 @@ pub fn warp_mesh_gray(s: &Surface, f: &(dyn Fn(f64, f64) -> (f64, f64) + Sync), let b = w.content_bounds(); if !b.is_empty() { let px = w.read_region(b); - let flat: Vec = px.chunks_exact(2).map(|p| p[0] * p[1] + default * (1.0 - p[1])).collect(); + let flat: Vec = px.as_chunks::<2>().0.iter().map(|p| p[0] * p[1] + default * (1.0 - p[1])).collect(); out.write_region(b, &flat); } out.prune(); diff --git a/crates/cms/src/lutfile.rs b/crates/cms/src/lutfile.rs index 74495151..7513f740 100644 --- a/crates/cms/src/lutfile.rs +++ b/crates/cms/src/lutfile.rs @@ -186,10 +186,10 @@ pub fn parse_look(text: &str) -> Result { let size: usize = tag("size").and_then(|s| s.parse().ok()).ok_or_else(|| LutError("no in .look".into()))?; let hex: Vec = tag("data").ok_or_else(|| LutError("no in .look".into()))?.bytes().filter(u8::is_ascii_hexdigit).collect(); let nib = |c: u8| (c as char).to_digit(16).unwrap_or(0) as u8; - let bytes: Vec = hex.chunks_exact(2).map(|p| nib(p[0]) << 4 | nib(p[1])).collect(); - let floats: Vec = bytes.chunks_exact(4).map(|b| f32::from_le_bytes([b[0], b[1], b[2], b[3]])).collect(); + let bytes: Vec = hex.as_chunks::<2>().0.iter().map(|p| nib(p[0]) << 4 | nib(p[1])).collect(); + let floats: Vec = bytes.as_chunks::<4>().0.iter().map(|b| f32::from_le_bytes([b[0], b[1], b[2], b[3]])).collect(); let n3 = size.pow(3); - let data = if floats.len() == n3 * 4 { floats.chunks_exact(4).flat_map(|c| [c[0], c[1], c[2]]).collect() } else { floats }; + let data = if floats.len() == n3 * 4 { floats.as_chunks::<4>().0.iter().flat_map(|c| [c[0], c[1], c[2]]).collect() } else { floats }; LutFile { title: tag("title").unwrap_or_default(), size, data }.check() } @@ -200,7 +200,7 @@ pub fn write_cube(l: &LutFile) -> String { s.push_str(&format!("TITLE \"{}\"\n", l.title.replace('"', "'"))); } s.push_str(&format!("LUT_3D_SIZE {}\n", l.size)); - for c in l.data.chunks_exact(3) { + for c in l.data.as_chunks::<3>().0 { s.push_str(&format!("{:.6} {:.6} {:.6}\n", c[0], c[1], c[2])); } s diff --git a/crates/cms/src/profile.rs b/crates/cms/src/profile.rs index 681129b3..f47376a0 100644 --- a/crates/cms/src/profile.rs +++ b/crates/cms/src/profile.rs @@ -525,7 +525,7 @@ fn parse_curve(d: &[u8]) -> Result<(Curve, usize), CmsError> { return Err(CmsError::Invalid("curve too long".into())); } let s = r.slice(12, n * 2)?; - let t = s.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]]) as f32 / 65535.0).collect(); + let t = s.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]]) as f32 / 65535.0).collect(); Ok((Curve::Table(t), len)) } } @@ -586,7 +586,7 @@ fn parse_lut(d: &[u8], a2b: bool) -> Result { for _ in 0..count { let s = r.slice(*off, len * bps)?; let t: Vec = if wide { - s.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]]) as f32 / 65535.0).collect() + s.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]]) as f32 / 65535.0).collect() } else { s.iter().map(|b| *b as f32 / 255.0).collect() }; @@ -603,7 +603,7 @@ fn parse_lut(d: &[u8], a2b: bool) -> Result { let total = nodes as usize * o; let s = r.slice(off, total * bps)?; let data: Vec = if wide { - s.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]]) as f32 / 65535.0).collect() + s.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]]) as f32 / 65535.0).collect() } else { s.iter().map(|b| *b as f32 / 255.0).collect() }; @@ -653,7 +653,7 @@ fn parse_lut(d: &[u8], a2b: bool) -> Result { let total = nodes as usize * cout; let data: Vec = match prec { 1 => r.slice(off + 20, total)?.iter().map(|b| *b as f32 / 255.0).collect(), - 2 => r.slice(off + 20, total * 2)?.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]]) as f32 / 65535.0).collect(), + 2 => r.slice(off + 20, total * 2)?.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]]) as f32 / 65535.0).collect(), _ => return Err(CmsError::Invalid(format!("CLUT precision {prec}"))), }; Ok(Stage::Clut(Clut::new(grid, cout, data))) @@ -730,7 +730,7 @@ fn parse_text(d: &[u8]) -> String { } let Some((off, len)) = best else { return String::new() }; let Ok(s) = r.slice(off, len) else { return String::new() }; - let units: Vec = s.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect(); + let units: Vec = s.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]])).collect(); String::from_utf16_lossy(&units).trim_end_matches('\0').trim().to_string() } _ => String::new(), diff --git a/crates/cms/src/transform.rs b/crates/cms/src/transform.rs index b8b95798..27fb12cd 100644 --- a/crates/cms/src/transform.rs +++ b/crates/cms/src/transform.rs @@ -429,18 +429,18 @@ impl Transform { let run = |(s, d): (&[u8], &mut [u8])| match sample { SampleKind::U8 => self.run_u8(s, src_stride, d, dst_stride, extra), SampleKind::U16 => { - let a: Vec = s.chunks_exact(2).map(|b| u16::from_ne_bytes([b[0], b[1]])).collect(); - let mut o: Vec = d.chunks_exact(2).map(|b| u16::from_ne_bytes([b[0], b[1]])).collect(); + let a: Vec = s.as_chunks::<2>().0.iter().map(|b| u16::from_ne_bytes([b[0], b[1]])).collect(); + let mut o: Vec = d.as_chunks::<2>().0.iter().map(|b| u16::from_ne_bytes([b[0], b[1]])).collect(); self.run_u16(&a, src_stride, &mut o, dst_stride, extra); - for (b, v) in d.chunks_exact_mut(2).zip(o) { + for (b, v) in d.as_chunks_mut::<2>().0.iter_mut().zip(o) { b.copy_from_slice(&v.to_ne_bytes()); } } SampleKind::F32 => { - let a: Vec = s.chunks_exact(4).map(|b| f32::from_ne_bytes([b[0], b[1], b[2], b[3]])).collect(); - let mut o: Vec = d.chunks_exact(4).map(|b| f32::from_ne_bytes([b[0], b[1], b[2], b[3]])).collect(); + let a: Vec = s.as_chunks::<4>().0.iter().map(|b| f32::from_ne_bytes([b[0], b[1], b[2], b[3]])).collect(); + let mut o: Vec = d.as_chunks::<4>().0.iter().map(|b| f32::from_ne_bytes([b[0], b[1], b[2], b[3]])).collect(); self.run_f32(&a, src_stride, &mut o, dst_stride, extra); - for (b, v) in d.chunks_exact_mut(4).zip(o) { + for (b, v) in d.as_chunks_mut::<4>().0.iter_mut().zip(o) { b.copy_from_slice(&v.to_ne_bytes()); } } diff --git a/crates/codecs/src/codecs/jpeg.rs b/crates/codecs/src/codecs/jpeg.rs index ae1a2172..c8733deb 100644 --- a/crates/codecs/src/codecs/jpeg.rs +++ b/crates/codecs/src/codecs/jpeg.rs @@ -133,7 +133,7 @@ pub(crate) fn decode(bytes: &[u8], limits: &Limits) -> Result // Adobe-style CMYK is stored inverted (255 = no ink). ColorSpace::CMYK => px.iter_mut().for_each(|v| *v = 255 - *v), ColorSpace::YCCK => { - for p in px.chunks_exact_mut(4) { + for p in px.as_chunks_mut::<4>().0 { let (y, cb, cr) = (p[0] as f32, p[1] as f32 - 128.0, p[2] as f32 - 128.0); let c = y + 1.402 * cr; let m = y - 0.344_136 * cb - 0.714_136 * cr; diff --git a/crates/codecs/src/codecs/png.rs b/crates/codecs/src/codecs/png.rs index f406d675..99fb2d62 100644 --- a/crates/codecs/src/codecs/png.rs +++ b/crates/codecs/src/codecs/png.rs @@ -48,7 +48,7 @@ pub(crate) fn decode(bytes: &[u8], limits: &Limits) -> Result // tolerated: pixel data is already complete. let _ = reader.finish(); if sample == SampleType::U16 { - for c in buf.chunks_exact_mut(2) { + for c in buf.as_chunks_mut::<2>().0 { let v = u16::from_be_bytes([c[0], c[1]]); c.copy_from_slice(&v.to_ne_bytes()); } @@ -114,7 +114,7 @@ pub(crate) fn encode(src: &Image, plan: Plan, opts: &EncodeOptions) -> Result().0 { let v = u16::from_ne_bytes([c[0], c[1]]); c.copy_from_slice(&v.to_be_bytes()); } diff --git a/crates/codecs/src/codecs/pnm.rs b/crates/codecs/src/codecs/pnm.rs index 07b16a26..94bd5420 100644 --- a/crates/codecs/src/codecs/pnm.rs +++ b/crates/codecs/src/codecs/pnm.rs @@ -103,7 +103,7 @@ fn read_binary(data: &[u8], n: usize, maxval: u32) -> Result, CodecErro if data.len() < n * 2 { return Err(err("truncated raster")); } - Ok(data[..n * 2].chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]]) as u32).collect()) + Ok(data[..n * 2].as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]]) as u32).collect()) } } diff --git a/crates/codecs/src/format.rs b/crates/codecs/src/format.rs index 37b01fcb..683d968e 100644 --- a/crates/codecs/src/format.rs +++ b/crates/codecs/src/format.rs @@ -243,7 +243,7 @@ fn is_avif_ftyp(b: &[u8]) -> bool { let size = u32::from_be_bytes([b[0], b[1], b[2], b[3]]) as usize; let end = size.clamp(12, b.len().min(64)); let brands = &b[8..end]; - brands.chunks_exact(4).enumerate().any(|(i, c)| i != 1 && (c == b"avif" || c == b"avis")) + brands.as_chunks::<4>().0.iter().enumerate().any(|(i, c)| i != 1 && (c == b"avif" || c == b"avis")) } fn looks_like_tga(b: &[u8]) -> bool { diff --git a/crates/codecs/src/image.rs b/crates/codecs/src/image.rs index 415de806..82c14b2f 100644 --- a/crates/codecs/src/image.rs +++ b/crates/codecs/src/image.rs @@ -238,17 +238,17 @@ impl Image { /// Copy samples out as `u16` (only when the sample type is `U16`). pub fn to_u16_samples(&self) -> Option> { - (self.sample == SampleType::U16).then(|| self.data.chunks_exact(2).map(|c| u16::from_ne_bytes([c[0], c[1]])).collect()) + (self.sample == SampleType::U16).then(|| self.data.as_chunks::<2>().0.iter().map(|c| u16::from_ne_bytes([c[0], c[1]])).collect()) } /// Copy samples out as `f16` (only when the sample type is `F16`). pub fn to_f16_samples(&self) -> Option> { - (self.sample == SampleType::F16).then(|| self.data.chunks_exact(2).map(|c| f16::from_bits(u16::from_ne_bytes([c[0], c[1]]))).collect()) + (self.sample == SampleType::F16).then(|| self.data.as_chunks::<2>().0.iter().map(|c| f16::from_bits(u16::from_ne_bytes([c[0], c[1]]))).collect()) } /// Copy samples out as `f32` (only when the sample type is `F32`). pub fn to_f32_samples(&self) -> Option> { - (self.sample == SampleType::F32).then(|| self.data.chunks_exact(4).map(|c| f32::from_ne_bytes([c[0], c[1], c[2], c[3]])).collect()) + (self.sample == SampleType::F32).then(|| self.data.as_chunks::<4>().0.iter().map(|c| f32::from_ne_bytes([c[0], c[1], c[2], c[3]])).collect()) } /// Sample `index` (in samples, not bytes) as a normalized f32. @@ -363,9 +363,9 @@ pub(crate) fn read_normalized(data: &[u8], sample: SampleType, i: usize) -> f32 pub(crate) fn to_normalized(data: &[u8], sample: SampleType) -> Vec { match sample { SampleType::U8 => data.iter().map(|&v| v as f32 / 255.0).collect(), - SampleType::U16 => data.chunks_exact(2).map(|c| u16::from_ne_bytes([c[0], c[1]]) as f32 / 65535.0).collect(), - SampleType::F16 => data.chunks_exact(2).map(|c| f16::from_bits(u16::from_ne_bytes([c[0], c[1]])).to_f32()).collect(), - SampleType::F32 => data.chunks_exact(4).map(|c| f32::from_ne_bytes([c[0], c[1], c[2], c[3]])).collect(), + SampleType::U16 => data.as_chunks::<2>().0.iter().map(|c| u16::from_ne_bytes([c[0], c[1]]) as f32 / 65535.0).collect(), + SampleType::F16 => data.as_chunks::<2>().0.iter().map(|c| f16::from_bits(u16::from_ne_bytes([c[0], c[1]])).to_f32()).collect(), + SampleType::F32 => data.as_chunks::<4>().0.iter().map(|c| f32::from_ne_bytes([c[0], c[1], c[2], c[3]])).collect(), } } diff --git a/crates/compose/src/lib.rs b/crates/compose/src/lib.rs index d81e8684..7d65613d 100644 --- a/crates/compose/src/lib.rs +++ b/crates/compose/src/lib.rs @@ -48,7 +48,7 @@ impl Buffer { } pub fn to_rgba8(&self) -> Rgba8Image { let mut img = Rgba8Image::new(self.rect.width(), self.rect.height()); - for (o, p) in img.pixels.chunks_exact_mut(4).zip(&self.px) { + for (o, p) in img.pixels.as_chunks_mut::<4>().0.iter_mut().zip(&self.px) { for (dst, v) in o.iter_mut().zip(p) { *dst = (v.clamp(0.0, 1.0) * 255.0 + 0.5) as u8; } diff --git a/crates/engine/src/color_cmds.rs b/crates/engine/src/color_cmds.rs index 2a80af71..63605a07 100644 --- a/crates/engine/src/color_cmds.rs +++ b/crates/engine/src/color_cmds.rs @@ -329,7 +329,7 @@ impl ColorState { let check = if pv.gamut_warning { Some(GamutCheck::new(&composite_profile(doc), &pv.setup.profile, pv.gamut_threshold).map_err(cms_err)?) } else { None }; let s = (size - 1) as f32; - for (i, px) in bytes.chunks_exact_mut(4).enumerate() { + for (i, px) in bytes.as_chunks_mut::<4>().0.iter_mut().enumerate() { let rgb = [(i % size) as f32 / s, ((i / size) % size) as f32 / s, (i / (size * size)) as f32 / s]; px[3] = if check.as_ref().is_some_and(|c| c.out_of_gamut(&rgb)) { 255 } else { 0 }; } @@ -1127,7 +1127,7 @@ mod tests { let surf = doc.layers[0].surface_mut().unwrap(); let mut bytes = vec![0u8; r.width() as usize * r.height() as usize * 4]; let mut x = 1u32; - for px in bytes.chunks_exact_mut(4) { + for px in bytes.as_chunks_mut::<4>().0 { x ^= x << 13; x ^= x >> 17; x ^= x << 5; diff --git a/crates/engine/src/filters_ext/tests.rs b/crates/engine/src/filters_ext/tests.rs index ecbd4a2e..67d6897b 100644 --- a/crates/engine/src/filters_ext/tests.rs +++ b/crates/engine/src/filters_ext/tests.rs @@ -158,7 +158,7 @@ fn colour_filters_use_and_record_tool_colours() { let r = s.execute("filter.render.fibers", json!({"seed": 1})).unwrap(); assert_eq!(r["filter"]["foreground"], json!([1.0, 0.0, 0.0, 1.0])); let px = pixels(&s); - for p in px.chunks_exact(4) { + for p in px.as_chunks::<4>().0 { assert!(p[1] < 1e-2 && (p[0] + p[2] - 1.0).abs() < 2e-2, "{p:?}"); } } diff --git a/crates/engine/src/render_cmds.rs b/crates/engine/src/render_cmds.rs index 892d1466..3660d3d7 100644 --- a/crates/engine/src/render_cmds.rs +++ b/crates/engine/src/render_cmds.rs @@ -234,7 +234,7 @@ mod tests { } fn opaque(s: &Session) -> usize { - pixels(s).chunks_exact(4).filter(|p| p[3] > 0.05).count() + pixels(s).as_chunks::<4>().0.iter().filter(|p| p[3] > 0.05).count() } #[test] @@ -294,7 +294,7 @@ mod tests { let r = s.execute("filter.render.tree", json!({"newLayer": true, "baseTreeType": 1, "leavesAmount": 100})).unwrap(); assert_eq!(r["newLayer"], json!(true)); let px = pixels(&s); - let right = px.chunks_exact(4).enumerate().filter(|(i, p)| i % 160 >= 81 && p[3] > 0.0).count(); + let right = px.as_chunks::<4>().0.iter().enumerate().filter(|(i, p)| i % 160 >= 81 && p[3] > 0.0).count(); assert_eq!(right, 0, "nothing drawn outside the selection"); assert!(opaque(&s) > 50); } diff --git a/crates/engine/src/transform_cmds.rs b/crates/engine/src/transform_cmds.rs index b344cc5d..30bfe00d 100644 --- a/crates/engine/src/transform_cmds.rs +++ b/crates/engine/src/transform_cmds.rs @@ -56,7 +56,7 @@ pub(crate) fn warp_gray(s: &Surface, h: &Homography, interp: Interp) -> Surface let b = w.content_bounds(); if !b.is_empty() { let px = w.read_region(b); - let flat: Vec = px.chunks_exact(2).map(|p| p[0] * p[1] + default * (1.0 - p[1])).collect(); + let flat: Vec = px.as_chunks::<2>().0.iter().map(|p| p[0] * p[1] + default * (1.0 - p[1])).collect(); out.write_region(b, &flat); } out.prune(); diff --git a/crates/engine/src/type_cmds.rs b/crates/engine/src/type_cmds.rs index 5656a8f2..99b87719 100644 --- a/crates/engine/src/type_cmds.rs +++ b/crates/engine/src/type_cmds.rs @@ -673,7 +673,7 @@ mod tests { // Red pixels exist. let c = t.cache.as_ref().unwrap(); let r = c.content_bounds(); - assert!(c.read_region(r).chunks_exact(4).any(|p| p[3] > 0.9 && p[0] > 0.9 && p[1] < 0.1)); + assert!(c.read_region(r).as_chunks::<4>().0.iter().any(|p| p[3] > 0.9 && p[0] > 0.9 && p[1] < 0.1)); // The TySh we generated parses back to the same model. let back = photocraft_text::psd::text_layer_from_tysh(t.psd_raw.as_ref().unwrap(), 72.0).unwrap(); assert_eq!(back.text, "Hello"); diff --git a/crates/engine/src/web_cmds.rs b/crates/engine/src/web_cmds.rs index aa6ffcd1..a9060c45 100644 --- a/crates/engine/src/web_cmds.rs +++ b/crates/engine/src/web_cmds.rs @@ -385,7 +385,7 @@ pub fn optimize(px: &[[f32; 4]], bw: usize, rect: Rect, st: &WebSettings, icc: O data.extend_from_slice(&[to8(q[0]), to8(q[1]), to8(q[2]), to8(q[3])][..k]); } if preview { - look = if alpha { data.clone() } else { data.chunks_exact(3).flat_map(|c| [c[0], c[1], c[2], 255]).collect() }; + look = if alpha { data.clone() } else { data.as_chunks::<3>().0.iter().flat_map(|c| [c[0], c[1], c[2], 255]).collect() }; } let layout = if alpha { photocraft_codecs::ChannelLayout::Rgba } else { photocraft_codecs::ChannelLayout::Rgb }; let meta = photocraft_codecs::Metadata { dpi: Some((dpi, dpi)), xmp: xmp.map(str::to_string), ..Default::default() }; @@ -412,7 +412,7 @@ pub fn optimize(px: &[[f32; 4]], bw: usize, rect: Rect, st: &WebSettings, icc: O // The preview shows the compression artefacts. look = match photocraft_codecs::decode(&bytes) { Ok(img) => img.convert(photocraft_codecs::ChannelLayout::Rgba, photocraft_codecs::SampleType::U8).data().to_vec(), - Err(_) => rgb.chunks_exact(3).flat_map(|c| [c[0], c[1], c[2], 255]).collect(), + Err(_) => rgb.as_chunks::<3>().0.iter().flat_map(|c| [c[0], c[1], c[2], 255]).collect(), }; } (bytes, None) diff --git a/crates/format/src/convert.rs b/crates/format/src/convert.rs index 1862afb7..12381df0 100644 --- a/crates/format/src/convert.rs +++ b/crates/format/src/convert.rs @@ -60,8 +60,8 @@ pub(crate) fn swap_to_le(bytes: &mut [u8], sample: SampleType) { if cfg!(target_endian = "big") { match sample { SampleType::U8 => {} - SampleType::U16 => bytes.chunks_exact_mut(2).for_each(|c| c.reverse()), - SampleType::F32 => bytes.chunks_exact_mut(4).for_each(|c| c.reverse()), + SampleType::U16 => bytes.as_chunks_mut::<2>().0.iter_mut().for_each(|c| c.reverse()), + SampleType::F32 => bytes.as_chunks_mut::<4>().0.iter_mut().for_each(|c| c.reverse()), } } } diff --git a/crates/io/src/annotations_map.rs b/crates/io/src/annotations_map.rs index 3b8c42e7..d3100852 100644 --- a/crates/io/src/annotations_map.rs +++ b/crates/io/src/annotations_map.rs @@ -103,7 +103,7 @@ fn color_from(space: u16, c: [u16; 4]) -> Color { fn decode_text(data: &[u8]) -> String { let s = if data.len() >= 2 && data[0] == 0xFE && data[1] == 0xFF { - let units: Vec = data[2..].chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect(); + let units: Vec = data[2..].as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]])).collect(); String::from_utf16_lossy(&units) } else { data.iter().map(|&c| c as char).collect() diff --git a/crates/io/src/blocks.rs b/crates/io/src/blocks.rs index 3da1bb88..fd8f0671 100644 --- a/crates/io/src/blocks.rs +++ b/crates/io/src/blocks.rs @@ -10,7 +10,7 @@ use photocraft_psd::layer::BlendingRanges; /// `brst` (channel blending restrictions): a list of big-endian u32 channel indices left out of /// blending → a bit mask (bit `i` = channel `i`; indices above 31 are ignored). pub fn parse_brst(data: &[u8]) -> u32 { - data.chunks_exact(4).map(|c| u32::from_be_bytes([c[0], c[1], c[2], c[3]])).filter(|&i| i < 32).fold(0, |m, i| m | 1 << i) + data.as_chunks::<4>().0.iter().map(|c| u32::from_be_bytes([c[0], c[1], c[2], c[3]])).filter(|&i| i < 32).fold(0, |m, i| m | 1 << i) } /// Inverse of [`parse_brst`]; `None` when every channel blends (no block). diff --git a/crates/io/src/channel_map.rs b/crates/io/src/channel_map.rs index dd892ca5..9374ad1d 100644 --- a/crates/io/src/channel_map.rs +++ b/crates/io/src/channel_map.rs @@ -42,7 +42,7 @@ pub(crate) fn display_info(channels: &[&AlphaChannel]) -> Vec { /// Applies a DisplayInfo resource (`versioned` = 1077) to the imported channels in order. pub(crate) fn apply_display_info(data: &[u8], versioned: bool, channels: &mut [AlphaChannel]) { let body = if versioned { data.get(4..).unwrap_or(&[]) } else { data }; - for (c, rec) in channels.iter_mut().zip(body.chunks_exact(14)) { + for (c, rec) in channels.iter_mut().zip(body.as_chunks::<14>().0) { let u = |i: usize| u16::from_be_bytes([rec[i], rec[i + 1]]); let comps = [u(2), u(4), u(6), u(8)]; let color = decode_color(u(0), comps); diff --git a/crates/io/src/lib.rs b/crates/io/src/lib.rs index 58d51b5b..5a1f97f3 100644 --- a/crates/io/src/lib.rs +++ b/crates/io/src/lib.rs @@ -148,7 +148,9 @@ pub fn merged_composite(file: &PsdFile) -> Result, IoError> { let unmatte = file.merged_has_alpha(); return Ok(img .data - .chunks_exact(4) + .as_chunks::<4>() + .0 + .iter() .map(|p| { let mut v: [f32; 4] = std::array::from_fn(|i| f32::from(p[i]) / 255.0); if unmatte { diff --git a/crates/io/src/linked.rs b/crates/io/src/linked.rs index b07d28ba..7f569ca1 100644 --- a/crates/io/src/linked.rs +++ b/crates/io/src/linked.rs @@ -43,7 +43,7 @@ impl<'a> Rd<'a> { fn unicode(&mut self) -> Option { let n = self.u32()? as usize; let raw = self.take(n.checked_mul(2)?)?; - let units: Vec = raw.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect(); + let units: Vec = raw.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]])).collect(); Some(String::from_utf16_lossy(&units).trim_end_matches('\0').to_string()) } } diff --git a/crates/io/src/psd_import.rs b/crates/io/src/psd_import.rs index c05d9149..cde71190 100644 --- a/crates/io/src/psd_import.rs +++ b/crates/io/src/psd_import.rs @@ -351,7 +351,7 @@ fn unicode_names(data: &[u8]) -> Vec { let n = u32::from_be_bytes([data[at], data[at + 1], data[at + 2], data[at + 3]]) as usize; at += 4; let Some(b) = data.get(at..at + n * 2) else { break }; - let units: Vec = b.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect(); + let units: Vec = b.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]])).collect(); out.push(String::from_utf16_lossy(&units).trim_end_matches('\0').to_string()); at += n * 2; } @@ -549,7 +549,9 @@ pub fn psd_to_document(file: &PsdFile) -> (Document, Vec) { let mut s = Surface::new(fmt); let vals: Vec = img .data - .chunks_exact(4) + .as_chunks::<4>() + .0 + .iter() .flat_map(|p| { let v = photocraft_raster::from_rgba(&fmt, [p[0], p[1], p[2], p[3]].map(|x| f32::from(x) / 255.0)); v.into_iter() diff --git a/crates/io/tests/flat.rs b/crates/io/tests/flat.rs index f1a4b41a..4ccb1a7a 100644 --- a/crates/io/tests/flat.rs +++ b/crates/io/tests/flat.rs @@ -119,7 +119,7 @@ fn layered_to_png_warns_flatten() { // Composite equals our flatten. let flat = photocraft_compose::flatten(&d).px; let s = back.layers[0].surface().unwrap(); - let px: Vec<[f32; 4]> = s.read_region(back.bounds()).chunks_exact(4).map(|p| [p[0], p[1], p[2], p[3]]).collect(); + let px: Vec<[f32; 4]> = s.read_region(back.bounds()).as_chunks::<4>().0.iter().map(|p| [p[0], p[1], p[2], p[3]]).collect(); assert!(max_diff(&px, &flat) <= 1.0 / 255.0 + 1e-4); } diff --git a/crates/paint/src/tile.rs b/crates/paint/src/tile.rs index 37bbf0b1..ecabcbb3 100644 --- a/crates/paint/src/tile.rs +++ b/crates/paint/src/tile.rs @@ -88,7 +88,7 @@ impl<'de> Deserialize<'de> for GrayTile { let data: Vec = match t.data { DataIn::B64(s) => { let b = b64_decode(&s).ok_or_else(|| D::Error::custom("invalid base64 in tile data"))?; - b.chunks_exact(2).map(|c| u16::from_le_bytes([c[0], c[1]])).collect() + b.as_chunks::<2>().0.iter().map(|c| u16::from_le_bytes([c[0], c[1]])).collect() } DataIn::Floats(v) => v.iter().map(|&x| q16(x)).collect(), }; diff --git a/crates/psd/src/layer.rs b/crates/psd/src/layer.rs index cdd8255a..bc5e3941 100644 --- a/crates/psd/src/layer.rs +++ b/crates/psd/src/layer.rs @@ -289,7 +289,7 @@ impl BlendingRanges { } /// Parsed entries (incomplete trailing bytes are ignored). pub fn ranges(&self) -> Vec { - self.data.chunks_exact(8).map(|c| BlendRange { source: [c[0], c[1], c[2], c[3]], dest: [c[4], c[5], c[6], c[7]] }).collect() + self.data.as_chunks::<8>().0.iter().map(|c| BlendRange { source: [c[0], c[1], c[2], c[3]], dest: [c[4], c[5], c[6], c[7]] }).collect() } } diff --git a/crates/psd/src/path.rs b/crates/psd/src/path.rs index e94e4d1c..ea345b8c 100644 --- a/crates/psd/src/path.rs +++ b/crates/psd/src/path.rs @@ -115,7 +115,9 @@ impl PathData { return Err(PsdError::LimitExceeded("path records")); } let records = data - .chunks_exact(RECORD_LEN) + .as_chunks::() + .0 + .iter() .map(|c| { let mut d = [0u8; 24]; d.copy_from_slice(&c[2..]); diff --git a/crates/psd/src/patterns.rs b/crates/psd/src/patterns.rs index 61c1aa85..ee598d2d 100644 --- a/crates/psd/src/patterns.rs +++ b/crates/psd/src/patterns.rs @@ -105,7 +105,7 @@ fn read_pattern(r: &mut Rd) -> Result { if n > 65_536 { return Err(PsdError::LimitExceeded("pattern name length")); } - let units: Vec = r.take(n * 2)?.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect(); + let units: Vec = r.take(n * 2)?.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]])).collect(); let name = String::from_utf16_lossy(&units).trim_end_matches('\0').to_string(); let idl = r.u8()? as usize; let id = String::from_utf8_lossy(r.take(idl)?).to_string(); diff --git a/crates/psd/src/pixels.rs b/crates/psd/src/pixels.rs index 94192c38..0f019741 100644 --- a/crates/psd/src/pixels.rs +++ b/crates/psd/src/pixels.rs @@ -12,12 +12,12 @@ use crate::layer::{CHANNEL_REAL_USER_MASK, CHANNEL_TRANSPARENCY, CHANNEL_USER_MA /// Interprets planar big-endian bytes as u16 samples. pub fn samples_u16(bytes: &[u8]) -> Vec { - bytes.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect() + bytes.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]])).collect() } /// Interprets planar big-endian bytes as f32 samples. pub fn samples_f32(bytes: &[u8]) -> Vec { - bytes.chunks_exact(4).map(|c| f32::from_be_bytes([c[0], c[1], c[2], c[3]])).collect() + bytes.as_chunks::<4>().0.iter().map(|c| f32::from_be_bytes([c[0], c[1], c[2], c[3]])).collect() } /// Encodes u16 samples as big-endian bytes. diff --git a/crates/psd/src/resources.rs b/crates/psd/src/resources.rs index 8a1966d0..ba2674ba 100644 --- a/crates/psd/src/resources.rs +++ b/crates/psd/src/resources.rs @@ -185,7 +185,7 @@ impl ImageResource { if !d.len().is_multiple_of(2) { Err(PsdError::invalid("layer group info has odd length")) } else { - Ok(ResourceData::LayerGroupInfo(d.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect())) + Ok(ResourceData::LayerGroupInfo(d.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]])).collect())) } } ids::THUMBNAIL | ids::THUMBNAIL_PS4 => Ok(ResourceData::Thumbnail(d)), diff --git a/crates/raster/src/lib.rs b/crates/raster/src/lib.rs index 991cf1c5..36d612df 100644 --- a/crates/raster/src/lib.rs +++ b/crates/raster/src/lib.rs @@ -277,13 +277,13 @@ impl Surface { match (fmt.mode, fmt.sample, fmt.alpha) { (ColorMode::Rgb, SampleType::U8, true) => { let src = &t.data[base..base + dst.len() * 4]; - for (d, s) in dst.iter_mut().zip(src.chunks_exact(4)) { + for (d, s) in dst.iter_mut().zip(src.as_chunks::<4>().0) { *d = [s[0] as f32 / 255.0, s[1] as f32 / 255.0, s[2] as f32 / 255.0, s[3] as f32 / 255.0]; } } (ColorMode::Grayscale, SampleType::U8, true) => { let src = &t.data[base..base + dst.len() * 2]; - for (d, s) in dst.iter_mut().zip(src.chunks_exact(2)) { + for (d, s) in dst.iter_mut().zip(src.as_chunks::<2>().0) { let g = s[0] as f32 / 255.0; *d = [g, g, g, s[1] as f32 / 255.0]; } @@ -324,7 +324,7 @@ impl Surface { Some(t) if rgba8 => { let base = (((y - tc.ty * TILE_SIZE) as usize) * TILE_SIZE as usize + (tr.x0 - tc.tx * TILE_SIZE) as usize) * 4; let len = dst.len(); - for (d, s) in dst.iter_mut().zip(t.data[base..base + len * 4].chunks_exact(4)) { + for (d, s) in dst.iter_mut().zip(t.data[base..base + len * 4].as_chunks::<4>().0) { *d = [s[0], s[1], s[2], s[3]]; } } diff --git a/crates/text/src/engine_data.rs b/crates/text/src/engine_data.rs index a3cb3219..c74986a0 100644 --- a/crates/text/src/engine_data.rs +++ b/crates/text/src/engine_data.rs @@ -206,7 +206,7 @@ impl Parser<'_> { fn decode_string(raw: &[u8]) -> String { if raw.len() >= 2 && raw[0] == 0xFE && raw[1] == 0xFF { - let u: Vec = raw[2..].chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect(); + let u: Vec = raw[2..].as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]])).collect(); String::from_utf16_lossy(&u) } else { raw.iter().map(|&c| c as char).collect() diff --git a/crates/text/src/psd_styles.rs b/crates/text/src/psd_styles.rs index 97d9e718..f34d68a3 100644 --- a/crates/text/src/psd_styles.rs +++ b/crates/text/src/psd_styles.rs @@ -192,9 +192,9 @@ pub fn write_style_sheets(tysh: &[u8], layer: &TextLayer, styles: &TextStyles, d } } let raw = crate::engine_data::write(&e); - match t.text.items.iter_mut().find(|(k, _)| k.is("EngineData")) { - Some(item) => item.1 = photocraft_psd::descriptor::Value::RawData(raw), - None => return None, + { + let item = t.text.items.iter_mut().find(|(k, _)| k.is("EngineData"))?; + item.1 = photocraft_psd::descriptor::Value::RawData(raw) } Some(write_tysh(&t)) } diff --git a/crates/text/src/tests.rs b/crates/text/src/tests.rs index d668618e..bdfba50a 100644 --- a/crates/text/src/tests.rs +++ b/crates/text/src/tests.rs @@ -272,12 +272,12 @@ fn multicolor_runs() { let (l, r) = e.render(&t, 72.0, PixelFormat::RGBA8); assert_eq!(l.glyphs.len(), 2); let px = r.surface.read_region(r.rect); - let opaque: Vec<&[f32]> = px.chunks_exact(4).filter(|p| p[3] > 0.99).collect(); + let opaque: Vec<&[f32; 4]> = px.as_chunks::<4>().0.iter().filter(|p| p[3] > 0.99).collect(); assert!(opaque.iter().any(|p| p[0] > 0.99 && p[2] < 0.01)); assert!(opaque.iter().any(|p| p[2] > 0.99 && p[0] < 0.01)); // CMYK target keeps colour in the document model. let (_, rc) = e.render(&t, 72.0, PixelFormat::CMYKA8); - assert!(rc.surface.read_region(rc.rect).chunks_exact(5).any(|p| p[4] > 0.99 && p[1] > 0.9 && p[2] > 0.9)); + assert!(rc.surface.read_region(rc.rect).as_chunks::<5>().0.iter().any(|p| p[4] > 0.99 && p[1] > 0.9 && p[2] > 0.9)); } #[test] diff --git a/crates/ui-egui/src/brush_panel.rs b/crates/ui-egui/src/brush_panel.rs index f8384b95..25af1ee2 100644 --- a/crates/ui-egui/src/brush_panel.rs +++ b/crates/ui-egui/src/brush_panel.rs @@ -481,7 +481,7 @@ mod tests { let mut b = BrushSettings { size: 400.0, ..Default::default() }; let px = preview_pixels(&b, 120, 40, [1.0, 0.0, 0.0, 1.0]); assert_eq!(px.len(), 120 * 40 * 4); - let covered = px.chunks_exact(4).filter(|p| p[3] > 128).count(); + let covered = px.as_chunks::<4>().0.iter().filter(|p| p[3] > 128).count(); assert!(covered > 200 && covered < 120 * 40 / 2, "{covered}"); // Dynamics change the preview. b.scattering.enabled = true; diff --git a/crates/ui-egui/src/gpu_canvas.rs b/crates/ui-egui/src/gpu_canvas.rs index c6b410c6..ba0f1b4a 100644 --- a/crates/ui-egui/src/gpu_canvas.rs +++ b/crates/ui-egui/src/gpu_canvas.rs @@ -341,7 +341,7 @@ impl Perf { /// Straight-alpha f32 RGBA (sRGB-encoded) → premultiplied RGBA8, split across threads on native. pub fn premultiply_rgba8(px: &[[f32; 4]]) -> Vec { fn convert(src: &[[f32; 4]], dst: &mut [u8]) { - for (o, p) in dst.chunks_exact_mut(4).zip(src) { + for (o, p) in dst.as_chunks_mut::<4>().0.iter_mut().zip(src) { let a = p[3].clamp(0.0, 1.0); o[0] = (p[0].clamp(0.0, 1.0) * a * 255.0 + 0.5) as u8; o[1] = (p[1].clamp(0.0, 1.0) * a * 255.0 + 0.5) as u8; diff --git a/crates/ui-egui/src/liquify_ui.rs b/crates/ui-egui/src/liquify_ui.rs index cd2e71ed..692a1c2c 100644 --- a/crates/ui-egui/src/liquify_ui.rs +++ b/crates/ui-egui/src/liquify_ui.rs @@ -686,7 +686,7 @@ fn draw_mesh(d: &LiquifyDialog, painter: &egui::Painter, area: ERect) { pts.push([pa[0] + (pb[0] - pa[0]) * t, pa[1] + (pb[1] - pa[1]) * t]); } } - for seg in pts.chunks_exact(2) { + for seg in pts.as_chunks::<2>().0 { painter.line_segment([to_screen(d, area, seg[0]), to_screen(d, area, seg[1])], stroke); } k += 1; diff --git a/crates/ui-egui/src/palette.rs b/crates/ui-egui/src/palette.rs index 2d942cd9..e5642f33 100644 --- a/crates/ui-egui/src/palette.rs +++ b/crates/ui-egui/src/palette.rs @@ -90,9 +90,7 @@ pub fn show(app: &mut PhotocraftApp, ctx: &egui::Context) { s, m.id, m.label.trim_end_matches('…').to_string(), - Some(path) - .filter(|_| true) - .map(|p| p + &m.shortcut.map(|s| format!(" {}", crate::shortcuts::pretty(&s))).unwrap_or_default()), + Some(path + &m.shortcut.map(|s| format!(" {}", crate::shortcuts::pretty(&s))).unwrap_or_default()), m.enabled, )) }) diff --git a/crates/ui-egui/src/tone.rs b/crates/ui-egui/src/tone.rs index 14b4fdbb..f73be59e 100644 --- a/crates/ui-egui/src/tone.rs +++ b/crates/ui-egui/src/tone.rs @@ -26,7 +26,7 @@ fn compute_histograms(doc: &Document, hide: LayerId) -> Histograms { } let img = photocraft_compose::thumbnail(&d, 384); let mut h = [[0u32; 256]; 4]; - for p in img.pixels.chunks_exact(4) { + for p in img.pixels.as_chunks::<4>().0 { if p[3] == 0 { continue; }