From f4d888f97d792b535b0c7a6773ccbc2fa2e1e8b9 Mon Sep 17 00:00:00 2001 From: DavidCrossman <22548398+DavidCrossman@users.noreply.github.com> Date: Fri, 10 Apr 2026 22:29:27 +0100 Subject: [PATCH 1/2] Use `<[T]>::as_chunks{_mut}` for exact size chunks --- crates/bevy_gizmos/src/rounded_box.rs | 4 +-- crates/bevy_image/src/dds.rs | 8 +++--- .../src/image_texture_conversion.rs | 11 +++----- crates/bevy_mesh/src/mesh.rs | 26 +++++++++---------- crates/bevy_mesh/src/primitives/extrusion.rs | 8 ++++-- .../mesh_picking/ray_cast/intersections.rs | 24 +++++++---------- crates/bevy_render/src/diagnostic/internal.rs | 12 ++++++--- crates/bevy_winit/src/cursor/custom_cursor.rs | 5 ++-- 8 files changed, 48 insertions(+), 50 deletions(-) diff --git a/crates/bevy_gizmos/src/rounded_box.rs b/crates/bevy_gizmos/src/rounded_box.rs index 31a9b4ed876df..5a715b7b1e36d 100644 --- a/crates/bevy_gizmos/src/rounded_box.rs +++ b/crates/bevy_gizmos/src/rounded_box.rs @@ -133,9 +133,9 @@ where ] .map(|vec3| config.isometry * vec3); - for chunk in vertices.chunks_exact(3) { + for &[a, b, c] in vertices.as_chunks().0 { self.gizmos - .short_arc_3d_between(chunk[1], chunk[0], chunk[2], config.color) + .short_arc_3d_between(b, a, c, config.color) .resolution(config.arc_resolution); } diff --git a/crates/bevy_image/src/dds.rs b/crates/bevy_image/src/dds.rs index a1f0a742a6af0..7470372d668ed 100644 --- a/crates/bevy_image/src/dds.rs +++ b/crates/bevy_image/src/dds.rs @@ -105,10 +105,10 @@ pub fn dds_buffer_to_image( image.data = if let Some(transcode_format) = transcode_format { match transcode_format { TranscodeFormat::Rgb8 => { - let data = dds - .data - .chunks_exact(3) - .flat_map(|pixel| [pixel[0], pixel[1], pixel[2], u8::MAX]) + let (chunks, _) = dds.data.as_chunks(); + let data = chunks + .iter() + .flat_map(|&[r, g, b]| [r, g, b, u8::MAX]) .collect(); Some(data) } diff --git a/crates/bevy_image/src/image_texture_conversion.rs b/crates/bevy_image/src/image_texture_conversion.rs index c6fb6e33e10b3..f9af22a21327c 100644 --- a/crates/bevy_image/src/image_texture_conversion.rs +++ b/crates/bevy_image/src/image_texture_conversion.rs @@ -112,12 +112,7 @@ impl Image { width as usize * height as usize * format.pixel_size().unwrap_or(0), ); - for pixel in image.into_raw().chunks_exact(3) { - // TODO: use the array_chunks method once stabilized - // https://github.com/rust-lang/rust/issues/74985 - let r = pixel[0]; - let g = pixel[1]; - let b = pixel[2]; + for [r, g, b] in image.into_raw().as_chunks().0 { let a = 1f32; local_data.extend_from_slice(&r.to_le_bytes()); @@ -191,8 +186,8 @@ impl Image { TextureFormat::Bgra8UnormSrgb | TextureFormat::Bgra8Unorm => { ImageBuffer::from_raw(width, height, { let mut data = data; - for bgra in data.chunks_exact_mut(4) { - bgra.swap(0, 2); + for [b, _, r, _] in data.as_chunks_mut().0 { + core::mem::swap(b, r); } data }) diff --git a/crates/bevy_mesh/src/mesh.rs b/crates/bevy_mesh/src/mesh.rs index ec7dd0bcdd508..dccb8cb8ff960 100644 --- a/crates/bevy_mesh/src/mesh.rs +++ b/crates/bevy_mesh/src/mesh.rs @@ -1231,15 +1231,12 @@ impl Mesh { ) -> Result<(), MeshWindingInvertError> { match topology { PrimitiveTopology::TriangleList => { - // Early return if the index count doesn't match - if !indices.len().is_multiple_of(3) { + let (chunks, []) = indices.as_chunks_mut() else { + // Early return if the index count doesn't match return Err(MeshWindingInvertError::AbruptIndicesEnd); - } - for chunk in indices.chunks_mut(3) { - // This currently can only be optimized away with unsafe, rework this when `feature(slice_as_chunks)` gets stable. - let [_, b, c] = chunk else { - return Err(MeshWindingInvertError::AbruptIndicesEnd); - }; + }; + + for [_, b, c] in chunks { core::mem::swap(b, c); } Ok(()) @@ -1353,9 +1350,10 @@ impl Mesh { .expect("`Mesh::ATTRIBUTE_POSITION` vertex attributes should be of type `float3`"); let normals: Vec<_> = positions - .chunks_exact(3) - .map(|p| triangle_normal(p[0], p[1], p[2])) - .flat_map(|normal| [normal; 3]) + .as_chunks() + .0 + .iter() + .flat_map(|&[a, b, c]| [triangle_normal(a, b, c); 3]) .collect(); self.try_insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals) @@ -1611,8 +1609,10 @@ impl Mesh { self.try_indices()? .iter() .collect::>() - .chunks_exact(3) - .for_each(|face| per_triangle([face[0], face[1], face[2]], positions, &mut normals)); + .as_chunks() + .0 + .iter() + .for_each(|&faces| per_triangle(faces, positions, &mut normals)); for normal in &mut normals { *normal = normal.try_normalize().unwrap_or(Vec3::ZERO); diff --git a/crates/bevy_mesh/src/primitives/extrusion.rs b/crates/bevy_mesh/src/primitives/extrusion.rs index 091735dc8349c..9df4821eb392b 100644 --- a/crates/bevy_mesh/src/primitives/extrusion.rs +++ b/crates/bevy_mesh/src/primitives/extrusion.rs @@ -212,10 +212,14 @@ where match topology { PrimitiveTopology::TriangleList => match indices { Indices::U16(indices) => { - indices.chunks_exact_mut(3).for_each(|arr| arr.swap(1, 0)); + for [a, b, _] in indices.as_chunks_mut().0 { + core::mem::swap(a, b); + } } Indices::U32(indices) => { - indices.chunks_exact_mut(3).for_each(|arr| arr.swap(1, 0)); + for [a, b, _] in indices.as_chunks_mut().0 { + core::mem::swap(a, b); + } } }, _ => { diff --git a/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs b/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs index 4d5aa6d81fd8a..48c63c5e1645a 100644 --- a/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs +++ b/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs @@ -104,16 +104,13 @@ where } indices - .chunks_exact(3) + .as_chunks() + .0 .enumerate() .fold( (f32::MAX, None), - |(closest_distance, closest_hit), (tri_idx, triangle)| { - let [Ok(a), Ok(b), Ok(c)] = [ - triangle[0].try_into(), - triangle[1].try_into(), - triangle[2].try_into(), - ] else { + |(closest_distance, closest_hit), (tri_idx, [a, b, c])| { + let [Ok(a), Ok(b), Ok(c)] = [a.try_into(), b.try_into(), c.try_into()] else { return (closest_distance, closest_hit); }; @@ -136,17 +133,14 @@ where .1 } else { positions - .chunks_exact(3) + .as_chunks() + .0 + .iter() + .map(|[a, b, c]| [Vec3::from(a), Vec3::from(b), Vec3::from(c)]) .enumerate() .fold( (f32::MAX, None), - |(closest_distance, closest_hit), (tri_idx, triangle)| { - let tri_vertices = [ - Vec3::from(triangle[0]), - Vec3::from(triangle[1]), - Vec3::from(triangle[2]), - ]; - + |(closest_distance, closest_hit), (tri_idx, tri_vertices)| { match ray_triangle_intersection(&ray, &tri_vertices, backface_culling) { Some(hit) if hit.distance >= 0. && hit.distance < closest_distance => { (hit.distance, Some((tri_idx, hit))) diff --git a/crates/bevy_render/src/diagnostic/internal.rs b/crates/bevy_render/src/diagnostic/internal.rs index ee9b502823e2e..a0573d3d753b4 100644 --- a/crates/bevy_render/src/diagnostic/internal.rs +++ b/crates/bevy_render/src/diagnostic/internal.rs @@ -581,15 +581,19 @@ impl FrameData { let data = read_buffer.slice(..).get_mapped_range(); let timestamps = data[..(self.num_timestamps * 8) as usize] - .chunks(8) - .map(|v| u64::from_le_bytes(v.try_into().unwrap())) + .as_chunks() + .0 + .iter() + .map(|&v| u64::from_le_bytes(v)) .collect::>(); let start = self.pipeline_statistics_buffer_offset as usize; let len = (self.num_pipeline_statistics as usize) * 40; let pipeline_statistics = data[start..start + len] - .chunks(8) - .map(|v| u64::from_le_bytes(v.try_into().unwrap())) + .as_chunks() + .0 + .iter() + .map(|&v| u64::from_le_bytes(v)) .collect::>(); let mut diagnostics = Vec::new(); diff --git a/crates/bevy_winit/src/cursor/custom_cursor.rs b/crates/bevy_winit/src/cursor/custom_cursor.rs index 00133cbb4bf98..d754e8a5a3f4d 100644 --- a/crates/bevy_winit/src/cursor/custom_cursor.rs +++ b/crates/bevy_winit/src/cursor/custom_cursor.rs @@ -90,9 +90,10 @@ pub(crate) fn extract_rgba_pixels(image: &Image) -> Option> { | TextureFormat::Rgba8Uint | TextureFormat::Rgba8Sint => Some(image.data.clone()?), TextureFormat::Rgba32Float => image.data.as_ref().map(|data| { - data.chunks(4) + data.as_chunks() + .0 + .iter() .map(|chunk| { - let chunk = chunk.try_into().unwrap(); let num = bytemuck::cast_ref::<[u8; 4], f32>(chunk); ops::round(num.clamp(0.0, 1.0) * 255.0) as u8 }) From e3d2659eb5160a7967270e1bdbae53291e76b0b7 Mon Sep 17 00:00:00 2001 From: DavidCrossman <22548398+DavidCrossman@users.noreply.github.com> Date: Fri, 10 Apr 2026 23:18:19 +0100 Subject: [PATCH 2/2] Fixes --- .../bevy_picking/src/mesh_picking/ray_cast/intersections.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs b/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs index 48c63c5e1645a..3643b719f964c 100644 --- a/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs +++ b/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs @@ -106,10 +106,11 @@ where indices .as_chunks() .0 + .iter() .enumerate() .fold( (f32::MAX, None), - |(closest_distance, closest_hit), (tri_idx, [a, b, c])| { + |(closest_distance, closest_hit), (tri_idx, &[a, b, c])| { let [Ok(a), Ok(b), Ok(c)] = [a.try_into(), b.try_into(), c.try_into()] else { return (closest_distance, closest_hit); }; @@ -136,7 +137,7 @@ where .as_chunks() .0 .iter() - .map(|[a, b, c]| [Vec3::from(a), Vec3::from(b), Vec3::from(c)]) + .map(|&[a, b, c]| [Vec3::from(a), Vec3::from(b), Vec3::from(c)]) .enumerate() .fold( (f32::MAX, None),