From 647777ebee42fdc44b3aef7703f7100ea9ffb019 Mon Sep 17 00:00:00 2001
From: Hanno Braun <hanno@braun-odw.eu>
Date: Fri, 11 Nov 2022 12:03:32 +0100
Subject: [PATCH 1/3] Add dependency on `iter_fixed` to `fj-kernel`

---
 Cargo.lock                  | 7 +++++++
 crates/fj-kernel/Cargo.toml | 1 +
 2 files changed, 8 insertions(+)

diff --git a/Cargo.lock b/Cargo.lock
index 386531c3e..ea3b7ad8a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1187,6 +1187,7 @@ dependencies = [
  "anyhow",
  "fj-interop",
  "fj-math",
+ "iter_fixed",
  "itertools",
  "parking_lot",
  "pretty_assertions",
@@ -1836,6 +1837,12 @@ version = "2.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745"
 
+[[package]]
+name = "iter_fixed"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d1d13810ef04ff22d946a8445d1e0016c9e98dbb6deeeb2af061e753060737c"
+
 [[package]]
 name = "itertools"
 version = "0.10.5"
diff --git a/crates/fj-kernel/Cargo.toml b/crates/fj-kernel/Cargo.toml
index 36545b3ad..bc62ee2d2 100644
--- a/crates/fj-kernel/Cargo.toml
+++ b/crates/fj-kernel/Cargo.toml
@@ -13,6 +13,7 @@ categories.workspace = true
 [dependencies]
 fj-interop.workspace = true
 fj-math.workspace = true
+iter_fixed = "0.3.1"
 itertools = "0.10.5"
 parking_lot = "0.12.0"
 pretty_assertions = "1.3.0"

From 27b0b202c78815753b68d006fdde4d5b283f7282 Mon Sep 17 00:00:00 2001
From: Hanno Braun <hanno@braun-odw.eu>
Date: Fri, 11 Nov 2022 12:20:07 +0100
Subject: [PATCH 2/3] Use `iter_fixed` to zip arrays

This is a bit more verbose, but it gives us support for zipping arrays
of arbitrary sizes.
---
 .../src/algorithms/intersect/face_face.rs     |  7 +++--
 crates/fj-kernel/src/algorithms/sweep/edge.rs |  9 +++++--
 crates/fj-kernel/src/builder/edge.rs          | 26 +++++++++++--------
 crates/fj-kernel/src/builder/shell.rs         | 12 ++++++---
 crates/fj-kernel/src/partial/util.rs          |  7 +++--
 5 files changed, 41 insertions(+), 20 deletions(-)

diff --git a/crates/fj-kernel/src/algorithms/intersect/face_face.rs b/crates/fj-kernel/src/algorithms/intersect/face_face.rs
index 9207a208e..6c3fb9c77 100644
--- a/crates/fj-kernel/src/algorithms/intersect/face_face.rs
+++ b/crates/fj-kernel/src/algorithms/intersect/face_face.rs
@@ -1,4 +1,5 @@
 use fj_interop::ext::ArrayExt;
+use iter_fixed::IntoIteratorFixed;
 
 use crate::{
     objects::{Curve, Face, Objects},
@@ -41,8 +42,10 @@ impl FaceFaceIntersection {
 
         let curve_face_intersections = intersection_curves
             .each_ref_ext()
-            .zip_ext(faces)
-            .map(|(curve, face)| CurveFaceIntersection::compute(curve, face));
+            .into_iter_fixed()
+            .zip(faces)
+            .map(|(curve, face)| CurveFaceIntersection::compute(curve, face))
+            .collect::<[_; 2]>();
 
         let intersection_intervals = {
             let [a, b] = curve_face_intersections;
diff --git a/crates/fj-kernel/src/algorithms/sweep/edge.rs b/crates/fj-kernel/src/algorithms/sweep/edge.rs
index e2d98a175..09ade40ac 100644
--- a/crates/fj-kernel/src/algorithms/sweep/edge.rs
+++ b/crates/fj-kernel/src/algorithms/sweep/edge.rs
@@ -1,5 +1,6 @@
 use fj_interop::{ext::ArrayExt, mesh::Color};
 use fj_math::{Line, Scalar, Vector};
+use iter_fixed::IntoIteratorFixed;
 
 use crate::{
     algorithms::{reverse::Reverse, transform::TransformObject},
@@ -65,7 +66,9 @@ impl Sweep for (Handle<HalfEdge>, Color) {
 
                 vertices
                     .each_ref_ext()
-                    .zip_ext(points_surface)
+                    .into_iter_fixed()
+                    .zip(points_surface)
+                    .collect::<[_; 2]>()
                     .try_map_ext(
                     |(vertex, point_surface)| -> Result<_, ValidationError> {
                         let surface_vertex = objects.surface_vertices.insert(
@@ -135,7 +138,9 @@ impl Sweep for (Handle<HalfEdge>, Color) {
 
             let vertices = bottom_vertices
                 .each_ref_ext()
-                .zip_ext(surface_vertices)
+                .into_iter_fixed()
+                .zip(surface_vertices)
+                .collect::<[_; 2]>()
                 .try_map_ext(|(vertex, surface_form)| {
                     objects.vertices.insert(Vertex::new(
                         vertex.position(),
diff --git a/crates/fj-kernel/src/builder/edge.rs b/crates/fj-kernel/src/builder/edge.rs
index 674183e11..928583ca0 100644
--- a/crates/fj-kernel/src/builder/edge.rs
+++ b/crates/fj-kernel/src/builder/edge.rs
@@ -1,5 +1,5 @@
-use fj_interop::ext::ArrayExt;
 use fj_math::{Point, Scalar};
+use iter_fixed::IntoIteratorFixed;
 
 use crate::{
     insert::Insert,
@@ -187,17 +187,21 @@ impl HalfEdgeBuilder for PartialHalfEdge {
                     .unwrap_or([None, None])
             };
 
-            vertices.zip_ext(global_forms).map(|(vertex, global_form)| {
-                vertex.update_partial(|vertex| {
-                    vertex.clone().with_surface_form(
-                        vertex.surface_form().update_partial(
-                            |surface_vertex| {
-                                surface_vertex.with_global_form(global_form)
-                            },
-                        ),
-                    )
+            vertices
+                .into_iter_fixed()
+                .zip(global_forms)
+                .collect::<[_; 2]>()
+                .map(|(vertex, global_form)| {
+                    vertex.update_partial(|vertex| {
+                        vertex.clone().with_surface_form(
+                            vertex.surface_form().update_partial(
+                                |surface_vertex| {
+                                    surface_vertex.with_global_form(global_form)
+                                },
+                            ),
+                        )
+                    })
                 })
-            })
         };
 
         self.with_curve(curve).with_vertices([back, front])
diff --git a/crates/fj-kernel/src/builder/shell.rs b/crates/fj-kernel/src/builder/shell.rs
index 34534a022..bee310e32 100644
--- a/crates/fj-kernel/src/builder/shell.rs
+++ b/crates/fj-kernel/src/builder/shell.rs
@@ -2,6 +2,7 @@ use std::array;
 
 use fj_interop::ext::{ArrayExt, SliceExt};
 use fj_math::Scalar;
+use iter_fixed::IntoIteratorFixed;
 
 use crate::{
     algorithms::transform::TransformObject,
@@ -235,8 +236,11 @@ impl<'a> ShellBuilder<'a> {
                 let mut edges = top_edges.iter();
                 let half_edges = array::from_fn(|_| edges.next().unwrap());
 
-                let [a, b, c, d] =
-                    points.zip_ext(half_edges).map(|(point, edge)| {
+                let [a, b, c, d] = points
+                    .into_iter_fixed()
+                    .zip(half_edges)
+                    .collect::<[_; 4]>()
+                    .map(|(point, edge)| {
                         let vertex = edge.back();
 
                         SurfaceVertex::partial()
@@ -263,7 +267,9 @@ impl<'a> ShellBuilder<'a> {
                 let vertices = edge
                     .vertices()
                     .each_ref_ext()
-                    .zip_ext(surface_vertices.clone())
+                    .into_iter_fixed()
+                    .zip(surface_vertices.clone())
+                    .collect::<[_; 2]>()
                     .map(|(vertex, surface_form)| {
                         Vertex::partial()
                             .with_position(Some(vertex.position()))
diff --git a/crates/fj-kernel/src/partial/util.rs b/crates/fj-kernel/src/partial/util.rs
index e0605ee1e..a0c11dc7c 100644
--- a/crates/fj-kernel/src/partial/util.rs
+++ b/crates/fj-kernel/src/partial/util.rs
@@ -1,4 +1,4 @@
-use fj_interop::ext::ArrayExt;
+use iter_fixed::IntoIteratorFixed;
 
 use super::{HasPartial, MaybePartial};
 
@@ -22,5 +22,8 @@ pub fn merge_arrays<T: HasPartial>(
     a: [MaybePartial<T>; 2],
     b: [MaybePartial<T>; 2],
 ) -> [MaybePartial<T>; 2] {
-    a.zip_ext(b).map(|(a, b)| a.merge_with(b))
+    a.into_iter_fixed()
+        .zip(b)
+        .collect::<[_; 2]>()
+        .map(|(a, b)| a.merge_with(b))
 }

From 7b2bb4a3520a0e6754c82fd3223f976c20d0af08 Mon Sep 17 00:00:00 2001
From: Hanno Braun <hanno@braun-odw.eu>
Date: Fri, 11 Nov 2022 12:20:45 +0100
Subject: [PATCH 3/3] Remove unused code

---
 crates/fj-interop/src/ext.rs | 19 -------------------
 1 file changed, 19 deletions(-)

diff --git a/crates/fj-interop/src/ext.rs b/crates/fj-interop/src/ext.rs
index 1a04248ee..cc5e5311e 100644
--- a/crates/fj-interop/src/ext.rs
+++ b/crates/fj-interop/src/ext.rs
@@ -13,11 +13,6 @@ pub trait ArrayExt<T, const N: usize> {
     fn try_map_ext<F, U, E>(self, f: F) -> Result<[U; N], E>
     where
         F: FnMut(T) -> Result<U, E>;
-
-    /// Stable replacement for `zip`
-    ///
-    /// <https://doc.rust-lang.org/std/primitive.array.html#method.zip>
-    fn zip_ext<U>(self, rhs: [U; N]) -> [(T, U); N];
 }
 
 impl<T> ArrayExt<T, 2> for [T; 2] {
@@ -33,13 +28,6 @@ impl<T> ArrayExt<T, 2> for [T; 2] {
         let [a, b] = self.map(f);
         Ok([a?, b?])
     }
-
-    fn zip_ext<U>(self, rhs: [U; 2]) -> [(T, U); 2] {
-        let [a, b] = self;
-        let [c, d] = rhs;
-
-        [(a, c), (b, d)]
-    }
 }
 
 impl<T> ArrayExt<T, 4> for [T; 4] {
@@ -55,13 +43,6 @@ impl<T> ArrayExt<T, 4> for [T; 4] {
         let [a, b, c, d] = self.map(f);
         Ok([a?, b?, c?, d?])
     }
-
-    fn zip_ext<U>(self, rhs: [U; 4]) -> [(T, U); 4] {
-        let [a, b, c, d] = self;
-        let [e, f, g, h] = rhs;
-
-        [(a, e), (b, f), (c, g), (d, h)]
-    }
 }
 
 /// Extension trait for arrays