CI: as_chunks instead of constant-size chunks_exact (clippy 1.99 chunks_exact_to_as_chunks)

Stable clippy 1.99 denies chunks_exact/chunks_exact_mut with a constant
size (32 sites), which failed the test job on main and every open PR.
Behaviour unchanged; MSRV 1.90 has as_chunks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Thomas
2026-10-04 12:48:43 -04:00
co-authored by Claude Opus 5.5
parent 788456a8e7
commit ab47bf4b9a
19 changed files with 41 additions and 33 deletions
+6 -6
View File
@@ -215,7 +215,7 @@ pub fn build(d: &Dict) -> Option<Stream> {
_ if markup => {
let q = nums(d, b"QuadPoints").filter(|q| !q.is_empty() && q.len() % 8 == 0)?;
let col = stroke?;
for quad in q.chunks_exact(8) {
for quad in q.as_chunks::<8>().0.iter() {
let p = |i: usize| (quad[2 * i], quad[2 * i + 1]);
let (p1, p2, p3, p4) = (p(0), p(1), p(2), p(3));
let h = (p1.0 - p3.0).hypot(p1.1 - p3.1);
@@ -268,7 +268,7 @@ pub fn build(d: &Dict) -> Option<Stream> {
let q = nums(d, b"QuadPoints").filter(|q| !q.is_empty() && q.len() % 8 == 0)?;
let col = stroke.unwrap_or([0.89, 0.13, 0.13]);
c.push_str(&format!("{}1 w\n", rg_stroke(col)));
for quad in q.chunks_exact(8) {
for quad in q.as_chunks::<8>().0.iter() {
c.push_str(&format!(
"{} {} m {} {} l {} {} l {} {} l h S\n",
n(quad[0]),
@@ -326,7 +326,7 @@ pub fn build(d: &Dict) -> Option<Stream> {
}
b"Polygon" | b"PolyLine" => {
let v = nums(d, b"Vertices").filter(|v| v.len() >= 4 && v.len() % 2 == 0)?;
let pts: Vec<(f64, f64)> = v.chunks_exact(2).map(|p| (p[0], p[1])).collect();
let pts: Vec<(f64, f64)> = v.as_chunks::<2>().0.iter().map(|p| (p[0], p[1])).collect();
let col = stroke;
let closed = subtype == b"Polygon";
let fill = if closed { color(d, b"IC")? } else { None };
@@ -388,7 +388,7 @@ pub fn build(d: &Dict) -> Option<Stream> {
c.push_str(&format!("{}{} w 1 J 1 j\n", rg_stroke(col), n(w)));
for s in list {
let pts: Vec<f64> = s.as_array()?.iter().map(|o| o.as_f64()).collect::<Option<_>>()?;
let pts: Vec<(f64, f64)> = pts.chunks_exact(2).map(|p| (p[0], p[1])).collect();
let pts: Vec<(f64, f64)> = pts.as_chunks::<2>().0.iter().map(|p| (p[0], p[1])).collect();
let Some(first) = pts.first() else { continue };
c.push_str(&format!("{} {} m\n", n(first.0), n(first.1)));
if pts.len() == 1 {
@@ -408,7 +408,7 @@ pub fn build(d: &Dict) -> Option<Stream> {
c.push_str(&rg(stroke.unwrap_or([0.0; 3])));
for contour in outline {
let v: Vec<f64> = contour.as_array().map(|a| a.iter().filter_map(Object::as_f64).collect()).unwrap_or_default();
for (i, p) in v.chunks_exact(2).enumerate() {
for (i, p) in v.as_chunks::<2>().0.iter().enumerate() {
c.push_str(&format!("{} {} {}\n", n(x0 + p[0] * w), n(y0 + p[1] * h), if i == 0 { "m" } else { "l" }));
}
if v.len() >= 6 {
@@ -515,7 +515,7 @@ pub fn build(d: &Dict) -> Option<Stream> {
return None;
}
let lw = bw.max(0.5);
let pts: Vec<(f64, f64)> = cl.chunks_exact(2).map(|p| (p[0], p[1])).collect();
let pts: Vec<(f64, f64)> = cl.as_chunks::<2>().0.iter().map(|p| (p[0], p[1])).collect();
c.push_str(&format!("{}{}{} w 1 J 1 j\n", rg_stroke(text_color), rg(bg.unwrap_or([1.0; 3])), n(lw)));
for (i, p) in pts.iter().enumerate() {
c.push_str(&format!("{} {} {}\n", n(p.0), n(p.1), if i == 0 { "m" } else { "l" }));
+4 -3
View File
@@ -714,7 +714,8 @@ fn rect_for(shape: &Shape, style: &Style) -> Result<[f64; 4], AnnotError> {
if quads.is_empty() || !quads.iter().all(|q| finite(q)) {
return Err(bad("text area (no quadrilaterals)"));
}
bounds(quads.iter().flat_map(|q| q.chunks_exact(2).map(|p| [p[0], p[1]]).collect::<Vec<_>>())).ok_or_else(|| bad("text area"))?
bounds(quads.iter().flat_map(|q| q.as_chunks::<2>().0.iter().map(|p| [p[0], p[1]]).collect::<Vec<_>>()))
.ok_or_else(|| bad("text area"))?
}
Shape::Rectangle { rect }
| Shape::Oval { rect }
@@ -1479,7 +1480,7 @@ pub fn summaries(doc: &Document) -> Vec<Summary> {
color = Some([f(i - 3), f(i - 2), f(i - 1)]);
}
}
let quads = nums(b"QuadPoints").chunks_exact(8).map(|q| <[f32; 8]>::try_from(q).unwrap_or_default()).collect();
let quads = nums(b"QuadPoints").as_chunks::<8>().0.to_vec();
let in_reply_to = d.get(b"IRT").map(|o| doc.resolve(o)).and_then(|o| o.as_dict().cloned()).and_then(|p| text_value(doc, &p, b"NM"));
out.push(Summary {
page,
@@ -1653,7 +1654,7 @@ pub fn erase_ink(doc: &mut Document, page: usize, index: usize, path: &[[f64; 2]
.iter()
.map(|s| {
let v: Vec<f64> = doc.resolve(s).as_array().map(|a| a.iter().filter_map(|x| doc.resolve(x).as_f64()).collect()).unwrap_or_default();
v.chunks_exact(2).map(|p| [p[0], p[1]]).collect()
v.as_chunks::<2>().0.iter().map(|p| [p[0], p[1]]).collect()
})
.collect();
// Distance from a point to the eraser's path (segments, or a single point).
+1 -1
View File
@@ -1506,7 +1506,7 @@ fn outline(items: &[printcraft_render::OutlineItem]) -> Value {
fn encode_png(width: u32, height: u32, premultiplied: &[u8]) -> Result<Vec<u8>> {
let mut rgba = premultiplied.to_vec();
for px in rgba.chunks_exact_mut(4) {
for px in rgba.as_chunks_mut::<4>().0 {
let a = u32::from(px[3]);
if a != 0 && a != 255 {
for c in &mut px[..3] {
+1 -1
View File
@@ -56,7 +56,7 @@ impl PdfString {
pub fn to_text(&self) -> String {
let b = &self.bytes;
if b.len() >= 2 && b[0] == 0xFE && b[1] == 0xFF {
let units: Vec<u16> = b[2..].chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect();
let units: Vec<u16> = b[2..].as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes(*c)).collect();
return String::from_utf16_lossy(&units);
}
if b.len() >= 3 && b[..3] == [0xEF, 0xBB, 0xBF] {
+2 -2
View File
@@ -230,7 +230,7 @@ fn unpack(data: &[u8], w: usize, h: usize, n: usize, bpc: usize) -> Option<Vec<u
let r = &data[y * row..(y + 1) * row];
match bpc {
8 => out.extend_from_slice(&r[..w * n]),
16 => out.extend(r.chunks_exact(2).take(w * n).map(|c| c[0])),
16 => out.extend(r.as_chunks::<2>().0.iter().take(w * n).map(|c| c[0])),
_ => {
let per = 8 / bpc;
let m = (1u8 << bpc) - 1;
@@ -275,7 +275,7 @@ fn png(w: u32, h: u32, rgb: &[u8], alpha: Option<&[u8]>) -> Result<Vec<u8>, Stri
let data: Vec<u8> = match alpha {
Some(a) => {
enc.set_color(png::ColorType::Rgba);
rgb.chunks_exact(3).zip(a).flat_map(|(c, a)| [c[0], c[1], c[2], *a]).collect()
rgb.as_chunks::<3>().0.iter().zip(a).flat_map(|(c, a)| [c[0], c[1], c[2], *a]).collect()
}
None => {
enc.set_color(png::ColorType::Rgb);
+9 -6
View File
@@ -266,10 +266,13 @@ fn png_image(name: &str, bytes: &[u8]) -> Result<Embedded, CreateError> {
/// 8-bit RGBA pixels → an image (gray when every pixel is, with a soft mask when any pixel is
/// not opaque).
fn rgba_image(rgba: &[u8], (w, h): (u32, u32), dpi: (f64, f64)) -> Embedded {
let gray = rgba.chunks_exact(4).all(|p| p[0] == p[1] && p[1] == p[2]);
let opaque = rgba.chunks_exact(4).all(|p| p[3] == 255);
let colour: Vec<u8> =
if gray { rgba.chunks_exact(4).map(|p| p[0]).collect() } else { rgba.chunks_exact(4).flat_map(|p| [p[0], p[1], p[2]]).collect() };
let gray = rgba.as_chunks::<4>().0.iter().all(|p| p[0] == p[1] && p[1] == p[2]);
let opaque = rgba.as_chunks::<4>().0.iter().all(|p| p[3] == 255);
let colour: Vec<u8> = if gray {
rgba.as_chunks::<4>().0.iter().map(|p| p[0]).collect()
} else {
rgba.as_chunks::<4>().0.iter().flat_map(|p| [p[0], p[1], p[2]]).collect()
};
let mut d = Dict::new();
d.set(b"ColorSpace".to_vec(), Object::name(if gray { "DeviceGray" } else { "DeviceRGB" }));
d.set(b"BitsPerComponent".to_vec(), Object::Int(8));
@@ -281,7 +284,7 @@ fn rgba_image(rgba: &[u8], (w, h): (u32, u32), dpi: (f64, f64)) -> Embedded {
m.set(b"Height".to_vec(), Object::Int(h as i64));
m.set(b"ColorSpace".to_vec(), Object::name("DeviceGray"));
m.set(b"BitsPerComponent".to_vec(), Object::Int(8));
(m, rgba.chunks_exact(4).map(|p| p[3]).collect())
(m, rgba.as_chunks::<4>().0.iter().map(|p| p[3]).collect())
});
Embedded { dict: d, data: colour, filtered: false, smask, px: (w, h), dpi }
}
@@ -351,7 +354,7 @@ fn tiff_pages(name: &str, bytes: &[u8]) -> Result<Vec<Embedded>, CreateError> {
}
C::RGBA(8 | 16) => rgba_image(&data, (w, h), dpi),
C::GrayA(8 | 16) => {
let rgba: Vec<u8> = data.chunks_exact(2).flat_map(|p| [p[0], p[0], p[0], p[1]]).collect();
let rgba: Vec<u8> = data.as_chunks::<2>().0.iter().flat_map(|p| [p[0], p[0], p[0], p[1]]).collect();
rgba_image(&rgba, (w, h), dpi)
}
other => return Err(bad(format!("{other:?} TIFF images aren't supported yet"))),
+4 -2
View File
@@ -105,7 +105,7 @@ impl Exporter {
/// Premultiplied RGBA → PNG (straight alpha).
pub fn encode_png(width: u32, height: u32, premultiplied: &[u8]) -> Result<Vec<u8>, String> {
let mut rgba = premultiplied.to_vec();
for px in rgba.chunks_exact_mut(4) {
for px in rgba.as_chunks_mut::<4>().0 {
let a = u32::from(px[3]);
if a != 0 && a != 255 {
for c in &mut px[..3] {
@@ -155,7 +155,9 @@ impl ImageFormat {
/// Premultiplied RGBA composited over white → RGB.
fn over_white(premultiplied: &[u8]) -> Vec<u8> {
premultiplied
.chunks_exact(4)
.as_chunks::<4>()
.0
.iter()
.flat_map(|p| {
let k = 255 - p[3];
[p[0].saturating_add(k), p[1].saturating_add(k), p[2].saturating_add(k)]
+1 -1
View File
@@ -114,7 +114,7 @@ impl Ocr {
}
// ocrs wants 1 or 3 channels.
let rgb: std::borrow::Cow<[u8]> = if pixels.len() == (width * height * 4) as usize {
pixels.chunks_exact(4).flat_map(|p| [p[0], p[1], p[2]]).collect::<Vec<u8>>().into()
pixels.as_chunks::<4>().0.iter().flat_map(|p| [p[0], p[1], p[2]]).collect::<Vec<u8>>().into()
} else {
pixels.into()
};
+1 -1
View File
@@ -131,7 +131,7 @@ pub fn page_label_ranges(doc: &Document) -> Vec<LabelRange> {
let node = doc.resolve(&node);
let Some(d) = node.as_dict() else { continue };
if let Some(nums) = d.get(b"Nums").map(|n| doc.resolve(n)).and_then(|n| n.as_array().cloned()) {
for pair in nums.chunks_exact(2) {
for pair in nums.as_chunks::<2>().0 {
let (Some(start), Some(spec)) = (pair[0].as_int(), doc.resolve(&pair[1]).as_dict().cloned()) else { continue };
if start < 0 {
continue;
+1 -1
View File
@@ -227,7 +227,7 @@ pub(crate) fn process(doc: &mut Document, scope: &mut Scope<'_>, streams: &[Vec<
let pts: Vec<(f64, f64)> = match o {
b"re" => op.nums::<4>().map(|[x, y, w, h]| vec![(x, y), (x + w, y), (x, y + h), (x + w, y + h)]).unwrap_or_default(),
b"h" | b"W" | b"W*" => Vec::new(),
_ => op.operands.iter().filter_map(Object::as_f64).collect::<Vec<_>>().chunks_exact(2).map(|p| (p[0], p[1])).collect(),
_ => op.operands.iter().filter_map(Object::as_f64).collect::<Vec<_>>().as_chunks::<2>().0.iter().map(|p| (p[0], p[1])).collect(),
};
for (x, y) in pts {
let (u, v) = gs.ctm.apply(x, y);
+3 -1
View File
@@ -141,7 +141,9 @@ pub fn marks(doc: &Document) -> Vec<Mark> {
.and_then(|q| doc.resolve(q).as_array().map(|a| a.iter().filter_map(Object::as_f64).collect()))
.unwrap_or_default();
let mut rects: Vec<[f64; 4]> = quads
.chunks_exact(8)
.as_chunks::<8>()
.0
.iter()
.map(|q| {
let xs = [q[0], q[2], q[4], q[6]];
let ys = [q[1], q[3], q[5], q[7]];
+1 -1
View File
@@ -586,7 +586,7 @@ impl<'a> Inspector<'a> {
let quads = match d.get(b"QuadPoints").map(|o| self.resolve(o)) {
Ok(Object::Array(q)) => {
let v: Vec<f32> = q.iter().map(|o| o.as_float().unwrap_or(0.0)).collect();
v.chunks_exact(8).map(|c| <[f32; 8]>::try_from(c).unwrap_or_default()).collect()
v.as_chunks::<8>().0.to_vec()
}
_ => Vec::new(),
};
+1 -1
View File
@@ -742,7 +742,7 @@ trailer << /Root 1 0 R >>
assert_eq!((looped.width, looped.height), (40, 40));
let plain = render(pdf("1 0 d0 0 0 1 1 re f"));
assert!(plain.error.is_none(), "{:?}", plain.error);
assert!(plain.rgba.chunks_exact(4).any(|p| p[0] < 128), "a normal Type 3 glyph still paints");
assert!(plain.rgba.as_chunks::<4>().0.iter().any(|p| p[0] < 128), "a normal Type 3 glyph still paints");
}
/// From `cargo xtask fuzz`: an inline image claiming /W 4294967295 over four bytes of data
+1 -1
View File
@@ -140,7 +140,7 @@ impl<'a> Tlv<'a> {
tag::UTF8_STRING | tag::PRINTABLE_STRING | tag::IA5_STRING => Some(String::from_utf8_lossy(self.value).into_owned()),
tag::T61_STRING => Some(self.value.iter().map(|b| *b as char).collect()),
tag::BMP_STRING => {
let units: Vec<u16> = self.value.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect();
let units: Vec<u16> = self.value.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]])).collect();
Some(String::from_utf16_lossy(&units))
}
_ => None,
+1 -1
View File
@@ -200,7 +200,7 @@ pub(crate) fn script_preview(text: &str, w: usize, h: usize) -> egui::ColorImage
}
}
xs.sort_by(|a, b| a.total_cmp(b));
for pair in xs.chunks_exact(2) {
for pair in xs.as_chunks::<2>().0 {
let (from, to) = (pair[0].round().max(0.0) as usize, (pair[1].round() as usize).min(w));
for x in from..to {
img[(x, y)] = Color32::BLACK;
+1 -1
View File
@@ -149,7 +149,7 @@ pub(crate) fn ink_bounds(w: usize, h: usize, rgba: &[u8]) -> Option<[f32; 4]> {
let ink = |p: &[u8]| p[3] > 16 && (p[0] < 240 || p[1] < 240 || p[2] < 240);
let (mut x0, mut y0, mut x1, mut y1) = (w, h, 0, 0);
for (y, row) in rgba.chunks_exact(w * 4).take(h).enumerate() {
for (x, p) in row.chunks_exact(4).enumerate() {
for (x, p) in row.as_chunks::<4>().0.iter().enumerate() {
if ink(p) {
x0 = x0.min(x);
x1 = x1.max(x + 1);
+1 -1
View File
@@ -252,7 +252,7 @@ fn marquee_zoom_and_snapshot() {
drag(&mut h, at(15.0, 175.0), at(180.0, 140.0));
let (w, hgt, px) = h.state().last_snapshot.clone().expect("a snapshot");
assert!(w > 50 && hgt > 10, "{w} × {hgt}");
assert!(px.chunks_exact(4).any(|p| p[0] < 100), "the text is in it");
assert!(px.as_chunks::<4>().0.iter().any(|p| p[0] < 100), "the text is in it");
// Marquee zoom on a small area zooms in, centred on it.
let before = h.state().views[i].zoom;
h.state_mut().set_option("quick", "marquee-zoom").unwrap();
+1 -1
View File
@@ -256,7 +256,7 @@ fn xfdf_annots(doc: &Document, out: &mut String) {
out.push_str("<inklist>");
for g in ink {
let v = nums_of(doc, Some(&g));
let pts: Vec<String> = v.chunks_exact(2).map(|p| format!("{},{}", n(p[0]), n(p[1]))).collect();
let pts: Vec<String> = v.as_chunks::<2>().0.iter().map(|p| format!("{},{}", n(p[0]), n(p[1]))).collect();
let _ = write!(out, "<gesture>{}</gesture>", pts.join(";"));
}
out.push_str("</inklist>");
+1 -1
View File
@@ -364,7 +364,7 @@ fn collect_outline(doc: &Document, node: ObjectId, out: &mut Vec<ObjectId>) {
/// Decode a PDF text string (UTF-16BE with BOM, else treated as Latin-1).
fn decode_text(bytes: &[u8]) -> String {
if let Some(rest) = bytes.strip_prefix(&[0xfe, 0xff]) {
let units: Vec<u16> = rest.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect();
let units: Vec<u16> = rest.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]])).collect();
String::from_utf16_lossy(&units)
} else {
bytes.iter().map(|&b| b as char).collect()