From 36792b50656b3bf8d8582fc6695a97bb6a12e123 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 23 Oct 2023 15:52:37 +0200
Subject: [PATCH 001/212] Add function largest_primes_below

---
 src/lib.rs | 113 +++++++++++++++++++++++++++++++++++------------------
 1 file changed, 74 insertions(+), 39 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 9ec4b9c..a00879e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -181,6 +181,79 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
     primes
 }
 
+/// Returns the `N` largest primes below the given upper limit.
+/// # Example
+/// ```
+/// # use const_primes::largest_primes_below;
+/// const P: [u64; 10] = largest_primes_below(100);
+/// assert_eq!(P, [53, 59, 61, 67, 71, 73, 79, 83, 89, 97]);
+/// ```
+pub const fn largest_primes_below<const N: usize>(mut upper_limit: u64) -> [u64; N] {
+    // This will be used to sieve all upper ranges.
+    let base_sieve: [bool; N] = are_prime();
+    let mut primes = [0; N];
+    let mut total_primes_found = 0;
+    'generate: while total_primes_found < N {
+        let upper_sieve = sieve_segment(&base_sieve, upper_limit);
+        let mut i = 0;
+        while i < N {
+            let j = N - 1 - i;
+            if upper_sieve[j] {
+                primes[N - total_primes_found - 1] = upper_limit - 1 - i as u64;
+                total_primes_found += 1;
+                if total_primes_found >= N {
+                    break 'generate;
+                }
+            }
+            i += 1;
+        }
+        upper_limit -= N as u64;
+    }
+
+    primes
+}
+
+/// Uses the primalities in `base_sieve` to sieve the numbers in the range `[upper_limit - N, upper_limit)`.
+const fn sieve_segment<const N: usize>(base_sieve: &[bool; N], upper_limit: u64) -> [bool; N] {
+    let mut segment_sieve = [true; N];
+
+    let lower_limit = upper_limit - N as u64;
+
+    // In case 0 and/or 1 are included in the upper sieve we need to treat them as a special case
+    // since they are not multiples of any prime in `base_sieve` even though they are not primes.
+    if lower_limit == 0 && N > 1 {
+        segment_sieve[0] = false;
+        segment_sieve[1] = false;
+    } else if lower_limit == 1 && N > 0 {
+        segment_sieve[0] = false;
+    }
+
+    let mut i = 0;
+    while i < N {
+        if base_sieve[i] {
+            let prime = i as u64;
+
+            // Find the smallest multiple of the prime larger than or equal to `lower_limit`.
+            let mut composite = (lower_limit / prime) * prime;
+            if composite < lower_limit {
+                composite += prime;
+            }
+            if composite == prime {
+                composite += prime;
+            }
+
+            // Sieve all numbers in the segment that are multiples of the prime.
+            while composite < upper_limit {
+                segment_sieve[(composite - lower_limit) as usize] = false;
+                composite += prime;
+            }
+        }
+        i += 1;
+    }
+
+    segment_sieve
+}
+
 /// Returns an array of size `N` that indicates which of the integers in `[upper_limit - N, upper_limit)` are prime,
 /// or in other words: the value at a given index represents whether `index + upper_limit - N` is prime.
 ///
@@ -248,45 +321,7 @@ pub const fn are_prime_below<const N: usize>(upper_limit: u64) -> [bool; N] {
         return base_sieve;
     }
 
-    // Otherwise we use the base sieve to sieve the upper range
-    let mut segment_sieve = [true; N];
-
-    let lower_limit = upper_limit - n64;
-
-    // In case 0 and/or 1 are included in the upper sieve we need to treat them as a special case
-    // since they are not multiples of any prime in `base_sieve` even though they are not primes.
-    if lower_limit == 0 && N > 1 {
-        segment_sieve[0] = false;
-        segment_sieve[1] = false;
-    } else if lower_limit == 1 && N > 0 {
-        segment_sieve[0] = false;
-    }
-
-    // For all the found primes
-    let mut i = 0;
-    while i < N {
-        if base_sieve[i] {
-            let prime = i as u64;
-
-            // Find the smallest multiple of the prime larger than or equal to `lower_limit`.
-            let mut composite = (lower_limit / prime) * prime;
-            if composite < lower_limit {
-                composite += prime;
-            }
-            if composite == prime {
-                composite += prime;
-            }
-
-            // Sieve all numbers in the segment that are multiples of the prime.
-            while composite < upper_limit {
-                segment_sieve[(composite - lower_limit) as usize] = false;
-                composite += prime;
-            }
-        }
-        i += 1;
-    }
-
-    segment_sieve
+    sieve_segment(&base_sieve, upper_limit)
 }
 
 /// Returns an array of size `N` where the value at a given index indicates whether the index is prime.

From 10c4744f97d0ae53ded22098d3e078bc56936b4a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 23 Oct 2023 15:59:24 +0200
Subject: [PATCH 002/212] Add unit test to largest_primes_below

---
 src/lib.rs | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/src/lib.rs b/src/lib.rs
index a00879e..3281c47 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -650,6 +650,22 @@ mod test {
         test_to_n!(0, 1, 2, 3, 4, 5, 10, 100, 1000, 10000);
     }
 
+    #[test]
+    fn check_largest_primes_below() {
+        macro_rules! test_n_below_100 {
+            ($($n:expr),+) => {
+                $(
+                    {
+                        println!("{}", $n);
+                        assert_eq!(PRECOMPUTED_PRIMES[25-$n..25], largest_primes_below::<$n>(100).map(|i| i as u32));
+                    }
+                )+
+            };
+        }
+
+        test_n_below_100!(10, 15);
+    }
+
     #[test]
     fn check_next_prime() {
         for i in 1..PRECOMPUTED_PRIMES.len() - 1 {

From c09b1438aad5642bc908f639392d6c96b2307b06 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 23 Oct 2023 16:04:48 +0200
Subject: [PATCH 003/212] Add early panic in largest_primes_below

---
 src/lib.rs | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/lib.rs b/src/lib.rs
index 3281c47..f4df7d7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -188,7 +188,16 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// const P: [u64; 10] = largest_primes_below(100);
 /// assert_eq!(P, [53, 59, 61, 67, 71, 73, 79, 83, 89, 97]);
 /// ```
+/// # Panics
+/// Panics if `upper_limit` is not in the range `[N, N^2]`.
 pub const fn largest_primes_below<const N: usize>(mut upper_limit: u64) -> [u64; N] {
+    let n64 = N as u64;
+    assert!(upper_limit >= n64, "`upper_limit` must be at least `N`");
+    match (n64).checked_mul(n64) {
+        Some(prod) => assert!(upper_limit <= prod, "`upper_limit` must be below `N^2`"),
+        None => panic!("`N^2` must fit in a `u64`"),
+    }
+
     // This will be used to sieve all upper ranges.
     let base_sieve: [bool; N] = are_prime();
     let mut primes = [0; N];

From e3d874984e64ddb2ea08377165da6f44242ab020 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 23 Oct 2023 16:08:07 +0200
Subject: [PATCH 004/212] Clarify sieve_segment docstring

---
 src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/lib.rs b/src/lib.rs
index f4df7d7..162489a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -222,7 +222,7 @@ pub const fn largest_primes_below<const N: usize>(mut upper_limit: u64) -> [u64;
     primes
 }
 
-/// Uses the primalities in `base_sieve` to sieve the numbers in the range `[upper_limit - N, upper_limit)`.
+/// Uses the primalities of the first `N` integers in `base_sieve` to sieve the numbers in the range `[upper_limit - N, upper_limit)`.
 const fn sieve_segment<const N: usize>(base_sieve: &[bool; N], upper_limit: u64) -> [bool; N] {
     let mut segment_sieve = [true; N];
 

From d57e5bd618774a90d9fc35ae9eccd84221e9c2a0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 23 Oct 2023 17:21:05 +0200
Subject: [PATCH 005/212] Discovered failing test

---
 src/lib.rs | 24 +++++++++++++-----------
 1 file changed, 13 insertions(+), 11 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 162489a..d9d4f8d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -200,15 +200,16 @@ pub const fn largest_primes_below<const N: usize>(mut upper_limit: u64) -> [u64;
 
     // This will be used to sieve all upper ranges.
     let base_sieve: [bool; N] = are_prime();
-    let mut primes = [0; N];
-    let mut total_primes_found = 0;
-    'generate: while total_primes_found < N {
-        let upper_sieve = sieve_segment(&base_sieve, upper_limit);
-        let mut i = 0;
+    let mut primes: [u64; N] = [0; N];
+    let mut total_primes_found: usize = 0;
+    'generate: while total_primes_found < N && upper_limit > 1 {
+        let upper_sieve: [bool; N] = sieve_segment(&base_sieve, upper_limit);
+        let mut smallest_found_prime = upper_limit;
+        let mut i: usize = 0;
         while i < N {
-            let j = N - 1 - i;
-            if upper_sieve[j] {
-                primes[N - total_primes_found - 1] = upper_limit - 1 - i as u64;
+            if upper_sieve[N - 1 - i] {
+                smallest_found_prime = upper_limit - 1 - i as u64;
+                primes[N - total_primes_found - 1] = smallest_found_prime;
                 total_primes_found += 1;
                 if total_primes_found >= N {
                     break 'generate;
@@ -216,7 +217,7 @@ pub const fn largest_primes_below<const N: usize>(mut upper_limit: u64) -> [u64;
             }
             i += 1;
         }
-        upper_limit -= N as u64;
+        upper_limit = smallest_found_prime;
     }
 
     primes
@@ -666,13 +667,14 @@ mod test {
                 $(
                     {
                         println!("{}", $n);
-                        assert_eq!(PRECOMPUTED_PRIMES[25-$n..25], largest_primes_below::<$n>(100).map(|i| i as u32));
+                        const P: [u64; $n] = largest_primes_below(100);
+                        assert_eq!(PRECOMPUTED_PRIMES[25-$n..25], P.map(|i|i as u32));
                     }
                 )+
             };
         }
 
-        test_n_below_100!(10, 15);
+        test_n_below_100!(10, 15, 20, 100);
     }
 
     #[test]

From 2311f8acf8839dff6a58b062316719c008823a9c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 24 Oct 2023 14:47:12 +0200
Subject: [PATCH 006/212] Fix longrunning test

---
 src/lib.rs     | 27 ++++++++++++++++++++++-----
 src/wrapper.rs |  2 +-
 2 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index d9d4f8d..8a4a322 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -182,7 +182,11 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 }
 
 /// Returns the `N` largest primes below the given upper limit.
+/// The return array fills from the end until either it is full or there are no more primes.
+/// If the primes run out before the array is filled the first elements will have a value of zero.
+///
 /// # Example
+///
 /// ```
 /// # use const_primes::largest_primes_below;
 /// const P: [u64; 10] = largest_primes_below(100);
@@ -198,16 +202,27 @@ pub const fn largest_primes_below<const N: usize>(mut upper_limit: u64) -> [u64;
         None => panic!("`N^2` must fit in a `u64`"),
     }
 
+    let mut primes: [u64; N] = [0; N];
+
+    // If the user requested only a single prime we just scan for it with `is_prime`.
+    if N == 1 {
+        if let Some(p) = largest_prime_leq(upper_limit - 1) {
+            primes[0] = p;
+        }
+        return primes;
+    }
+
     // This will be used to sieve all upper ranges.
     let base_sieve: [bool; N] = are_prime();
-    let mut primes: [u64; N] = [0; N];
+
     let mut total_primes_found: usize = 0;
-    'generate: while total_primes_found < N && upper_limit > 1 {
+    'generate: while total_primes_found < N && upper_limit > 2 {
         let upper_sieve: [bool; N] = sieve_segment(&base_sieve, upper_limit);
-        let mut smallest_found_prime = upper_limit;
+        let mut smallest_found_prime = primes[N - total_primes_found - 1];
         let mut i: usize = 0;
         while i < N {
-            if upper_sieve[N - 1 - i] {
+            let j = N - 1 - i;
+            if upper_sieve[j] {
                 smallest_found_prime = upper_limit - 1 - i as u64;
                 primes[N - total_primes_found - 1] = smallest_found_prime;
                 total_primes_found += 1;
@@ -674,7 +689,9 @@ mod test {
             };
         }
 
-        test_n_below_100!(10, 15, 20, 100);
+        test_n_below_100!(10, 15, 20);
+
+        assert_eq!([0, 0, 0, 0, 2, 3, 5, 7], largest_primes_below(10));
     }
 
     #[test]
diff --git a/src/wrapper.rs b/src/wrapper.rs
index 3537ef0..5d85db5 100644
--- a/src/wrapper.rs
+++ b/src/wrapper.rs
@@ -527,7 +527,7 @@ mod test {
     }
 
     #[test]
-    fn verity_as_slice() {
+    fn verify_as_slice() {
         const N: usize = 10;
         const P: Primes<N> = Primes::new();
         const A: [Underlying; N] = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29];

From 3ac94ac43827cd4cac4a5c9c35634bf1e6bcb753 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 24 Oct 2023 15:39:20 +0200
Subject: [PATCH 007/212] Add more examples to docstring of
 largest_primes_below

---
 src/lib.rs | 43 ++++++++++++++++++++++++++++++++++++-------
 1 file changed, 36 insertions(+), 7 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 8a4a322..2433b38 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -182,23 +182,53 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 }
 
 /// Returns the `N` largest primes below the given upper limit.
+///
 /// The return array fills from the end until either it is full or there are no more primes.
 /// If the primes run out before the array is filled the first elements will have a value of zero.
 ///
 /// # Example
+/// Basic usage
+/// ```
+/// # use const_primes::largest_primes_below;
+/// const PRIMES: [u64; 10] = largest_primes_below(100);
 ///
+/// assert_eq!(PRIMES, [53, 59, 61, 67, 71, 73, 79, 83, 89, 97]);
+/// ```
+/// Compute larger primes without starting from zero
 /// ```
 /// # use const_primes::largest_primes_below;
-/// const P: [u64; 10] = largest_primes_below(100);
-/// assert_eq!(P, [53, 59, 61, 67, 71, 73, 79, 83, 89, 97]);
+/// const N: usize = 2237;
+/// const BIG_PRIMES: [u64; N] = largest_primes_below(5_000_035);
+///
+/// assert_eq!(&BIG_PRIMES[..3], &[4_965_731, 4_965_739, 4_965_743]);
+/// assert_eq!(&BIG_PRIMES[N - 3..], &[4_999_963, 4_999_999, 5_000_011]);
+/// ```
+/// If there are not enough primes to fill the requested array, the first
+/// elements will have a value of zero.
+/// ```
+/// # use const_primes::largest_primes_below;
+/// const PRIMES: [u64; 9] = largest_primes_below(10);
+///
+/// assert_eq!(PRIMES, [0, 0, 0, 0, 0, 2, 3, 5, 7]);
 /// ```
 /// # Panics
-/// Panics if `upper_limit` is not in the range `[N, N^2]`.
+/// Panics if `upper_limit` is not in the range `(N, N^2]`.
+/// ```compile_fail
+/// # use const_primes::largest_primes_below;
+/// const PRIMES: [u64; 5] = largest_primes_below(5);
+/// ```
+/// ```compile_fail
+/// # use const_primes::largest_primes_below;
+/// const PRIMES: [u64; 5] = largest_primes_below(26);
+/// ```
 pub const fn largest_primes_below<const N: usize>(mut upper_limit: u64) -> [u64; N] {
     let n64 = N as u64;
-    assert!(upper_limit >= n64, "`upper_limit` must be at least `N`");
+    assert!(upper_limit > n64, "`upper_limit` must be larger than `N`");
     match (n64).checked_mul(n64) {
-        Some(prod) => assert!(upper_limit <= prod, "`upper_limit` must be below `N^2`"),
+        Some(prod) => assert!(
+            upper_limit <= prod,
+            "`upper_limit` must be less than or equal to `N^2`"
+        ),
         None => panic!("`N^2` must fit in a `u64`"),
     }
 
@@ -214,7 +244,6 @@ pub const fn largest_primes_below<const N: usize>(mut upper_limit: u64) -> [u64;
 
     // This will be used to sieve all upper ranges.
     let base_sieve: [bool; N] = are_prime();
-
     let mut total_primes_found: usize = 0;
     'generate: while total_primes_found < N && upper_limit > 2 {
         let upper_sieve: [bool; N] = sieve_segment(&base_sieve, upper_limit);
@@ -691,7 +720,7 @@ mod test {
 
         test_n_below_100!(10, 15, 20);
 
-        assert_eq!([0, 0, 0, 0, 2, 3, 5, 7], largest_primes_below(10));
+        assert_eq!([0, 0, 0, 0, 0, 2, 3, 5, 7], largest_primes_below(10));
     }
 
     #[test]

From f1749449ca73823b0972f4730eeeef726bb5b374 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 24 Oct 2023 15:44:39 +0200
Subject: [PATCH 008/212] Remove N=1 special case, as that can not succeed. Add
 test for smallest possible result.

---
 src/lib.rs | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 2433b38..88f5bd2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -234,14 +234,6 @@ pub const fn largest_primes_below<const N: usize>(mut upper_limit: u64) -> [u64;
 
     let mut primes: [u64; N] = [0; N];
 
-    // If the user requested only a single prime we just scan for it with `is_prime`.
-    if N == 1 {
-        if let Some(p) = largest_prime_leq(upper_limit - 1) {
-            primes[0] = p;
-        }
-        return primes;
-    }
-
     // This will be used to sieve all upper ranges.
     let base_sieve: [bool; N] = are_prime();
     let mut total_primes_found: usize = 0;
@@ -721,6 +713,8 @@ mod test {
         test_n_below_100!(10, 15, 20);
 
         assert_eq!([0, 0, 0, 0, 0, 2, 3, 5, 7], largest_primes_below(10));
+
+        assert_eq!([0, 2], largest_primes_below(3));
     }
 
     #[test]

From 7a5f293002caad7a506db86f430477845e77f18b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 24 Oct 2023 15:52:32 +0200
Subject: [PATCH 009/212] Increase upper_limit in primes_larger_than docstring

---
 src/lib.rs | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 88f5bd2..5dda15e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -197,11 +197,12 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// Compute larger primes without starting from zero
 /// ```
 /// # use const_primes::largest_primes_below;
-/// const N: usize = 2237;
-/// const BIG_PRIMES: [u64; N] = largest_primes_below(5_000_035);
+/// const N: usize = 70711;
+/// # #[allow(long_running_const_eval)]
+/// const BIG_PRIMES: [u64; N] = largest_primes_below(5_000_000_030);
 ///
-/// assert_eq!(&BIG_PRIMES[..3], &[4_965_731, 4_965_739, 4_965_743]);
-/// assert_eq!(&BIG_PRIMES[N - 3..], &[4_999_963, 4_999_999, 5_000_011]);
+/// assert_eq!(&BIG_PRIMES[..3], &[4_998_417_421, 4_998_417_427, 4_998_417_443]);
+/// assert_eq!(&BIG_PRIMES[N - 3..], &[4_999_999_903, 4_999_999_937, 5_000_000_029]);
 /// ```
 /// If there are not enough primes to fill the requested array, the first
 /// elements will have a value of zero.

From cea6fa853fd5076c3d9ca5d2b8aea85d80509080 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 24 Oct 2023 16:01:56 +0200
Subject: [PATCH 010/212] Add note about compile error in const contexts to
 largest_primes_below

---
 src/lib.rs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/lib.rs b/src/lib.rs
index 5dda15e..57e2df3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -213,7 +213,8 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// assert_eq!(PRIMES, [0, 0, 0, 0, 0, 2, 3, 5, 7]);
 /// ```
 /// # Panics
-/// Panics if `upper_limit` is not in the range `(N, N^2]`.
+/// Panics if `upper_limit` is not in the range `(N, N^2]`. This is a compile error
+/// in const contexts
 /// ```compile_fail
 /// # use const_primes::largest_primes_below;
 /// const PRIMES: [u64; 5] = largest_primes_below(5);

From 3275ca2a1322680f74c2f7b2665e4a79ca7e56e1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 24 Oct 2023 16:05:17 +0200
Subject: [PATCH 011/212] use : before code examples

---
 src/lib.rs | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 57e2df3..d5c5254 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -185,16 +185,19 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 ///
 /// The return array fills from the end until either it is full or there are no more primes.
 /// If the primes run out before the array is filled the first elements will have a value of zero.
+/// 
+/// Due to the limitations on memory allocation in `const` contexts the value of `N`
+/// must satisfy the bounds `N < upper_limit <= N^2`.
 ///
 /// # Example
-/// Basic usage
+/// Basic usage:
 /// ```
 /// # use const_primes::largest_primes_below;
 /// const PRIMES: [u64; 10] = largest_primes_below(100);
 ///
 /// assert_eq!(PRIMES, [53, 59, 61, 67, 71, 73, 79, 83, 89, 97]);
 /// ```
-/// Compute larger primes without starting from zero
+/// Compute larger primes without starting from zero:
 /// ```
 /// # use const_primes::largest_primes_below;
 /// const N: usize = 70711;
@@ -205,7 +208,7 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// assert_eq!(&BIG_PRIMES[N - 3..], &[4_999_999_903, 4_999_999_937, 5_000_000_029]);
 /// ```
 /// If there are not enough primes to fill the requested array, the first
-/// elements will have a value of zero.
+/// elements will have a value of zero:
 /// ```
 /// # use const_primes::largest_primes_below;
 /// const PRIMES: [u64; 9] = largest_primes_below(10);
@@ -214,7 +217,7 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// ```
 /// # Panics
 /// Panics if `upper_limit` is not in the range `(N, N^2]`. This is a compile error
-/// in const contexts
+/// in const contexts:
 /// ```compile_fail
 /// # use const_primes::largest_primes_below;
 /// const PRIMES: [u64; 5] = largest_primes_below(5);

From e1e019636ec5a23bcd5f5c3bb2de86df97ebe30a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 24 Oct 2023 17:02:30 +0200
Subject: [PATCH 012/212] Add some comments

---
 src/lib.rs | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index d5c5254..fd8a468 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -241,18 +241,24 @@ pub const fn largest_primes_below<const N: usize>(mut upper_limit: u64) -> [u64;
 
     // This will be used to sieve all upper ranges.
     let base_sieve: [bool; N] = are_prime();
+
     let mut total_primes_found: usize = 0;
     'generate: while total_primes_found < N && upper_limit > 2 {
+        // This is the smallest prime we have found so far.
+        let mut smallest_found_prime = primes[N - 1 - total_primes_found];
+        // Sieve for primes in the segment.
         let upper_sieve: [bool; N] = sieve_segment(&base_sieve, upper_limit);
-        let mut smallest_found_prime = primes[N - total_primes_found - 1];
+        
         let mut i: usize = 0;
         while i < N {
-            let j = N - 1 - i;
-            if upper_sieve[j] {
+            // Iterate backwards through the upper sieve.
+            if upper_sieve[N - 1 - i] {
                 smallest_found_prime = upper_limit - 1 - i as u64;
-                primes[N - total_primes_found - 1] = smallest_found_prime;
+                // Write every found prime to the primes array.
+                primes[N - 1 - total_primes_found] = smallest_found_prime;
                 total_primes_found += 1;
                 if total_primes_found >= N {
+                    // If we have found enough primes we stop sieving.
                     break 'generate;
                 }
             }

From 190a4054bb836eb3f0dbf7d7476ec3b1eec6b96c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Wed, 25 Oct 2023 16:10:29 +0200
Subject: [PATCH 013/212] Grouped into submodules

---
 src/generation.rs | 253 +++++++++++++++++++++++++
 src/lib.rs        | 470 +++-------------------------------------------
 src/next_prime.rs |  73 +++++++
 src/sieve.rs      | 159 ++++++++++++++++
 4 files changed, 515 insertions(+), 440 deletions(-)
 create mode 100644 src/generation.rs
 create mode 100644 src/next_prime.rs
 create mode 100644 src/sieve.rs

diff --git a/src/generation.rs b/src/generation.rs
new file mode 100644
index 0000000..ed4ef7e
--- /dev/null
+++ b/src/generation.rs
@@ -0,0 +1,253 @@
+use crate::{are_prime, sieve::sieve_segment, Underlying};
+
+/// Returns the `N` first prime numbers.
+///
+/// [`Primes`] might be relevant for you if you intend to later use these prime numbers for related computations.
+///
+/// Uses a [segmented sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Segmented_sieve).
+///
+/// # Example
+/// ```
+/// # use const_primes::primes;
+/// const PRIMES: [u32; 10] = primes();
+/// assert_eq!(PRIMES, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]);
+/// ```
+/// # Panics
+/// Panics if a computed prime overflows a `u32`. This will result in a compile error in a const context.  
+#[must_use = "the function only returns a new value"]
+pub const fn primes<const N: usize>() -> [Underlying; N] {
+    if N == 0 {
+        return [0; N];
+    } else if N == 1 {
+        return [2; N];
+    } else if N == 2 {
+        let mut primes = [0; N];
+        primes[0] = 2;
+        primes[1] = 3;
+        return primes;
+    }
+
+    // This is a segmented sieve that runs until it has found enough primes.
+
+    // This array is the output in the end
+    let mut primes = [0; N];
+    // This keeps track of how many primes we've found so far.
+    let mut prime_count = 0;
+
+    // Sieve the first primes below N
+    let mut sieve: [bool; N] = are_prime();
+
+    // Count how many primes we found
+    // and store them in the final array
+    let mut number = 0;
+    while number < N {
+        if sieve[number] {
+            primes[prime_count] = number as Underlying;
+            prime_count += 1;
+        }
+
+        number += 1;
+    }
+
+    // For every segment of N numbers
+    let mut low = N - 1;
+    let mut high = 2 * N - 1;
+    'generate: while prime_count < N {
+        // reset the sieve for the segment
+        sieve = [true; N];
+        let mut i = 0;
+
+        // and repeat for each prime found so far:
+        while i < prime_count {
+            let prime = primes[i] as usize;
+
+            // Find the smallest composite in the current segment,
+            let mut composite = (low / prime) * prime;
+            if composite < low {
+                composite += prime;
+            }
+
+            // and sieve all numbers in the segment that are multiples of the prime.
+            while composite < high {
+                sieve[composite - low] = false;
+                composite += prime;
+            }
+
+            i += 1;
+        }
+
+        // Move the found primes into the final array
+        i = low;
+        while i < high {
+            if sieve[i - low] {
+                primes[prime_count] = i as Underlying;
+                prime_count += 1;
+                // and stop the generation of primes if we're done.
+                if prime_count == N {
+                    break 'generate;
+                }
+            }
+            i += 1;
+        }
+
+        // Update low and high for the next segment
+        low += N;
+        high += N;
+    }
+
+    primes
+}
+
+/// Returns the `N` largest primes below the given upper limit.
+///
+/// The return array fills from the end until either it is full or there are no more primes.
+/// If the primes run out before the array is filled the first elements will have a value of zero.
+///
+/// Due to the limitations on memory allocation in `const` contexts the value of `N`
+/// must satisfy the bounds `N < upper_limit <= N^2`.
+///
+/// # Example
+/// Basic usage:
+/// ```
+/// # use const_primes::primes_below;
+/// const PRIMES: [u64; 10] = primes_below(100);
+///
+/// assert_eq!(PRIMES, [53, 59, 61, 67, 71, 73, 79, 83, 89, 97]);
+/// ```
+/// Compute larger primes without starting from zero:
+/// ```
+/// # use const_primes::primes_below;
+/// const N: usize = 70711;
+/// # #[allow(long_running_const_eval)]
+/// const BIG_PRIMES: [u64; N] = primes_below(5_000_000_030);
+///
+/// assert_eq!(&BIG_PRIMES[..3], &[4_998_417_421, 4_998_417_427, 4_998_417_443]);
+/// assert_eq!(&BIG_PRIMES[N - 3..], &[4_999_999_903, 4_999_999_937, 5_000_000_029]);
+/// ```
+/// If there are not enough primes to fill the requested array, the first
+/// elements will have a value of zero:
+/// ```
+/// # use const_primes::primes_below;
+/// const PRIMES: [u64; 9] = primes_below(10);
+///
+/// assert_eq!(PRIMES, [0, 0, 0, 0, 0, 2, 3, 5, 7]);
+/// ```
+/// # Panics
+/// Panics if `upper_limit` is not in the range `(N, N^2]`. This is a compile error
+/// in const contexts:
+/// ```compile_fail
+/// # use const_primes::primes_below;
+/// const PRIMES: [u64; 5] = primes_below(5);
+/// ```
+/// ```compile_fail
+/// # use const_primes::primes_below;
+/// const PRIMES: [u64; 5] = primes_below(26);
+/// ```
+pub const fn primes_below<const N: usize>(mut upper_limit: u64) -> [u64; N] {
+    let n64 = N as u64;
+    assert!(upper_limit > n64, "`upper_limit` must be larger than `N`");
+    match (n64).checked_mul(n64) {
+        Some(prod) => assert!(
+            upper_limit <= prod,
+            "`upper_limit` must be less than or equal to `N^2`"
+        ),
+        None => panic!("`N^2` must fit in a `u64`"),
+    }
+
+    let mut primes: [u64; N] = [0; N];
+
+    // This will be used to sieve all upper ranges.
+    let base_sieve: [bool; N] = are_prime();
+
+    let mut total_primes_found: usize = 0;
+    'generate: while total_primes_found < N && upper_limit > 2 {
+        // This is the smallest prime we have found so far.
+        let mut smallest_found_prime = primes[N - 1 - total_primes_found];
+        // Sieve for primes in the segment.
+        let upper_sieve: [bool; N] = sieve_segment(&base_sieve, upper_limit);
+
+        let mut i: usize = 0;
+        while i < N {
+            // Iterate backwards through the upper sieve.
+            if upper_sieve[N - 1 - i] {
+                smallest_found_prime = upper_limit - 1 - i as u64;
+                // Write every found prime to the primes array.
+                primes[N - 1 - total_primes_found] = smallest_found_prime;
+                total_primes_found += 1;
+                if total_primes_found >= N {
+                    // If we have found enough primes we stop sieving.
+                    break 'generate;
+                }
+            }
+            i += 1;
+        }
+        upper_limit = smallest_found_prime;
+    }
+
+    primes
+}
+
+/// Returns an array of the `N` smallest primes greater than or equal to `lower_limit`.
+pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> [u64; N] {
+    let n64 = N as u64;
+    if n64.checked_mul(n64).is_none() {
+        panic!("`N^2` must fit in a `u64`");
+    }
+
+    let mut primes = [0; N];
+    let base_sieve: [bool; N] = are_prime();
+    let mut total_found_primes = 0;
+    'generate: while total_found_primes < N && lower_limit + n64 <= n64 * n64 {
+        let mut largest_found_prime = primes[total_found_primes];
+        let upper_sieve = sieve_segment(&base_sieve, lower_limit + n64);
+        let mut i = 0;
+        // Move the found primes into the output vector.
+        while i < N {
+            if upper_sieve[i] {
+                largest_found_prime = lower_limit + i as u64;
+                primes[total_found_primes] = largest_found_prime;
+                total_found_primes += 1;
+                if total_found_primes >= N {
+                    break 'generate;
+                }
+            }
+            i += 1;
+        }
+        lower_limit = largest_found_prime + 1;
+    }
+    primes
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn sanity_check_primes_geq() {
+        {
+            const P: [u64; 5] = primes_geq(10);
+            assert_eq!(P, [11, 13, 17, 19, 23]);
+        }
+        {
+            const P: [u64; 5] = primes_geq(0);
+            assert_eq!(P, [2, 3, 5, 7, 11]);
+        }
+        {
+            const P: [u64; 0] = primes_geq(0);
+            assert_eq!(P, []);
+        }
+        {
+            const P: [u64; 1] = primes_geq(0);
+            assert_eq!(P, [0]);
+        }
+    }
+
+    #[test]
+    fn check_primes_geq_large() {
+        const N: usize = 71_000;
+        #[allow(long_running_const_eval)]
+        const P: [u64; N] = primes_geq(5_000_000_030);
+        assert_eq!(P[..3], [5_000_000_039, 5_000_000_059, 5_000_000_063]);
+        assert_eq!(P[N - 3..], [5_001_586_727, 5_001_586_729, 5_001_586_757]);
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index fd8a468..0dd372c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -76,358 +76,20 @@
 // This is used since there is currently no way to be generic over types that can do arithmetic at compile time.
 type Underlying = u32;
 
+mod generation;
 mod imath;
 mod miller_rabin;
+mod next_prime;
+mod sieve;
 mod wrapper;
+
+pub use generation::{primes, primes_below, primes_geq};
 use imath::isqrt;
 pub use miller_rabin::is_prime;
+pub use next_prime::{largest_prime_leq, smallest_prime_geq};
+pub use sieve::{are_prime, are_prime_below};
 pub use wrapper::Primes;
 
-/// Returns the `N` first prime numbers.
-///
-/// [`Primes`] might be relevant for you if you intend to later use these prime numbers for related computations.
-///
-/// Uses a [segmented sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Segmented_sieve).
-///
-/// # Example
-/// ```
-/// # use const_primes::primes;
-/// const PRIMES: [u32; 10] = primes();
-/// assert_eq!(PRIMES, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]);
-/// ```
-/// # Panics
-/// Panics if a computed prime overflows a `u32`. This will result in a compile error in a const context.  
-#[must_use = "the function only returns a new value"]
-pub const fn primes<const N: usize>() -> [Underlying; N] {
-    if N == 0 {
-        return [0; N];
-    } else if N == 1 {
-        return [2; N];
-    } else if N == 2 {
-        let mut primes = [0; N];
-        primes[0] = 2;
-        primes[1] = 3;
-        return primes;
-    }
-
-    // This is a segmented sieve that runs until it has found enough primes.
-
-    // This array is the output in the end
-    let mut primes = [0; N];
-    // This keeps track of how many primes we've found so far.
-    let mut prime_count = 0;
-
-    // Sieve the first primes below N
-    let mut sieve: [bool; N] = are_prime();
-
-    // Count how many primes we found
-    // and store them in the final array
-    let mut number = 0;
-    while number < N {
-        if sieve[number] {
-            primes[prime_count] = number as Underlying;
-            prime_count += 1;
-        }
-
-        number += 1;
-    }
-
-    // For every segment of N numbers
-    let mut low = N - 1;
-    let mut high = 2 * N - 1;
-    'generate: while prime_count < N {
-        // reset the sieve for the segment
-        sieve = [true; N];
-        let mut i = 0;
-
-        // and repeat for each prime found so far:
-        while i < prime_count {
-            let prime = primes[i] as usize;
-
-            // Find the smallest composite in the current segment,
-            let mut composite = (low / prime) * prime;
-            if composite < low {
-                composite += prime;
-            }
-
-            // and sieve all numbers in the segment that are multiples of the prime.
-            while composite < high {
-                sieve[composite - low] = false;
-                composite += prime;
-            }
-
-            i += 1;
-        }
-
-        // Move the found primes into the final array
-        i = low;
-        while i < high {
-            if sieve[i - low] {
-                primes[prime_count] = i as Underlying;
-                prime_count += 1;
-                // and stop the generation of primes if we're done.
-                if prime_count == N {
-                    break 'generate;
-                }
-            }
-            i += 1;
-        }
-
-        // Update low and high for the next segment
-        low += N;
-        high += N;
-    }
-
-    primes
-}
-
-/// Returns the `N` largest primes below the given upper limit.
-///
-/// The return array fills from the end until either it is full or there are no more primes.
-/// If the primes run out before the array is filled the first elements will have a value of zero.
-/// 
-/// Due to the limitations on memory allocation in `const` contexts the value of `N`
-/// must satisfy the bounds `N < upper_limit <= N^2`.
-///
-/// # Example
-/// Basic usage:
-/// ```
-/// # use const_primes::largest_primes_below;
-/// const PRIMES: [u64; 10] = largest_primes_below(100);
-///
-/// assert_eq!(PRIMES, [53, 59, 61, 67, 71, 73, 79, 83, 89, 97]);
-/// ```
-/// Compute larger primes without starting from zero:
-/// ```
-/// # use const_primes::largest_primes_below;
-/// const N: usize = 70711;
-/// # #[allow(long_running_const_eval)]
-/// const BIG_PRIMES: [u64; N] = largest_primes_below(5_000_000_030);
-///
-/// assert_eq!(&BIG_PRIMES[..3], &[4_998_417_421, 4_998_417_427, 4_998_417_443]);
-/// assert_eq!(&BIG_PRIMES[N - 3..], &[4_999_999_903, 4_999_999_937, 5_000_000_029]);
-/// ```
-/// If there are not enough primes to fill the requested array, the first
-/// elements will have a value of zero:
-/// ```
-/// # use const_primes::largest_primes_below;
-/// const PRIMES: [u64; 9] = largest_primes_below(10);
-///
-/// assert_eq!(PRIMES, [0, 0, 0, 0, 0, 2, 3, 5, 7]);
-/// ```
-/// # Panics
-/// Panics if `upper_limit` is not in the range `(N, N^2]`. This is a compile error
-/// in const contexts:
-/// ```compile_fail
-/// # use const_primes::largest_primes_below;
-/// const PRIMES: [u64; 5] = largest_primes_below(5);
-/// ```
-/// ```compile_fail
-/// # use const_primes::largest_primes_below;
-/// const PRIMES: [u64; 5] = largest_primes_below(26);
-/// ```
-pub const fn largest_primes_below<const N: usize>(mut upper_limit: u64) -> [u64; N] {
-    let n64 = N as u64;
-    assert!(upper_limit > n64, "`upper_limit` must be larger than `N`");
-    match (n64).checked_mul(n64) {
-        Some(prod) => assert!(
-            upper_limit <= prod,
-            "`upper_limit` must be less than or equal to `N^2`"
-        ),
-        None => panic!("`N^2` must fit in a `u64`"),
-    }
-
-    let mut primes: [u64; N] = [0; N];
-
-    // This will be used to sieve all upper ranges.
-    let base_sieve: [bool; N] = are_prime();
-
-    let mut total_primes_found: usize = 0;
-    'generate: while total_primes_found < N && upper_limit > 2 {
-        // This is the smallest prime we have found so far.
-        let mut smallest_found_prime = primes[N - 1 - total_primes_found];
-        // Sieve for primes in the segment.
-        let upper_sieve: [bool; N] = sieve_segment(&base_sieve, upper_limit);
-        
-        let mut i: usize = 0;
-        while i < N {
-            // Iterate backwards through the upper sieve.
-            if upper_sieve[N - 1 - i] {
-                smallest_found_prime = upper_limit - 1 - i as u64;
-                // Write every found prime to the primes array.
-                primes[N - 1 - total_primes_found] = smallest_found_prime;
-                total_primes_found += 1;
-                if total_primes_found >= N {
-                    // If we have found enough primes we stop sieving.
-                    break 'generate;
-                }
-            }
-            i += 1;
-        }
-        upper_limit = smallest_found_prime;
-    }
-
-    primes
-}
-
-/// Uses the primalities of the first `N` integers in `base_sieve` to sieve the numbers in the range `[upper_limit - N, upper_limit)`.
-const fn sieve_segment<const N: usize>(base_sieve: &[bool; N], upper_limit: u64) -> [bool; N] {
-    let mut segment_sieve = [true; N];
-
-    let lower_limit = upper_limit - N as u64;
-
-    // In case 0 and/or 1 are included in the upper sieve we need to treat them as a special case
-    // since they are not multiples of any prime in `base_sieve` even though they are not primes.
-    if lower_limit == 0 && N > 1 {
-        segment_sieve[0] = false;
-        segment_sieve[1] = false;
-    } else if lower_limit == 1 && N > 0 {
-        segment_sieve[0] = false;
-    }
-
-    let mut i = 0;
-    while i < N {
-        if base_sieve[i] {
-            let prime = i as u64;
-
-            // Find the smallest multiple of the prime larger than or equal to `lower_limit`.
-            let mut composite = (lower_limit / prime) * prime;
-            if composite < lower_limit {
-                composite += prime;
-            }
-            if composite == prime {
-                composite += prime;
-            }
-
-            // Sieve all numbers in the segment that are multiples of the prime.
-            while composite < upper_limit {
-                segment_sieve[(composite - lower_limit) as usize] = false;
-                composite += prime;
-            }
-        }
-        i += 1;
-    }
-
-    segment_sieve
-}
-
-/// Returns an array of size `N` that indicates which of the integers in `[upper_limit - N, upper_limit)` are prime,
-/// or in other words: the value at a given index represents whether `index + upper_limit - N` is prime.
-///
-/// If you just want the prime status of the first `N` integers, see [`are_prime`].
-///
-/// Uses a sieve of Eratosthenes to sieve the first `N` integers
-/// and then uses the result to sieve the output range if needed.
-///
-/// # Examples
-/// Basic usage
-/// ```
-/// # use const_primes::are_prime_below;
-/// const PRIME_STATUSES: [bool; 10] = are_prime_below(30);
-///
-/// assert_eq!(
-///     PRIME_STATUSES,
-/// //   20     21     22     23    24     25     26     27     28     29
-///     [false, false, false, true, false, false, false, false, false, true],
-/// );
-/// ```
-/// Sieve limited ranges of very large values
-/// ```
-/// # use const_primes::are_prime_below;
-/// const BIG_NUMBER: u64 = 5_000_000_031;
-/// const CEIL_SQRT_BIG_NUMBER: usize = 70711;
-/// const BIG_PRIME_STATUSES: [bool; CEIL_SQRT_BIG_NUMBER] = are_prime_below(BIG_NUMBER);
-/// assert_eq!(
-///     BIG_PRIME_STATUSES[CEIL_SQRT_BIG_NUMBER - 3..],
-/// //  5_000_000_028  5_000_000_029  5_000_000_030
-///     [false,        true,          false],
-/// );
-/// ```
-///
-/// # Panics
-/// Panics if `upper_limit` is not in the range `[N, N^2]`, or if `N^2` overflows a `u64`.
-/// These are compile errors in const contexts.
-/// ```compile_fail
-/// # use const_primes::are_prime_below;
-/// const PRIME_STATUSES: [bool; 5] = are_prime_below(26);
-/// ```
-/// ```compile_fail
-/// # use const_primes::are_prime_below;
-/// const PRIME_STATUSES: [bool; 5] = are_prime_below(4);
-/// ```
-#[must_use = "the function returns a new value and does not modify its input"]
-pub const fn are_prime_below<const N: usize>(upper_limit: u64) -> [bool; N] {
-    let n64 = N as u64;
-
-    // Since panics are compile time errors in const contexts
-    // we check all the preconditions here and panic early.
-    match n64.checked_mul(n64) {
-        Some(prod) => assert!(
-            upper_limit <= prod,
-            "`upper_limit` must be smaller than or equal to `N`^2"
-        ),
-        None => panic!("`N`^2 must fit in a `u64`"),
-    }
-    assert!(upper_limit >= n64, "`upper_limit` must be at least `N`");
-
-    // Use a normal sieve of Eratosthenes for the first N numbers.
-    let base_sieve: [bool; N] = are_prime();
-
-    if upper_limit == n64 {
-        // If we are not interested in sieving a larger range we can just return early.
-        return base_sieve;
-    }
-
-    sieve_segment(&base_sieve, upper_limit)
-}
-
-/// Returns an array of size `N` where the value at a given index indicates whether the index is prime.
-///
-/// Uses a sieve of Eratosthenes.
-///
-/// # Example
-/// ```
-/// # use const_primes::are_prime;
-/// const PRIMALITY: [bool; 10] = are_prime();
-/// //                     0      1      2     3     4      5     6      7     8      9
-/// assert_eq!(PRIMALITY, [false, false, true, true, false, true, false, true, false, false]);
-/// ```
-#[must_use = "the function only returns a new value"]
-pub const fn are_prime<const N: usize>() -> [bool; N] {
-    let mut sieve = [true; N];
-    if N > 0 {
-        sieve[0] = false;
-    }
-    if N > 1 {
-        sieve[1] = false;
-    }
-
-    let mut number: usize = 2;
-    let bound = isqrt(N as u64);
-    // For all numbers up to and including sqrt(n):
-    while (number as u64) <= bound {
-        if sieve[number] {
-            // If a number is prime we enumerate all multiples of it
-            // starting from its square,
-            let Some(mut composite) = number.checked_mul(number) else {
-                break;
-            };
-
-            // and mark them as not prime.
-            while composite < N {
-                sieve[composite] = false;
-                composite = match composite.checked_add(number) {
-                    Some(sum) => sum,
-                    None => break,
-                };
-            }
-        }
-        number += 1;
-    }
-
-    sieve
-}
-
 /// Returns the value of the [Möbius function](https://en.wikipedia.org/wiki/M%C3%B6bius_function).
 ///
 /// This function is
@@ -490,78 +152,6 @@ pub const fn moebius(mut x: u64) -> i8 {
     }
 }
 
-/// Returns the largest prime smaller than or equal to `n` if there is one.
-///
-/// Scans for primes downwards from the input with [`is_prime`].
-///
-/// # Examples
-/// ```
-/// # use const_primes::largest_prime_leq;
-/// const LPLEQ: Option<u64> = largest_prime_leq(400);
-/// assert_eq!(LPLEQ, Some(397));
-/// ```
-/// There's no prime smaller than or equal to one
-/// ```
-/// # use const_primes::largest_prime_leq;
-/// const NOSUCH: Option<u64> = largest_prime_leq(1);
-/// assert!(NOSUCH.is_none());
-/// ```
-#[must_use = "the function only returns a new value and does not modify its input"]
-pub const fn largest_prime_leq(mut n: u64) -> Option<u64> {
-    if n == 0 || n == 1 {
-        None
-    } else if n == 2 {
-        Some(2)
-    } else {
-        if n % 2 == 0 {
-            n -= 1;
-        }
-
-        while !is_prime(n) {
-            n -= 2;
-        }
-
-        Some(n)
-    }
-}
-
-/// Returns the smallest prime greater than or equal to `n` if there is one that
-/// can be represented by a `u64`.
-///
-/// Scans for primes upwards from the input with [`is_prime`].
-///
-/// # Example
-/// ```
-/// # use const_primes::smallest_prime_geq;
-/// const SPGEQ: Option<u64> = smallest_prime_geq(400);
-/// assert_eq!(SPGEQ, Some(401));
-/// ```
-/// Primes larger than 18446744073709551557 can not be represented by a `u64`
-/// ```
-/// # use const_primes::smallest_prime_geq;
-/// const NOSUCH: Option<u64> = smallest_prime_geq(18_446_744_073_709_551_558);
-/// assert!(NOSUCH.is_none());
-/// ```
-#[must_use = "the function only returns a new value and does not modify its input"]
-pub const fn smallest_prime_geq(mut n: u64) -> Option<u64> {
-    // The largest prime smaller than 2^64
-    if n > 18_446_744_073_709_551_557 {
-        None
-    } else if n <= 2 {
-        Some(2)
-    } else {
-        if n % 2 == 0 {
-            n += 1;
-        }
-
-        while !is_prime(n) {
-            n += 2;
-        }
-
-        Some(n)
-    }
-}
-
 /// Returns an array of size `N` where the value at a given index is how many primes are less than or equal to the index.
 ///
 /// Sieves primes with [`are_prime`] and then counts them.
@@ -672,25 +262,6 @@ mod test {
         assert_eq!(moebius(u32::MAX.into()), -1);
     }
 
-    #[test]
-    fn check_are_prime_below() {
-        macro_rules! test_n_below_100 {
-            ($($n:expr),+) => {
-                $(
-                    println!("{}", $n);
-                    assert_eq!(&PRIMALITIES[100-$n..], are_prime_below::<$n>(100));
-                )+
-            };
-        }
-        test_n_below_100!(
-            10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
-            32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
-            54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
-            76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
-            98, 99
-        );
-    }
-
     #[test]
     fn verify_primes() {
         macro_rules! test_to_n {
@@ -708,13 +279,13 @@ mod test {
     }
 
     #[test]
-    fn check_largest_primes_below() {
+    fn check_primes_below() {
         macro_rules! test_n_below_100 {
             ($($n:expr),+) => {
                 $(
                     {
                         println!("{}", $n);
-                        const P: [u64; $n] = largest_primes_below(100);
+                        const P: [u64; $n] = primes_below(100);
                         assert_eq!(PRECOMPUTED_PRIMES[25-$n..25], P.map(|i|i as u32));
                     }
                 )+
@@ -723,9 +294,28 @@ mod test {
 
         test_n_below_100!(10, 15, 20);
 
-        assert_eq!([0, 0, 0, 0, 0, 2, 3, 5, 7], largest_primes_below(10));
+        assert_eq!([0, 0, 0, 0, 0, 2, 3, 5, 7], primes_below(10));
+
+        assert_eq!([0, 2], primes_below(3));
+    }
 
-        assert_eq!([0, 2], largest_primes_below(3));
+    #[test]
+    fn check_are_prime_below() {
+        macro_rules! test_n_below_100 {
+            ($($n:expr),+) => {
+                $(
+                    println!("{}", $n);
+                    assert_eq!(&PRIMALITIES[100-$n..], are_prime_below::<$n>(100));
+                )+
+            };
+        }
+        test_n_below_100!(
+            10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+            32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
+            54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,
+            76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
+            98, 99
+        );
     }
 
     #[test]
diff --git a/src/next_prime.rs b/src/next_prime.rs
new file mode 100644
index 0000000..c6d0116
--- /dev/null
+++ b/src/next_prime.rs
@@ -0,0 +1,73 @@
+use crate::is_prime;
+
+/// Returns the largest prime smaller than or equal to `n` if there is one.
+///
+/// Scans for primes downwards from the input with [`is_prime`].
+///
+/// # Examples
+/// ```
+/// # use const_primes::largest_prime_leq;
+/// const LPLEQ: Option<u64> = largest_prime_leq(400);
+/// assert_eq!(LPLEQ, Some(397));
+/// ```
+/// There's no prime smaller than or equal to one
+/// ```
+/// # use const_primes::largest_prime_leq;
+/// const NOSUCH: Option<u64> = largest_prime_leq(1);
+/// assert!(NOSUCH.is_none());
+/// ```
+#[must_use = "the function only returns a new value and does not modify its input"]
+pub const fn largest_prime_leq(mut n: u64) -> Option<u64> {
+    if n == 0 || n == 1 {
+        None
+    } else if n == 2 {
+        Some(2)
+    } else {
+        if n % 2 == 0 {
+            n -= 1;
+        }
+
+        while !is_prime(n) {
+            n -= 2;
+        }
+
+        Some(n)
+    }
+}
+
+/// Returns the smallest prime greater than or equal to `n` if there is one that
+/// can be represented by a `u64`.
+///
+/// Scans for primes upwards from the input with [`is_prime`].
+///
+/// # Example
+/// ```
+/// # use const_primes::smallest_prime_geq;
+/// const SPGEQ: Option<u64> = smallest_prime_geq(400);
+/// assert_eq!(SPGEQ, Some(401));
+/// ```
+/// Primes larger than 18446744073709551557 can not be represented by a `u64`
+/// ```
+/// # use const_primes::smallest_prime_geq;
+/// const NOSUCH: Option<u64> = smallest_prime_geq(18_446_744_073_709_551_558);
+/// assert!(NOSUCH.is_none());
+/// ```
+#[must_use = "the function only returns a new value and does not modify its input"]
+pub const fn smallest_prime_geq(mut n: u64) -> Option<u64> {
+    // The largest prime smaller than 2^64
+    if n > 18_446_744_073_709_551_557 {
+        None
+    } else if n <= 2 {
+        Some(2)
+    } else {
+        if n % 2 == 0 {
+            n += 1;
+        }
+
+        while !is_prime(n) {
+            n += 2;
+        }
+
+        Some(n)
+    }
+}
diff --git a/src/sieve.rs b/src/sieve.rs
new file mode 100644
index 0000000..0cef8e5
--- /dev/null
+++ b/src/sieve.rs
@@ -0,0 +1,159 @@
+use crate::isqrt;
+
+/// Uses the primalities of the first `N` integers in `base_sieve` to sieve the numbers in the range `[upper_limit - N, upper_limit)`.
+pub const fn sieve_segment<const N: usize>(base_sieve: &[bool; N], upper_limit: u64) -> [bool; N] {
+    let mut segment_sieve = [true; N];
+
+    let lower_limit = upper_limit - N as u64;
+
+    // In case 0 and/or 1 are included in the upper sieve we need to treat them as a special case
+    // since they are not multiples of any prime in `base_sieve` even though they are not primes.
+    if lower_limit == 0 && N > 1 {
+        segment_sieve[0] = false;
+        segment_sieve[1] = false;
+    } else if lower_limit == 1 && N > 0 {
+        segment_sieve[0] = false;
+    }
+
+    let mut i = 0;
+    while i < N {
+        if base_sieve[i] {
+            let prime = i as u64;
+
+            // Find the smallest multiple of the prime larger than or equal to `lower_limit`.
+            let mut composite = (lower_limit / prime) * prime;
+            if composite < lower_limit {
+                composite += prime;
+            }
+            if composite == prime {
+                composite += prime;
+            }
+
+            // Sieve all numbers in the segment that are multiples of the prime.
+            while composite < upper_limit {
+                segment_sieve[(composite - lower_limit) as usize] = false;
+                composite += prime;
+            }
+        }
+        i += 1;
+    }
+
+    segment_sieve
+}
+
+/// Returns an array of size `N` that indicates which of the integers in `[upper_limit - N, upper_limit)` are prime,
+/// or in other words: the value at a given index represents whether `index + upper_limit - N` is prime.
+///
+/// If you just want the prime status of the first `N` integers, see [`are_prime`].
+///
+/// Uses a sieve of Eratosthenes to sieve the first `N` integers
+/// and then uses the result to sieve the output range if needed.
+///
+/// # Examples
+/// Basic usage
+/// ```
+/// # use const_primes::are_prime_below;
+/// const PRIME_STATUSES: [bool; 10] = are_prime_below(30);
+///
+/// assert_eq!(
+///     PRIME_STATUSES,
+/// //   20     21     22     23    24     25     26     27     28     29
+///     [false, false, false, true, false, false, false, false, false, true],
+/// );
+/// ```
+/// Sieve limited ranges of very large values
+/// ```
+/// # use const_primes::are_prime_below;
+/// const BIG_NUMBER: u64 = 5_000_000_031;
+/// const CEIL_SQRT_BIG_NUMBER: usize = 70711;
+/// const BIG_PRIME_STATUSES: [bool; CEIL_SQRT_BIG_NUMBER] = are_prime_below(BIG_NUMBER);
+/// assert_eq!(
+///     BIG_PRIME_STATUSES[CEIL_SQRT_BIG_NUMBER - 3..],
+/// //  5_000_000_028  5_000_000_029  5_000_000_030
+///     [false,        true,          false],
+/// );
+/// ```
+///
+/// # Panics
+/// Panics if `upper_limit` is not in the range `[N, N^2]`, or if `N^2` overflows a `u64`.
+/// These are compile errors in const contexts.
+/// ```compile_fail
+/// # use const_primes::are_prime_below;
+/// const PRIME_STATUSES: [bool; 5] = are_prime_below(26);
+/// ```
+/// ```compile_fail
+/// # use const_primes::are_prime_below;
+/// const PRIME_STATUSES: [bool; 5] = are_prime_below(4);
+/// ```
+#[must_use = "the function returns a new value and does not modify its input"]
+pub const fn are_prime_below<const N: usize>(upper_limit: u64) -> [bool; N] {
+    let n64 = N as u64;
+
+    // Since panics are compile time errors in const contexts
+    // we check all the preconditions here and panic early.
+    match n64.checked_mul(n64) {
+        Some(prod) => assert!(
+            upper_limit <= prod,
+            "`upper_limit` must be smaller than or equal to `N`^2"
+        ),
+        None => panic!("`N`^2 must fit in a `u64`"),
+    }
+    assert!(upper_limit >= n64, "`upper_limit` must be at least `N`");
+
+    // Use a normal sieve of Eratosthenes for the first N numbers.
+    let base_sieve: [bool; N] = are_prime();
+
+    if upper_limit == n64 {
+        // If we are not interested in sieving a larger range we can just return early.
+        return base_sieve;
+    }
+
+    sieve_segment(&base_sieve, upper_limit)
+}
+
+/// Returns an array of size `N` where the value at a given index indicates whether the index is prime.
+///
+/// Uses a sieve of Eratosthenes.
+///
+/// # Example
+/// ```
+/// # use const_primes::are_prime;
+/// const PRIMALITY: [bool; 10] = are_prime();
+/// //                     0      1      2     3     4      5     6      7     8      9
+/// assert_eq!(PRIMALITY, [false, false, true, true, false, true, false, true, false, false]);
+/// ```
+#[must_use = "the function only returns a new value"]
+pub const fn are_prime<const N: usize>() -> [bool; N] {
+    let mut sieve = [true; N];
+    if N > 0 {
+        sieve[0] = false;
+    }
+    if N > 1 {
+        sieve[1] = false;
+    }
+
+    let mut number: usize = 2;
+    let bound = isqrt(N as u64);
+    // For all numbers up to and including sqrt(n):
+    while (number as u64) <= bound {
+        if sieve[number] {
+            // If a number is prime we enumerate all multiples of it
+            // starting from its square,
+            let Some(mut composite) = number.checked_mul(number) else {
+                break;
+            };
+
+            // and mark them as not prime.
+            while composite < N {
+                sieve[composite] = false;
+                composite = match composite.checked_add(number) {
+                    Some(sum) => sum,
+                    None => break,
+                };
+            }
+        }
+        number += 1;
+    }
+
+    sieve
+}

From 07a592d3740808fd4ecd9e187d906a92cecb6c3f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Wed, 25 Oct 2023 16:41:05 +0200
Subject: [PATCH 014/212] Begin unifying names, complete
 `primes_greater_than_or_equal_to`

---
 src/generation.rs | 69 +++++++++++++++++++++++++++++------------------
 src/lib.rs        | 10 +++----
 2 files changed, 48 insertions(+), 31 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index ed4ef7e..49f7696 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -109,17 +109,17 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// # Example
 /// Basic usage:
 /// ```
-/// # use const_primes::primes_below;
-/// const PRIMES: [u64; 10] = primes_below(100);
+/// # use const_primes::primes_less_than;
+/// const PRIMES: [u64; 10] = primes_less_than(100);
 ///
 /// assert_eq!(PRIMES, [53, 59, 61, 67, 71, 73, 79, 83, 89, 97]);
 /// ```
 /// Compute larger primes without starting from zero:
 /// ```
-/// # use const_primes::primes_below;
+/// # use const_primes::primes_less_than;
 /// const N: usize = 70711;
 /// # #[allow(long_running_const_eval)]
-/// const BIG_PRIMES: [u64; N] = primes_below(5_000_000_030);
+/// const BIG_PRIMES: [u64; N] = primes_less_than(5_000_000_030);
 ///
 /// assert_eq!(&BIG_PRIMES[..3], &[4_998_417_421, 4_998_417_427, 4_998_417_443]);
 /// assert_eq!(&BIG_PRIMES[N - 3..], &[4_999_999_903, 4_999_999_937, 5_000_000_029]);
@@ -127,8 +127,8 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// If there are not enough primes to fill the requested array, the first
 /// elements will have a value of zero:
 /// ```
-/// # use const_primes::primes_below;
-/// const PRIMES: [u64; 9] = primes_below(10);
+/// # use const_primes::primes_less_than;
+/// const PRIMES: [u64; 9] = primes_less_than(10);
 ///
 /// assert_eq!(PRIMES, [0, 0, 0, 0, 0, 2, 3, 5, 7]);
 /// ```
@@ -136,14 +136,14 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// Panics if `upper_limit` is not in the range `(N, N^2]`. This is a compile error
 /// in const contexts:
 /// ```compile_fail
-/// # use const_primes::primes_below;
-/// const PRIMES: [u64; 5] = primes_below(5);
+/// # use const_primes::primes_less_than;
+/// const PRIMES: [u64; 5] = primes_less_than(5);
 /// ```
 /// ```compile_fail
-/// # use const_primes::primes_below;
-/// const PRIMES: [u64; 5] = primes_below(26);
+/// # use const_primes::primes_less_than;
+/// const PRIMES: [u64; 5] = primes_less_than(26);
 /// ```
-pub const fn primes_below<const N: usize>(mut upper_limit: u64) -> [u64; N] {
+pub const fn primes_less_than<const N: usize>(mut upper_limit: u64) -> [u64; N] {
     let n64 = N as u64;
     assert!(upper_limit > n64, "`upper_limit` must be larger than `N`");
     match (n64).checked_mul(n64) {
@@ -188,7 +188,33 @@ pub const fn primes_below<const N: usize>(mut upper_limit: u64) -> [u64; N] {
 }
 
 /// Returns an array of the `N` smallest primes greater than or equal to `lower_limit`.
-pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> [u64; N] {
+/// 
+/// This function will fill the output array from index 0 and stop generating primes if they exceed `N^2`.
+/// In that case the remaining elements of the output array will be 0.
+/// 
+/// # Example
+/// Basic usage:
+/// ```
+/// # use const_primes::primes_greater_than_or_equal_to;
+/// const PRIMES: [u64; 5] = primes_greater_than_or_equal_to(10);
+/// assert_eq!(PRIMES, [11, 13, 17, 19, 23]);
+/// ```
+/// Compute larger primes without starting from zero:
+/// ```
+/// # use const_primes::primes_greater_than_or_equal_to;
+/// const N: usize = 71_000;
+/// # #[allow(long_running_const_eval)]
+/// const P: [u64; N] = primes_greater_than_or_equal_to(5_000_000_030);
+/// assert_eq!(P[..3], [5_000_000_039, 5_000_000_059, 5_000_000_063]);
+/// assert_eq!(P[N - 3..], [5_001_586_727, 5_001_586_729, 5_001_586_757]);
+/// ```
+/// Only primes smaller than or equal to `N^2` will be generated:
+/// ```
+/// # use const_primes::primes_greater_than_or_equal_to;
+/// const PRIMES: [u64; 3] = primes_greater_than_or_equal_to(5);
+/// assert_eq!(PRIMES, [5, 7, 0]);
+/// ```
+pub const fn primes_greater_than_or_equal_to<const N: usize>(mut lower_limit: u64) -> [u64; N] {
     let n64 = N as u64;
     if n64.checked_mul(n64).is_none() {
         panic!("`N^2` must fit in a `u64`");
@@ -223,31 +249,22 @@ mod test {
     use super::*;
 
     #[test]
-    fn sanity_check_primes_geq() {
+    fn sanity_check_primes_greater_than_or_equal_to() {
         {
-            const P: [u64; 5] = primes_geq(10);
+            const P: [u64; 5] = primes_greater_than_or_equal_to(10);
             assert_eq!(P, [11, 13, 17, 19, 23]);
         }
         {
-            const P: [u64; 5] = primes_geq(0);
+            const P: [u64; 5] = primes_greater_than_or_equal_to(0);
             assert_eq!(P, [2, 3, 5, 7, 11]);
         }
         {
-            const P: [u64; 0] = primes_geq(0);
+            const P: [u64; 0] = primes_greater_than_or_equal_to(0);
             assert_eq!(P, []);
         }
         {
-            const P: [u64; 1] = primes_geq(0);
+            const P: [u64; 1] = primes_greater_than_or_equal_to(0);
             assert_eq!(P, [0]);
         }
     }
-
-    #[test]
-    fn check_primes_geq_large() {
-        const N: usize = 71_000;
-        #[allow(long_running_const_eval)]
-        const P: [u64; N] = primes_geq(5_000_000_030);
-        assert_eq!(P[..3], [5_000_000_039, 5_000_000_059, 5_000_000_063]);
-        assert_eq!(P[N - 3..], [5_001_586_727, 5_001_586_729, 5_001_586_757]);
-    }
 }
diff --git a/src/lib.rs b/src/lib.rs
index 0dd372c..fecd3a0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -83,7 +83,7 @@ mod next_prime;
 mod sieve;
 mod wrapper;
 
-pub use generation::{primes, primes_below, primes_geq};
+pub use generation::{primes_less_than, primes, primes_greater_than_or_equal_to};
 use imath::isqrt;
 pub use miller_rabin::is_prime;
 pub use next_prime::{largest_prime_leq, smallest_prime_geq};
@@ -279,13 +279,13 @@ mod test {
     }
 
     #[test]
-    fn check_primes_below() {
+    fn check_primes_less_than() {
         macro_rules! test_n_below_100 {
             ($($n:expr),+) => {
                 $(
                     {
                         println!("{}", $n);
-                        const P: [u64; $n] = primes_below(100);
+                        const P: [u64; $n] = primes_less_than(100);
                         assert_eq!(PRECOMPUTED_PRIMES[25-$n..25], P.map(|i|i as u32));
                     }
                 )+
@@ -294,9 +294,9 @@ mod test {
 
         test_n_below_100!(10, 15, 20);
 
-        assert_eq!([0, 0, 0, 0, 0, 2, 3, 5, 7], primes_below(10));
+        assert_eq!([0, 0, 0, 0, 0, 2, 3, 5, 7], primes_less_than(10));
 
-        assert_eq!([0, 2], primes_below(3));
+        assert_eq!([0, 2], primes_less_than(3));
     }
 
     #[test]

From 2670aa5b829e631e0386834e0dd7b95898e4edc1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Wed, 25 Oct 2023 16:42:21 +0200
Subject: [PATCH 015/212] limit sieve_segment to the crate

---
 src/sieve.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/sieve.rs b/src/sieve.rs
index 0cef8e5..5ba6ba9 100644
--- a/src/sieve.rs
+++ b/src/sieve.rs
@@ -1,7 +1,7 @@
 use crate::isqrt;
 
 /// Uses the primalities of the first `N` integers in `base_sieve` to sieve the numbers in the range `[upper_limit - N, upper_limit)`.
-pub const fn sieve_segment<const N: usize>(base_sieve: &[bool; N], upper_limit: u64) -> [bool; N] {
+pub(crate) const fn sieve_segment<const N: usize>(base_sieve: &[bool; N], upper_limit: u64) -> [bool; N] {
     let mut segment_sieve = [true; N];
 
     let lower_limit = upper_limit - N as u64;

From 727fc55a4d43d58ea0064c2d7cdd201aefb3eb7a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Wed, 25 Oct 2023 17:00:41 +0200
Subject: [PATCH 016/212] Finalized the naming convention for specifying output
 range

---
 benches/prime_benches.rs |  4 ++--
 src/generation.rs        | 18 +++++++--------
 src/lib.rs               | 48 +++++++++++++++++++++-------------------
 src/next_prime.rs        | 20 ++++++++---------
 src/sieve.rs             | 33 ++++++++++++++-------------
 5 files changed, 64 insertions(+), 59 deletions(-)

diff --git a/benches/prime_benches.rs b/benches/prime_benches.rs
index 29eaa95..26e9eac 100644
--- a/benches/prime_benches.rs
+++ b/benches/prime_benches.rs
@@ -1,4 +1,4 @@
-use const_primes::{are_prime, is_prime, moebius, primes};
+use const_primes::{is_prime, moebius, primes, sieve_numbers};
 use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
 use rand::prelude::*;
 use std::hint::black_box;
@@ -21,7 +21,7 @@ fn benchmarks(c: &mut Criterion) {
     });
 
     c.bench_function("sieve 10000 integers", |b| {
-        b.iter(|| black_box(are_prime::<10_000>()))
+        b.iter(|| black_box(sieve_numbers::<10_000>()))
     });
 
     let ints: Vec<_> = (1..1_000_000).map(|n| n).collect();
diff --git a/src/generation.rs b/src/generation.rs
index 49f7696..f759158 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -1,8 +1,8 @@
-use crate::{are_prime, sieve::sieve_segment, Underlying};
+use crate::{sieve::sieve_segment, sieve_numbers, Underlying};
 
 /// Returns the `N` first prime numbers.
 ///
-/// [`Primes`] might be relevant for you if you intend to later use these prime numbers for related computations.
+/// [`Primes`](crate::Primes) might be relevant for you if you intend to later use these prime numbers for related computations.
 ///
 /// Uses a [segmented sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Segmented_sieve).
 ///
@@ -35,7 +35,7 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
     let mut prime_count = 0;
 
     // Sieve the first primes below N
-    let mut sieve: [bool; N] = are_prime();
+    let mut sieve: [bool; N] = sieve_numbers();
 
     // Count how many primes we found
     // and store them in the final array
@@ -98,7 +98,7 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
     primes
 }
 
-/// Returns the `N` largest primes below the given upper limit.
+/// Returns the `N` largest primes less than `upper_limit`.
 ///
 /// The return array fills from the end until either it is full or there are no more primes.
 /// If the primes run out before the array is filled the first elements will have a value of zero.
@@ -157,7 +157,7 @@ pub const fn primes_less_than<const N: usize>(mut upper_limit: u64) -> [u64; N]
     let mut primes: [u64; N] = [0; N];
 
     // This will be used to sieve all upper ranges.
-    let base_sieve: [bool; N] = are_prime();
+    let base_sieve: [bool; N] = sieve_numbers();
 
     let mut total_primes_found: usize = 0;
     'generate: while total_primes_found < N && upper_limit > 2 {
@@ -187,11 +187,11 @@ pub const fn primes_less_than<const N: usize>(mut upper_limit: u64) -> [u64; N]
     primes
 }
 
-/// Returns an array of the `N` smallest primes greater than or equal to `lower_limit`.
-/// 
+/// Returns the `N` smallest primes greater than or equal to `lower_limit`.
+///
 /// This function will fill the output array from index 0 and stop generating primes if they exceed `N^2`.
 /// In that case the remaining elements of the output array will be 0.
-/// 
+///
 /// # Example
 /// Basic usage:
 /// ```
@@ -221,7 +221,7 @@ pub const fn primes_greater_than_or_equal_to<const N: usize>(mut lower_limit: u6
     }
 
     let mut primes = [0; N];
-    let base_sieve: [bool; N] = are_prime();
+    let base_sieve: [bool; N] = sieve_numbers();
     let mut total_found_primes = 0;
     'generate: while total_found_primes < N && lower_limit + n64 <= n64 * n64 {
         let mut largest_found_prime = primes[total_found_primes];
diff --git a/src/lib.rs b/src/lib.rs
index fecd3a0..ead88ce 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -50,19 +50,19 @@
 //! const CHECK: bool = is_prime(18_446_744_073_709_551_557);
 //! assert!(CHECK);
 //! ```
-//! or [`are_prime`] to compute the prime status of the `N` first integers,
+//! or [`sieve_numbers`] to compute the prime status of the `N` first integers,
 //! ```
-//! # use const_primes::are_prime;
+//! # use const_primes::sieve_numbers;
 //! const N: usize = 10;
-//! const PRIME_STATUS: [bool; N] = are_prime();
+//! const PRIME_STATUS: [bool; N] = sieve_numbers();
 //! //                        0      1      2     3     4      5     6      7     8      9
 //! assert_eq!(PRIME_STATUS, [false, false, true, true, false, true, false, true, false, false]);
 //! ```
-//! or [`are_prime_below`] to compute the prime status of the `N` largest integers below a given value,
+//! or [`sieve_numbers_less_than`] to compute the prime status of the `N` largest integers below a given value,
 //! ```
-//! # use const_primes::are_prime_below;
+//! # use const_primes::sieve_numbers_less_than;
 //! const N: usize = 70711;
-//! const BIG_PRIME_STATUS: [bool; N] = are_prime_below(5_000_000_031);
+//! const BIG_PRIME_STATUS: [bool; N] = sieve_numbers_less_than(5_000_000_031);
 //! //                                     5_000_000_028  5_000_000_029  5_000_000_030
 //! assert_eq!(BIG_PRIME_STATUS[N - 3..], [false,         true,          false]);
 //! ```
@@ -83,11 +83,13 @@ mod next_prime;
 mod sieve;
 mod wrapper;
 
-pub use generation::{primes_less_than, primes, primes_greater_than_or_equal_to};
+pub use generation::{primes, primes_greater_than_or_equal_to, primes_less_than};
 use imath::isqrt;
 pub use miller_rabin::is_prime;
-pub use next_prime::{largest_prime_leq, smallest_prime_geq};
-pub use sieve::{are_prime, are_prime_below};
+pub use next_prime::{
+    largest_prime_less_than_or_equal_to, smallest_prime_greater_than_or_equal_to,
+};
+pub use sieve::{sieve_numbers, sieve_numbers_less_than};
 pub use wrapper::Primes;
 
 /// Returns the value of the [Möbius function](https://en.wikipedia.org/wiki/M%C3%B6bius_function).
@@ -154,7 +156,7 @@ pub const fn moebius(mut x: u64) -> i8 {
 
 /// Returns an array of size `N` where the value at a given index is how many primes are less than or equal to the index.
 ///
-/// Sieves primes with [`are_prime`] and then counts them.
+/// Sieves primes with [`sieve_numbers`] and then counts them.
 ///
 /// # Example
 /// Basic usage
@@ -170,7 +172,7 @@ pub const fn prime_counts<const N: usize>() -> [usize; N] {
         return counts;
     }
     counts[2] = 1;
-    let prime_status: [bool; N] = are_prime();
+    let prime_status: [bool; N] = sieve_numbers();
     let mut count = 1;
     let mut i = 3;
     while i < N {
@@ -203,12 +205,12 @@ mod test {
     }
 
     #[test]
-    fn check_are_prime() {
+    fn check_sieve_numbers() {
         macro_rules! test_to {
             ($($n:expr),+) => {
                 $(
                     println!("{}", $n);
-                    assert_eq!(&PRIMALITIES[..$n], are_prime::<$n>());
+                    assert_eq!(&PRIMALITIES[..$n], sieve_numbers::<$n>());
                 )+
             };
         }
@@ -300,12 +302,12 @@ mod test {
     }
 
     #[test]
-    fn check_are_prime_below() {
+    fn check_sieve_numbers_less_than() {
         macro_rules! test_n_below_100 {
             ($($n:expr),+) => {
                 $(
                     println!("{}", $n);
-                    assert_eq!(&PRIMALITIES[100-$n..], are_prime_below::<$n>(100));
+                    assert_eq!(&PRIMALITIES[100-$n..], sieve_numbers_less_than::<$n>(100));
                 )+
             };
         }
@@ -322,21 +324,21 @@ mod test {
     fn check_next_prime() {
         for i in 1..PRECOMPUTED_PRIMES.len() - 1 {
             assert_eq!(
-                smallest_prime_geq(PRECOMPUTED_PRIMES[i] as u64 + 1),
+                smallest_prime_greater_than_or_equal_to(PRECOMPUTED_PRIMES[i] as u64 + 1),
                 Some(PRECOMPUTED_PRIMES[i + 1] as u64)
             );
             assert_eq!(
-                largest_prime_leq(PRECOMPUTED_PRIMES[i] as u64 - 1),
+                largest_prime_less_than_or_equal_to(PRECOMPUTED_PRIMES[i] as u64 - 1),
                 Some(PRECOMPUTED_PRIMES[i - 1] as u64)
             );
         }
 
-        assert_eq!(smallest_prime_geq(0), Some(2));
-        assert_eq!(smallest_prime_geq(1), Some(2));
-        assert_eq!(smallest_prime_geq(2), Some(2));
-        assert_eq!(largest_prime_leq(0), None);
-        assert_eq!(largest_prime_leq(1), None);
-        assert_eq!(largest_prime_leq(2), Some(2));
+        assert_eq!(smallest_prime_greater_than_or_equal_to(0), Some(2));
+        assert_eq!(smallest_prime_greater_than_or_equal_to(1), Some(2));
+        assert_eq!(smallest_prime_greater_than_or_equal_to(2), Some(2));
+        assert_eq!(largest_prime_less_than_or_equal_to(0), None);
+        assert_eq!(largest_prime_less_than_or_equal_to(1), None);
+        assert_eq!(largest_prime_less_than_or_equal_to(2), Some(2));
     }
 
     #[rustfmt::skip]
diff --git a/src/next_prime.rs b/src/next_prime.rs
index c6d0116..da6d479 100644
--- a/src/next_prime.rs
+++ b/src/next_prime.rs
@@ -6,18 +6,18 @@ use crate::is_prime;
 ///
 /// # Examples
 /// ```
-/// # use const_primes::largest_prime_leq;
-/// const LPLEQ: Option<u64> = largest_prime_leq(400);
+/// # use const_primes::largest_prime_less_than_or_equal_to;
+/// const LPLEQ: Option<u64> = largest_prime_less_than_or_equal_to(400);
 /// assert_eq!(LPLEQ, Some(397));
 /// ```
 /// There's no prime smaller than or equal to one
 /// ```
-/// # use const_primes::largest_prime_leq;
-/// const NOSUCH: Option<u64> = largest_prime_leq(1);
+/// # use const_primes::largest_prime_less_than_or_equal_to;
+/// const NOSUCH: Option<u64> = largest_prime_less_than_or_equal_to(1);
 /// assert!(NOSUCH.is_none());
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
-pub const fn largest_prime_leq(mut n: u64) -> Option<u64> {
+pub const fn largest_prime_less_than_or_equal_to(mut n: u64) -> Option<u64> {
     if n == 0 || n == 1 {
         None
     } else if n == 2 {
@@ -42,18 +42,18 @@ pub const fn largest_prime_leq(mut n: u64) -> Option<u64> {
 ///
 /// # Example
 /// ```
-/// # use const_primes::smallest_prime_geq;
-/// const SPGEQ: Option<u64> = smallest_prime_geq(400);
+/// # use const_primes::smallest_prime_greater_than_or_equal_to;
+/// const SPGEQ: Option<u64> = smallest_prime_greater_than_or_equal_to(400);
 /// assert_eq!(SPGEQ, Some(401));
 /// ```
 /// Primes larger than 18446744073709551557 can not be represented by a `u64`
 /// ```
-/// # use const_primes::smallest_prime_geq;
-/// const NOSUCH: Option<u64> = smallest_prime_geq(18_446_744_073_709_551_558);
+/// # use const_primes::smallest_prime_greater_than_or_equal_to;
+/// const NOSUCH: Option<u64> = smallest_prime_greater_than_or_equal_to(18_446_744_073_709_551_558);
 /// assert!(NOSUCH.is_none());
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
-pub const fn smallest_prime_geq(mut n: u64) -> Option<u64> {
+pub const fn smallest_prime_greater_than_or_equal_to(mut n: u64) -> Option<u64> {
     // The largest prime smaller than 2^64
     if n > 18_446_744_073_709_551_557 {
         None
diff --git a/src/sieve.rs b/src/sieve.rs
index 5ba6ba9..af7619f 100644
--- a/src/sieve.rs
+++ b/src/sieve.rs
@@ -1,7 +1,10 @@
 use crate::isqrt;
 
 /// Uses the primalities of the first `N` integers in `base_sieve` to sieve the numbers in the range `[upper_limit - N, upper_limit)`.
-pub(crate) const fn sieve_segment<const N: usize>(base_sieve: &[bool; N], upper_limit: u64) -> [bool; N] {
+pub(crate) const fn sieve_segment<const N: usize>(
+    base_sieve: &[bool; N],
+    upper_limit: u64,
+) -> [bool; N] {
     let mut segment_sieve = [true; N];
 
     let lower_limit = upper_limit - N as u64;
@@ -44,7 +47,7 @@ pub(crate) const fn sieve_segment<const N: usize>(base_sieve: &[bool; N], upper_
 /// Returns an array of size `N` that indicates which of the integers in `[upper_limit - N, upper_limit)` are prime,
 /// or in other words: the value at a given index represents whether `index + upper_limit - N` is prime.
 ///
-/// If you just want the prime status of the first `N` integers, see [`are_prime`].
+/// If you just want the prime status of the first `N` integers, see [`sieve_numbers`].
 ///
 /// Uses a sieve of Eratosthenes to sieve the first `N` integers
 /// and then uses the result to sieve the output range if needed.
@@ -52,8 +55,8 @@ pub(crate) const fn sieve_segment<const N: usize>(base_sieve: &[bool; N], upper_
 /// # Examples
 /// Basic usage
 /// ```
-/// # use const_primes::are_prime_below;
-/// const PRIME_STATUSES: [bool; 10] = are_prime_below(30);
+/// # use const_primes::sieve_numbers_less_than;
+/// const PRIME_STATUSES: [bool; 10] = sieve_numbers_less_than(30);
 ///
 /// assert_eq!(
 ///     PRIME_STATUSES,
@@ -63,10 +66,10 @@ pub(crate) const fn sieve_segment<const N: usize>(base_sieve: &[bool; N], upper_
 /// ```
 /// Sieve limited ranges of very large values
 /// ```
-/// # use const_primes::are_prime_below;
+/// # use const_primes::sieve_numbers_less_than;
 /// const BIG_NUMBER: u64 = 5_000_000_031;
 /// const CEIL_SQRT_BIG_NUMBER: usize = 70711;
-/// const BIG_PRIME_STATUSES: [bool; CEIL_SQRT_BIG_NUMBER] = are_prime_below(BIG_NUMBER);
+/// const BIG_PRIME_STATUSES: [bool; CEIL_SQRT_BIG_NUMBER] = sieve_numbers_less_than(BIG_NUMBER);
 /// assert_eq!(
 ///     BIG_PRIME_STATUSES[CEIL_SQRT_BIG_NUMBER - 3..],
 /// //  5_000_000_028  5_000_000_029  5_000_000_030
@@ -78,15 +81,15 @@ pub(crate) const fn sieve_segment<const N: usize>(base_sieve: &[bool; N], upper_
 /// Panics if `upper_limit` is not in the range `[N, N^2]`, or if `N^2` overflows a `u64`.
 /// These are compile errors in const contexts.
 /// ```compile_fail
-/// # use const_primes::are_prime_below;
-/// const PRIME_STATUSES: [bool; 5] = are_prime_below(26);
+/// # use const_primes::sieve_numbers_less_than;
+/// const PRIME_STATUSES: [bool; 5] = sieve_numbers_less_than(26);
 /// ```
 /// ```compile_fail
-/// # use const_primes::are_prime_below;
-/// const PRIME_STATUSES: [bool; 5] = are_prime_below(4);
+/// # use const_primes::sieve_numbers_less_than;
+/// const PRIME_STATUSES: [bool; 5] = sieve_numbers_less_than(4);
 /// ```
 #[must_use = "the function returns a new value and does not modify its input"]
-pub const fn are_prime_below<const N: usize>(upper_limit: u64) -> [bool; N] {
+pub const fn sieve_numbers_less_than<const N: usize>(upper_limit: u64) -> [bool; N] {
     let n64 = N as u64;
 
     // Since panics are compile time errors in const contexts
@@ -101,7 +104,7 @@ pub const fn are_prime_below<const N: usize>(upper_limit: u64) -> [bool; N] {
     assert!(upper_limit >= n64, "`upper_limit` must be at least `N`");
 
     // Use a normal sieve of Eratosthenes for the first N numbers.
-    let base_sieve: [bool; N] = are_prime();
+    let base_sieve: [bool; N] = sieve_numbers();
 
     if upper_limit == n64 {
         // If we are not interested in sieving a larger range we can just return early.
@@ -117,13 +120,13 @@ pub const fn are_prime_below<const N: usize>(upper_limit: u64) -> [bool; N] {
 ///
 /// # Example
 /// ```
-/// # use const_primes::are_prime;
-/// const PRIMALITY: [bool; 10] = are_prime();
+/// # use const_primes::sieve_numbers;
+/// const PRIMALITY: [bool; 10] = sieve_numbers();
 /// //                     0      1      2     3     4      5     6      7     8      9
 /// assert_eq!(PRIMALITY, [false, false, true, true, false, true, false, true, false, false]);
 /// ```
 #[must_use = "the function only returns a new value"]
-pub const fn are_prime<const N: usize>() -> [bool; N] {
+pub const fn sieve_numbers<const N: usize>() -> [bool; N] {
     let mut sieve = [true; N];
     if N > 0 {
         sieve[0] = false;

From ad8de4126f043b64d1f439dba5196dad489a0bf0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Wed, 25 Oct 2023 17:09:15 +0200
Subject: [PATCH 017/212] rename generation module to generate

---
 src/{generation.rs => generate.rs} | 0
 src/lib.rs                         | 4 ++--
 2 files changed, 2 insertions(+), 2 deletions(-)
 rename src/{generation.rs => generate.rs} (100%)

diff --git a/src/generation.rs b/src/generate.rs
similarity index 100%
rename from src/generation.rs
rename to src/generate.rs
diff --git a/src/lib.rs b/src/lib.rs
index ead88ce..5eb2295 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -76,14 +76,14 @@
 // This is used since there is currently no way to be generic over types that can do arithmetic at compile time.
 type Underlying = u32;
 
-mod generation;
+mod generate;
 mod imath;
 mod miller_rabin;
 mod next_prime;
 mod sieve;
 mod wrapper;
 
-pub use generation::{primes, primes_greater_than_or_equal_to, primes_less_than};
+pub use generate::{primes, primes_greater_than_or_equal_to, primes_less_than};
 use imath::isqrt;
 pub use miller_rabin::is_prime;
 pub use next_prime::{

From 9cf3f12e0f6645fcf40b6ea01cdafbc3f5ada4bb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Wed, 25 Oct 2023 17:36:23 +0200
Subject: [PATCH 018/212] Add sieve_numbers_greater_than_or_equal_to

---
 src/lib.rs   |  2 +-
 src/sieve.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 48 insertions(+), 3 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 5eb2295..3dc640f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -89,7 +89,7 @@ pub use miller_rabin::is_prime;
 pub use next_prime::{
     largest_prime_less_than_or_equal_to, smallest_prime_greater_than_or_equal_to,
 };
-pub use sieve::{sieve_numbers, sieve_numbers_less_than};
+pub use sieve::{sieve_numbers, sieve_numbers_greater_than_or_equal_to, sieve_numbers_less_than};
 pub use wrapper::Primes;
 
 /// Returns the value of the [Möbius function](https://en.wikipedia.org/wiki/M%C3%B6bius_function).
diff --git a/src/sieve.rs b/src/sieve.rs
index af7619f..21afb1f 100644
--- a/src/sieve.rs
+++ b/src/sieve.rs
@@ -78,8 +78,7 @@ pub(crate) const fn sieve_segment<const N: usize>(
 /// ```
 ///
 /// # Panics
-/// Panics if `upper_limit` is not in the range `[N, N^2]`, or if `N^2` overflows a `u64`.
-/// These are compile errors in const contexts.
+/// Panics if `upper_limit` is not in the range `[N, N^2]`. In const contexts these are compile errors:
 /// ```compile_fail
 /// # use const_primes::sieve_numbers_less_than;
 /// const PRIME_STATUSES: [bool; 5] = sieve_numbers_less_than(26);
@@ -160,3 +159,49 @@ pub const fn sieve_numbers<const N: usize>() -> [bool; N] {
 
     sieve
 }
+
+/// Returns the prime status of the `N` smallest integers greater than or equal to `lower_limit`.
+/// 
+/// # Example
+/// Basic usage:
+/// ```
+/// # use const_primes::sieve_numbers_greater_than_or_equal_to;
+/// const PRIME_STATUS: [bool; 5] = sieve_numbers_greater_than_or_equal_to(10);
+/// //                        10     11    12     13    14
+/// assert_eq!(PRIME_STATUS, [false, true, false, true, false]);
+/// ```
+/// # Panics
+/// Panics if `N + lower_limit` is larger than `N^2`. In const contexts this is a compile error:
+/// ```compile_fail
+/// # use const_primes::sieve_numbers_greater_than_or_equal_to;
+/// const P: [bool; 5] = sieve_numbers_greater_than_or_equal_to(21);
+/// ```
+pub const fn sieve_numbers_greater_than_or_equal_to<const N: usize>(lower_limit: u64) -> [bool; N] {
+    let n64 = N as u64;
+
+    // Since panics are compile time errors in const contexts
+    // we check all the preconditions here and panic early.
+    let upper_limit = if let Some(sum) = n64.checked_add(lower_limit) {
+        sum
+    } else {
+        panic!("`N + lower_limit` must fit in a `u64`")
+    };
+    if let Some(n_sqr) = n64.checked_mul(n64) {
+        assert!(
+            upper_limit <= n_sqr,
+            "`lower_limit + N` must be less than or equal to `N^2`"
+        );
+    } else {
+        panic!("`N^2` must fit in a `u64`")
+    }
+    
+    let base_sieve: [bool; N] = sieve_numbers();
+    
+    // If `lower_limit` is zero the upper range is the same as what we already sieved,
+    // so we return early.
+    if lower_limit == 0 {
+        return base_sieve;
+    }
+
+    sieve_segment(&base_sieve, upper_limit)
+}

From e98b84959d0db954443eb07b2c3c5f03536be534 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 26 Oct 2023 17:31:09 +0200
Subject: [PATCH 019/212] Remove the moebius function as it is out of scope for
 the crate

---
 benches/prime_benches.rs | 11 +-----
 src/lib.rs               | 77 ----------------------------------------
 src/sieve.rs             |  6 ++--
 3 files changed, 4 insertions(+), 90 deletions(-)

diff --git a/benches/prime_benches.rs b/benches/prime_benches.rs
index 26e9eac..cd2c50f 100644
--- a/benches/prime_benches.rs
+++ b/benches/prime_benches.rs
@@ -1,4 +1,4 @@
-use const_primes::{is_prime, moebius, primes, sieve_numbers};
+use const_primes::{is_prime, primes, sieve_numbers};
 use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
 use rand::prelude::*;
 use std::hint::black_box;
@@ -23,15 +23,6 @@ fn benchmarks(c: &mut Criterion) {
     c.bench_function("sieve 10000 integers", |b| {
         b.iter(|| black_box(sieve_numbers::<10_000>()))
     });
-
-    let ints: Vec<_> = (1..1_000_000).map(|n| n).collect();
-    c.bench_function("möbius of first 1e6 integers", |b| {
-        b.iter(|| {
-            for &i in &ints {
-                black_box(moebius(i));
-            }
-        })
-    });
 }
 
 criterion_group!(benches, benchmarks);
diff --git a/src/lib.rs b/src/lib.rs
index 3dc640f..3a2246c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -92,68 +92,6 @@ pub use next_prime::{
 pub use sieve::{sieve_numbers, sieve_numbers_greater_than_or_equal_to, sieve_numbers_less_than};
 pub use wrapper::Primes;
 
-/// Returns the value of the [Möbius function](https://en.wikipedia.org/wiki/M%C3%B6bius_function).
-///
-/// This function is
-/// - 1 if `x` is a square-free integer with an even number of prime factors,  
-/// - -1 if `x` is a square-free integer with an odd number of prime factors,  
-/// - 0 if `x` has a squared prime factor.
-///
-/// Uses a small wheel to check prime factors up to `√x` and exits early if
-/// there is a squared factor.
-///
-/// # Example
-/// ```
-/// # use const_primes::moebius;
-/// const N: u64 = 1001;
-/// const MÖBIUS1001: i8 = moebius(N);
-/// assert_eq!(MÖBIUS1001, -1);
-/// ```
-// I have added this code to Rosettacode: https://www.rosettacode.org/wiki/M%C3%B6bius_function#Rust
-// as of the writing of this comment.
-pub const fn moebius(mut x: u64) -> i8 {
-    let mut prime_count: u64 = 0;
-
-    /// If x is divisible by the any of the given factors this macro counts the factor and divides it out.
-    /// It then returns zero if x is still divisible by the factor.
-    macro_rules! handle_factors {
-        ($($factor:expr),+) => {
-            $(
-                if x % $factor == 0 {
-                    x /= $factor;
-                    prime_count += 1;
-                    // If x is still divisible by the factor that means x has a
-                    // square or more prime factor, and we return 0.
-                    if x % $factor == 0 { return 0; }
-                }
-            )+
-        };
-    }
-
-    // Handle 2 and 3 separately, since the wheel will not find these factors.
-    handle_factors!(2, 3);
-
-    // Handle the remaining factors <= √x with the wheel.
-    let mut i = 5;
-    let bound = isqrt(x);
-    while i <= bound {
-        handle_factors!(i, i + 2);
-        i += 6;
-    }
-
-    // There can exist one prime factor larger than √x,
-    // in that case we can check if x is still larger than one, and then count it.
-    if x > 1 {
-        prime_count += 1;
-    }
-
-    if prime_count % 2 == 0 {
-        1
-    } else {
-        -1
-    }
-}
-
 /// Returns an array of size `N` where the value at a given index is how many primes are less than or equal to the index.
 ///
 /// Sieves primes with [`sieve_numbers`] and then counts them.
@@ -249,21 +187,6 @@ mod test {
         test_prime_counts_up_to!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 50, 100);
     }
 
-    #[test]
-    fn check_möbius() {
-        #[rustfmt::skip]
-        const TEST_CASES: [i8; 51] = [0, 1, -1, -1, 0, -1, 1, -1, 0, 0, 1, -1, 0, -1, 1, 1, 0, -1, 0, -1, 0, 1, 1, -1, 0, 0, 1, 0, 0, -1, -1, -1, 0, 1, 1, 1, 0, -1, 1, 1, 0, -1, -1, -1, 0, 0, 1, -1, 0, 0, 0];
-        for (n, ans) in TEST_CASES.into_iter().enumerate() {
-            assert_eq!(moebius(n as u64), ans);
-        }
-        #[rustfmt::skip]
-        const BIG_TEST_CASES: [i8; 51] = [0, -1, -1, 1, 0, -1, 1, 1, 0, -1, -1, 1, 0, -1, 0, -1, 0, 0, 1, -1, 0, -1, -1, -1, 0, 0, 0, 1, 0, 0, -1, -1, 0, -1, -1, 0, 0, 1, -1, -1, 0, 1, 1, 1, 0, -1, 1, 1, 0, -1, 0];
-        for (n, ans) in BIG_TEST_CASES.into_iter().enumerate() {
-            assert_eq!(moebius(n as u64 + 1000), ans);
-        }
-        assert_eq!(moebius(u32::MAX.into()), -1);
-    }
-
     #[test]
     fn verify_primes() {
         macro_rules! test_to_n {
diff --git a/src/sieve.rs b/src/sieve.rs
index 21afb1f..b1a4acd 100644
--- a/src/sieve.rs
+++ b/src/sieve.rs
@@ -161,7 +161,7 @@ pub const fn sieve_numbers<const N: usize>() -> [bool; N] {
 }
 
 /// Returns the prime status of the `N` smallest integers greater than or equal to `lower_limit`.
-/// 
+///
 /// # Example
 /// Basic usage:
 /// ```
@@ -194,9 +194,9 @@ pub const fn sieve_numbers_greater_than_or_equal_to<const N: usize>(lower_limit:
     } else {
         panic!("`N^2` must fit in a `u64`")
     }
-    
+
     let base_sieve: [bool; N] = sieve_numbers();
-    
+
     // If `lower_limit` is zero the upper range is the same as what we already sieved,
     // so we return early.
     if lower_limit == 0 {

From 2f98d59795e9215e88a75570da467dc9cb770098 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 09:57:35 +0200
Subject: [PATCH 020/212] Remove panics section that is not needed

---
 src/generate.rs | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/generate.rs b/src/generate.rs
index f759158..e889161 100644
--- a/src/generate.rs
+++ b/src/generate.rs
@@ -12,8 +12,6 @@ use crate::{sieve::sieve_segment, sieve_numbers, Underlying};
 /// const PRIMES: [u32; 10] = primes();
 /// assert_eq!(PRIMES, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]);
 /// ```
-/// # Panics
-/// Panics if a computed prime overflows a `u32`. This will result in a compile error in a const context.  
 #[must_use = "the function only returns a new value"]
 pub const fn primes<const N: usize>() -> [Underlying; N] {
     if N == 0 {
@@ -83,7 +81,7 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
                 primes[prime_count] = i as Underlying;
                 prime_count += 1;
                 // and stop the generation of primes if we're done.
-                if prime_count == N {
+                if prime_count >= N {
                     break 'generate;
                 }
             }

From 97654518a362aca8e23144c4af8dded2adb4b648 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 10:07:05 +0200
Subject: [PATCH 021/212] Remove '_numbers' from the names of sieving functions

---
 benches/prime_benches.rs           |  4 +--
 src/{generate.rs => generation.rs} |  8 +++---
 src/lib.rs                         | 30 +++++++++++-----------
 src/{sieve.rs => sieving.rs}       | 40 +++++++++++++++---------------
 4 files changed, 41 insertions(+), 41 deletions(-)
 rename src/{generate.rs => generation.rs} (97%)
 rename src/{sieve.rs => sieving.rs} (83%)

diff --git a/benches/prime_benches.rs b/benches/prime_benches.rs
index cd2c50f..f750a79 100644
--- a/benches/prime_benches.rs
+++ b/benches/prime_benches.rs
@@ -1,4 +1,4 @@
-use const_primes::{is_prime, primes, sieve_numbers};
+use const_primes::{is_prime, primes, sieve};
 use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
 use rand::prelude::*;
 use std::hint::black_box;
@@ -21,7 +21,7 @@ fn benchmarks(c: &mut Criterion) {
     });
 
     c.bench_function("sieve 10000 integers", |b| {
-        b.iter(|| black_box(sieve_numbers::<10_000>()))
+        b.iter(|| black_box(sieve::<10_000>()))
     });
 }
 
diff --git a/src/generate.rs b/src/generation.rs
similarity index 97%
rename from src/generate.rs
rename to src/generation.rs
index e889161..40dadd7 100644
--- a/src/generate.rs
+++ b/src/generation.rs
@@ -1,4 +1,4 @@
-use crate::{sieve::sieve_segment, sieve_numbers, Underlying};
+use crate::{sieve, sieving::sieve_segment, Underlying};
 
 /// Returns the `N` first prime numbers.
 ///
@@ -33,7 +33,7 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
     let mut prime_count = 0;
 
     // Sieve the first primes below N
-    let mut sieve: [bool; N] = sieve_numbers();
+    let mut sieve: [bool; N] = sieve();
 
     // Count how many primes we found
     // and store them in the final array
@@ -155,7 +155,7 @@ pub const fn primes_less_than<const N: usize>(mut upper_limit: u64) -> [u64; N]
     let mut primes: [u64; N] = [0; N];
 
     // This will be used to sieve all upper ranges.
-    let base_sieve: [bool; N] = sieve_numbers();
+    let base_sieve: [bool; N] = sieve();
 
     let mut total_primes_found: usize = 0;
     'generate: while total_primes_found < N && upper_limit > 2 {
@@ -219,7 +219,7 @@ pub const fn primes_greater_than_or_equal_to<const N: usize>(mut lower_limit: u6
     }
 
     let mut primes = [0; N];
-    let base_sieve: [bool; N] = sieve_numbers();
+    let base_sieve: [bool; N] = sieve();
     let mut total_found_primes = 0;
     'generate: while total_found_primes < N && lower_limit + n64 <= n64 * n64 {
         let mut largest_found_prime = primes[total_found_primes];
diff --git a/src/lib.rs b/src/lib.rs
index 3a2246c..cea24f4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -50,19 +50,19 @@
 //! const CHECK: bool = is_prime(18_446_744_073_709_551_557);
 //! assert!(CHECK);
 //! ```
-//! or [`sieve_numbers`] to compute the prime status of the `N` first integers,
+//! or [`sieve`] to compute the prime status of the `N` first integers,
 //! ```
-//! # use const_primes::sieve_numbers;
+//! # use const_primes::sieve;
 //! const N: usize = 10;
-//! const PRIME_STATUS: [bool; N] = sieve_numbers();
+//! const PRIME_STATUS: [bool; N] = sieve();
 //! //                        0      1      2     3     4      5     6      7     8      9
 //! assert_eq!(PRIME_STATUS, [false, false, true, true, false, true, false, true, false, false]);
 //! ```
-//! or [`sieve_numbers_less_than`] to compute the prime status of the `N` largest integers below a given value,
+//! or [`sieve_less_than`] to compute the prime status of the `N` largest integers below a given value,
 //! ```
-//! # use const_primes::sieve_numbers_less_than;
+//! # use const_primes::sieve_less_than;
 //! const N: usize = 70711;
-//! const BIG_PRIME_STATUS: [bool; N] = sieve_numbers_less_than(5_000_000_031);
+//! const BIG_PRIME_STATUS: [bool; N] = sieve_less_than(5_000_000_031);
 //! //                                     5_000_000_028  5_000_000_029  5_000_000_030
 //! assert_eq!(BIG_PRIME_STATUS[N - 3..], [false,         true,          false]);
 //! ```
@@ -76,25 +76,25 @@
 // This is used since there is currently no way to be generic over types that can do arithmetic at compile time.
 type Underlying = u32;
 
-mod generate;
+mod generation;
 mod imath;
 mod miller_rabin;
 mod next_prime;
-mod sieve;
+mod sieving;
 mod wrapper;
 
-pub use generate::{primes, primes_greater_than_or_equal_to, primes_less_than};
+pub use generation::{primes, primes_greater_than_or_equal_to, primes_less_than};
 use imath::isqrt;
 pub use miller_rabin::is_prime;
 pub use next_prime::{
     largest_prime_less_than_or_equal_to, smallest_prime_greater_than_or_equal_to,
 };
-pub use sieve::{sieve_numbers, sieve_numbers_greater_than_or_equal_to, sieve_numbers_less_than};
+pub use sieving::{sieve, sieve_greater_than_or_equal_to, sieve_less_than};
 pub use wrapper::Primes;
 
 /// Returns an array of size `N` where the value at a given index is how many primes are less than or equal to the index.
 ///
-/// Sieves primes with [`sieve_numbers`] and then counts them.
+/// Sieves primes with [`sieve`] and then counts them.
 ///
 /// # Example
 /// Basic usage
@@ -110,7 +110,7 @@ pub const fn prime_counts<const N: usize>() -> [usize; N] {
         return counts;
     }
     counts[2] = 1;
-    let prime_status: [bool; N] = sieve_numbers();
+    let prime_status: [bool; N] = sieve();
     let mut count = 1;
     let mut i = 3;
     while i < N {
@@ -143,12 +143,12 @@ mod test {
     }
 
     #[test]
-    fn check_sieve_numbers() {
+    fn check_sieve() {
         macro_rules! test_to {
             ($($n:expr),+) => {
                 $(
                     println!("{}", $n);
-                    assert_eq!(&PRIMALITIES[..$n], sieve_numbers::<$n>());
+                    assert_eq!(&PRIMALITIES[..$n], sieve::<$n>());
                 )+
             };
         }
@@ -230,7 +230,7 @@ mod test {
             ($($n:expr),+) => {
                 $(
                     println!("{}", $n);
-                    assert_eq!(&PRIMALITIES[100-$n..], sieve_numbers_less_than::<$n>(100));
+                    assert_eq!(&PRIMALITIES[100-$n..], sieve_less_than::<$n>(100));
                 )+
             };
         }
diff --git a/src/sieve.rs b/src/sieving.rs
similarity index 83%
rename from src/sieve.rs
rename to src/sieving.rs
index b1a4acd..10b477d 100644
--- a/src/sieve.rs
+++ b/src/sieving.rs
@@ -47,7 +47,7 @@ pub(crate) const fn sieve_segment<const N: usize>(
 /// Returns an array of size `N` that indicates which of the integers in `[upper_limit - N, upper_limit)` are prime,
 /// or in other words: the value at a given index represents whether `index + upper_limit - N` is prime.
 ///
-/// If you just want the prime status of the first `N` integers, see [`sieve_numbers`].
+/// If you just want the prime status of the first `N` integers, see [`sieve`].
 ///
 /// Uses a sieve of Eratosthenes to sieve the first `N` integers
 /// and then uses the result to sieve the output range if needed.
@@ -55,8 +55,8 @@ pub(crate) const fn sieve_segment<const N: usize>(
 /// # Examples
 /// Basic usage
 /// ```
-/// # use const_primes::sieve_numbers_less_than;
-/// const PRIME_STATUSES: [bool; 10] = sieve_numbers_less_than(30);
+/// # use const_primes::sieve_less_than;
+/// const PRIME_STATUSES: [bool; 10] = sieve_less_than(30);
 ///
 /// assert_eq!(
 ///     PRIME_STATUSES,
@@ -66,10 +66,10 @@ pub(crate) const fn sieve_segment<const N: usize>(
 /// ```
 /// Sieve limited ranges of very large values
 /// ```
-/// # use const_primes::sieve_numbers_less_than;
+/// # use const_primes::sieve_less_than;
 /// const BIG_NUMBER: u64 = 5_000_000_031;
 /// const CEIL_SQRT_BIG_NUMBER: usize = 70711;
-/// const BIG_PRIME_STATUSES: [bool; CEIL_SQRT_BIG_NUMBER] = sieve_numbers_less_than(BIG_NUMBER);
+/// const BIG_PRIME_STATUSES: [bool; CEIL_SQRT_BIG_NUMBER] = sieve_less_than(BIG_NUMBER);
 /// assert_eq!(
 ///     BIG_PRIME_STATUSES[CEIL_SQRT_BIG_NUMBER - 3..],
 /// //  5_000_000_028  5_000_000_029  5_000_000_030
@@ -80,15 +80,15 @@ pub(crate) const fn sieve_segment<const N: usize>(
 /// # Panics
 /// Panics if `upper_limit` is not in the range `[N, N^2]`. In const contexts these are compile errors:
 /// ```compile_fail
-/// # use const_primes::sieve_numbers_less_than;
-/// const PRIME_STATUSES: [bool; 5] = sieve_numbers_less_than(26);
+/// # use const_primes::sieve_less_than;
+/// const PRIME_STATUSES: [bool; 5] = sieve_less_than(26);
 /// ```
 /// ```compile_fail
-/// # use const_primes::sieve_numbers_less_than;
-/// const PRIME_STATUSES: [bool; 5] = sieve_numbers_less_than(4);
+/// # use const_primes::sieve_less_than;
+/// const PRIME_STATUSES: [bool; 5] = sieve_less_than(4);
 /// ```
 #[must_use = "the function returns a new value and does not modify its input"]
-pub const fn sieve_numbers_less_than<const N: usize>(upper_limit: u64) -> [bool; N] {
+pub const fn sieve_less_than<const N: usize>(upper_limit: u64) -> [bool; N] {
     let n64 = N as u64;
 
     // Since panics are compile time errors in const contexts
@@ -103,7 +103,7 @@ pub const fn sieve_numbers_less_than<const N: usize>(upper_limit: u64) -> [bool;
     assert!(upper_limit >= n64, "`upper_limit` must be at least `N`");
 
     // Use a normal sieve of Eratosthenes for the first N numbers.
-    let base_sieve: [bool; N] = sieve_numbers();
+    let base_sieve: [bool; N] = sieve();
 
     if upper_limit == n64 {
         // If we are not interested in sieving a larger range we can just return early.
@@ -119,13 +119,13 @@ pub const fn sieve_numbers_less_than<const N: usize>(upper_limit: u64) -> [bool;
 ///
 /// # Example
 /// ```
-/// # use const_primes::sieve_numbers;
-/// const PRIMALITY: [bool; 10] = sieve_numbers();
+/// # use const_primes::sieve;
+/// const PRIMALITY: [bool; 10] = sieve();
 /// //                     0      1      2     3     4      5     6      7     8      9
 /// assert_eq!(PRIMALITY, [false, false, true, true, false, true, false, true, false, false]);
 /// ```
 #[must_use = "the function only returns a new value"]
-pub const fn sieve_numbers<const N: usize>() -> [bool; N] {
+pub const fn sieve<const N: usize>() -> [bool; N] {
     let mut sieve = [true; N];
     if N > 0 {
         sieve[0] = false;
@@ -165,18 +165,18 @@ pub const fn sieve_numbers<const N: usize>() -> [bool; N] {
 /// # Example
 /// Basic usage:
 /// ```
-/// # use const_primes::sieve_numbers_greater_than_or_equal_to;
-/// const PRIME_STATUS: [bool; 5] = sieve_numbers_greater_than_or_equal_to(10);
+/// # use const_primes::sieve_greater_than_or_equal_to;
+/// const PRIME_STATUS: [bool; 5] = sieve_greater_than_or_equal_to(10);
 /// //                        10     11    12     13    14
 /// assert_eq!(PRIME_STATUS, [false, true, false, true, false]);
 /// ```
 /// # Panics
 /// Panics if `N + lower_limit` is larger than `N^2`. In const contexts this is a compile error:
 /// ```compile_fail
-/// # use const_primes::sieve_numbers_greater_than_or_equal_to;
-/// const P: [bool; 5] = sieve_numbers_greater_than_or_equal_to(21);
+/// # use const_primes::sieve_greater_than_or_equal_to;
+/// const P: [bool; 5] = sieve_greater_than_or_equal_to(21);
 /// ```
-pub const fn sieve_numbers_greater_than_or_equal_to<const N: usize>(lower_limit: u64) -> [bool; N] {
+pub const fn sieve_greater_than_or_equal_to<const N: usize>(lower_limit: u64) -> [bool; N] {
     let n64 = N as u64;
 
     // Since panics are compile time errors in const contexts
@@ -195,7 +195,7 @@ pub const fn sieve_numbers_greater_than_or_equal_to<const N: usize>(lower_limit:
         panic!("`N^2` must fit in a `u64`")
     }
 
-    let base_sieve: [bool; N] = sieve_numbers();
+    let base_sieve: [bool; N] = sieve();
 
     // If `lower_limit` is zero the upper range is the same as what we already sieved,
     // so we return early.

From 5ee65ba78fd154be051671a3464177e5ae125830 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 10:13:59 +0200
Subject: [PATCH 022/212] Add test for sieve_geq

---
 src/lib.rs | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/src/lib.rs b/src/lib.rs
index cea24f4..67f502d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -225,7 +225,7 @@ mod test {
     }
 
     #[test]
-    fn check_sieve_numbers_less_than() {
+    fn check_sieve_less_than() {
         macro_rules! test_n_below_100 {
             ($($n:expr),+) => {
                 $(
@@ -243,6 +243,19 @@ mod test {
         );
     }
 
+    #[test]
+    fn check_sieve_geq() {
+        macro_rules! test_n_geq_10 {
+            ($($n:expr),+) => {
+                $(
+                    println!("{}", $n);
+                    assert_eq!(&PRIMALITIES[10..10+$n], sieve_greater_than_or_equal_to::<$n>(10));
+                )+
+            };
+        }
+        test_n_geq_10!(4, 5, 10, 20, 30, 40, 50);
+    }
+
     #[test]
     fn check_next_prime() {
         for i in 1..PRECOMPUTED_PRIMES.len() - 1 {

From 22ce04bc4def74d18b0277ed772a3f08c6b56fa3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 10:19:30 +0200
Subject: [PATCH 023/212] Make some tests use the const eval

---
 src/lib.rs | 19 ++++++++++++-------
 1 file changed, 12 insertions(+), 7 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 67f502d..3408fb9 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -147,8 +147,10 @@ mod test {
         macro_rules! test_to {
             ($($n:expr),+) => {
                 $(
-                    println!("{}", $n);
-                    assert_eq!(&PRIMALITIES[..$n], sieve::<$n>());
+                    {
+                        const P: [bool; $n] = sieve();
+                        assert_eq!(&PRIMALITIES[..$n], P);
+                    }
                 )+
             };
         }
@@ -209,7 +211,6 @@ mod test {
             ($($n:expr),+) => {
                 $(
                     {
-                        println!("{}", $n);
                         const P: [u64; $n] = primes_less_than(100);
                         assert_eq!(PRECOMPUTED_PRIMES[25-$n..25], P.map(|i|i as u32));
                     }
@@ -229,8 +230,10 @@ mod test {
         macro_rules! test_n_below_100 {
             ($($n:expr),+) => {
                 $(
-                    println!("{}", $n);
-                    assert_eq!(&PRIMALITIES[100-$n..], sieve_less_than::<$n>(100));
+                    {
+                        const P: [bool; $n] = sieve_less_than(100);
+                        assert_eq!(&PRIMALITIES[100-$n..], P);
+                    }
                 )+
             };
         }
@@ -248,8 +251,10 @@ mod test {
         macro_rules! test_n_geq_10 {
             ($($n:expr),+) => {
                 $(
-                    println!("{}", $n);
-                    assert_eq!(&PRIMALITIES[10..10+$n], sieve_greater_than_or_equal_to::<$n>(10));
+                    {
+                        const P: [bool; $n] = sieve_greater_than_or_equal_to(10);
+                        assert_eq!(&PRIMALITIES[10..10+$n], P);
+                    }
                 )+
             };
         }

From ba516ec7afad7741ff2ad5ca4bddd8274c3129a2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 10:29:50 +0200
Subject: [PATCH 024/212] Add example of sieve_geq to crate docstring

---
 src/lib.rs | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 3408fb9..74ed8ed 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -58,13 +58,16 @@
 //! //                        0      1      2     3     4      5     6      7     8      9
 //! assert_eq!(PRIME_STATUS, [false, false, true, true, false, true, false, true, false, false]);
 //! ```
-//! or [`sieve_less_than`] to compute the prime status of the `N` largest integers below a given value,
+//! or [`sieve_less_than`] and [`sieve_greater_than_or_equal_to`] to compute the prime status of the integers below or above a given value,
 //! ```
-//! # use const_primes::sieve_less_than;
-//! const N: usize = 70711;
-//! const BIG_PRIME_STATUS: [bool; N] = sieve_less_than(5_000_000_031);
-//! //                                     5_000_000_028  5_000_000_029  5_000_000_030
-//! assert_eq!(BIG_PRIME_STATUS[N - 3..], [false,         true,          false]);
+//! # use const_primes::{sieve_less_than, sieve_greater_than_or_equal_to};
+//! const N: usize = 70800;
+//! const LOW_BIG_PRIME_STATUS: [bool; N] = sieve_less_than(5_000_000_031);
+//! const HIGH_BIG_PRIME_STATUS: [bool; N] = sieve_greater_than_or_equal_to(5_000_000_031);
+//! //                                          5_000_000_028  5_000_000_029  5_000_000_030
+//! assert_eq!(LOW_BIG_PRIME_STATUS[N - 3..],  [false,         true,          false]);
+//! //                                          5_000_000_031  5_000_000_032  5_000_000_033
+//! assert_eq!(HIGH_BIG_PRIME_STATUS[..3],     [false,         false,          false]);
 //! ```
 //! and more!
 

From 64b41c0d7afdbba176070d41f200892b51a1e22e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 10:33:56 +0200
Subject: [PATCH 025/212] Add example of sieve_geq to README

---
 README.md  | 17 ++++++++++-------
 src/lib.rs | 12 ++++++------
 2 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/README.md b/README.md
index ce4b1cd..86888c7 100644
--- a/README.md
+++ b/README.md
@@ -48,19 +48,22 @@ Use `is_prime` to test whether a given number is prime
 const CHECK: bool = is_prime(18_446_744_073_709_551_557);
 assert!(CHECK);
 ```
-or `are_prime` to compute the prime status of the `N` first integers,
+or `sieve` to compute the prime status of the `N` first integers,
 ```rust
 const N: usize = 10;
-const PRIME_STATUS: [bool; N] = are_prime();
+const PRIME_STATUS: [bool; N] = sieve();
 //                        0      1      2     3     4      5     6      7     8      9
 assert_eq!(PRIME_STATUS, [false, false, true, true, false, true, false, true, false, false]);
 ```
-or `are_prime_below` to compute the prime status of the `N` largest integers below a given value,
+or `sieve_less_than` and `sieve_greater_than_or_equal_to` to compute the prime status of the integers below or above a given value,
 ```rust
-const N: usize = 70711;
-const BIG_PRIME_STATUS: [bool; N] = are_prime_below(5_000_000_031);
-//                                     5_000_000_028  5_000_000_029  5_000_000_030
-assert_eq!(BIG_PRIME_STATUS[N - 3..], [false,         true,          false]);
+const N: usize = 70800;
+const PRIME_STATUS_BELOW: [bool; N] = sieve_less_than(5_000_000_031);
+const PRIME_STATUS_ABOVE: [bool; N] = sieve_greater_than_or_equal_to(5_000_000_031);
+//                                       5_000_000_028  5_000_000_029  5_000_000_030
+assert_eq!(PRIME_STATUS_BELOW[N - 3..], [false,         true,          false]);
+//                                       5_000_000_031  5_000_000_032  5_000_000_033
+assert_eq!(PRIME_STATUS_ABOVE[..3],     [false,         false,          false]);
 ```
 and more!
 
diff --git a/src/lib.rs b/src/lib.rs
index 74ed8ed..961ee04 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -62,12 +62,12 @@
 //! ```
 //! # use const_primes::{sieve_less_than, sieve_greater_than_or_equal_to};
 //! const N: usize = 70800;
-//! const LOW_BIG_PRIME_STATUS: [bool; N] = sieve_less_than(5_000_000_031);
-//! const HIGH_BIG_PRIME_STATUS: [bool; N] = sieve_greater_than_or_equal_to(5_000_000_031);
-//! //                                          5_000_000_028  5_000_000_029  5_000_000_030
-//! assert_eq!(LOW_BIG_PRIME_STATUS[N - 3..],  [false,         true,          false]);
-//! //                                          5_000_000_031  5_000_000_032  5_000_000_033
-//! assert_eq!(HIGH_BIG_PRIME_STATUS[..3],     [false,         false,          false]);
+//! const PRIME_STATUS_BELOW: [bool; N] = sieve_less_than(5_000_000_031);
+//! const PRIME_STATUS_ABOVE: [bool; N] = sieve_greater_than_or_equal_to(5_000_000_031);
+//! //                                       5_000_000_028  5_000_000_029  5_000_000_030
+//! assert_eq!(PRIME_STATUS_BELOW[N - 3..], [false,         true,          false]);
+//! //                                       5_000_000_031  5_000_000_032  5_000_000_033
+//! assert_eq!(PRIME_STATUS_ABOVE[..3],     [false,         false,          false]);
 //! ```
 //! and more!
 

From fd8567e5524ee33e240e47f675a4f9670782d9c8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 10:48:14 +0200
Subject: [PATCH 026/212] Add benchmark to all prime generation functions

---
 benches/prime_benches.rs | 17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/benches/prime_benches.rs b/benches/prime_benches.rs
index f750a79..2df5b2a 100644
--- a/benches/prime_benches.rs
+++ b/benches/prime_benches.rs
@@ -1,12 +1,21 @@
-use const_primes::{is_prime, primes, sieve};
+use const_primes::{is_prime, primes, primes_greater_than_or_equal_to, primes_less_than, sieve};
 use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
 use rand::prelude::*;
 use std::hint::black_box;
 
 fn benchmarks(c: &mut Criterion) {
-    c.bench_function("generate 10000 primes", |b| {
-        b.iter(|| black_box(primes::<10_000>()))
-    });
+    {
+        let mut prime_generation = c.benchmark_group("prime generation");
+        prime_generation.bench_function("first 10000 primes", |b| {
+            b.iter(|| black_box(primes::<10_000>()))
+        });
+        prime_generation.bench_function("10000 primes < 100000000", |b| {
+            b.iter(|| black_box(primes_less_than::<10000>(100000000)))
+        });
+        prime_generation.bench_function("10000 primes >= 99990000", |b| {
+            b.iter(|| black_box(primes_greater_than_or_equal_to::<10000>(99990000)))
+        });
+    }
 
     c.bench_function("is_prime on random numbers", |b| {
         b.iter_batched(

From ae2c7bff5f655b7542b3ff63e5c10c90294c92fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 10:52:05 +0200
Subject: [PATCH 027/212] Add benchmark to all sieve functions

---
 benches/prime_benches.rs | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/benches/prime_benches.rs b/benches/prime_benches.rs
index 2df5b2a..9d1109e 100644
--- a/benches/prime_benches.rs
+++ b/benches/prime_benches.rs
@@ -1,4 +1,4 @@
-use const_primes::{is_prime, primes, primes_greater_than_or_equal_to, primes_less_than, sieve};
+use const_primes::{is_prime, primes, primes_greater_than_or_equal_to, primes_less_than, sieve, sieve_less_than, sieve_greater_than_or_equal_to};
 use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
 use rand::prelude::*;
 use std::hint::black_box;
@@ -17,7 +17,7 @@ fn benchmarks(c: &mut Criterion) {
         });
     }
 
-    c.bench_function("is_prime on random numbers", |b| {
+    c.bench_function("is_prime on 10000 random numbers", |b| {
         b.iter_batched(
             || (0..10_000).map(|_| random()).collect::<Vec<u64>>(),
             |data| {
@@ -29,9 +29,18 @@ fn benchmarks(c: &mut Criterion) {
         )
     });
 
-    c.bench_function("sieve 10000 integers", |b| {
-        b.iter(|| black_box(sieve::<10_000>()))
-    });
+    {
+        let mut sieving = c.benchmark_group("prime sieving");
+        sieving.bench_function("first 10000 integers", |b| {
+            b.iter(|| black_box(sieve::<10_000>()))
+        });
+        sieving.bench_function("10000 integers < 100000000", |b| {
+            b.iter(|| black_box(sieve_less_than::<10_000>(100000000)))
+        });
+        sieving.bench_function("10000 integers >= 99990000", |b| {
+            b.iter(|| black_box(sieve_greater_than_or_equal_to::<10_000>(99990000)))
+        });
+    }
 }
 
 criterion_group!(benches, benchmarks);

From 011aa7b8ef62fbee916d1229f77758a08aeaba1c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 11:01:42 +0200
Subject: [PATCH 028/212] Name benchmark groups programmatically

---
 benches/prime_benches.rs | 60 +++++++++++++++++++++++-----------------
 1 file changed, 35 insertions(+), 25 deletions(-)

diff --git a/benches/prime_benches.rs b/benches/prime_benches.rs
index 9d1109e..2a5ca5f 100644
--- a/benches/prime_benches.rs
+++ b/benches/prime_benches.rs
@@ -1,44 +1,54 @@
-use const_primes::{is_prime, primes, primes_greater_than_or_equal_to, primes_less_than, sieve, sieve_less_than, sieve_greater_than_or_equal_to};
-use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
+use const_primes::{
+    is_prime, primes, primes_greater_than_or_equal_to, primes_less_than, sieve,
+    sieve_greater_than_or_equal_to, sieve_less_than,
+};
+use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput};
 use rand::prelude::*;
 use std::hint::black_box;
 
 fn benchmarks(c: &mut Criterion) {
     {
+        const N: usize = 10_000;
         let mut prime_generation = c.benchmark_group("prime generation");
-        prime_generation.bench_function("first 10000 primes", |b| {
-            b.iter(|| black_box(primes::<10_000>()))
+        prime_generation.bench_function(format!("first {N} primes"), |b| {
+            b.iter(|| black_box(primes::<N>()))
         });
-        prime_generation.bench_function("10000 primes < 100000000", |b| {
-            b.iter(|| black_box(primes_less_than::<10000>(100000000)))
+        prime_generation.bench_function(format!("{N} primes < 100000000"), |b| {
+            b.iter(|| black_box(primes_less_than::<N>(100000000)))
         });
-        prime_generation.bench_function("10000 primes >= 99990000", |b| {
-            b.iter(|| black_box(primes_greater_than_or_equal_to::<10000>(99990000)))
+        prime_generation.bench_function(format!("{N} primes >= 99990000"), |b| {
+            b.iter(|| black_box(primes_greater_than_or_equal_to::<N>(99990000)))
         });
     }
 
-    c.bench_function("is_prime on 10000 random numbers", |b| {
-        b.iter_batched(
-            || (0..10_000).map(|_| random()).collect::<Vec<u64>>(),
-            |data| {
-                for number in data.iter() {
-                    black_box(is_prime(*number));
-                }
-            },
-            BatchSize::SmallInput,
-        )
-    });
+    {
+        const N: u64 = 10_000;
+        let mut primality_testing = c.benchmark_group("primality testing");
+        primality_testing.throughput(Throughput::Elements(N));
+        primality_testing.bench_function(format!("is_prime on {N} random numbers"), |b| {
+            b.iter_batched(
+                || (0..N).map(|_| random()).collect::<Vec<u64>>(),
+                |data| {
+                    for number in data.iter() {
+                        black_box(is_prime(*number));
+                    }
+                },
+                BatchSize::SmallInput,
+            )
+        });
+    }
 
     {
+        const N: usize = 10_000;
         let mut sieving = c.benchmark_group("prime sieving");
-        sieving.bench_function("first 10000 integers", |b| {
-            b.iter(|| black_box(sieve::<10_000>()))
+        sieving.bench_function(format!("first {N} integers"), |b| {
+            b.iter(|| black_box(sieve::<N>()))
         });
-        sieving.bench_function("10000 integers < 100000000", |b| {
-            b.iter(|| black_box(sieve_less_than::<10_000>(100000000)))
+        sieving.bench_function(format!("{N} integers < 100000000"), |b| {
+            b.iter(|| black_box(sieve_less_than::<N>(100000000)))
         });
-        sieving.bench_function("10000 integers >= 99990000", |b| {
-            b.iter(|| black_box(sieve_greater_than_or_equal_to::<10_000>(99990000)))
+        sieving.bench_function(format!("{N} integers >= 99990000"), |b| {
+            b.iter(|| black_box(sieve_greater_than_or_equal_to::<N>(99990000)))
         });
     }
 }

From 9023e5da5d34803590161df0d2d64948859dbc4d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 12:24:09 +0200
Subject: [PATCH 029/212] Add runtime tests to some functions so that codecov
 can see it

---
 src/lib.rs | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 961ee04..b1ff8ce 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -153,6 +153,7 @@ mod test {
                     {
                         const P: [bool; $n] = sieve();
                         assert_eq!(&PRIMALITIES[..$n], P);
+                        assert_eq!(&PRIMALITIES[..$n], sieve::<$n>());
                     }
                 )+
             };
@@ -182,8 +183,8 @@ mod test {
                                 i += 1;
                             }
                         }
-
                         assert_eq!(PRIME_COUNTS, counts);
+                        assert_eq!(counts, prime_counts());
                     }
                 )+
             };
@@ -198,8 +199,9 @@ mod test {
             ($($n:expr),+) => {
                 $(
                     {
-                        const PRIMES: [Underlying; $n] = $crate::primes();
+                        const PRIMES: [Underlying; $n] = primes();
                         assert_eq!(PRIMES, PRECOMPUTED_PRIMES[..$n]);
+                        assert_eq!(PRECOMPUTED_PRIMES[..$n], primes::<$n>());
                     }
                 )+
             };
@@ -216,6 +218,10 @@ mod test {
                     {
                         const P: [u64; $n] = primes_less_than(100);
                         assert_eq!(PRECOMPUTED_PRIMES[25-$n..25], P.map(|i|i as u32));
+                        assert_eq!(
+                            PRECOMPUTED_PRIMES[25-$n..25],
+                            primes_less_than::<$n>(100).into_iter().map(|i|i as u32).collect::<Vec<_>>()
+                        );
                     }
                 )+
             };
@@ -236,6 +242,7 @@ mod test {
                     {
                         const P: [bool; $n] = sieve_less_than(100);
                         assert_eq!(&PRIMALITIES[100-$n..], P);
+                        assert_eq!(&PRIMALITIES[100-$n..], sieve_less_than::<$n>(100));
                     }
                 )+
             };
@@ -257,6 +264,7 @@ mod test {
                     {
                         const P: [bool; $n] = sieve_greater_than_or_equal_to(10);
                         assert_eq!(&PRIMALITIES[10..10+$n], P);
+                        assert_eq!(&PRIMALITIES[10..10+$n], sieve_greater_than_or_equal_to::<$n>(10));
                     }
                 )+
             };

From 821475d04a22b29a751581f1c462f47189572f02 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 12:28:57 +0200
Subject: [PATCH 030/212] Add test of None path to smallest_prime_geq

---
 src/lib.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/lib.rs b/src/lib.rs
index b1ff8ce..224c3f9 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -285,6 +285,7 @@ mod test {
             );
         }
 
+        assert_eq!(smallest_prime_greater_than_or_equal_to(18_446_744_073_709_551_558), None);
         assert_eq!(smallest_prime_greater_than_or_equal_to(0), Some(2));
         assert_eq!(smallest_prime_greater_than_or_equal_to(1), Some(2));
         assert_eq!(smallest_prime_greater_than_or_equal_to(2), Some(2));

From 5e335dd0e8eb5447549c6b3a55563c6d95dd7b35 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 12:40:18 +0200
Subject: [PATCH 031/212] cargo fmt

---
 src/lib.rs | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/lib.rs b/src/lib.rs
index 224c3f9..d14ffa7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -285,7 +285,10 @@ mod test {
             );
         }
 
-        assert_eq!(smallest_prime_greater_than_or_equal_to(18_446_744_073_709_551_558), None);
+        assert_eq!(
+            smallest_prime_greater_than_or_equal_to(18_446_744_073_709_551_558),
+            None
+        );
         assert_eq!(smallest_prime_greater_than_or_equal_to(0), Some(2));
         assert_eq!(smallest_prime_greater_than_or_equal_to(1), Some(2));
         assert_eq!(smallest_prime_greater_than_or_equal_to(2), Some(2));

From 6dfe3a31707b469cc725aecf41a98818c87871c9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 12:40:49 +0200
Subject: [PATCH 032/212] Correct sieve_segment behaviour when the requested
 segment starts at zero, and add a test for it

---
 src/sieving.rs | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/src/sieving.rs b/src/sieving.rs
index 10b477d..16c0703 100644
--- a/src/sieving.rs
+++ b/src/sieving.rs
@@ -9,12 +9,12 @@ pub(crate) const fn sieve_segment<const N: usize>(
 
     let lower_limit = upper_limit - N as u64;
 
-    // In case 0 and/or 1 are included in the upper sieve we need to treat them as a special case
-    // since they are not multiples of any prime in `base_sieve` even though they are not primes.
     if lower_limit == 0 && N > 1 {
-        segment_sieve[0] = false;
-        segment_sieve[1] = false;
+        // If the lower limit is 0 we can just return the base sieve.
+        return *base_sieve;
     } else if lower_limit == 1 && N > 0 {
+        // In case 1 is included in the upper sieve we need to treat it as a special case
+        // since it's not a multiple of any prime in `base_sieve` even though it's not prime.
         segment_sieve[0] = false;
     }
 
@@ -205,3 +205,16 @@ pub const fn sieve_greater_than_or_equal_to<const N: usize>(lower_limit: u64) ->
 
     sieve_segment(&base_sieve, upper_limit)
 }
+
+#[cfg(test)]
+mod test {
+    use super::{sieve, sieve_segment};
+
+    #[test]
+    fn test_consistency_of_sieve_segment() {
+        const P: [bool; 10] = sieve_segment(&sieve(), 10);
+        const PP: [bool; 10] = sieve_segment(&sieve(), 11);
+        assert_eq!(P, sieve());
+        assert_eq!(PP, sieve::<11>()[1..]);
+    }
+}

From 015a3a89c08cc77fb9716193b44a1580317c1f2e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 13:13:45 +0200
Subject: [PATCH 033/212] make next_prime functions always jump ahead

---
 src/lib.rs        | 23 +++++++++++------------
 src/next_prime.rs | 40 ++++++++++++++++++++++------------------
 2 files changed, 33 insertions(+), 30 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index d14ffa7..34e8f70 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -89,9 +89,7 @@ mod wrapper;
 pub use generation::{primes, primes_greater_than_or_equal_to, primes_less_than};
 use imath::isqrt;
 pub use miller_rabin::is_prime;
-pub use next_prime::{
-    largest_prime_less_than_or_equal_to, smallest_prime_greater_than_or_equal_to,
-};
+pub use next_prime::{largest_prime_less_than, smallest_prime_greater_than};
 pub use sieving::{sieve, sieve_greater_than_or_equal_to, sieve_less_than};
 pub use wrapper::Primes;
 
@@ -276,25 +274,26 @@ mod test {
     fn check_next_prime() {
         for i in 1..PRECOMPUTED_PRIMES.len() - 1 {
             assert_eq!(
-                smallest_prime_greater_than_or_equal_to(PRECOMPUTED_PRIMES[i] as u64 + 1),
+                smallest_prime_greater_than(PRECOMPUTED_PRIMES[i] as u64),
                 Some(PRECOMPUTED_PRIMES[i + 1] as u64)
             );
             assert_eq!(
-                largest_prime_less_than_or_equal_to(PRECOMPUTED_PRIMES[i] as u64 - 1),
+                largest_prime_less_than(PRECOMPUTED_PRIMES[i] as u64),
                 Some(PRECOMPUTED_PRIMES[i - 1] as u64)
             );
         }
 
         assert_eq!(
-            smallest_prime_greater_than_or_equal_to(18_446_744_073_709_551_558),
+            smallest_prime_greater_than(18_446_744_073_709_551_558),
             None
         );
-        assert_eq!(smallest_prime_greater_than_or_equal_to(0), Some(2));
-        assert_eq!(smallest_prime_greater_than_or_equal_to(1), Some(2));
-        assert_eq!(smallest_prime_greater_than_or_equal_to(2), Some(2));
-        assert_eq!(largest_prime_less_than_or_equal_to(0), None);
-        assert_eq!(largest_prime_less_than_or_equal_to(1), None);
-        assert_eq!(largest_prime_less_than_or_equal_to(2), Some(2));
+        assert_eq!(smallest_prime_greater_than(0), Some(2));
+        assert_eq!(smallest_prime_greater_than(1), Some(2));
+        assert_eq!(smallest_prime_greater_than(2), Some(3));
+        assert_eq!(largest_prime_less_than(0), None);
+        assert_eq!(largest_prime_less_than(1), None);
+        assert_eq!(largest_prime_less_than(2), None);
+        assert_eq!(largest_prime_less_than(3), Some(2));
     }
 
     #[rustfmt::skip]
diff --git a/src/next_prime.rs b/src/next_prime.rs
index da6d479..1037d57 100644
--- a/src/next_prime.rs
+++ b/src/next_prime.rs
@@ -1,28 +1,30 @@
 use crate::is_prime;
 
-/// Returns the largest prime smaller than or equal to `n` if there is one.
+/// Returns the largest prime smaller than `n` if there is one.
 ///
 /// Scans for primes downwards from the input with [`is_prime`].
 ///
 /// # Examples
 /// ```
-/// # use const_primes::largest_prime_less_than_or_equal_to;
-/// const LPLEQ: Option<u64> = largest_prime_less_than_or_equal_to(400);
+/// # use const_primes::largest_prime_less_than;
+/// const LPLEQ: Option<u64> = largest_prime_less_than(400);
 /// assert_eq!(LPLEQ, Some(397));
 /// ```
-/// There's no prime smaller than or equal to one
+/// There's no prime smaller than two
 /// ```
-/// # use const_primes::largest_prime_less_than_or_equal_to;
-/// const NOSUCH: Option<u64> = largest_prime_less_than_or_equal_to(1);
+/// # use const_primes::largest_prime_less_than;
+/// const NOSUCH: Option<u64> = largest_prime_less_than(2);
 /// assert!(NOSUCH.is_none());
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
-pub const fn largest_prime_less_than_or_equal_to(mut n: u64) -> Option<u64> {
-    if n == 0 || n == 1 {
+pub const fn largest_prime_less_than(mut n: u64) -> Option<u64> {
+    if n <= 2 {
         None
-    } else if n == 2 {
+    } else if n == 3 {
         Some(2)
     } else {
+        n -= 1;
+
         if n % 2 == 0 {
             n -= 1;
         }
@@ -35,31 +37,33 @@ pub const fn largest_prime_less_than_or_equal_to(mut n: u64) -> Option<u64> {
     }
 }
 
-/// Returns the smallest prime greater than or equal to `n` if there is one that
+/// Returns the smallest prime greater than `n` if there is one that
 /// can be represented by a `u64`.
 ///
 /// Scans for primes upwards from the input with [`is_prime`].
 ///
 /// # Example
 /// ```
-/// # use const_primes::smallest_prime_greater_than_or_equal_to;
-/// const SPGEQ: Option<u64> = smallest_prime_greater_than_or_equal_to(400);
+/// # use const_primes::smallest_prime_greater_than;
+/// const SPGEQ: Option<u64> = smallest_prime_greater_than(400);
 /// assert_eq!(SPGEQ, Some(401));
 /// ```
 /// Primes larger than 18446744073709551557 can not be represented by a `u64`
 /// ```
-/// # use const_primes::smallest_prime_greater_than_or_equal_to;
-/// const NOSUCH: Option<u64> = smallest_prime_greater_than_or_equal_to(18_446_744_073_709_551_558);
+/// # use const_primes::smallest_prime_greater_than;
+/// const NOSUCH: Option<u64> = smallest_prime_greater_than(18_446_744_073_709_551_557);
 /// assert!(NOSUCH.is_none());
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
-pub const fn smallest_prime_greater_than_or_equal_to(mut n: u64) -> Option<u64> {
-    // The largest prime smaller than 2^64
-    if n > 18_446_744_073_709_551_557 {
+pub const fn smallest_prime_greater_than(mut n: u64) -> Option<u64> {
+    // The largest prime smaller than u64::MAX
+    if n >= 18_446_744_073_709_551_557 {
         None
-    } else if n <= 2 {
+    } else if n <= 1 {
         Some(2)
     } else {
+        n += 1;
+
         if n % 2 == 0 {
             n += 1;
         }

From 8bfad4c050ccfc5c0d77d22528871a48a27d1f5e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 13:21:44 +0200
Subject: [PATCH 034/212] Improve docstrings of next_prime functions

---
 src/next_prime.rs | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/next_prime.rs b/src/next_prime.rs
index 1037d57..e55d341 100644
--- a/src/next_prime.rs
+++ b/src/next_prime.rs
@@ -5,12 +5,13 @@ use crate::is_prime;
 /// Scans for primes downwards from the input with [`is_prime`].
 ///
 /// # Examples
+/// Basic usage:
 /// ```
 /// # use const_primes::largest_prime_less_than;
 /// const LPLEQ: Option<u64> = largest_prime_less_than(400);
 /// assert_eq!(LPLEQ, Some(397));
 /// ```
-/// There's no prime smaller than two
+/// There's no prime smaller than two:
 /// ```
 /// # use const_primes::largest_prime_less_than;
 /// const NOSUCH: Option<u64> = largest_prime_less_than(2);
@@ -43,12 +44,13 @@ pub const fn largest_prime_less_than(mut n: u64) -> Option<u64> {
 /// Scans for primes upwards from the input with [`is_prime`].
 ///
 /// # Example
+/// Basic usage:
 /// ```
 /// # use const_primes::smallest_prime_greater_than;
 /// const SPGEQ: Option<u64> = smallest_prime_greater_than(400);
 /// assert_eq!(SPGEQ, Some(401));
 /// ```
-/// Primes larger than 18446744073709551557 can not be represented by a `u64`
+/// Primes larger than 18446744073709551557 can not be represented by a `u64`:
 /// ```
 /// # use const_primes::smallest_prime_greater_than;
 /// const NOSUCH: Option<u64> = smallest_prime_greater_than(18_446_744_073_709_551_557);

From 5b5f9ebcc5687301eecd5e85364921da81142fed Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 14:32:45 +0200
Subject: [PATCH 035/212] Shorten names

---
 benches/prime_benches.rs | 13 ++++-----
 src/generation.rs        | 46 ++++++++++++++++----------------
 src/lib.rs               | 57 +++++++++++++++++++---------------------
 src/next_prime.rs        | 20 +++++++-------
 src/sieving.rs           | 28 ++++++++++----------
 5 files changed, 79 insertions(+), 85 deletions(-)

diff --git a/benches/prime_benches.rs b/benches/prime_benches.rs
index 2a5ca5f..fe8fa80 100644
--- a/benches/prime_benches.rs
+++ b/benches/prime_benches.rs
@@ -1,7 +1,4 @@
-use const_primes::{
-    is_prime, primes, primes_greater_than_or_equal_to, primes_less_than, sieve,
-    sieve_greater_than_or_equal_to, sieve_less_than,
-};
+use const_primes::{is_prime, primes, primes_geq, primes_lt, sieve, sieve_geq, sieve_lt};
 use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput};
 use rand::prelude::*;
 use std::hint::black_box;
@@ -14,10 +11,10 @@ fn benchmarks(c: &mut Criterion) {
             b.iter(|| black_box(primes::<N>()))
         });
         prime_generation.bench_function(format!("{N} primes < 100000000"), |b| {
-            b.iter(|| black_box(primes_less_than::<N>(100000000)))
+            b.iter(|| black_box(primes_lt::<N>(100000000)))
         });
         prime_generation.bench_function(format!("{N} primes >= 99990000"), |b| {
-            b.iter(|| black_box(primes_greater_than_or_equal_to::<N>(99990000)))
+            b.iter(|| black_box(primes_geq::<N>(99990000)))
         });
     }
 
@@ -45,10 +42,10 @@ fn benchmarks(c: &mut Criterion) {
             b.iter(|| black_box(sieve::<N>()))
         });
         sieving.bench_function(format!("{N} integers < 100000000"), |b| {
-            b.iter(|| black_box(sieve_less_than::<N>(100000000)))
+            b.iter(|| black_box(sieve_lt::<N>(100000000)))
         });
         sieving.bench_function(format!("{N} integers >= 99990000"), |b| {
-            b.iter(|| black_box(sieve_greater_than_or_equal_to::<N>(99990000)))
+            b.iter(|| black_box(sieve_geq::<N>(99990000)))
         });
     }
 }
diff --git a/src/generation.rs b/src/generation.rs
index 40dadd7..65c81ff 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -107,17 +107,17 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// # Example
 /// Basic usage:
 /// ```
-/// # use const_primes::primes_less_than;
-/// const PRIMES: [u64; 10] = primes_less_than(100);
+/// # use const_primes::primes_lt;
+/// const PRIMES: [u64; 10] = primes_lt(100);
 ///
 /// assert_eq!(PRIMES, [53, 59, 61, 67, 71, 73, 79, 83, 89, 97]);
 /// ```
 /// Compute larger primes without starting from zero:
 /// ```
-/// # use const_primes::primes_less_than;
+/// # use const_primes::primes_lt;
 /// const N: usize = 70711;
 /// # #[allow(long_running_const_eval)]
-/// const BIG_PRIMES: [u64; N] = primes_less_than(5_000_000_030);
+/// const BIG_PRIMES: [u64; N] = primes_lt(5_000_000_030);
 ///
 /// assert_eq!(&BIG_PRIMES[..3], &[4_998_417_421, 4_998_417_427, 4_998_417_443]);
 /// assert_eq!(&BIG_PRIMES[N - 3..], &[4_999_999_903, 4_999_999_937, 5_000_000_029]);
@@ -125,8 +125,8 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// If there are not enough primes to fill the requested array, the first
 /// elements will have a value of zero:
 /// ```
-/// # use const_primes::primes_less_than;
-/// const PRIMES: [u64; 9] = primes_less_than(10);
+/// # use const_primes::primes_lt;
+/// const PRIMES: [u64; 9] = primes_lt(10);
 ///
 /// assert_eq!(PRIMES, [0, 0, 0, 0, 0, 2, 3, 5, 7]);
 /// ```
@@ -134,14 +134,14 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// Panics if `upper_limit` is not in the range `(N, N^2]`. This is a compile error
 /// in const contexts:
 /// ```compile_fail
-/// # use const_primes::primes_less_than;
-/// const PRIMES: [u64; 5] = primes_less_than(5);
+/// # use const_primes::primes_lt;
+/// const PRIMES: [u64; 5] = primes_lt(5);
 /// ```
 /// ```compile_fail
-/// # use const_primes::primes_less_than;
-/// const PRIMES: [u64; 5] = primes_less_than(26);
+/// # use const_primes::primes_lt;
+/// const PRIMES: [u64; 5] = primes_lt(26);
 /// ```
-pub const fn primes_less_than<const N: usize>(mut upper_limit: u64) -> [u64; N] {
+pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> [u64; N] {
     let n64 = N as u64;
     assert!(upper_limit > n64, "`upper_limit` must be larger than `N`");
     match (n64).checked_mul(n64) {
@@ -193,26 +193,26 @@ pub const fn primes_less_than<const N: usize>(mut upper_limit: u64) -> [u64; N]
 /// # Example
 /// Basic usage:
 /// ```
-/// # use const_primes::primes_greater_than_or_equal_to;
-/// const PRIMES: [u64; 5] = primes_greater_than_or_equal_to(10);
+/// # use const_primes::primes_geq;
+/// const PRIMES: [u64; 5] = primes_geq(10);
 /// assert_eq!(PRIMES, [11, 13, 17, 19, 23]);
 /// ```
 /// Compute larger primes without starting from zero:
 /// ```
-/// # use const_primes::primes_greater_than_or_equal_to;
+/// # use const_primes::primes_geq;
 /// const N: usize = 71_000;
 /// # #[allow(long_running_const_eval)]
-/// const P: [u64; N] = primes_greater_than_or_equal_to(5_000_000_030);
+/// const P: [u64; N] = primes_geq(5_000_000_030);
 /// assert_eq!(P[..3], [5_000_000_039, 5_000_000_059, 5_000_000_063]);
 /// assert_eq!(P[N - 3..], [5_001_586_727, 5_001_586_729, 5_001_586_757]);
 /// ```
 /// Only primes smaller than or equal to `N^2` will be generated:
 /// ```
-/// # use const_primes::primes_greater_than_or_equal_to;
-/// const PRIMES: [u64; 3] = primes_greater_than_or_equal_to(5);
+/// # use const_primes::primes_geq;
+/// const PRIMES: [u64; 3] = primes_geq(5);
 /// assert_eq!(PRIMES, [5, 7, 0]);
 /// ```
-pub const fn primes_greater_than_or_equal_to<const N: usize>(mut lower_limit: u64) -> [u64; N] {
+pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> [u64; N] {
     let n64 = N as u64;
     if n64.checked_mul(n64).is_none() {
         panic!("`N^2` must fit in a `u64`");
@@ -247,21 +247,21 @@ mod test {
     use super::*;
 
     #[test]
-    fn sanity_check_primes_greater_than_or_equal_to() {
+    fn sanity_check_primes_geq() {
         {
-            const P: [u64; 5] = primes_greater_than_or_equal_to(10);
+            const P: [u64; 5] = primes_geq(10);
             assert_eq!(P, [11, 13, 17, 19, 23]);
         }
         {
-            const P: [u64; 5] = primes_greater_than_or_equal_to(0);
+            const P: [u64; 5] = primes_geq(0);
             assert_eq!(P, [2, 3, 5, 7, 11]);
         }
         {
-            const P: [u64; 0] = primes_greater_than_or_equal_to(0);
+            const P: [u64; 0] = primes_geq(0);
             assert_eq!(P, []);
         }
         {
-            const P: [u64; 1] = primes_greater_than_or_equal_to(0);
+            const P: [u64; 1] = primes_geq(0);
             assert_eq!(P, [0]);
         }
     }
diff --git a/src/lib.rs b/src/lib.rs
index 34e8f70..ae9c4a0 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -58,12 +58,12 @@
 //! //                        0      1      2     3     4      5     6      7     8      9
 //! assert_eq!(PRIME_STATUS, [false, false, true, true, false, true, false, true, false, false]);
 //! ```
-//! or [`sieve_less_than`] and [`sieve_greater_than_or_equal_to`] to compute the prime status of the integers below or above a given value,
+//! or [`sieve_lt`] and [`sieve_geq`] to compute the prime status of the integers below or above a given value,
 //! ```
-//! # use const_primes::{sieve_less_than, sieve_greater_than_or_equal_to};
+//! # use const_primes::{sieve_lt, sieve_geq};
 //! const N: usize = 70800;
-//! const PRIME_STATUS_BELOW: [bool; N] = sieve_less_than(5_000_000_031);
-//! const PRIME_STATUS_ABOVE: [bool; N] = sieve_greater_than_or_equal_to(5_000_000_031);
+//! const PRIME_STATUS_BELOW: [bool; N] = sieve_lt(5_000_000_031);
+//! const PRIME_STATUS_ABOVE: [bool; N] = sieve_geq(5_000_000_031);
 //! //                                       5_000_000_028  5_000_000_029  5_000_000_030
 //! assert_eq!(PRIME_STATUS_BELOW[N - 3..], [false,         true,          false]);
 //! //                                       5_000_000_031  5_000_000_032  5_000_000_033
@@ -86,11 +86,11 @@ mod next_prime;
 mod sieving;
 mod wrapper;
 
-pub use generation::{primes, primes_greater_than_or_equal_to, primes_less_than};
+pub use generation::{primes, primes_geq, primes_lt};
 use imath::isqrt;
 pub use miller_rabin::is_prime;
-pub use next_prime::{largest_prime_less_than, smallest_prime_greater_than};
-pub use sieving::{sieve, sieve_greater_than_or_equal_to, sieve_less_than};
+pub use next_prime::{largest_prime_lt, smallest_prime_gt};
+pub use sieving::{sieve, sieve_geq, sieve_lt};
 pub use wrapper::Primes;
 
 /// Returns an array of size `N` where the value at a given index is how many primes are less than or equal to the index.
@@ -209,16 +209,16 @@ mod test {
     }
 
     #[test]
-    fn check_primes_less_than() {
+    fn check_primes_lt() {
         macro_rules! test_n_below_100 {
             ($($n:expr),+) => {
                 $(
                     {
-                        const P: [u64; $n] = primes_less_than(100);
+                        const P: [u64; $n] = primes_lt(100);
                         assert_eq!(PRECOMPUTED_PRIMES[25-$n..25], P.map(|i|i as u32));
                         assert_eq!(
                             PRECOMPUTED_PRIMES[25-$n..25],
-                            primes_less_than::<$n>(100).into_iter().map(|i|i as u32).collect::<Vec<_>>()
+                            primes_lt::<$n>(100).into_iter().map(|i|i as u32).collect::<Vec<_>>()
                         );
                     }
                 )+
@@ -227,20 +227,20 @@ mod test {
 
         test_n_below_100!(10, 15, 20);
 
-        assert_eq!([0, 0, 0, 0, 0, 2, 3, 5, 7], primes_less_than(10));
+        assert_eq!([0, 0, 0, 0, 0, 2, 3, 5, 7], primes_lt(10));
 
-        assert_eq!([0, 2], primes_less_than(3));
+        assert_eq!([0, 2], primes_lt(3));
     }
 
     #[test]
-    fn check_sieve_less_than() {
+    fn check_sieve_lt() {
         macro_rules! test_n_below_100 {
             ($($n:expr),+) => {
                 $(
                     {
-                        const P: [bool; $n] = sieve_less_than(100);
+                        const P: [bool; $n] = sieve_lt(100);
                         assert_eq!(&PRIMALITIES[100-$n..], P);
-                        assert_eq!(&PRIMALITIES[100-$n..], sieve_less_than::<$n>(100));
+                        assert_eq!(&PRIMALITIES[100-$n..], sieve_lt::<$n>(100));
                     }
                 )+
             };
@@ -260,9 +260,9 @@ mod test {
             ($($n:expr),+) => {
                 $(
                     {
-                        const P: [bool; $n] = sieve_greater_than_or_equal_to(10);
+                        const P: [bool; $n] = sieve_geq(10);
                         assert_eq!(&PRIMALITIES[10..10+$n], P);
-                        assert_eq!(&PRIMALITIES[10..10+$n], sieve_greater_than_or_equal_to::<$n>(10));
+                        assert_eq!(&PRIMALITIES[10..10+$n], sieve_geq::<$n>(10));
                     }
                 )+
             };
@@ -274,26 +274,23 @@ mod test {
     fn check_next_prime() {
         for i in 1..PRECOMPUTED_PRIMES.len() - 1 {
             assert_eq!(
-                smallest_prime_greater_than(PRECOMPUTED_PRIMES[i] as u64),
+                smallest_prime_gt(PRECOMPUTED_PRIMES[i] as u64),
                 Some(PRECOMPUTED_PRIMES[i + 1] as u64)
             );
             assert_eq!(
-                largest_prime_less_than(PRECOMPUTED_PRIMES[i] as u64),
+                largest_prime_lt(PRECOMPUTED_PRIMES[i] as u64),
                 Some(PRECOMPUTED_PRIMES[i - 1] as u64)
             );
         }
 
-        assert_eq!(
-            smallest_prime_greater_than(18_446_744_073_709_551_558),
-            None
-        );
-        assert_eq!(smallest_prime_greater_than(0), Some(2));
-        assert_eq!(smallest_prime_greater_than(1), Some(2));
-        assert_eq!(smallest_prime_greater_than(2), Some(3));
-        assert_eq!(largest_prime_less_than(0), None);
-        assert_eq!(largest_prime_less_than(1), None);
-        assert_eq!(largest_prime_less_than(2), None);
-        assert_eq!(largest_prime_less_than(3), Some(2));
+        assert_eq!(smallest_prime_gt(18_446_744_073_709_551_558), None);
+        assert_eq!(smallest_prime_gt(0), Some(2));
+        assert_eq!(smallest_prime_gt(1), Some(2));
+        assert_eq!(smallest_prime_gt(2), Some(3));
+        assert_eq!(largest_prime_lt(0), None);
+        assert_eq!(largest_prime_lt(1), None);
+        assert_eq!(largest_prime_lt(2), None);
+        assert_eq!(largest_prime_lt(3), Some(2));
     }
 
     #[rustfmt::skip]
diff --git a/src/next_prime.rs b/src/next_prime.rs
index e55d341..84bfda5 100644
--- a/src/next_prime.rs
+++ b/src/next_prime.rs
@@ -7,18 +7,18 @@ use crate::is_prime;
 /// # Examples
 /// Basic usage:
 /// ```
-/// # use const_primes::largest_prime_less_than;
-/// const LPLEQ: Option<u64> = largest_prime_less_than(400);
+/// # use const_primes::largest_prime_lt;
+/// const LPLEQ: Option<u64> = largest_prime_lt(400);
 /// assert_eq!(LPLEQ, Some(397));
 /// ```
 /// There's no prime smaller than two:
 /// ```
-/// # use const_primes::largest_prime_less_than;
-/// const NOSUCH: Option<u64> = largest_prime_less_than(2);
+/// # use const_primes::largest_prime_lt;
+/// const NOSUCH: Option<u64> = largest_prime_lt(2);
 /// assert!(NOSUCH.is_none());
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
-pub const fn largest_prime_less_than(mut n: u64) -> Option<u64> {
+pub const fn largest_prime_lt(mut n: u64) -> Option<u64> {
     if n <= 2 {
         None
     } else if n == 3 {
@@ -46,18 +46,18 @@ pub const fn largest_prime_less_than(mut n: u64) -> Option<u64> {
 /// # Example
 /// Basic usage:
 /// ```
-/// # use const_primes::smallest_prime_greater_than;
-/// const SPGEQ: Option<u64> = smallest_prime_greater_than(400);
+/// # use const_primes::smallest_prime_gt;
+/// const SPGEQ: Option<u64> = smallest_prime_gt(400);
 /// assert_eq!(SPGEQ, Some(401));
 /// ```
 /// Primes larger than 18446744073709551557 can not be represented by a `u64`:
 /// ```
-/// # use const_primes::smallest_prime_greater_than;
-/// const NOSUCH: Option<u64> = smallest_prime_greater_than(18_446_744_073_709_551_557);
+/// # use const_primes::smallest_prime_gt;
+/// const NOSUCH: Option<u64> = smallest_prime_gt(18_446_744_073_709_551_557);
 /// assert!(NOSUCH.is_none());
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
-pub const fn smallest_prime_greater_than(mut n: u64) -> Option<u64> {
+pub const fn smallest_prime_gt(mut n: u64) -> Option<u64> {
     // The largest prime smaller than u64::MAX
     if n >= 18_446_744_073_709_551_557 {
         None
diff --git a/src/sieving.rs b/src/sieving.rs
index 16c0703..22a0982 100644
--- a/src/sieving.rs
+++ b/src/sieving.rs
@@ -55,8 +55,8 @@ pub(crate) const fn sieve_segment<const N: usize>(
 /// # Examples
 /// Basic usage
 /// ```
-/// # use const_primes::sieve_less_than;
-/// const PRIME_STATUSES: [bool; 10] = sieve_less_than(30);
+/// # use const_primes::sieve_lt;
+/// const PRIME_STATUSES: [bool; 10] = sieve_lt(30);
 ///
 /// assert_eq!(
 ///     PRIME_STATUSES,
@@ -66,10 +66,10 @@ pub(crate) const fn sieve_segment<const N: usize>(
 /// ```
 /// Sieve limited ranges of very large values
 /// ```
-/// # use const_primes::sieve_less_than;
+/// # use const_primes::sieve_lt;
 /// const BIG_NUMBER: u64 = 5_000_000_031;
 /// const CEIL_SQRT_BIG_NUMBER: usize = 70711;
-/// const BIG_PRIME_STATUSES: [bool; CEIL_SQRT_BIG_NUMBER] = sieve_less_than(BIG_NUMBER);
+/// const BIG_PRIME_STATUSES: [bool; CEIL_SQRT_BIG_NUMBER] = sieve_lt(BIG_NUMBER);
 /// assert_eq!(
 ///     BIG_PRIME_STATUSES[CEIL_SQRT_BIG_NUMBER - 3..],
 /// //  5_000_000_028  5_000_000_029  5_000_000_030
@@ -80,15 +80,15 @@ pub(crate) const fn sieve_segment<const N: usize>(
 /// # Panics
 /// Panics if `upper_limit` is not in the range `[N, N^2]`. In const contexts these are compile errors:
 /// ```compile_fail
-/// # use const_primes::sieve_less_than;
-/// const PRIME_STATUSES: [bool; 5] = sieve_less_than(26);
+/// # use const_primes::sieve_lt;
+/// const PRIME_STATUSES: [bool; 5] = sieve_lt(26);
 /// ```
 /// ```compile_fail
-/// # use const_primes::sieve_less_than;
-/// const PRIME_STATUSES: [bool; 5] = sieve_less_than(4);
+/// # use const_primes::sieve_lt;
+/// const PRIME_STATUSES: [bool; 5] = sieve_lt(4);
 /// ```
 #[must_use = "the function returns a new value and does not modify its input"]
-pub const fn sieve_less_than<const N: usize>(upper_limit: u64) -> [bool; N] {
+pub const fn sieve_lt<const N: usize>(upper_limit: u64) -> [bool; N] {
     let n64 = N as u64;
 
     // Since panics are compile time errors in const contexts
@@ -165,18 +165,18 @@ pub const fn sieve<const N: usize>() -> [bool; N] {
 /// # Example
 /// Basic usage:
 /// ```
-/// # use const_primes::sieve_greater_than_or_equal_to;
-/// const PRIME_STATUS: [bool; 5] = sieve_greater_than_or_equal_to(10);
+/// # use const_primes::sieve_geq;
+/// const PRIME_STATUS: [bool; 5] = sieve_geq(10);
 /// //                        10     11    12     13    14
 /// assert_eq!(PRIME_STATUS, [false, true, false, true, false]);
 /// ```
 /// # Panics
 /// Panics if `N + lower_limit` is larger than `N^2`. In const contexts this is a compile error:
 /// ```compile_fail
-/// # use const_primes::sieve_greater_than_or_equal_to;
-/// const P: [bool; 5] = sieve_greater_than_or_equal_to(21);
+/// # use const_primes::sieve_geq;
+/// const P: [bool; 5] = sieve_geq(21);
 /// ```
-pub const fn sieve_greater_than_or_equal_to<const N: usize>(lower_limit: u64) -> [bool; N] {
+pub const fn sieve_geq<const N: usize>(lower_limit: u64) -> [bool; N] {
     let n64 = N as u64;
 
     // Since panics are compile time errors in const contexts

From 6f69dda0ab2a1b0273a7fe0908b58ef8ef217fd6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 15:01:01 +0200
Subject: [PATCH 036/212] Add panics section to primes_geq docstring

---
 src/generation.rs | 12 +++++++++++-
 src/lib.rs        | 37 +++++++++++++++++++++++++------------
 2 files changed, 36 insertions(+), 13 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 65c81ff..391dca0 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -104,6 +104,8 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// Due to the limitations on memory allocation in `const` contexts the value of `N`
 /// must satisfy the bounds `N < upper_limit <= N^2`.
 ///
+/// If you want to compute primes that are larger than the input, take a look at [`primes_geq`].
+///
 /// # Example
 /// Basic usage:
 /// ```
@@ -190,6 +192,8 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> [u64; N] {
 /// This function will fill the output array from index 0 and stop generating primes if they exceed `N^2`.
 /// In that case the remaining elements of the output array will be 0.
 ///
+/// If you want to compute primes smaller than the input, take a look at [`primes_lt`].
+///
 /// # Example
 /// Basic usage:
 /// ```
@@ -206,12 +210,18 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> [u64; N] {
 /// assert_eq!(P[..3], [5_000_000_039, 5_000_000_059, 5_000_000_063]);
 /// assert_eq!(P[N - 3..], [5_001_586_727, 5_001_586_729, 5_001_586_757]);
 /// ```
-/// Only primes smaller than or equal to `N^2` will be generated:
+/// Only primes smaller than to `N^2` will be generated:
 /// ```
 /// # use const_primes::primes_geq;
 /// const PRIMES: [u64; 3] = primes_geq(5);
 /// assert_eq!(PRIMES, [5, 7, 0]);
 /// ```
+/// # Panics
+/// Panics if `N^2` does not fit in a `u64`.
+/// ```compile_fail
+/// # use const_primes::primes_geq;
+/// const P: [u64; u32::MAX as usize + 1] = primes_geq(0);
+/// ```
 pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> [u64; N] {
     let n64 = N as u64;
     if n64.checked_mul(n64).is_none() {
diff --git a/src/lib.rs b/src/lib.rs
index ae9c4a0..0994631 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -42,6 +42,30 @@
 //! # use const_primes::Primes;
 //! const PRIMES: Primes<0> = Primes::new();
 //! ```
+//!
+//! ## Arbitrary ranges
+//!
+//! The crate provides prime generation and sieving functions with suffixes, e.g. [`primes_geq`] and [`sieve_lt`]
+//! that can be used to work with ranges that don't start at zero.
+//! ```
+//! # use const_primes::{sieve_lt, primes_geq};
+//! const N: usize = 70722;
+//! # #[allow(long_running_const_eval)]
+//! const PRIMES_GEQ: [u64; N] = primes_geq(5_000_000_031);
+//!
+//! assert_eq!(PRIMES_GEQ[..3], [5_000_000_039, 5_000_000_059, 5_000_000_063]);
+//! ```
+//! ```
+//! # use const_primes::{sieve_lt, primes_geq};
+//! const N: usize = 70711;
+//! const PRIME_STATUS_LT: [bool; N] = sieve_lt(5_000_000_031);
+//! //                                    5_000_000_028  5_000_000_029  5_000_000_030
+//! assert_eq!(PRIME_STATUS_LT[N - 3..], [false,         true,          false]);
+//! ```
+//! Unfortunately the output array must be large enough to contain the prime sieve, which scales with
+//! the square root of largest relavant number, which is why the examples use a size of over 70000 even though
+//! they're only interested in three numbers.
+//!
 //! ## Other functionality
 //!
 //! Use [`is_prime`] to test whether a given number is prime,
@@ -50,7 +74,7 @@
 //! const CHECK: bool = is_prime(18_446_744_073_709_551_557);
 //! assert!(CHECK);
 //! ```
-//! or [`sieve`] to compute the prime status of the `N` first integers,
+//! or [`sieve`] to compute the prime status of the `N` first integers.
 //! ```
 //! # use const_primes::sieve;
 //! const N: usize = 10;
@@ -58,17 +82,6 @@
 //! //                        0      1      2     3     4      5     6      7     8      9
 //! assert_eq!(PRIME_STATUS, [false, false, true, true, false, true, false, true, false, false]);
 //! ```
-//! or [`sieve_lt`] and [`sieve_geq`] to compute the prime status of the integers below or above a given value,
-//! ```
-//! # use const_primes::{sieve_lt, sieve_geq};
-//! const N: usize = 70800;
-//! const PRIME_STATUS_BELOW: [bool; N] = sieve_lt(5_000_000_031);
-//! const PRIME_STATUS_ABOVE: [bool; N] = sieve_geq(5_000_000_031);
-//! //                                       5_000_000_028  5_000_000_029  5_000_000_030
-//! assert_eq!(PRIME_STATUS_BELOW[N - 3..], [false,         true,          false]);
-//! //                                       5_000_000_031  5_000_000_032  5_000_000_033
-//! assert_eq!(PRIME_STATUS_ABOVE[..3],     [false,         false,          false]);
-//! ```
 //! and more!
 
 #![forbid(unsafe_code)]

From f591acb30ce254b33964067d12a0aa325a9c3380 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 15:09:56 +0200
Subject: [PATCH 037/212] Clean up panics section of primes_lt

---
 src/generation.rs | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 391dca0..6a3295c 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -101,9 +101,6 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// The return array fills from the end until either it is full or there are no more primes.
 /// If the primes run out before the array is filled the first elements will have a value of zero.
 ///
-/// Due to the limitations on memory allocation in `const` contexts the value of `N`
-/// must satisfy the bounds `N < upper_limit <= N^2`.
-///
 /// If you want to compute primes that are larger than the input, take a look at [`primes_geq`].
 ///
 /// # Example
@@ -133,11 +130,11 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// assert_eq!(PRIMES, [0, 0, 0, 0, 0, 2, 3, 5, 7]);
 /// ```
 /// # Panics
-/// Panics if `upper_limit` is not in the range `(N, N^2]`. This is a compile error
+/// Panics if `N^2` does not fit in a `u64` or if `upper_limit` is larger than `N^2`. This is a compile error
 /// in const contexts:
 /// ```compile_fail
 /// # use const_primes::primes_lt;
-/// const PRIMES: [u64; 5] = primes_lt(5);
+/// const PRIMES: [u64; u32::MAX as usize + 1] = primes_lt(100);
 /// ```
 /// ```compile_fail
 /// # use const_primes::primes_lt;
@@ -145,7 +142,6 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// ```
 pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> [u64; N] {
     let n64 = N as u64;
-    assert!(upper_limit > n64, "`upper_limit` must be larger than `N`");
     match (n64).checked_mul(n64) {
         Some(prod) => assert!(
             upper_limit <= prod,

From 64e581911e64c99ca50d1c2fecd92d449ce3311c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 15:13:49 +0200
Subject: [PATCH 038/212] Add comments to compile_fail exampels

---
 src/generation.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/generation.rs b/src/generation.rs
index 6a3295c..0ab08ed 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -134,10 +134,12 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// in const contexts:
 /// ```compile_fail
 /// # use const_primes::primes_lt;
+/// //                  N is too large
 /// const PRIMES: [u64; u32::MAX as usize + 1] = primes_lt(100);
 /// ```
 /// ```compile_fail
 /// # use const_primes::primes_lt;
+/// //                  N              upper_limit > N^2
 /// const PRIMES: [u64; 5] = primes_lt(26);
 /// ```
 pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> [u64; N] {

From 92a92f99ee4e7410186c3adaf82783b2e581bdcc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 16:02:48 +0200
Subject: [PATCH 039/212] Add primality verification to primes_geq test

---
 src/generation.rs | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/generation.rs b/src/generation.rs
index 0ab08ed..48a9a02 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -252,6 +252,8 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> [u64; N] {
 
 #[cfg(test)]
 mod test {
+    use crate::is_prime;
+
     use super::*;
 
     #[test]
@@ -272,5 +274,11 @@ mod test {
             const P: [u64; 1] = primes_geq(0);
             assert_eq!(P, [0]);
         }
+        for prime in primes_geq::<2_000>(3_998_000) {
+            if prime == 0 {
+                break;
+            }
+            assert!(is_prime(prime));
+        }
     }
 }

From 41c3a7dddb665aecb7f599d550dc721feed1b860 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 17:00:09 +0200
Subject: [PATCH 040/212] Ensured that potential false positives are ignored

---
 src/generation.rs | 5 +++++
 src/sieving.rs    | 6 +++---
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 48a9a02..4d7b3fe 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -237,9 +237,14 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> [u64; N] {
         while i < N {
             if upper_sieve[i] {
                 largest_found_prime = lower_limit + i as u64;
+                if largest_found_prime >= n64 * n64 {
+                    // We do not know if this is actually a prime
+                    break 'generate;
+                }
                 primes[total_found_primes] = largest_found_prime;
                 total_found_primes += 1;
                 if total_found_primes >= N {
+                    // We've found enough primes
                     break 'generate;
                 }
             }
diff --git a/src/sieving.rs b/src/sieving.rs
index 22a0982..e9923d7 100644
--- a/src/sieving.rs
+++ b/src/sieving.rs
@@ -171,10 +171,10 @@ pub const fn sieve<const N: usize>() -> [bool; N] {
 /// assert_eq!(PRIME_STATUS, [false, true, false, true, false]);
 /// ```
 /// # Panics
-/// Panics if `N + lower_limit` is larger than `N^2`. In const contexts this is a compile error:
+/// Panics if `N + lower_limit` is larger than or equal to `N^2`. In const contexts this is a compile error:
 /// ```compile_fail
 /// # use const_primes::sieve_geq;
-/// const P: [bool; 5] = sieve_geq(21);
+/// const P: [bool; 5] = sieve_geq(20);
 /// ```
 pub const fn sieve_geq<const N: usize>(lower_limit: u64) -> [bool; N] {
     let n64 = N as u64;
@@ -188,7 +188,7 @@ pub const fn sieve_geq<const N: usize>(lower_limit: u64) -> [bool; N] {
     };
     if let Some(n_sqr) = n64.checked_mul(n64) {
         assert!(
-            upper_limit <= n_sqr,
+            upper_limit < n_sqr,
             "`lower_limit + N` must be less than or equal to `N^2`"
         );
     } else {

From 52cbd6d06523940b755d90b488a6de2ecc7a4b9a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 17:04:19 +0200
Subject: [PATCH 041/212] Motivate early exit

---
 src/generation.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/generation.rs b/src/generation.rs
index 4d7b3fe..02c05bb 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -239,6 +239,8 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> [u64; N] {
                 largest_found_prime = lower_limit + i as u64;
                 if largest_found_prime >= n64 * n64 {
                     // We do not know if this is actually a prime
+                    // since the base sieve does not contain information about
+                    // the prime status of N.
                     break 'generate;
                 }
                 primes[total_found_primes] = largest_found_prime;

From d939966f54c74212e5bdf74a32de626d9014a80b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 17:13:23 +0200
Subject: [PATCH 042/212] Remove now redundant check

---
 src/generation.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 02c05bb..aca87b9 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -229,7 +229,7 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> [u64; N] {
     let mut primes = [0; N];
     let base_sieve: [bool; N] = sieve();
     let mut total_found_primes = 0;
-    'generate: while total_found_primes < N && lower_limit + n64 <= n64 * n64 {
+    'generate: while total_found_primes < N {
         let mut largest_found_prime = primes[total_found_primes];
         let upper_sieve = sieve_segment(&base_sieve, lower_limit + n64);
         let mut i = 0;
@@ -240,7 +240,7 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> [u64; N] {
                 if largest_found_prime >= n64 * n64 {
                     // We do not know if this is actually a prime
                     // since the base sieve does not contain information about
-                    // the prime status of N.
+                    // the prime status of numbers larger than or equal to N.
                     break 'generate;
                 }
                 primes[total_found_primes] = largest_found_prime;

From 737aa022b97a3baabf2e1ee109e923bff52be228 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 17:14:40 +0200
Subject: [PATCH 043/212] grammar

---
 src/generation.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/generation.rs b/src/generation.rs
index aca87b9..c8b51f8 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -208,7 +208,7 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> [u64; N] {
 /// assert_eq!(P[..3], [5_000_000_039, 5_000_000_059, 5_000_000_063]);
 /// assert_eq!(P[N - 3..], [5_001_586_727, 5_001_586_729, 5_001_586_757]);
 /// ```
-/// Only primes smaller than to `N^2` will be generated:
+/// Only primes smaller than `N^2` will be generated:
 /// ```
 /// # use const_primes::primes_geq;
 /// const PRIMES: [u64; 3] = primes_geq(5);

From 76c948037b5d5895285ecec069ee6471f40d8b02 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 17:21:36 +0200
Subject: [PATCH 044/212] move backticks in panic massage of sieve_lt

---
 src/sieving.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/sieving.rs b/src/sieving.rs
index e9923d7..616ab4c 100644
--- a/src/sieving.rs
+++ b/src/sieving.rs
@@ -96,9 +96,9 @@ pub const fn sieve_lt<const N: usize>(upper_limit: u64) -> [bool; N] {
     match n64.checked_mul(n64) {
         Some(prod) => assert!(
             upper_limit <= prod,
-            "`upper_limit` must be smaller than or equal to `N`^2"
+            "`upper_limit` must be smaller than or equal to `N^2`"
         ),
-        None => panic!("`N`^2 must fit in a `u64`"),
+        None => panic!("`N^2` must fit in a `u64`"),
     }
     assert!(upper_limit >= n64, "`upper_limit` must be at least `N`");
 

From 24025e2d866856a5967ea93ceb08e3294c7899ec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 17:24:12 +0200
Subject: [PATCH 045/212] Add note about assumtions in sieve_segment

---
 src/sieving.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/sieving.rs b/src/sieving.rs
index 616ab4c..4d30eb3 100644
--- a/src/sieving.rs
+++ b/src/sieving.rs
@@ -1,6 +1,8 @@
 use crate::isqrt;
 
 /// Uses the primalities of the first `N` integers in `base_sieve` to sieve the numbers in the range `[upper_limit - N, upper_limit)`.
+/// Assumes that the base sieve contains the prime status of the `N` fist integers. The output is only meaningful
+/// for the numbers below `N^2`.
 pub(crate) const fn sieve_segment<const N: usize>(
     base_sieve: &[bool; N],
     upper_limit: u64,

From 13a0371a5e3ceac2eee81c359d03730f3c69a756 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 18:51:11 +0200
Subject: [PATCH 046/212] Remove unused imports in crate docstring examples

---
 src/lib.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 0994631..1b1da4e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -48,7 +48,7 @@
 //! The crate provides prime generation and sieving functions with suffixes, e.g. [`primes_geq`] and [`sieve_lt`]
 //! that can be used to work with ranges that don't start at zero.
 //! ```
-//! # use const_primes::{sieve_lt, primes_geq};
+//! # use const_primes::primes_geq;
 //! const N: usize = 70722;
 //! # #[allow(long_running_const_eval)]
 //! const PRIMES_GEQ: [u64; N] = primes_geq(5_000_000_031);
@@ -56,7 +56,7 @@
 //! assert_eq!(PRIMES_GEQ[..3], [5_000_000_039, 5_000_000_059, 5_000_000_063]);
 //! ```
 //! ```
-//! # use const_primes::{sieve_lt, primes_geq};
+//! # use const_primes::sieve_lt;
 //! const N: usize = 70711;
 //! const PRIME_STATUS_LT: [bool; N] = sieve_lt(5_000_000_031);
 //! //                                    5_000_000_028  5_000_000_029  5_000_000_030

From 2e8272c66fd4a5d9fd3ddf4e7aa5c6ff5ac289ce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 18:59:36 +0200
Subject: [PATCH 047/212] Add #[must_use]

---
 src/generation.rs | 2 ++
 src/sieving.rs    | 4 +++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/generation.rs b/src/generation.rs
index c8b51f8..3bcbaf5 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -142,6 +142,7 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// //                  N              upper_limit > N^2
 /// const PRIMES: [u64; 5] = primes_lt(26);
 /// ```
+#[must_use = "the function only returns a new value and does not modify its input"]
 pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> [u64; N] {
     let n64 = N as u64;
     match (n64).checked_mul(n64) {
@@ -220,6 +221,7 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> [u64; N] {
 /// # use const_primes::primes_geq;
 /// const P: [u64; u32::MAX as usize + 1] = primes_geq(0);
 /// ```
+#[must_use = "the function only returns a new value and does not modify its input"]
 pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> [u64; N] {
     let n64 = N as u64;
     if n64.checked_mul(n64).is_none() {
diff --git a/src/sieving.rs b/src/sieving.rs
index 4d30eb3..97e1e69 100644
--- a/src/sieving.rs
+++ b/src/sieving.rs
@@ -3,6 +3,7 @@ use crate::isqrt;
 /// Uses the primalities of the first `N` integers in `base_sieve` to sieve the numbers in the range `[upper_limit - N, upper_limit)`.
 /// Assumes that the base sieve contains the prime status of the `N` fist integers. The output is only meaningful
 /// for the numbers below `N^2`.
+#[must_use = "the function only returns a new value and does not modify its inputs"]
 pub(crate) const fn sieve_segment<const N: usize>(
     base_sieve: &[bool; N],
     upper_limit: u64,
@@ -89,7 +90,7 @@ pub(crate) const fn sieve_segment<const N: usize>(
 /// # use const_primes::sieve_lt;
 /// const PRIME_STATUSES: [bool; 5] = sieve_lt(4);
 /// ```
-#[must_use = "the function returns a new value and does not modify its input"]
+#[must_use = "the function only returns a new value and does not modify its input"]
 pub const fn sieve_lt<const N: usize>(upper_limit: u64) -> [bool; N] {
     let n64 = N as u64;
 
@@ -178,6 +179,7 @@ pub const fn sieve<const N: usize>() -> [bool; N] {
 /// # use const_primes::sieve_geq;
 /// const P: [bool; 5] = sieve_geq(20);
 /// ```
+#[must_use = "the function only returns a new value and does not modify its input"]
 pub const fn sieve_geq<const N: usize>(lower_limit: u64) -> [bool; N] {
     let n64 = N as u64;
 

From 9e715e126ca411e36805520063fd6c17964d2171 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 21:57:56 +0200
Subject: [PATCH 048/212] rename next_prime module to other_prime

---
 src/lib.rs                            | 24 ++++++++++++------------
 src/{next_prime.rs => other_prime.rs} | 20 ++++++++++----------
 2 files changed, 22 insertions(+), 22 deletions(-)
 rename src/{next_prime.rs => other_prime.rs} (72%)

diff --git a/src/lib.rs b/src/lib.rs
index 1b1da4e..80c58ea 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -95,14 +95,14 @@ type Underlying = u32;
 mod generation;
 mod imath;
 mod miller_rabin;
-mod next_prime;
+mod other_prime;
 mod sieving;
 mod wrapper;
 
 pub use generation::{primes, primes_geq, primes_lt};
 use imath::isqrt;
 pub use miller_rabin::is_prime;
-pub use next_prime::{largest_prime_lt, smallest_prime_gt};
+pub use other_prime::{next_prime, previous_prime};
 pub use sieving::{sieve, sieve_geq, sieve_lt};
 pub use wrapper::Primes;
 
@@ -287,23 +287,23 @@ mod test {
     fn check_next_prime() {
         for i in 1..PRECOMPUTED_PRIMES.len() - 1 {
             assert_eq!(
-                smallest_prime_gt(PRECOMPUTED_PRIMES[i] as u64),
+                next_prime(PRECOMPUTED_PRIMES[i] as u64),
                 Some(PRECOMPUTED_PRIMES[i + 1] as u64)
             );
             assert_eq!(
-                largest_prime_lt(PRECOMPUTED_PRIMES[i] as u64),
+                previous_prime(PRECOMPUTED_PRIMES[i] as u64),
                 Some(PRECOMPUTED_PRIMES[i - 1] as u64)
             );
         }
 
-        assert_eq!(smallest_prime_gt(18_446_744_073_709_551_558), None);
-        assert_eq!(smallest_prime_gt(0), Some(2));
-        assert_eq!(smallest_prime_gt(1), Some(2));
-        assert_eq!(smallest_prime_gt(2), Some(3));
-        assert_eq!(largest_prime_lt(0), None);
-        assert_eq!(largest_prime_lt(1), None);
-        assert_eq!(largest_prime_lt(2), None);
-        assert_eq!(largest_prime_lt(3), Some(2));
+        assert_eq!(next_prime(18_446_744_073_709_551_558), None);
+        assert_eq!(next_prime(0), Some(2));
+        assert_eq!(next_prime(1), Some(2));
+        assert_eq!(next_prime(2), Some(3));
+        assert_eq!(previous_prime(0), None);
+        assert_eq!(previous_prime(1), None);
+        assert_eq!(previous_prime(2), None);
+        assert_eq!(previous_prime(3), Some(2));
     }
 
     #[rustfmt::skip]
diff --git a/src/next_prime.rs b/src/other_prime.rs
similarity index 72%
rename from src/next_prime.rs
rename to src/other_prime.rs
index 84bfda5..b37690a 100644
--- a/src/next_prime.rs
+++ b/src/other_prime.rs
@@ -7,18 +7,18 @@ use crate::is_prime;
 /// # Examples
 /// Basic usage:
 /// ```
-/// # use const_primes::largest_prime_lt;
-/// const LPLEQ: Option<u64> = largest_prime_lt(400);
+/// # use const_primes::previous_prime;
+/// const LPLEQ: Option<u64> = previous_prime(400);
 /// assert_eq!(LPLEQ, Some(397));
 /// ```
 /// There's no prime smaller than two:
 /// ```
-/// # use const_primes::largest_prime_lt;
-/// const NOSUCH: Option<u64> = largest_prime_lt(2);
+/// # use const_primes::previous_prime;
+/// const NOSUCH: Option<u64> = previous_prime(2);
 /// assert!(NOSUCH.is_none());
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
-pub const fn largest_prime_lt(mut n: u64) -> Option<u64> {
+pub const fn previous_prime(mut n: u64) -> Option<u64> {
     if n <= 2 {
         None
     } else if n == 3 {
@@ -46,18 +46,18 @@ pub const fn largest_prime_lt(mut n: u64) -> Option<u64> {
 /// # Example
 /// Basic usage:
 /// ```
-/// # use const_primes::smallest_prime_gt;
-/// const SPGEQ: Option<u64> = smallest_prime_gt(400);
+/// # use const_primes::next_prime;
+/// const SPGEQ: Option<u64> = next_prime(400);
 /// assert_eq!(SPGEQ, Some(401));
 /// ```
 /// Primes larger than 18446744073709551557 can not be represented by a `u64`:
 /// ```
-/// # use const_primes::smallest_prime_gt;
-/// const NOSUCH: Option<u64> = smallest_prime_gt(18_446_744_073_709_551_557);
+/// # use const_primes::next_prime;
+/// const NOSUCH: Option<u64> = next_prime(18_446_744_073_709_551_557);
 /// assert!(NOSUCH.is_none());
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
-pub const fn smallest_prime_gt(mut n: u64) -> Option<u64> {
+pub const fn next_prime(mut n: u64) -> Option<u64> {
     // The largest prime smaller than u64::MAX
     if n >= 18_446_744_073_709_551_557 {
         None

From 1a4d8efa3eee93f61c324b26de9d7e8228f08f04 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 27 Oct 2023 22:18:17 +0200
Subject: [PATCH 049/212] Update documentation string of crate and README

---
 README.md  | 54 +++++++++++++++++++++++++++++++++++-------------------
 src/lib.rs | 35 ++++++++++++++++++++---------------
 2 files changed, 55 insertions(+), 34 deletions(-)

diff --git a/README.md b/README.md
index 86888c7..e10b91a 100644
--- a/README.md
+++ b/README.md
@@ -9,13 +9,13 @@ A crate for generating and working with prime numbers in const contexts.
 `#![no_std]` compatible.
 
 ## Examples
-Generate arrays of prime numbers with the function `primes` which uses a [segmented sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Segmented_sieve).
+Generate arrays of prime numbers with the function `primes` which uses a [segmented sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Segmented_sieve):
 ```rust
 const PRIMES: [u32; 10] = primes();
 assert_eq!(PRIMES[5], 13);
 assert_eq!(PRIMES, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]);
 ```
-or with the type `Primes` which ensures that a non-zero number of primes are generated:
+or with the wrapping type [`Primes`]:
 ```rust
 const PRIMES: Primes<10> = Primes::new();
 assert_eq!(PRIMES[5], 13);
@@ -40,30 +40,46 @@ assert_eq!(PRIMES_LEQ_100, Some(25));
 assert!(CACHE.is_prime(1000).is_none());
 assert!(CACHE.count_primes_leq(1000).is_none());
 ```
-Creating a `Primes<0>` is a compile fail in const contexts and a panic otherwise.  
-
-### Other functionality
-Use `is_prime` to test whether a given number is prime
-```rust
-const CHECK: bool = is_prime(18_446_744_073_709_551_557);
-assert!(CHECK);
-```
-or `sieve` to compute the prime status of the `N` first integers,
+Sieve a range of numbers for their prime status with `sieve`:
 ```rust
 const N: usize = 10;
 const PRIME_STATUS: [bool; N] = sieve();
 //                        0      1      2     3     4      5     6      7     8      9
 assert_eq!(PRIME_STATUS, [false, false, true, true, false, true, false, true, false, false]);
+```  
+
+## Arbitrary ranges
+The crate provides prime generation and sieving functions with suffixes, e.g. `primes_geq` and `sieve_lt`
+that can be used to work with ranges that don't start at zero.
+```rust
+const N: usize = 70722;
+const PRIMES_GEQ: [u64; N] = primes_geq(5_000_000_031);
+assert_eq!(PRIMES_GEQ[..3], [5_000_000_039, 5_000_000_059, 5_000_000_063]);
 ```
-or `sieve_less_than` and `sieve_greater_than_or_equal_to` to compute the prime status of the integers below or above a given value,
 ```rust
-const N: usize = 70800;
-const PRIME_STATUS_BELOW: [bool; N] = sieve_less_than(5_000_000_031);
-const PRIME_STATUS_ABOVE: [bool; N] = sieve_greater_than_or_equal_to(5_000_000_031);
-//                                       5_000_000_028  5_000_000_029  5_000_000_030
-assert_eq!(PRIME_STATUS_BELOW[N - 3..], [false,         true,          false]);
-//                                       5_000_000_031  5_000_000_032  5_000_000_033
-assert_eq!(PRIME_STATUS_ABOVE[..3],     [false,         false,          false]);
+const N: usize = 70711;
+const PRIME_STATUS_LT: [bool; N] = sieve_lt(5_000_000_031);
+//                                    5_000_000_028  5_000_000_029  5_000_000_030
+assert_eq!(PRIME_STATUS_LT[N - 3..], [false,         true,          false]);
+```
+Unfortunately the output array must be large enough to contain the prime sieve, which scales with
+the square root of largest relavant number, which is why the examples use a size of over 70000 even though
+they're only interested in three numbers.
+## Other functionality
+Use `is_prime` to test whether a given number is prime:
+```rust
+const CHECK: bool = is_prime(18_446_744_073_709_551_557);
+assert!(CHECK);
+```
+Find the next or previous prime numbers with `next_prime` and `previous_prime` if they exist:
+```rust
+const NEXT: Option<u64> = next_prime(25);
+const PREV: Option<u64> = previous_prime(25);
+const NOSUCH: Option<u64> = previous_prime(2);
+
+assert_eq!(NEXT, Some(29));
+assert_eq!(PREV, Some(23));
+assert_eq!(NOSUCH, None);
 ```
 and more!
 
diff --git a/src/lib.rs b/src/lib.rs
index 80c58ea..bc3b199 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -4,21 +4,21 @@
 //!
 //! # Examples
 //! Generate arrays of prime numbers with the function [`primes`] which uses a
-//! [segmented sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Segmented_sieve).
+//! [segmented sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Segmented_sieve):
 //! ```
 //! use const_primes::primes;
 //! const PRIMES: [u32; 10] = primes();
 //! assert_eq!(PRIMES[5], 13);
 //! assert_eq!(PRIMES, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]);
 //! ```
-//! or with the type [`Primes`], which ensures that a non-zero number of primes are generated
+//! or with the wrapping type [`Primes`]:
 //! ```
 //! use const_primes::Primes;
 //! const PRIMES: Primes<10> = Primes::new();
 //! assert_eq!(PRIMES[5], 13);
 //! assert_eq!(PRIMES, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]);
 //! ```
-//! It also lets you reuse it as a cache of primes for related computations
+//! which lets you reuse it as a cache of primes for related computations:
 //! ```
 //! # use const_primes::Primes;
 //! const CACHE: Primes<100> = Primes::new();
@@ -37,12 +37,14 @@
 //! assert!(CACHE.is_prime(1000).is_none());
 //! assert!(CACHE.count_primes_leq(1000).is_none());
 //! ```
-//! Creating a `Primes<0>` is a compile fail in const contexts and a panic otherwise.
-//! ```compile_fail
-//! # use const_primes::Primes;
-//! const PRIMES: Primes<0> = Primes::new();
+//! Sieve a range of numbers for their prime status with [`sieve`]:
+//! ```
+//! # use const_primes::sieve;
+//! const N: usize = 10;
+//! const PRIME_STATUS: [bool; N] = sieve();
+//! //                        0      1      2     3     4      5     6      7     8      9
+//! assert_eq!(PRIME_STATUS, [false, false, true, true, false, true, false, true, false, false]);
 //! ```
-//!
 //! ## Arbitrary ranges
 //!
 //! The crate provides prime generation and sieving functions with suffixes, e.g. [`primes_geq`] and [`sieve_lt`]
@@ -68,19 +70,22 @@
 //!
 //! ## Other functionality
 //!
-//! Use [`is_prime`] to test whether a given number is prime,
+//! Use [`is_prime`] to test whether a given number is prime:
 //! ```
 //! # use const_primes::is_prime;
 //! const CHECK: bool = is_prime(18_446_744_073_709_551_557);
 //! assert!(CHECK);
 //! ```
-//! or [`sieve`] to compute the prime status of the `N` first integers.
+//! Find the next or previous prime numbers with [`next_prime`] and [`previous_prime`] if they exist:
 //! ```
-//! # use const_primes::sieve;
-//! const N: usize = 10;
-//! const PRIME_STATUS: [bool; N] = sieve();
-//! //                        0      1      2     3     4      5     6      7     8      9
-//! assert_eq!(PRIME_STATUS, [false, false, true, true, false, true, false, true, false, false]);
+//! # use const_primes::{next_prime, previous_prime};
+//! const NEXT: Option<u64> = next_prime(25);
+//! const PREV: Option<u64> = previous_prime(25);
+//! const NOSUCH: Option<u64> = previous_prime(2);
+//!
+//! assert_eq!(NEXT, Some(29));
+//! assert_eq!(PREV, Some(23));
+//! assert_eq!(NOSUCH, None);
 //! ```
 //! and more!
 

From e4f7e43f1f3f97a22be6ece52d3e93d2946df2e2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 29 Oct 2023 15:45:27 +0100
Subject: [PATCH 050/212] Add array_section module

---
 src/array_section.rs | 132 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 132 insertions(+)
 create mode 100644 src/array_section.rs

diff --git a/src/array_section.rs b/src/array_section.rs
new file mode 100644
index 0000000..b9ed260
--- /dev/null
+++ b/src/array_section.rs
@@ -0,0 +1,132 @@
+use core::ops::Range;
+
+/// An array where only a section of the data may be viewed,
+/// as the other data may be e.g. not uphold some invariant.
+#[derive(Debug)]
+pub struct RestrictedArray<const N: usize, T> {
+    start: usize,
+    end: usize,
+    array: [T; N],
+}
+
+impl<const N: usize, T: Clone> Clone for RestrictedArray<N, T> {
+    fn clone(&self) -> Self {
+        Self {
+            start: self.start,
+            end: self.end,
+            array: self.array.clone(),
+        }
+    }
+}
+
+impl<const N: usize, T: Copy> Copy for RestrictedArray<N, T> {}
+
+impl<const N: usize, T: PartialEq<T>> PartialEq<RestrictedArray<N, T>> for RestrictedArray<N, T> {
+    /// This method tests for `self` and `other` values to be equal, and is used by `==`.  
+    /// Only compares the *unrestricted* part of `self` against the *unrestricted* part of `other`.
+    fn eq(&self, other: &RestrictedArray<N, T>) -> bool {
+        self.as_slice() == other.as_slice()
+    }
+}
+
+impl<const N: usize, T> RestrictedArray<N, T> {
+    /// Restrict a given array so that only elements within the given range are viewable.
+    ///
+    /// # Panics
+    /// Panics if the range of indices is out of bounds of the array.
+    pub const fn new(sub_range: Range<usize>, array: [T; N]) -> Self {
+        assert!(
+            sub_range.start < N && sub_range.end <= N,
+            "the sub-range must be in bounds"
+        );
+
+        if sub_range.start > sub_range.end {
+            Self {
+                start: 0,
+                end: 0,
+                array,
+            }
+        } else {
+            Self {
+                start: sub_range.start,
+                end: sub_range.end,
+                array,
+            }
+        }
+    }
+
+    /// Returns a reference to the full underlying array.
+    pub const fn as_full_array(&self) -> &[T; N] {
+        &self.array
+    }
+
+    /// Converts `self` into the full underlying array.
+    pub fn into_full_array(self) -> [T; N] {
+        self.array
+    }
+
+    /// Returns the unrestricted part of the array as a slice.
+    pub const fn as_slice(&self) -> &[T] {
+        let (_, tail) = self.array.split_at(self.start);
+        tail.split_at(self.end - self.start).0
+    }
+
+    /// Returns the length of the unrestricted part of the array.
+    pub const fn len(&self) -> usize {
+        self.end - self.start
+    }
+
+    /// Returns whether the unrestricted part is empty.
+    pub const fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Returns whether there are parts of the array that are restricted.
+    /// If this is `false` it is completely fine to call [`as_full_array`](RestrictedArray::as_full_array)
+    /// or [`into_full_array`](RestrictedArray::into_full_array).
+    pub const fn is_restricted(&self) -> bool {
+        self.len() == N
+    }
+
+    /// Returns an iterator over the unrestricted section.
+    pub fn iter(&self) -> core::slice::Iter<'_, T> {
+        self.as_slice().iter()
+    }
+}
+
+impl<const N: usize, T> core::ops::Index<usize> for RestrictedArray<N, T> {
+    type Output = T;
+    fn index(&self, index: usize) -> &Self::Output {
+        let i = match self.start.checked_add(index) {
+            Some(sum) => sum,
+            None => panic!("index overflowed"),
+        };
+
+        if i >= self.end {
+            panic!("index was {i} when len was {}", self.end - self.start);
+        }
+
+        &self.array[i]
+    }
+}
+
+impl<const N: usize, T> IntoIterator for RestrictedArray<N, T> {
+    type IntoIter = core::iter::Take<core::iter::Skip<core::array::IntoIter<T, N>>>;
+    type Item = <[T; N] as IntoIterator>::Item;
+    fn into_iter(self) -> Self::IntoIter {
+        let start = self.start;
+        let len = self.len();
+        self.array.into_iter().skip(start).take(len)
+    }
+}
+
+impl<const N: usize, T, U> PartialEq<U> for RestrictedArray<N, T>
+where
+    U: PartialEq<[T]>,
+{
+    /// This method tests for `self` and `other` values to be equal, and is used by `==`.  
+    /// Only compares the *unrestricted* part of `self` against `other`.
+    fn eq(&self, other: &U) -> bool {
+        other == self.as_slice()
+    }
+}

From 53c5e81b22232a7f69b686cd7cb6d5cc6aaa0f99 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 29 Oct 2023 15:55:16 +0100
Subject: [PATCH 051/212] Use a newtype for RestrictedArray IntoIter

---
 src/array_section.rs | 30 ++++++++++++++++++++++++++----
 1 file changed, 26 insertions(+), 4 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index b9ed260..e353731 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -1,4 +1,4 @@
-use core::ops::Range;
+use core::{iter::FusedIterator, ops::Range};
 
 /// An array where only a section of the data may be viewed,
 /// as the other data may be e.g. not uphold some invariant.
@@ -110,13 +110,35 @@ impl<const N: usize, T> core::ops::Index<usize> for RestrictedArray<N, T> {
     }
 }
 
+pub struct RestrictedArrayIntoIter<const N: usize, T>(
+    core::iter::Take<core::iter::Skip<core::array::IntoIter<T, N>>>,
+);
+
+impl<const N: usize, T> Iterator for RestrictedArrayIntoIter<N, T> {
+    type Item = T;
+    fn next(&mut self) -> Option<Self::Item> {
+        self.0.next()
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.0.size_hint()
+    }
+}
+impl<const N: usize, T> FusedIterator for RestrictedArrayIntoIter<N, T> {}
+impl<const N: usize, T> ExactSizeIterator for RestrictedArrayIntoIter<N, T> {}
+impl<const N: usize, T> DoubleEndedIterator for RestrictedArrayIntoIter<N, T> {
+    fn next_back(&mut self) -> Option<Self::Item> {
+        self.0.next_back()
+    }
+}
+
 impl<const N: usize, T> IntoIterator for RestrictedArray<N, T> {
-    type IntoIter = core::iter::Take<core::iter::Skip<core::array::IntoIter<T, N>>>;
-    type Item = <[T; N] as IntoIterator>::Item;
+    type IntoIter = RestrictedArrayIntoIter<N, T>;
+    type Item = <RestrictedArrayIntoIter<N, T> as Iterator>::Item;
     fn into_iter(self) -> Self::IntoIter {
         let start = self.start;
         let len = self.len();
-        self.array.into_iter().skip(start).take(len)
+        RestrictedArrayIntoIter(self.array.into_iter().skip(start).take(len))
     }
 }
 

From 8b1add357eea9c63635769825e5202d70443d620 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 29 Oct 2023 15:56:05 +0100
Subject: [PATCH 052/212] Simplify docstring

---
 src/array_section.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index e353731..d9ee956 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -30,7 +30,7 @@ impl<const N: usize, T: PartialEq<T>> PartialEq<RestrictedArray<N, T>> for Restr
 }
 
 impl<const N: usize, T> RestrictedArray<N, T> {
-    /// Restrict a given array so that only elements within the given range are viewable.
+    /// Restrict an array so that only elements within the given range are viewable.
     ///
     /// # Panics
     /// Panics if the range of indices is out of bounds of the array.

From 86c840bce3ec2eb370772478c4f9f27a5defdef1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 29 Oct 2023 15:56:25 +0100
Subject: [PATCH 053/212] grammar

---
 src/array_section.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index d9ee956..be36100 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -1,7 +1,7 @@
 use core::{iter::FusedIterator, ops::Range};
 
 /// An array where only a section of the data may be viewed,
-/// as the other data may be e.g. not uphold some invariant.
+/// as the other data may e.g. not uphold some invariant.
 #[derive(Debug)]
 pub struct RestrictedArray<const N: usize, T> {
     start: usize,

From b6b6be749d507b4a276732fcaf332be166e5ba32 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 29 Oct 2023 15:57:49 +0100
Subject: [PATCH 054/212] Add conditional impl of Eq

---
 src/array_section.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/array_section.rs b/src/array_section.rs
index be36100..af42fd4 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -29,6 +29,8 @@ impl<const N: usize, T: PartialEq<T>> PartialEq<RestrictedArray<N, T>> for Restr
     }
 }
 
+impl<const N: usize, T: Eq> Eq for RestrictedArray<N, T> {}
+
 impl<const N: usize, T> RestrictedArray<N, T> {
     /// Restrict an array so that only elements within the given range are viewable.
     ///

From 1a70333df93c0ade2e3629a581052c9cfb7af4a8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 29 Oct 2023 16:02:54 +0100
Subject: [PATCH 055/212] rename array_section to restricted_array

---
 src/{array_section.rs => restricted_array.rs} | 1 +
 1 file changed, 1 insertion(+)
 rename src/{array_section.rs => restricted_array.rs} (98%)

diff --git a/src/array_section.rs b/src/restricted_array.rs
similarity index 98%
rename from src/array_section.rs
rename to src/restricted_array.rs
index af42fd4..2529dd8 100644
--- a/src/array_section.rs
+++ b/src/restricted_array.rs
@@ -112,6 +112,7 @@ impl<const N: usize, T> core::ops::Index<usize> for RestrictedArray<N, T> {
     }
 }
 
+/// Created by the [`IntoIterator`] trait implementation on [`RestrictedArray`].
 pub struct RestrictedArrayIntoIter<const N: usize, T>(
     core::iter::Take<core::iter::Skip<core::array::IntoIter<T, N>>>,
 );

From 823f7d236064e32f119d3c8c385376b33bc566d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 29 Oct 2023 16:08:26 +0100
Subject: [PATCH 056/212] Add restricted_array to the crate as a module

---
 src/lib.rs              |  1 +
 src/restricted_array.rs | 11 +++++++++++
 2 files changed, 12 insertions(+)

diff --git a/src/lib.rs b/src/lib.rs
index bc3b199..d73172a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -97,6 +97,7 @@
 // This is used since there is currently no way to be generic over types that can do arithmetic at compile time.
 type Underlying = u32;
 
+pub mod restricted_array;
 mod generation;
 mod imath;
 mod miller_rabin;
diff --git a/src/restricted_array.rs b/src/restricted_array.rs
index 2529dd8..017cb62 100644
--- a/src/restricted_array.rs
+++ b/src/restricted_array.rs
@@ -73,6 +73,17 @@ impl<const N: usize, T> RestrictedArray<N, T> {
         tail.split_at(self.end - self.start).0
     }
 
+    /// Returns the index of the first element of the underlying array that's not restricted.
+    pub const fn start(&self) -> usize {
+        self.start
+    }
+
+    /// Returns the index of the first element of the underlying array that is
+    /// restricted again after the end of the unrestricted part.
+    pub const fn end(&self) -> usize {
+        self.end
+    }
+
     /// Returns the length of the unrestricted part of the array.
     pub const fn len(&self) -> usize {
         self.end - self.start

From 48f7986821db6e34a6a99721f947d51a12170f58 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 29 Oct 2023 16:09:12 +0100
Subject: [PATCH 057/212] cargo fmt

---
 src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/lib.rs b/src/lib.rs
index d73172a..a14a0da 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -97,11 +97,11 @@
 // This is used since there is currently no way to be generic over types that can do arithmetic at compile time.
 type Underlying = u32;
 
-pub mod restricted_array;
 mod generation;
 mod imath;
 mod miller_rabin;
 mod other_prime;
+pub mod restricted_array;
 mod sieving;
 mod wrapper;
 

From 94a1c2ee22a3fb8f9825e15929456e12e7f0e8b8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 29 Oct 2023 16:13:24 +0100
Subject: [PATCH 058/212] Change order of generic paramters to match array

---
 src/restricted_array.rs | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/src/restricted_array.rs b/src/restricted_array.rs
index 017cb62..aefe596 100644
--- a/src/restricted_array.rs
+++ b/src/restricted_array.rs
@@ -3,13 +3,13 @@ use core::{iter::FusedIterator, ops::Range};
 /// An array where only a section of the data may be viewed,
 /// as the other data may e.g. not uphold some invariant.
 #[derive(Debug)]
-pub struct RestrictedArray<const N: usize, T> {
+pub struct RestrictedArray<T, const N: usize> {
     start: usize,
     end: usize,
     array: [T; N],
 }
 
-impl<const N: usize, T: Clone> Clone for RestrictedArray<N, T> {
+impl<const N: usize, T: Clone> Clone for RestrictedArray<T, N> {
     fn clone(&self) -> Self {
         Self {
             start: self.start,
@@ -19,19 +19,19 @@ impl<const N: usize, T: Clone> Clone for RestrictedArray<N, T> {
     }
 }
 
-impl<const N: usize, T: Copy> Copy for RestrictedArray<N, T> {}
+impl<const N: usize, T: Copy> Copy for RestrictedArray<T, N> {}
 
-impl<const N: usize, T: PartialEq<T>> PartialEq<RestrictedArray<N, T>> for RestrictedArray<N, T> {
+impl<const N: usize, T: PartialEq<T>> PartialEq<RestrictedArray<T, N>> for RestrictedArray<T, N> {
     /// This method tests for `self` and `other` values to be equal, and is used by `==`.  
     /// Only compares the *unrestricted* part of `self` against the *unrestricted* part of `other`.
-    fn eq(&self, other: &RestrictedArray<N, T>) -> bool {
+    fn eq(&self, other: &RestrictedArray<T, N>) -> bool {
         self.as_slice() == other.as_slice()
     }
 }
 
-impl<const N: usize, T: Eq> Eq for RestrictedArray<N, T> {}
+impl<const N: usize, T: Eq> Eq for RestrictedArray<T, N> {}
 
-impl<const N: usize, T> RestrictedArray<N, T> {
+impl<const N: usize, T> RestrictedArray<T, N> {
     /// Restrict an array so that only elements within the given range are viewable.
     ///
     /// # Panics
@@ -107,7 +107,7 @@ impl<const N: usize, T> RestrictedArray<N, T> {
     }
 }
 
-impl<const N: usize, T> core::ops::Index<usize> for RestrictedArray<N, T> {
+impl<const N: usize, T> core::ops::Index<usize> for RestrictedArray<T, N> {
     type Output = T;
     fn index(&self, index: usize) -> &Self::Output {
         let i = match self.start.checked_add(index) {
@@ -146,7 +146,7 @@ impl<const N: usize, T> DoubleEndedIterator for RestrictedArrayIntoIter<N, T> {
     }
 }
 
-impl<const N: usize, T> IntoIterator for RestrictedArray<N, T> {
+impl<const N: usize, T> IntoIterator for RestrictedArray<T, N> {
     type IntoIter = RestrictedArrayIntoIter<N, T>;
     type Item = <RestrictedArrayIntoIter<N, T> as Iterator>::Item;
     fn into_iter(self) -> Self::IntoIter {
@@ -156,7 +156,7 @@ impl<const N: usize, T> IntoIterator for RestrictedArray<N, T> {
     }
 }
 
-impl<const N: usize, T, U> PartialEq<U> for RestrictedArray<N, T>
+impl<const N: usize, T, U> PartialEq<U> for RestrictedArray<T, N>
 where
     U: PartialEq<[T]>,
 {

From cd29f38717ff0d1008ea07f35465ad218f4180c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 29 Oct 2023 18:21:13 +0100
Subject: [PATCH 059/212] PARTIAL COMMIT, primes_geq fails some tests

---
 benches/prime_benches.rs                      |   2 +-
 src/{generation.rs => generation/mod.rs}      |  74 +++++----
 src/generation/segmented_generation_result.rs | 148 ++++++++++++++++++
 src/lib.rs                                    |  20 ++-
 src/restricted_array.rs                       |  22 ++-
 5 files changed, 222 insertions(+), 44 deletions(-)
 rename src/{generation.rs => generation/mod.rs} (76%)
 create mode 100644 src/generation/segmented_generation_result.rs

diff --git a/benches/prime_benches.rs b/benches/prime_benches.rs
index fe8fa80..a4604b3 100644
--- a/benches/prime_benches.rs
+++ b/benches/prime_benches.rs
@@ -1,4 +1,4 @@
-use const_primes::{is_prime, primes, primes_geq, primes_lt, sieve, sieve_geq, sieve_lt};
+use const_primes::{is_prime, primes, generation::{primes_geq, primes_lt}, sieve, sieve_geq, sieve_lt};
 use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput};
 use rand::prelude::*;
 use std::hint::black_box;
diff --git a/src/generation.rs b/src/generation/mod.rs
similarity index 76%
rename from src/generation.rs
rename to src/generation/mod.rs
index 3bcbaf5..bcf62cd 100644
--- a/src/generation.rs
+++ b/src/generation/mod.rs
@@ -1,5 +1,8 @@
-use crate::{sieve, sieving::sieve_segment, Underlying};
+use crate::{restricted_array::RestrictedArray, sieve, sieving::sieve_segment, Underlying};
 
+pub mod segmented_generation_result;
+
+pub use segmented_generation_result::SegmentedGenerationResult;
 /// Returns the `N` first prime numbers.
 ///
 /// [`Primes`](crate::Primes) might be relevant for you if you intend to later use these prime numbers for related computations.
@@ -106,44 +109,46 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// # Example
 /// Basic usage:
 /// ```
-/// # use const_primes::primes_lt;
-/// const PRIMES: [u64; 10] = primes_lt(100);
-///
+/// # use const_primes::generation::{SegmentedGenerationResult, primes_lt};
+/// const PRIMES: SegmentedGenerationResult<10> = primes_lt(100);
+/// assert_eq!(PRIMES[2], 61);
 /// assert_eq!(PRIMES, [53, 59, 61, 67, 71, 73, 79, 83, 89, 97]);
 /// ```
 /// Compute larger primes without starting from zero:
 /// ```
-/// # use const_primes::primes_lt;
+/// # use const_primes::generation::{SegmentedGenerationResult, primes_lt};
 /// const N: usize = 70711;
 /// # #[allow(long_running_const_eval)]
-/// const BIG_PRIMES: [u64; N] = primes_lt(5_000_000_030);
+/// // If the generation results in a completely filled array, it can be extracted like this:
+/// const BIG_PRIMES: [u64; N] = match primes_lt(5_000_000_030).complete() {Some(array) => array, _ => panic!()};
 ///
-/// assert_eq!(&BIG_PRIMES[..3], &[4_998_417_421, 4_998_417_427, 4_998_417_443]);
-/// assert_eq!(&BIG_PRIMES[N - 3..], &[4_999_999_903, 4_999_999_937, 5_000_000_029]);
+/// assert_eq!(BIG_PRIMES[..3],     [4_998_417_421, 4_998_417_427, 4_998_417_443]);
+/// assert_eq!(BIG_PRIMES[N - 3..], [4_999_999_903, 4_999_999_937, 5_000_000_029]);
 /// ```
-/// If there are not enough primes to fill the requested array, the first
-/// elements will have a value of zero:
+/// If there are not enough primes to fill the requested array, 
+/// the output will be the [`SegmentedGenerationResult::Partial`] variant,
+/// which contains fewer primes than requested:
 /// ```
-/// # use const_primes::primes_lt;
-/// const PRIMES: [u64; 9] = primes_lt(10);
-///
-/// assert_eq!(PRIMES, [0, 0, 0, 0, 0, 2, 3, 5, 7]);
+/// # use const_primes::generation::{SegmentedGenerationResult, primes_lt};
+/// const PRIMES: SegmentedGenerationResult<9> = primes_lt(10);
+/// // There are only four primes less than 10:
+/// assert_eq!(PRIMES, [2, 3, 5, 7]);
 /// ```
 /// # Panics
 /// Panics if `N^2` does not fit in a `u64` or if `upper_limit` is larger than `N^2`. This is a compile error
 /// in const contexts:
 /// ```compile_fail
-/// # use const_primes::primes_lt;
-/// //                  N is too large
-/// const PRIMES: [u64; u32::MAX as usize + 1] = primes_lt(100);
+/// # use const_primes::generation::{SegmentedGenerationResult,primes_lt};
+/// //                                       N is too large
+/// const PRIMES: SegmentedGenerationResult<{u32::MAX as usize + 1}> = primes_lt(100);
 /// ```
 /// ```compile_fail
-/// # use const_primes::primes_lt;
-/// //                  N              upper_limit > N^2
-/// const PRIMES: [u64; 5] = primes_lt(26);
+/// # use const_primes::generation::{primes_lt, SegmentedGenerationResult};
+/// //                                      N              upper_limit > N^2
+/// const PRIMES: SegmentedGenerationResult<5> = primes_lt(26);
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
-pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> [u64; N] {
+pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> SegmentedGenerationResult<N> {
     let n64 = N as u64;
     match (n64).checked_mul(n64) {
         Some(prod) => assert!(
@@ -159,7 +164,7 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> [u64; N] {
     let base_sieve: [bool; N] = sieve();
 
     let mut total_primes_found: usize = 0;
-    'generate: while total_primes_found < N && upper_limit > 2 {
+    'generate: while total_primes_found < N {
         // This is the smallest prime we have found so far.
         let mut smallest_found_prime = primes[N - 1 - total_primes_found];
         // Sieve for primes in the segment.
@@ -181,9 +186,13 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> [u64; N] {
             i += 1;
         }
         upper_limit = smallest_found_prime;
+        if upper_limit <= 2 {
+            let restricted = RestrictedArray::new(N - total_primes_found..N, primes);
+            return SegmentedGenerationResult::Partial(restricted);
+        }
     }
 
-    primes
+    SegmentedGenerationResult::Complete(primes)
 }
 
 /// Returns the `N` smallest primes greater than or equal to `lower_limit`.
@@ -222,7 +231,7 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> [u64; N] {
 /// const P: [u64; u32::MAX as usize + 1] = primes_geq(0);
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
-pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> [u64; N] {
+pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> SegmentedGenerationResult<N> {
     let n64 = N as u64;
     if n64.checked_mul(n64).is_none() {
         panic!("`N^2` must fit in a `u64`");
@@ -243,7 +252,8 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> [u64; N] {
                     // We do not know if this is actually a prime
                     // since the base sieve does not contain information about
                     // the prime status of numbers larger than or equal to N.
-                    break 'generate;
+                    let restricted = RestrictedArray::new(0..total_found_primes, primes);
+                    return SegmentedGenerationResult::Partial(restricted);
                 }
                 primes[total_found_primes] = largest_found_prime;
                 total_found_primes += 1;
@@ -256,7 +266,7 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> [u64; N] {
         }
         lower_limit = largest_found_prime + 1;
     }
-    primes
+    SegmentedGenerationResult::Complete(primes)
 }
 
 #[cfg(test)]
@@ -268,20 +278,20 @@ mod test {
     #[test]
     fn sanity_check_primes_geq() {
         {
-            const P: [u64; 5] = primes_geq(10);
+            const P: [u64; 5] = match primes_geq(10).complete() {Some(a) => a, _ => panic!()};
             assert_eq!(P, [11, 13, 17, 19, 23]);
         }
         {
-            const P: [u64; 5] = primes_geq(0);
+            const P: [u64; 5] = match primes_geq(0).complete() {Some(a) => a, _ => panic!()};
             assert_eq!(P, [2, 3, 5, 7, 11]);
         }
         {
-            const P: [u64; 0] = primes_geq(0);
-            assert_eq!(P, []);
+            const P: SegmentedGenerationResult<0> = primes_geq(0);
+            assert_eq!(P.as_ref(), []);
         }
         {
-            const P: [u64; 1] = primes_geq(0);
-            assert_eq!(P, [0]);
+            const P: SegmentedGenerationResult<1> = primes_geq(0);
+            assert_eq!(P, [2]);
         }
         for prime in primes_geq::<2_000>(3_998_000) {
             if prime == 0 {
diff --git a/src/generation/segmented_generation_result.rs b/src/generation/segmented_generation_result.rs
new file mode 100644
index 0000000..8ac2739
--- /dev/null
+++ b/src/generation/segmented_generation_result.rs
@@ -0,0 +1,148 @@
+use core::iter::FusedIterator;
+
+use crate::restricted_array::RestrictedArray;
+
+/// An enum describing whether the requested array could be filled completely, or only a partially.
+/// A partial array can be returned by [`primes_lt`](crate::generation::primes_lt) if the size of the requested
+/// array is larger than the actual number of primes less than the given `upper_limit`.
+/// It can also be returned by [`primes_geq`](crate::generation::primes_geq) if it needs to sieve into a
+/// region of numbers that exceed the square of the size of the requested array.
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum SegmentedGenerationResult<const N: usize> {
+    /// The complete range could be sieved, and the entire output array contains prime numbers.
+    Complete([u64; N]),
+    /// Only a part of the range could be sieved before the primes either exceeded `N^2` or ran out,
+    /// and so only a part of the output array contains prime numbers.
+    Partial(RestrictedArray<u64, N>),
+}
+
+// region: enum convenience method impls
+impl<const N: usize> SegmentedGenerationResult<N> {
+    /// Returns the complete array, if there is one.
+    pub const fn complete(self) -> Option<[u64; N]> {
+        match self {
+            Self::Complete(array) => Some(array),
+            _ => None,
+        }
+    }
+
+    /// Returns the restriced array, if there is one.
+    pub const fn partial(self) -> Option<RestrictedArray<u64, N>> {
+        match self {
+            Self::Partial(restricted_array) => Some(restricted_array),
+            _ => None,
+        }
+    }
+
+    /// Returns `true` if this is the `Complete` variant.
+    pub const fn is_complete(&self) -> bool {
+        match self {
+            Self::Complete(_) => true,
+            _ => false,
+        }
+    }
+
+    /// Returns `true` if this is the `Partial` variant.
+    pub const fn is_partial(&self) -> bool {
+        match self {
+            Self::Partial(_) => true,
+            _ => false,
+        }
+    }
+}
+// endregion: enum convenience method impls
+
+// region: IntoIterator impl
+/// An iterator created by the [`IntoIterator`] impl on [`SegmentedGenerationResult`].
+pub enum SegmentedGenerationResultIntoIter<const N: usize> {
+    Complete(<[u64; N] as IntoIterator>::IntoIter),
+    Partial(<RestrictedArray<u64, N> as IntoIterator>::IntoIter),
+}
+
+impl<const N: usize> Iterator for SegmentedGenerationResultIntoIter<N> {
+    type Item = u64;
+    fn next(&mut self) -> Option<Self::Item> {
+        match self {
+            Self::Complete(array_iter) => array_iter.next(),
+            Self::Partial(restricted_array_iter) => restricted_array_iter.next(),
+        }
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        match self {
+            Self::Complete(array_iter) => array_iter.size_hint(),
+            Self::Partial(restricted_array_iter) => restricted_array_iter.size_hint(),
+        }
+    }
+}
+
+impl<const N: usize> DoubleEndedIterator for SegmentedGenerationResultIntoIter<N> {
+    fn next_back(&mut self) -> Option<Self::Item> {
+        match self {
+            Self::Complete(array_iter) => array_iter.next_back(),
+            Self::Partial(restricted_array_iter) => restricted_array_iter.next_back(),
+        }
+    }
+}
+
+impl<const N: usize> FusedIterator for SegmentedGenerationResultIntoIter<N> {}
+impl<const N: usize> ExactSizeIterator for SegmentedGenerationResultIntoIter<N> {}
+
+impl<const N: usize> IntoIterator for SegmentedGenerationResult<N> {
+    type IntoIter = SegmentedGenerationResultIntoIter<N>;
+    type Item = u64;
+    fn into_iter(self) -> Self::IntoIter {
+        match self {
+            Self::Complete(array) => SegmentedGenerationResultIntoIter::Complete(array.into_iter()),
+            Self::Partial(restricted_array) => {
+                SegmentedGenerationResultIntoIter::Partial(restricted_array.into_iter())
+            }
+        }
+    }
+}
+// endregion: IntoIterator impl
+
+// region: PartialEq impls
+impl<const N: usize, T> PartialEq<T> for SegmentedGenerationResult<N>
+where
+    T: PartialEq<[u64]>,
+{
+    fn eq(&self, other: &T) -> bool {
+        match self {
+            Self::Complete(array) => other == array.as_ref(),
+            Self::Partial(restricted_array) => other == restricted_array.as_slice(),
+        }
+    }
+}
+
+impl<const N: usize, T> PartialEq<SegmentedGenerationResult<N>> for [T]
+where
+    T: PartialEq<u64>,
+{
+    fn eq(&self, other: &SegmentedGenerationResult<N>) -> bool {
+        match other {
+            SegmentedGenerationResult::Complete(array) => self == array,
+            SegmentedGenerationResult::Partial(restricted_array) => restricted_array == self,
+        }
+    }
+}
+// endregion: PartialEq impls
+
+impl<const N: usize> AsRef<[u64]> for SegmentedGenerationResult<N> {
+    fn as_ref(&self) -> &[u64] {
+        match self {
+            Self::Complete(array) => array.as_slice(),
+            Self::Partial(restricted_array) => restricted_array.as_slice(),
+        }
+    }
+}
+
+impl<const N: usize> core::ops::Index<usize> for SegmentedGenerationResult<N> {
+    type Output = u64;
+    fn index(&self, index: usize) -> &Self::Output {
+        match self {
+            Self::Complete(array) => &array[index],
+            Self::Partial(restricted_array) => &restricted_array[index],
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index a14a0da..8152add 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -47,10 +47,10 @@
 //! ```
 //! ## Arbitrary ranges
 //!
-//! The crate provides prime generation and sieving functions with suffixes, e.g. [`primes_geq`] and [`sieve_lt`]
+//! The crate provides prime generation and sieving functions with suffixes, e.g. [`primes_geq`](crate::generation::primes_geq) and [`sieve_lt`]
 //! that can be used to work with ranges that don't start at zero.
 //! ```
-//! # use const_primes::primes_geq;
+//! # use const_primes::generation::primes_geq;
 //! const N: usize = 70722;
 //! # #[allow(long_running_const_eval)]
 //! const PRIMES_GEQ: [u64; N] = primes_geq(5_000_000_031);
@@ -97,7 +97,7 @@
 // This is used since there is currently no way to be generic over types that can do arithmetic at compile time.
 type Underlying = u32;
 
-mod generation;
+pub mod generation;
 mod imath;
 mod miller_rabin;
 mod other_prime;
@@ -105,7 +105,7 @@ pub mod restricted_array;
 mod sieving;
 mod wrapper;
 
-pub use generation::{primes, primes_geq, primes_lt};
+pub use generation::primes;
 use imath::isqrt;
 pub use miller_rabin::is_prime;
 pub use other_prime::{next_prime, previous_prime};
@@ -150,6 +150,8 @@ pub const fn prime_counts<const N: usize>() -> [usize; N] {
 mod test {
     use super::*;
 
+    use generation::{primes_lt, segmented_generation_result::SegmentedGenerationResult};
+
     #[test]
     fn check_primes_is_prime() {
         const SET: Primes<3> = Primes::new();
@@ -233,8 +235,10 @@ mod test {
             ($($n:expr),+) => {
                 $(
                     {
-                        const P: [u64; $n] = primes_lt(100);
-                        assert_eq!(PRECOMPUTED_PRIMES[25-$n..25], P.map(|i|i as u32));
+                        const P: SegmentedGenerationResult<$n> = primes_lt(100);
+                        for (i, prime) in P.into_iter().enumerate() {
+                            assert_eq!(PRECOMPUTED_PRIMES[25-$n..25][i], prime as u32);
+                        }
                         assert_eq!(
                             PRECOMPUTED_PRIMES[25-$n..25],
                             primes_lt::<$n>(100).into_iter().map(|i|i as u32).collect::<Vec<_>>()
@@ -246,9 +250,9 @@ mod test {
 
         test_n_below_100!(10, 15, 20);
 
-        assert_eq!([0, 0, 0, 0, 0, 2, 3, 5, 7], primes_lt(10));
+        assert_eq!([2, 3, 5, 7], primes_lt::<9>(10).as_ref());
 
-        assert_eq!([0, 2], primes_lt(3));
+        assert_eq!(primes_lt::<2>(3), [2]);
     }
 
     #[test]
diff --git a/src/restricted_array.rs b/src/restricted_array.rs
index aefe596..755eadd 100644
--- a/src/restricted_array.rs
+++ b/src/restricted_array.rs
@@ -156,13 +156,29 @@ impl<const N: usize, T> IntoIterator for RestrictedArray<T, N> {
     }
 }
 
-impl<const N: usize, T, U> PartialEq<U> for RestrictedArray<T, N>
+// region: PartialEq impls
+impl<const N: usize, T, U> PartialEq<[U]> for RestrictedArray<T, N>
 where
-    U: PartialEq<[T]>,
+    U: PartialEq<T>,
 {
     /// This method tests for `self` and `other` values to be equal, and is used by `==`.  
     /// Only compares the *unrestricted* part of `self` against `other`.
-    fn eq(&self, other: &U) -> bool {
+    fn eq(&self, other: &[U]) -> bool {
         other == self.as_slice()
     }
 }
+
+impl<const N: usize, T, U: PartialEq<T>> PartialEq<RestrictedArray<T, N>> for [U] {
+    /// This method tests for `self` and `other` values to be equal, and is used by `==`.  
+    /// Only compares the *unrestricted* part of `other` against `self`.
+    fn eq(&self, other: &RestrictedArray<T, N>) -> bool {
+        self == other.as_slice()
+    }
+}
+// endregion: PartialEq impls
+
+impl<const N: usize, T> AsRef<[T]> for RestrictedArray<T, N> {
+    fn as_ref(&self) -> &[T] {
+        self.as_slice()
+    }
+}
\ No newline at end of file

From 5a131630bf5acb4300513a52fc537eb8879fd527 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 30 Oct 2023 12:18:35 +0100
Subject: [PATCH 060/212] Shorten docstring of enum variants

---
 src/generation/segmented_generation_result.rs | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/generation/segmented_generation_result.rs b/src/generation/segmented_generation_result.rs
index 8ac2739..ac90520 100644
--- a/src/generation/segmented_generation_result.rs
+++ b/src/generation/segmented_generation_result.rs
@@ -9,10 +9,9 @@ use crate::restricted_array::RestrictedArray;
 /// region of numbers that exceed the square of the size of the requested array.
 #[derive(Debug, Clone, Copy, PartialEq)]
 pub enum SegmentedGenerationResult<const N: usize> {
-    /// The complete range could be sieved, and the entire output array contains prime numbers.
+    /// The entire output array contains prime numbers.
     Complete([u64; N]),
-    /// Only a part of the range could be sieved before the primes either exceeded `N^2` or ran out,
-    /// and so only a part of the output array contains prime numbers.
+    /// Only a part of the output array contains prime numbers as they either exceeded `N^2` or ran out.
     Partial(RestrictedArray<u64, N>),
 }
 

From f41eeea8bf45c50fcdd5e76f9b5906f858586348 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 30 Oct 2023 12:28:17 +0100
Subject: [PATCH 061/212] Talk about RestrictedArray in terms of visiblillity

---
 benches/prime_benches.rs                      |  5 ++-
 src/generation/mod.rs                         | 12 +++++--
 src/generation/segmented_generation_result.rs |  2 +-
 src/restricted_array.rs                       | 34 ++++++++++---------
 4 files changed, 32 insertions(+), 21 deletions(-)

diff --git a/benches/prime_benches.rs b/benches/prime_benches.rs
index a4604b3..21c2cdf 100644
--- a/benches/prime_benches.rs
+++ b/benches/prime_benches.rs
@@ -1,4 +1,7 @@
-use const_primes::{is_prime, primes, generation::{primes_geq, primes_lt}, sieve, sieve_geq, sieve_lt};
+use const_primes::{
+    generation::{primes_geq, primes_lt},
+    is_prime, primes, sieve, sieve_geq, sieve_lt,
+};
 use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput};
 use rand::prelude::*;
 use std::hint::black_box;
diff --git a/src/generation/mod.rs b/src/generation/mod.rs
index bcf62cd..201c0a1 100644
--- a/src/generation/mod.rs
+++ b/src/generation/mod.rs
@@ -125,7 +125,7 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// assert_eq!(BIG_PRIMES[..3],     [4_998_417_421, 4_998_417_427, 4_998_417_443]);
 /// assert_eq!(BIG_PRIMES[N - 3..], [4_999_999_903, 4_999_999_937, 5_000_000_029]);
 /// ```
-/// If there are not enough primes to fill the requested array, 
+/// If there are not enough primes to fill the requested array,
 /// the output will be the [`SegmentedGenerationResult::Partial`] variant,
 /// which contains fewer primes than requested:
 /// ```
@@ -278,11 +278,17 @@ mod test {
     #[test]
     fn sanity_check_primes_geq() {
         {
-            const P: [u64; 5] = match primes_geq(10).complete() {Some(a) => a, _ => panic!()};
+            const P: [u64; 5] = match primes_geq(10).complete() {
+                Some(a) => a,
+                _ => panic!(),
+            };
             assert_eq!(P, [11, 13, 17, 19, 23]);
         }
         {
-            const P: [u64; 5] = match primes_geq(0).complete() {Some(a) => a, _ => panic!()};
+            const P: [u64; 5] = match primes_geq(0).complete() {
+                Some(a) => a,
+                _ => panic!(),
+            };
             assert_eq!(P, [2, 3, 5, 7, 11]);
         }
         {
diff --git a/src/generation/segmented_generation_result.rs b/src/generation/segmented_generation_result.rs
index ac90520..f817ff7 100644
--- a/src/generation/segmented_generation_result.rs
+++ b/src/generation/segmented_generation_result.rs
@@ -144,4 +144,4 @@ impl<const N: usize> core::ops::Index<usize> for SegmentedGenerationResult<N> {
             Self::Partial(restricted_array) => &restricted_array[index],
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/restricted_array.rs b/src/restricted_array.rs
index 755eadd..ef69ea3 100644
--- a/src/restricted_array.rs
+++ b/src/restricted_array.rs
@@ -23,7 +23,7 @@ impl<const N: usize, T: Copy> Copy for RestrictedArray<T, N> {}
 
 impl<const N: usize, T: PartialEq<T>> PartialEq<RestrictedArray<T, N>> for RestrictedArray<T, N> {
     /// This method tests for `self` and `other` values to be equal, and is used by `==`.  
-    /// Only compares the *unrestricted* part of `self` against the *unrestricted* part of `other`.
+    /// Only compares the *visible* part of `self` against the *visible* part of `other`.
     fn eq(&self, other: &RestrictedArray<T, N>) -> bool {
         self.as_slice() == other.as_slice()
     }
@@ -32,7 +32,7 @@ impl<const N: usize, T: PartialEq<T>> PartialEq<RestrictedArray<T, N>> for Restr
 impl<const N: usize, T: Eq> Eq for RestrictedArray<T, N> {}
 
 impl<const N: usize, T> RestrictedArray<T, N> {
-    /// Restrict an array so that only elements within the given range are viewable.
+    /// Restrict an array so that only elements within the given range are visible.
     ///
     /// # Panics
     /// Panics if the range of indices is out of bounds of the array.
@@ -57,51 +57,53 @@ impl<const N: usize, T> RestrictedArray<T, N> {
         }
     }
 
-    /// Returns a reference to the full underlying array.
+    /// Returns a reference to the full underlying array. There is no guarantee about the data
+    /// outside the visible region.
     pub const fn as_full_array(&self) -> &[T; N] {
         &self.array
     }
 
-    /// Converts `self` into the full underlying array.
+    /// Converts `self` into the full underlying array. There is no guarantee about the data
+    /// outside the visible region.
     pub fn into_full_array(self) -> [T; N] {
         self.array
     }
 
-    /// Returns the unrestricted part of the array as a slice.
+    /// Returns the visible part of the array as a slice.
     pub const fn as_slice(&self) -> &[T] {
         let (_, tail) = self.array.split_at(self.start);
         tail.split_at(self.end - self.start).0
     }
 
-    /// Returns the index of the first element of the underlying array that's not restricted.
+    /// Returns the index of the first element of the underlying array that's inside the visible region.
     pub const fn start(&self) -> usize {
         self.start
     }
 
     /// Returns the index of the first element of the underlying array that is
-    /// restricted again after the end of the unrestricted part.
+    /// invisible again after the end of the visible part.
     pub const fn end(&self) -> usize {
         self.end
     }
 
-    /// Returns the length of the unrestricted part of the array.
+    /// Returns the length of the visible part of the array.
     pub const fn len(&self) -> usize {
         self.end - self.start
     }
 
-    /// Returns whether the unrestricted part is empty.
+    /// Returns whether the visible part is empty.
     pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
 
-    /// Returns whether there are parts of the array that are restricted.
-    /// If this is `false` it is completely fine to call [`as_full_array`](RestrictedArray::as_full_array)
+    /// Returns whether there are no parts of the array that are invisible.
+    /// If this is `true` it is completely fine to call [`as_full_array`](RestrictedArray::as_full_array)
     /// or [`into_full_array`](RestrictedArray::into_full_array).
-    pub const fn is_restricted(&self) -> bool {
+    pub const fn is_fully_visible(&self) -> bool {
         self.len() == N
     }
 
-    /// Returns an iterator over the unrestricted section.
+    /// Returns an iterator over the visible section.
     pub fn iter(&self) -> core::slice::Iter<'_, T> {
         self.as_slice().iter()
     }
@@ -162,7 +164,7 @@ where
     U: PartialEq<T>,
 {
     /// This method tests for `self` and `other` values to be equal, and is used by `==`.  
-    /// Only compares the *unrestricted* part of `self` against `other`.
+    /// Only compares the *visible* part of `self` against `other`.
     fn eq(&self, other: &[U]) -> bool {
         other == self.as_slice()
     }
@@ -170,7 +172,7 @@ where
 
 impl<const N: usize, T, U: PartialEq<T>> PartialEq<RestrictedArray<T, N>> for [U] {
     /// This method tests for `self` and `other` values to be equal, and is used by `==`.  
-    /// Only compares the *unrestricted* part of `other` against `self`.
+    /// Only compares the *visible* part of `other` against `self`.
     fn eq(&self, other: &RestrictedArray<T, N>) -> bool {
         self == other.as_slice()
     }
@@ -181,4 +183,4 @@ impl<const N: usize, T> AsRef<[T]> for RestrictedArray<T, N> {
     fn as_ref(&self) -> &[T] {
         self.as_slice()
     }
-}
\ No newline at end of file
+}

From c5e5daf4cf06740b4b73b17173b401bc55af6f56 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 30 Oct 2023 12:32:10 +0100
Subject: [PATCH 062/212] Improve docstring for RestrictedArrayIntoIter

---
 src/restricted_array.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/restricted_array.rs b/src/restricted_array.rs
index ef69ea3..9ee059e 100644
--- a/src/restricted_array.rs
+++ b/src/restricted_array.rs
@@ -125,7 +125,7 @@ impl<const N: usize, T> core::ops::Index<usize> for RestrictedArray<T, N> {
     }
 }
 
-/// Created by the [`IntoIterator`] trait implementation on [`RestrictedArray`].
+/// Created by the [`into_iter`](RestrictedArray::into_iter) function on [`RestrictedArray`], see it for more information.
 pub struct RestrictedArrayIntoIter<const N: usize, T>(
     core::iter::Take<core::iter::Skip<core::array::IntoIter<T, N>>>,
 );

From 1e38b8947cd4b27f73d15c3c5e242e127b840e36 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 30 Oct 2023 12:35:10 +0100
Subject: [PATCH 063/212] Add note about comparisons to RestirctedArray
 docstring

---
 src/restricted_array.rs | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/restricted_array.rs b/src/restricted_array.rs
index 9ee059e..36a6524 100644
--- a/src/restricted_array.rs
+++ b/src/restricted_array.rs
@@ -1,7 +1,9 @@
 use core::{iter::FusedIterator, ops::Range};
 
 /// An array where only a section of the data may be viewed,
-/// as the other data may e.g. not uphold some invariant.
+/// as the other data may e.g. not uphold some invariant.  
+/// When this type is compared against some other type, only
+/// data in the visible part is compared.
 #[derive(Debug)]
 pub struct RestrictedArray<T, const N: usize> {
     start: usize,

From 9445e49211e9f4fc245f62728ea2cc9ba91a12aa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 Nov 2023 08:31:04 +0100
Subject: [PATCH 064/212] Refactor result

---
 src/{generation/mod.rs => generation.rs}      | 120 +++++++++-----
 src/generation/segmented_generation_result.rs | 147 ------------------
 src/lib.rs                                    |  28 +++-
 3 files changed, 103 insertions(+), 192 deletions(-)
 rename src/{generation/mod.rs => generation.rs} (70%)
 delete mode 100644 src/generation/segmented_generation_result.rs

diff --git a/src/generation/mod.rs b/src/generation.rs
similarity index 70%
rename from src/generation/mod.rs
rename to src/generation.rs
index 201c0a1..a28edf5 100644
--- a/src/generation/mod.rs
+++ b/src/generation.rs
@@ -1,8 +1,10 @@
+use core::fmt;
+
 use crate::{restricted_array::RestrictedArray, sieve, sieving::sieve_segment, Underlying};
 
-pub mod segmented_generation_result;
+/// Type alias for the type returned by the segmented generation functions, that otherwise has two generics that must be the same.
+pub type SegmentedGenerationResult<const N: usize> = Result<[u64; N], SegmentedGenerationError<N>>;
 
-pub use segmented_generation_result::SegmentedGenerationResult;
 /// Returns the `N` first prime numbers.
 ///
 /// [`Primes`](crate::Primes) might be relevant for you if you intend to later use these prime numbers for related computations.
@@ -109,30 +111,35 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// # Example
 /// Basic usage:
 /// ```
-/// # use const_primes::generation::{SegmentedGenerationResult, primes_lt};
+/// # use const_primes::generation::{SegmentedGenerationResult, primes_lt, SegmentedGenerationError};
 /// const PRIMES: SegmentedGenerationResult<10> = primes_lt(100);
-/// assert_eq!(PRIMES[2], 61);
-/// assert_eq!(PRIMES, [53, 59, 61, 67, 71, 73, 79, 83, 89, 97]);
+/// assert_eq!(PRIMES?, [53, 59, 61, 67, 71, 73, 79, 83, 89, 97]);
+/// # Ok::<(), SegmentedGenerationError<10>>(())
 /// ```
 /// Compute larger primes without starting from zero:
 /// ```
-/// # use const_primes::generation::{SegmentedGenerationResult, primes_lt};
+/// # use const_primes::generation::{SegmentedGenerationResult, primes_lt, SegmentedGenerationError};
 /// const N: usize = 70711;
 /// # #[allow(long_running_const_eval)]
 /// // If the generation results in a completely filled array, it can be extracted like this:
-/// const BIG_PRIMES: [u64; N] = match primes_lt(5_000_000_030).complete() {Some(array) => array, _ => panic!()};
+/// const BIG_PRIMES: SegmentedGenerationResult<N> = primes_lt(5_000_000_030);
 ///
-/// assert_eq!(BIG_PRIMES[..3],     [4_998_417_421, 4_998_417_427, 4_998_417_443]);
-/// assert_eq!(BIG_PRIMES[N - 3..], [4_999_999_903, 4_999_999_937, 5_000_000_029]);
+/// assert_eq!(BIG_PRIMES?[..3],     [4_998_417_421, 4_998_417_427, 4_998_417_443]);
+/// assert_eq!(BIG_PRIMES?[N - 3..], [4_999_999_903, 4_999_999_937, 5_000_000_029]);
+/// # Ok::<(), SegmentedGenerationError<N>>(())
 /// ```
 /// If there are not enough primes to fill the requested array,
-/// the output will be the [`SegmentedGenerationResult::Partial`] variant,
+/// the output will be the [`SegmentedGenerationError::PartialOk`] variant,
 /// which contains fewer primes than requested:
 /// ```
 /// # use const_primes::generation::{SegmentedGenerationResult, primes_lt};
 /// const PRIMES: SegmentedGenerationResult<9> = primes_lt(10);
-/// // There are only four primes less than 10:
-/// assert_eq!(PRIMES, [2, 3, 5, 7]);
+/// match PRIMES.err() {
+///     Some(SegmentedGenerationError::PartialOk(arr)) => {
+///         // There are only four primes less than 10:
+///         assert_eq!(arr.as_slice(), [2, 3, 5, 7]);}
+///     _ => panic!(),
+/// }
 /// ```
 /// # Panics
 /// Panics if `N^2` does not fit in a `u64` or if `upper_limit` is larger than `N^2`. This is a compile error
@@ -151,11 +158,12 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> SegmentedGenerationResult<N> {
     let n64 = N as u64;
     match (n64).checked_mul(n64) {
-        Some(prod) => assert!(
-            upper_limit <= prod,
-            "`upper_limit` must be less than or equal to `N^2`"
-        ),
-        None => panic!("`N^2` must fit in a `u64`"),
+        Some(prod) => {
+            if upper_limit > prod {
+                return Err(SegmentedGenerationError::TooLargeLimit);
+            }
+        }
+        None => return Err(SegmentedGenerationError::TooLargeN),
     }
 
     let mut primes: [u64; N] = [0; N];
@@ -186,13 +194,13 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> SegmentedGenerat
             i += 1;
         }
         upper_limit = smallest_found_prime;
-        if upper_limit <= 2 {
+        if upper_limit <= 2 && total_primes_found < N {
             let restricted = RestrictedArray::new(N - total_primes_found..N, primes);
-            return SegmentedGenerationResult::Partial(restricted);
+            return Err(SegmentedGenerationError::PartialOk(restricted));
         }
     }
 
-    SegmentedGenerationResult::Complete(primes)
+    Ok(primes)
 }
 
 /// Returns the `N` smallest primes greater than or equal to `lower_limit`.
@@ -234,7 +242,7 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> SegmentedGenerat
 pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> SegmentedGenerationResult<N> {
     let n64 = N as u64;
     if n64.checked_mul(n64).is_none() {
-        panic!("`N^2` must fit in a `u64`");
+        return Err(SegmentedGenerationError::TooLargeN);
     }
 
     let mut primes = [0; N];
@@ -253,7 +261,7 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> SegmentedGenera
                     // since the base sieve does not contain information about
                     // the prime status of numbers larger than or equal to N.
                     let restricted = RestrictedArray::new(0..total_found_primes, primes);
-                    return SegmentedGenerationResult::Partial(restricted);
+                    return Err(SegmentedGenerationError::PartialOk(restricted));
                 }
                 primes[total_found_primes] = largest_found_prime;
                 total_found_primes += 1;
@@ -266,7 +274,47 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> SegmentedGenera
         }
         lower_limit = largest_found_prime + 1;
     }
-    SegmentedGenerationResult::Complete(primes)
+    Ok(primes)
+}
+
+/// An enum describing whether the requested array could be filled completely, or only a partially.
+/// A partial array can be returned by [`primes_lt`](crate::generation::primes_lt) if the size of the requested
+/// array is larger than the actual number of primes less than the given `upper_limit`.
+/// It can also be returned by [`primes_geq`](crate::generation::primes_geq) if it needs to sieve into a
+/// region of numbers that exceed the square of the size of the requested array.
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub enum SegmentedGenerationError<const N: usize> {
+    /// `N^2`` did not fit in a `u64`.
+    TooLargeN,
+    /// the upper limit was larger than `N^2`.
+    TooLargeLimit,
+    /// Only a part of the output array contains prime numbers as they either exceeded `N^2` or ran out.
+    PartialOk(RestrictedArray<u64, N>),
+}
+
+impl<const N: usize> SegmentedGenerationError<N> {
+    /// Returns the partial result as a restricted array, if there is one.
+    pub const fn partial_ok(self) -> Option<RestrictedArray<u64, N>> {
+        match self {
+            Self::PartialOk(restricted_array) => Some(restricted_array),
+            _ => None,
+        }
+    }
+
+    /// Returns `true` if this is the `PartialOk` variant.
+    pub const fn is_partial_ok(&self) -> bool {
+        matches!(self, Self::PartialOk(_))
+    }
+}
+
+impl<const N: usize> fmt::Display for SegmentedGenerationError<N> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            Self::TooLargeN => write!(f, "`N^2` did not fit in a `u64`"),
+            Self::TooLargeLimit => write!(f, "the upper limit was larger than `N^2`"),
+            Self::PartialOk(_) => write!(f, "the sieve entered into a range it's too small for, or the primes ran out. You can access the partially completed result with the function `partial_result`"),
+        }
+    }
 }
 
 #[cfg(test)]
@@ -278,28 +326,22 @@ mod test {
     #[test]
     fn sanity_check_primes_geq() {
         {
-            const P: [u64; 5] = match primes_geq(10).complete() {
-                Some(a) => a,
-                _ => panic!(),
-            };
-            assert_eq!(P, [11, 13, 17, 19, 23]);
+            const P: SegmentedGenerationResult<5> = primes_geq(10);
+            assert_eq!(P, Ok([11, 13, 17, 19, 23]));
         }
         {
-            const P: [u64; 5] = match primes_geq(0).complete() {
-                Some(a) => a,
-                _ => panic!(),
-            };
-            assert_eq!(P, [2, 3, 5, 7, 11]);
-        }
-        {
-            const P: SegmentedGenerationResult<0> = primes_geq(0);
-            assert_eq!(P.as_ref(), []);
+            const P: SegmentedGenerationResult<5> = primes_geq(0);
+            assert_eq!(P, Ok([2, 3, 5, 7, 11]));
         }
         {
             const P: SegmentedGenerationResult<1> = primes_geq(0);
-            assert_eq!(P, [2]);
+            assert_eq!(P, Err(SegmentedGenerationError::TooLargeLimit));
         }
-        for prime in primes_geq::<2_000>(3_998_000) {
+        for prime in primes_geq::<2_000>(3_998_000)
+            .unwrap_err()
+            .partial_ok()
+            .unwrap()
+        {
             if prime == 0 {
                 break;
             }
diff --git a/src/generation/segmented_generation_result.rs b/src/generation/segmented_generation_result.rs
deleted file mode 100644
index f817ff7..0000000
--- a/src/generation/segmented_generation_result.rs
+++ /dev/null
@@ -1,147 +0,0 @@
-use core::iter::FusedIterator;
-
-use crate::restricted_array::RestrictedArray;
-
-/// An enum describing whether the requested array could be filled completely, or only a partially.
-/// A partial array can be returned by [`primes_lt`](crate::generation::primes_lt) if the size of the requested
-/// array is larger than the actual number of primes less than the given `upper_limit`.
-/// It can also be returned by [`primes_geq`](crate::generation::primes_geq) if it needs to sieve into a
-/// region of numbers that exceed the square of the size of the requested array.
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum SegmentedGenerationResult<const N: usize> {
-    /// The entire output array contains prime numbers.
-    Complete([u64; N]),
-    /// Only a part of the output array contains prime numbers as they either exceeded `N^2` or ran out.
-    Partial(RestrictedArray<u64, N>),
-}
-
-// region: enum convenience method impls
-impl<const N: usize> SegmentedGenerationResult<N> {
-    /// Returns the complete array, if there is one.
-    pub const fn complete(self) -> Option<[u64; N]> {
-        match self {
-            Self::Complete(array) => Some(array),
-            _ => None,
-        }
-    }
-
-    /// Returns the restriced array, if there is one.
-    pub const fn partial(self) -> Option<RestrictedArray<u64, N>> {
-        match self {
-            Self::Partial(restricted_array) => Some(restricted_array),
-            _ => None,
-        }
-    }
-
-    /// Returns `true` if this is the `Complete` variant.
-    pub const fn is_complete(&self) -> bool {
-        match self {
-            Self::Complete(_) => true,
-            _ => false,
-        }
-    }
-
-    /// Returns `true` if this is the `Partial` variant.
-    pub const fn is_partial(&self) -> bool {
-        match self {
-            Self::Partial(_) => true,
-            _ => false,
-        }
-    }
-}
-// endregion: enum convenience method impls
-
-// region: IntoIterator impl
-/// An iterator created by the [`IntoIterator`] impl on [`SegmentedGenerationResult`].
-pub enum SegmentedGenerationResultIntoIter<const N: usize> {
-    Complete(<[u64; N] as IntoIterator>::IntoIter),
-    Partial(<RestrictedArray<u64, N> as IntoIterator>::IntoIter),
-}
-
-impl<const N: usize> Iterator for SegmentedGenerationResultIntoIter<N> {
-    type Item = u64;
-    fn next(&mut self) -> Option<Self::Item> {
-        match self {
-            Self::Complete(array_iter) => array_iter.next(),
-            Self::Partial(restricted_array_iter) => restricted_array_iter.next(),
-        }
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        match self {
-            Self::Complete(array_iter) => array_iter.size_hint(),
-            Self::Partial(restricted_array_iter) => restricted_array_iter.size_hint(),
-        }
-    }
-}
-
-impl<const N: usize> DoubleEndedIterator for SegmentedGenerationResultIntoIter<N> {
-    fn next_back(&mut self) -> Option<Self::Item> {
-        match self {
-            Self::Complete(array_iter) => array_iter.next_back(),
-            Self::Partial(restricted_array_iter) => restricted_array_iter.next_back(),
-        }
-    }
-}
-
-impl<const N: usize> FusedIterator for SegmentedGenerationResultIntoIter<N> {}
-impl<const N: usize> ExactSizeIterator for SegmentedGenerationResultIntoIter<N> {}
-
-impl<const N: usize> IntoIterator for SegmentedGenerationResult<N> {
-    type IntoIter = SegmentedGenerationResultIntoIter<N>;
-    type Item = u64;
-    fn into_iter(self) -> Self::IntoIter {
-        match self {
-            Self::Complete(array) => SegmentedGenerationResultIntoIter::Complete(array.into_iter()),
-            Self::Partial(restricted_array) => {
-                SegmentedGenerationResultIntoIter::Partial(restricted_array.into_iter())
-            }
-        }
-    }
-}
-// endregion: IntoIterator impl
-
-// region: PartialEq impls
-impl<const N: usize, T> PartialEq<T> for SegmentedGenerationResult<N>
-where
-    T: PartialEq<[u64]>,
-{
-    fn eq(&self, other: &T) -> bool {
-        match self {
-            Self::Complete(array) => other == array.as_ref(),
-            Self::Partial(restricted_array) => other == restricted_array.as_slice(),
-        }
-    }
-}
-
-impl<const N: usize, T> PartialEq<SegmentedGenerationResult<N>> for [T]
-where
-    T: PartialEq<u64>,
-{
-    fn eq(&self, other: &SegmentedGenerationResult<N>) -> bool {
-        match other {
-            SegmentedGenerationResult::Complete(array) => self == array,
-            SegmentedGenerationResult::Partial(restricted_array) => restricted_array == self,
-        }
-    }
-}
-// endregion: PartialEq impls
-
-impl<const N: usize> AsRef<[u64]> for SegmentedGenerationResult<N> {
-    fn as_ref(&self) -> &[u64] {
-        match self {
-            Self::Complete(array) => array.as_slice(),
-            Self::Partial(restricted_array) => restricted_array.as_slice(),
-        }
-    }
-}
-
-impl<const N: usize> core::ops::Index<usize> for SegmentedGenerationResult<N> {
-    type Output = u64;
-    fn index(&self, index: usize) -> &Self::Output {
-        match self {
-            Self::Complete(array) => &array[index],
-            Self::Partial(restricted_array) => &restricted_array[index],
-        }
-    }
-}
diff --git a/src/lib.rs b/src/lib.rs
index 8152add..4f353af 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -150,7 +150,7 @@ pub const fn prime_counts<const N: usize>() -> [usize; N] {
 mod test {
     use super::*;
 
-    use generation::{primes_lt, segmented_generation_result::SegmentedGenerationResult};
+    use generation::{primes_lt, SegmentedGenerationError};
 
     #[test]
     fn check_primes_is_prime() {
@@ -235,13 +235,13 @@ mod test {
             ($($n:expr),+) => {
                 $(
                     {
-                        const P: SegmentedGenerationResult<$n> = primes_lt(100);
-                        for (i, prime) in P.into_iter().enumerate() {
+                        const P: Result<[u64; 10], SegmentedGenerationError<10>> = primes_lt(100);
+                        for (i, prime) in P.unwrap().into_iter().enumerate() {
                             assert_eq!(PRECOMPUTED_PRIMES[25-$n..25][i], prime as u32);
                         }
                         assert_eq!(
                             PRECOMPUTED_PRIMES[25-$n..25],
-                            primes_lt::<$n>(100).into_iter().map(|i|i as u32).collect::<Vec<_>>()
+                            primes_lt::<$n>(100).unwrap().into_iter().map(|i|i as u32).collect::<Vec<_>>()
                         );
                     }
                 )+
@@ -250,9 +250,25 @@ mod test {
 
         test_n_below_100!(10, 15, 20);
 
-        assert_eq!([2, 3, 5, 7], primes_lt::<9>(10).as_ref());
+        assert_eq!(
+            [2, 3, 5, 7],
+            primes_lt::<9>(10)
+                .err()
+                .unwrap()
+                .partial_ok()
+                .unwrap()
+                .as_slice()
+        );
 
-        assert_eq!(primes_lt::<2>(3), [2]);
+        assert_eq!(
+            primes_lt::<2>(3)
+                .err()
+                .unwrap()
+                .partial_ok()
+                .unwrap()
+                .as_slice(),
+            [2]
+        );
     }
 
     #[test]

From 05a68b67492b5dccb245d93e397c22c219d86aac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 Nov 2023 13:13:55 +0100
Subject: [PATCH 065/212] smallest_prime_geq --> next_prime

---
 src/wrapper.rs | 35 +++++++++++++++++++++--------------
 1 file changed, 21 insertions(+), 14 deletions(-)

diff --git a/src/wrapper.rs b/src/wrapper.rs
index 5d85db5..97ba1fd 100644
--- a/src/wrapper.rs
+++ b/src/wrapper.rs
@@ -151,21 +151,28 @@ impl<const N: usize> Primes<N> {
         }
     }
 
-    /// Returns the smallest prime greater than or equal to `n`.  
-    /// If `n` is larger than the largest prime in `self` this returns `None`.
+    /// Returns the smallest prime greater than `n`.  
+    /// If `n` is larger than or equal to the largest prime in `self` this returns `None`.
     ///
     /// Uses a binary search.
     /// # Example
     /// ```
     /// # use const_primes::Primes;
     /// const CACHE: Primes<100> = Primes::new();
-    /// const SPGEQ: Option<u32> = CACHE.smallest_prime_geq(400);
-    /// assert_eq!(SPGEQ, Some(401));
+    /// const NEXT: Option<u32> = CACHE.next_prime(400);
+    /// assert_eq!(NEXT, Some(401));
     /// ```
     #[must_use = "the method only returns a new value and does not modify `self`"]
-    pub const fn smallest_prime_geq(&self, n: Underlying) -> Option<Underlying> {
+    pub const fn next_prime(&self, n: Underlying) -> Option<Underlying> {
         match self.binary_search(n) {
-            Ok(i) | Err(Some(i)) => Some(self.primes[i]),
+            Ok(i) => {
+                if i + 1 < self.len() {
+                    Some(self.primes[i + 1])
+                } else {
+                    None
+                }
+            }
+            Err(Some(i)) => Some(self.primes[i]),
             Err(None) => None,
         }
     }
@@ -494,27 +501,27 @@ mod test {
     }
 
     #[test]
-    fn check_smallest_prime_geq() {
+    fn check_next_prime() {
         const CACHE: Primes<100> = Primes::new();
-        const SPGEQ0: Option<Underlying> = CACHE.smallest_prime_geq(0);
-        const SPGEQ400: Option<Underlying> = CACHE.smallest_prime_geq(400);
-        const SPGEQ541: Option<Underlying> = CACHE.smallest_prime_geq(541);
-        const SPGEQ542: Option<Underlying> = CACHE.smallest_prime_geq(542);
+        const SPGEQ0: Option<Underlying> = CACHE.next_prime(0);
+        const SPGEQ400: Option<Underlying> = CACHE.next_prime(400);
+        const SPGEQ541: Option<Underlying> = CACHE.next_prime(540);
+        const SPGEQ542: Option<Underlying> = CACHE.next_prime(541);
         assert_eq!(SPGEQ0, Some(2));
         assert_eq!(SPGEQ400, Some(401));
         assert_eq!(SPGEQ541, Some(541));
         assert_eq!(SPGEQ542, None);
 
-        const N: usize = 32;
+        const N: usize = 31;
         const NEXT_PRIME: [u32; N] = [
-            2, 2, 2, 3, 5, 5, 7, 7, 11, 11, 11, 11, 13, 13, 17, 17, 17, 17, 19, 19, 23, 23, 23, 23,
+            2, 2, 3, 5, 5, 7, 7, 11, 11, 11, 11, 13, 13, 17, 17, 17, 17, 19, 19, 23, 23, 23, 23,
             29, 29, 29, 29, 29, 29, 31, 31,
         ];
         const P: Primes<N> = Primes::new();
 
         for n in 0..N {
             println!("{n}");
-            assert_eq!(P.smallest_prime_geq(n as u32), Some(NEXT_PRIME[n]));
+            assert_eq!(P.next_prime(n as u32), Some(NEXT_PRIME[n]));
         }
     }
 

From 7d843a9db593d0ccceb21c6c4accd9d427369dde Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 Nov 2023 13:25:32 +0100
Subject: [PATCH 066/212] rename largest_prime_leq to previous_prime

---
 src/wrapper.rs | 46 +++++++++++++++++++++++++++++-----------------
 1 file changed, 29 insertions(+), 17 deletions(-)

diff --git a/src/wrapper.rs b/src/wrapper.rs
index 97ba1fd..d881541 100644
--- a/src/wrapper.rs
+++ b/src/wrapper.rs
@@ -127,25 +127,30 @@ impl<const N: usize> Primes<N> {
 
     // region: Next prime
 
-    /// Returns the largest prime less than or equal to `n`.  
-    /// If `n` is 0, 1, or larger than the largest prime in `self` this returns `None`.
+    /// Returns the largest prime less than `n`.  
+    /// If `n` is 0, 1, 2, or larger than the largest prime in `self` this returns `None`.
     ///
     /// Uses a binary search.
     /// # Example
     /// ```
     /// # use const_primes::Primes;
     /// const CACHE: Primes<100> = Primes::new();
-    /// const LPLEQ400: Option<u32> = CACHE.largest_prime_leq(400);
-    /// assert_eq!(LPLEQ400, Some(397));
+    /// const PREV400: Option<u32> = CACHE.previous_prime(400);
+    /// assert_eq!(PREV400, Some(397));
     /// ```
     #[must_use = "the method only returns a new value and does not modify `self`"]
-    pub const fn largest_prime_leq(&self, n: Underlying) -> Option<Underlying> {
-        if n <= 1 {
+    pub const fn previous_prime(&self, n: Underlying) -> Option<Underlying> {
+        if n <= 2 {
             None
         } else {
             match self.binary_search(n) {
-                Ok(i) => Some(self.primes[i]),
-                Err(Some(i)) => Some(self.primes[i - 1]),
+                Ok(i) | Err(Some(i)) => {
+                    if i > 0 {
+                        Some(self.primes[i - 1])
+                    } else {
+                        None
+                    }
+                }
                 Err(None) => None,
             }
         }
@@ -488,16 +493,23 @@ mod test {
     }
 
     #[test]
-    fn check_largest_prime_leq() {
+    fn check_previous_prime() {
         const CACHE: Primes<100> = Primes::new();
-        const LPLEQ0: Option<Underlying> = CACHE.largest_prime_leq(0);
-        const LPLEQ400: Option<Underlying> = CACHE.largest_prime_leq(400);
-        const LPLEQ541: Option<Underlying> = CACHE.largest_prime_leq(541);
-        const LPLEQ542: Option<Underlying> = CACHE.largest_prime_leq(542);
-        assert_eq!(LPLEQ0, None);
-        assert_eq!(LPLEQ400, Some(397));
-        assert_eq!(LPLEQ541, Some(541));
-        assert_eq!(LPLEQ542, None);
+        const PREV0: Option<Underlying> = CACHE.previous_prime(0);
+        const PREV400: Option<Underlying> = CACHE.previous_prime(400);
+        const PREV541: Option<Underlying> = CACHE.previous_prime(541);
+        const PREV542: Option<Underlying> = CACHE.previous_prime(542);
+        const PREVS: [Underlying; 18] = [
+            2, 3, 3, 5, 5, 7, 7, 7, 7, 11, 11, 13, 13, 13, 13, 17, 17, 19,
+        ];
+        for (i, prev) in PREVS.into_iter().enumerate() {
+            println!("n = {}", i + 3);
+            assert_eq!(Some(prev), CACHE.previous_prime(i as u32 + 3));
+        }
+        assert_eq!(PREV0, None);
+        assert_eq!(PREV400, Some(397));
+        assert_eq!(PREV541, Some(523));
+        assert_eq!(PREV542, None);
     }
 
     #[test]

From 52f4f2bc045d6f90bdf83045376ce3181f70b429 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 3 Nov 2023 11:21:46 +0100
Subject: [PATCH 067/212] Improve some docstrings

---
 src/generation.rs | 4 ++--
 src/wrapper.rs    | 6 +++---
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index a28edf5..024f9d9 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -278,9 +278,9 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> SegmentedGenera
 }
 
 /// An enum describing whether the requested array could be filled completely, or only a partially.
-/// A partial array can be returned by [`primes_lt`](crate::generation::primes_lt) if the size of the requested
+/// A partial array can be returned by [`primes_lt`] if the size of the requested
 /// array is larger than the actual number of primes less than the given `upper_limit`.
-/// It can also be returned by [`primes_geq`](crate::generation::primes_geq) if it needs to sieve into a
+/// It can also be returned by [`primes_geq`] if it needs to sieve into a
 /// region of numbers that exceed the square of the size of the requested array.
 #[derive(Debug, Clone, Copy, PartialEq)]
 pub enum SegmentedGenerationError<const N: usize> {
diff --git a/src/wrapper.rs b/src/wrapper.rs
index d881541..6072f48 100644
--- a/src/wrapper.rs
+++ b/src/wrapper.rs
@@ -187,10 +187,10 @@ impl<const N: usize> Primes<N> {
     /// Searches the underlying array of primes for the target integer.
     /// If the target is found it returns a [`Result::Ok`] that contains the index of the matching element.
     /// If the target is not found in the array a [`Result::Err`] is returned that contains an [`Option`].   
-    /// If the target could be inserted into the array while maintaining the sorted order, the [`Some`](Option::Some)
-    /// variant contains the index of that location.
+    /// If the target could be inserted into the array while maintaining the sorted order, the [`Option::Some`]
+    /// variant is returned and contains the index of that location.
     /// If the target is larger than the largest prime in the array no information about where it might fit is available,
-    /// and a [`None`](Option::None) is returned.
+    /// and an [`Option::None`] is returned.
     #[must_use = "the method only returns a new value and does not modify `self`"]
     pub const fn binary_search(&self, target: Underlying) -> Result<usize, Option<usize>> {
         if target > *self.last() {

From cfbc1ac34467b8244d03ff990e76eec2b961f3dc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 3 Nov 2023 12:35:26 +0100
Subject: [PATCH 068/212] Add std feature

---
 Cargo.toml        | 3 +++
 src/generation.rs | 6 +++++-
 src/lib.rs        | 6 +++---
 3 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 0544736..497bbb8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,6 +15,9 @@ repository = "https://github.com/JSorngard/const-primes"
 criterion = {version = "0.5", features = ["html_reports"]}
 rand = "0.8"
 
+[features]
+std = []
+
 [[bench]]
 name = "prime_benches"
 harness = false
\ No newline at end of file
diff --git a/src/generation.rs b/src/generation.rs
index 024f9d9..8c91b4f 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -244,6 +244,9 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> SegmentedGenera
     if n64.checked_mul(n64).is_none() {
         return Err(SegmentedGenerationError::TooLargeN);
     }
+    if lower_limit >= n64 * n64 {
+        return Err(SegmentedGenerationError::TooLargeLimit);
+    }
 
     let mut primes = [0; N];
     let base_sieve: [bool; N] = sieve();
@@ -255,6 +258,7 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> SegmentedGenera
         // Move the found primes into the output vector.
         while i < N {
             if upper_sieve[i] {
+                // FIXME: BUG IDENTIFIED: THIS COULD BE 0
                 largest_found_prime = lower_limit + i as u64;
                 if largest_found_prime >= n64 * n64 {
                     // We do not know if this is actually a prime
@@ -335,7 +339,7 @@ mod test {
         }
         {
             const P: SegmentedGenerationResult<1> = primes_geq(0);
-            assert_eq!(P, Err(SegmentedGenerationError::TooLargeLimit));
+            assert_eq!(P, Err(SegmentedGenerationError::PartialOk(RestrictedArray::new(0..0, [0]))));
         }
         for prime in primes_geq::<2_000>(3_998_000)
             .unwrap_err()
diff --git a/src/lib.rs b/src/lib.rs
index 4f353af..50cee99 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -90,7 +90,7 @@
 //! and more!
 
 #![forbid(unsafe_code)]
-#![cfg_attr(not(test), no_std)]
+#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
 
 /// The type that `Primes<N>` stores, and `primes::<N>()`` returns. Currently `u32`.
 // Just change this to whatever unsigned primitive integer type you want and it should work as long as it has enough bits for your purposes.
@@ -150,7 +150,7 @@ pub const fn prime_counts<const N: usize>() -> [usize; N] {
 mod test {
     use super::*;
 
-    use generation::{primes_lt, SegmentedGenerationError};
+    use generation::{primes_lt, SegmentedGenerationResult};
 
     #[test]
     fn check_primes_is_prime() {
@@ -235,7 +235,7 @@ mod test {
             ($($n:expr),+) => {
                 $(
                     {
-                        const P: Result<[u64; 10], SegmentedGenerationError<10>> = primes_lt(100);
+                        const P: SegmentedGenerationResult<10> = primes_lt(100);
                         for (i, prime) in P.unwrap().into_iter().enumerate() {
                             assert_eq!(PRECOMPUTED_PRIMES[25-$n..25][i], prime as u32);
                         }

From a2e708633216149fe70e7f082fc5ea2ebd292fae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 3 Nov 2023 15:26:09 +0100
Subject: [PATCH 069/212] rename std --> alloc

---
 Cargo.toml        | 2 +-
 src/generation.rs | 8 +++++++-
 src/lib.rs        | 5 ++++-
 src/wrapper.rs    | 8 ++++++++
 4 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 497bbb8..cfd6c43 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,7 +16,7 @@ criterion = {version = "0.5", features = ["html_reports"]}
 rand = "0.8"
 
 [features]
-std = []
+alloc = []
 
 [[bench]]
 name = "prime_benches"
diff --git a/src/generation.rs b/src/generation.rs
index 8c91b4f..d82cd1f 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -339,7 +339,13 @@ mod test {
         }
         {
             const P: SegmentedGenerationResult<1> = primes_geq(0);
-            assert_eq!(P, Err(SegmentedGenerationError::PartialOk(RestrictedArray::new(0..0, [0]))));
+            assert_eq!(
+                P,
+                Err(SegmentedGenerationError::PartialOk(RestrictedArray::new(
+                    0..0,
+                    [0]
+                )))
+            );
         }
         for prime in primes_geq::<2_000>(3_998_000)
             .unwrap_err()
diff --git a/src/lib.rs b/src/lib.rs
index 50cee99..0f148c3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -90,7 +90,10 @@
 //! and more!
 
 #![forbid(unsafe_code)]
-#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
+#![cfg_attr(not(test), no_std)]
+
+#[cfg(feature = "alloc")]
+extern crate alloc;
 
 /// The type that `Primes<N>` stores, and `primes::<N>()`` returns. Currently `u32`.
 // Just change this to whatever unsigned primitive integer type you want and it should work as long as it has enough bits for your purposes.
diff --git a/src/wrapper.rs b/src/wrapper.rs
index 6072f48..09f07e4 100644
--- a/src/wrapper.rs
+++ b/src/wrapper.rs
@@ -246,6 +246,14 @@ impl<const N: usize> Primes<N> {
         self.primes.as_slice()
     }
 
+    #[cfg(feature = "alloc")]
+    /// Returns a newly allocated `Vec` that contains the underlying prime numbers.
+    #[inline]
+    #[must_use = "the method only returns a new value and does not modify `self`"]
+    pub fn to_vec(&self) -> alloc::vec::Vec<Underlying> {
+        self.primes.to_vec()
+    }
+
     // endregion: Conversions
 
     /// Returns a reference to the element at the given index if it is within bounds.

From 642a535f62e313d11f8fa11e7a97dc011f100c22 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 3 Nov 2023 15:33:56 +0100
Subject: [PATCH 070/212] Remove alloc feature

---
 Cargo.toml     | 3 ---
 src/lib.rs     | 3 ---
 src/wrapper.rs | 8 --------
 3 files changed, 14 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index cfd6c43..0544736 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,9 +15,6 @@ repository = "https://github.com/JSorngard/const-primes"
 criterion = {version = "0.5", features = ["html_reports"]}
 rand = "0.8"
 
-[features]
-alloc = []
-
 [[bench]]
 name = "prime_benches"
 harness = false
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index 0f148c3..fe646b7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -92,9 +92,6 @@
 #![forbid(unsafe_code)]
 #![cfg_attr(not(test), no_std)]
 
-#[cfg(feature = "alloc")]
-extern crate alloc;
-
 /// The type that `Primes<N>` stores, and `primes::<N>()`` returns. Currently `u32`.
 // Just change this to whatever unsigned primitive integer type you want and it should work as long as it has enough bits for your purposes.
 // This is used since there is currently no way to be generic over types that can do arithmetic at compile time.
diff --git a/src/wrapper.rs b/src/wrapper.rs
index 09f07e4..6072f48 100644
--- a/src/wrapper.rs
+++ b/src/wrapper.rs
@@ -246,14 +246,6 @@ impl<const N: usize> Primes<N> {
         self.primes.as_slice()
     }
 
-    #[cfg(feature = "alloc")]
-    /// Returns a newly allocated `Vec` that contains the underlying prime numbers.
-    #[inline]
-    #[must_use = "the method only returns a new value and does not modify `self`"]
-    pub fn to_vec(&self) -> alloc::vec::Vec<Underlying> {
-        self.primes.to_vec()
-    }
-
     // endregion: Conversions
 
     /// Returns a reference to the element at the given index if it is within bounds.

From 22f7d1060e5c1d58e43f3e03b6c32916e795199e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 20 Nov 2023 11:29:28 +0100
Subject: [PATCH 071/212] Add keywords field

---
 Cargo.toml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Cargo.toml b/Cargo.toml
index 0544736..42024af 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,6 +4,7 @@ authors = ["Johanna Sörngård (jsorngard@gmail.com)"]
 version = "0.4.8"
 edition = "2021"
 license = "MIT OR Apache-2.0"
+keywords = ["prime", "const"]
 description = "Generate and work with prime numbers in const contexts"
 repository = "https://github.com/JSorngard/const-primes"
 

From baa6e10198fc0f3d7fead454f2a5965c0ffa18bb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 5 Dec 2023 23:00:12 +0100
Subject: [PATCH 072/212] change keyword 'prime' to 'primes'

---
 Cargo.toml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 42024af..1aca1c0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,7 +4,7 @@ authors = ["Johanna Sörngård (jsorngard@gmail.com)"]
 version = "0.4.8"
 edition = "2021"
 license = "MIT OR Apache-2.0"
-keywords = ["prime", "const"]
+keywords = ["primes", "const"]
 description = "Generate and work with prime numbers in const contexts"
 repository = "https://github.com/JSorngard/const-primes"
 
@@ -13,9 +13,9 @@ repository = "https://github.com/JSorngard/const-primes"
 [dependencies]
 
 [dev-dependencies]
-criterion = {version = "0.5", features = ["html_reports"]}
+criterion = { version = "0.5", features = ["html_reports"] }
 rand = "0.8"
 
 [[bench]]
 name = "prime_benches"
-harness = false
\ No newline at end of file
+harness = false

From 47719ce5b347e71a5a93f90991e99d4196d1fcfe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Wed, 27 Dec 2023 11:46:24 +0100
Subject: [PATCH 073/212] move clone and copy into derive

---
 src/restricted_array.rs | 14 +-------------
 1 file changed, 1 insertion(+), 13 deletions(-)

diff --git a/src/restricted_array.rs b/src/restricted_array.rs
index 36a6524..18ac589 100644
--- a/src/restricted_array.rs
+++ b/src/restricted_array.rs
@@ -4,25 +4,13 @@ use core::{iter::FusedIterator, ops::Range};
 /// as the other data may e.g. not uphold some invariant.  
 /// When this type is compared against some other type, only
 /// data in the visible part is compared.
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy)]
 pub struct RestrictedArray<T, const N: usize> {
     start: usize,
     end: usize,
     array: [T; N],
 }
 
-impl<const N: usize, T: Clone> Clone for RestrictedArray<T, N> {
-    fn clone(&self) -> Self {
-        Self {
-            start: self.start,
-            end: self.end,
-            array: self.array.clone(),
-        }
-    }
-}
-
-impl<const N: usize, T: Copy> Copy for RestrictedArray<T, N> {}
-
 impl<const N: usize, T: PartialEq<T>> PartialEq<RestrictedArray<T, N>> for RestrictedArray<T, N> {
     /// This method tests for `self` and `other` values to be equal, and is used by `==`.  
     /// Only compares the *visible* part of `self` against the *visible* part of `other`.

From df305d924c91ec49e3dff813c59ffb95913debe4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Wed, 27 Dec 2023 11:57:56 +0100
Subject: [PATCH 074/212] Move Eq impl to derive

---
 src/restricted_array.rs | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/restricted_array.rs b/src/restricted_array.rs
index 18ac589..221f5bb 100644
--- a/src/restricted_array.rs
+++ b/src/restricted_array.rs
@@ -4,7 +4,7 @@ use core::{iter::FusedIterator, ops::Range};
 /// as the other data may e.g. not uphold some invariant.  
 /// When this type is compared against some other type, only
 /// data in the visible part is compared.
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, Eq)]
 pub struct RestrictedArray<T, const N: usize> {
     start: usize,
     end: usize,
@@ -19,8 +19,6 @@ impl<const N: usize, T: PartialEq<T>> PartialEq<RestrictedArray<T, N>> for Restr
     }
 }
 
-impl<const N: usize, T: Eq> Eq for RestrictedArray<T, N> {}
-
 impl<const N: usize, T> RestrictedArray<T, N> {
     /// Restrict an array so that only elements within the given range are visible.
     ///

From c9cf0c844b97fb904e85b6b1039babd18ce9a6ba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 19 Feb 2024 17:38:24 +0100
Subject: [PATCH 075/212] impl IntoIterator for &RestrictedArray

---
 src/restricted_array.rs | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/src/restricted_array.rs b/src/restricted_array.rs
index 221f5bb..b52fb6f 100644
--- a/src/restricted_array.rs
+++ b/src/restricted_array.rs
@@ -92,6 +92,7 @@ impl<const N: usize, T> RestrictedArray<T, N> {
     }
 
     /// Returns an iterator over the visible section.
+    #[inline]
     pub fn iter(&self) -> core::slice::Iter<'_, T> {
         self.as_slice().iter()
     }
@@ -99,6 +100,7 @@ impl<const N: usize, T> RestrictedArray<T, N> {
 
 impl<const N: usize, T> core::ops::Index<usize> for RestrictedArray<T, N> {
     type Output = T;
+    #[inline]
     fn index(&self, index: usize) -> &Self::Output {
         let i = match self.start.checked_add(index) {
             Some(sum) => sum,
@@ -120,17 +122,30 @@ pub struct RestrictedArrayIntoIter<const N: usize, T>(
 
 impl<const N: usize, T> Iterator for RestrictedArrayIntoIter<N, T> {
     type Item = T;
+    #[inline]
     fn next(&mut self) -> Option<Self::Item> {
         self.0.next()
     }
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         self.0.size_hint()
     }
+
+    #[inline]
+    fn last(self) -> Option<T> {
+        self.0.last()
+    }
+
+    #[inline]
+    fn count(self) -> usize {
+        self.0.count()
+    }
 }
 impl<const N: usize, T> FusedIterator for RestrictedArrayIntoIter<N, T> {}
 impl<const N: usize, T> ExactSizeIterator for RestrictedArrayIntoIter<N, T> {}
 impl<const N: usize, T> DoubleEndedIterator for RestrictedArrayIntoIter<N, T> {
+    #[inline]
     fn next_back(&mut self) -> Option<Self::Item> {
         self.0.next_back()
     }
@@ -146,6 +161,15 @@ impl<const N: usize, T> IntoIterator for RestrictedArray<T, N> {
     }
 }
 
+impl<'a, const N: usize, T> IntoIterator for &'a RestrictedArray<T, N> {
+    type IntoIter = core::slice::Iter<'a, T>;
+    type Item = &'a <RestrictedArrayIntoIter<N, T> as Iterator>::Item;
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        self.as_slice().iter()
+    }
+}
+
 // region: PartialEq impls
 impl<const N: usize, T, U> PartialEq<[U]> for RestrictedArray<T, N>
 where

From 1f402c402f3af4016e2405bd1a77e3b187379c1c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 19 Feb 2024 17:42:24 +0100
Subject: [PATCH 076/212] impl IndexMut for RestrictedArray

---
 src/restricted_array.rs | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/src/restricted_array.rs b/src/restricted_array.rs
index b52fb6f..ad311aa 100644
--- a/src/restricted_array.rs
+++ b/src/restricted_array.rs
@@ -115,6 +115,21 @@ impl<const N: usize, T> core::ops::Index<usize> for RestrictedArray<T, N> {
     }
 }
 
+impl<const N: usize, T> core::ops::IndexMut<usize> for RestrictedArray<T, N> {
+    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+        let i = match self.start.checked_add(index) {
+            Some(sum) => sum,
+            None => panic!("index overflowed"),
+        };
+
+        if i >= self.end {
+            panic!("index was {i} when len was {}", self.end - self.start);
+        }
+
+        &mut self.array[i]
+    }
+}
+
 /// Created by the [`into_iter`](RestrictedArray::into_iter) function on [`RestrictedArray`], see it for more information.
 pub struct RestrictedArrayIntoIter<const N: usize, T>(
     core::iter::Take<core::iter::Skip<core::array::IntoIter<T, N>>>,

From 1f0e96b167e743de517ef2bad643753ea14e0356 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 19 Feb 2024 17:50:51 +0100
Subject: [PATCH 077/212] Add as_slice_mut

---
 src/restricted_array.rs | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/src/restricted_array.rs b/src/restricted_array.rs
index ad311aa..d7108b8 100644
--- a/src/restricted_array.rs
+++ b/src/restricted_array.rs
@@ -63,6 +63,12 @@ impl<const N: usize, T> RestrictedArray<T, N> {
         tail.split_at(self.end - self.start).0
     }
 
+    /// Returns the visible part of the array as a mutable slice.
+    pub fn as_slice_mut(&mut self) -> &mut [T] {
+        let (_, tail) = self.array.split_at_mut(self.start);
+        tail.split_at_mut(self.end - self.start).0
+    }
+
     /// Returns the index of the first element of the underlying array that's inside the visible region.
     pub const fn start(&self) -> usize {
         self.start
@@ -102,20 +108,18 @@ impl<const N: usize, T> core::ops::Index<usize> for RestrictedArray<T, N> {
     type Output = T;
     #[inline]
     fn index(&self, index: usize) -> &Self::Output {
-        let i = match self.start.checked_add(index) {
-            Some(sum) => sum,
-            None => panic!("index overflowed"),
-        };
-
-        if i >= self.end {
-            panic!("index was {i} when len was {}", self.end - self.start);
+        match self.as_slice().get(index) {
+            Some(element) => element,
+            None => panic!(
+                "the index was {index} but the len was {}",
+                self.end - self.start
+            ),
         }
-
-        &self.array[i]
     }
 }
 
 impl<const N: usize, T> core::ops::IndexMut<usize> for RestrictedArray<T, N> {
+    #[inline]
     fn index_mut(&mut self, index: usize) -> &mut Self::Output {
         let i = match self.start.checked_add(index) {
             Some(sum) => sum,

From c9628b92576bfa7b8ef9eda1bcf770c7986d004e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 19 Feb 2024 17:53:13 +0100
Subject: [PATCH 078/212] implement Intex(Mut) in terms of as_slice(_mut)

---
 src/restricted_array.rs | 19 ++-----------------
 1 file changed, 2 insertions(+), 17 deletions(-)

diff --git a/src/restricted_array.rs b/src/restricted_array.rs
index d7108b8..d58511e 100644
--- a/src/restricted_array.rs
+++ b/src/restricted_array.rs
@@ -108,29 +108,14 @@ impl<const N: usize, T> core::ops::Index<usize> for RestrictedArray<T, N> {
     type Output = T;
     #[inline]
     fn index(&self, index: usize) -> &Self::Output {
-        match self.as_slice().get(index) {
-            Some(element) => element,
-            None => panic!(
-                "the index was {index} but the len was {}",
-                self.end - self.start
-            ),
-        }
+        &self.as_slice()[index]
     }
 }
 
 impl<const N: usize, T> core::ops::IndexMut<usize> for RestrictedArray<T, N> {
     #[inline]
     fn index_mut(&mut self, index: usize) -> &mut Self::Output {
-        let i = match self.start.checked_add(index) {
-            Some(sum) => sum,
-            None => panic!("index overflowed"),
-        };
-
-        if i >= self.end {
-            panic!("index was {i} when len was {}", self.end - self.start);
-        }
-
-        &mut self.array[i]
+        &mut self.as_slice_mut()[index]
     }
 }
 

From 83d186255f8a4bdbadb3b3e3ca59476e1ac0e786 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 19 Feb 2024 17:58:58 +0100
Subject: [PATCH 079/212] Add where clause for signature looks

---
 src/restricted_array.rs | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/restricted_array.rs b/src/restricted_array.rs
index d58511e..d7ae543 100644
--- a/src/restricted_array.rs
+++ b/src/restricted_array.rs
@@ -186,7 +186,10 @@ where
     }
 }
 
-impl<const N: usize, T, U: PartialEq<T>> PartialEq<RestrictedArray<T, N>> for [U] {
+impl<const N: usize, T, U> PartialEq<RestrictedArray<T, N>> for [U]
+where
+    U: PartialEq<T>,
+{
     /// This method tests for `self` and `other` values to be equal, and is used by `==`.  
     /// Only compares the *visible* part of `other` against `self`.
     fn eq(&self, other: &RestrictedArray<T, N>) -> bool {

From d391e9e64231df8f0d880f9d8f591d6a3a9dcb0a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 19 Feb 2024 21:04:04 +0100
Subject: [PATCH 080/212] implement size_hint in terms of len

---
 src/restricted_array.rs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/restricted_array.rs b/src/restricted_array.rs
index d7ae543..e6dc130 100644
--- a/src/restricted_array.rs
+++ b/src/restricted_array.rs
@@ -133,7 +133,8 @@ impl<const N: usize, T> Iterator for RestrictedArrayIntoIter<N, T> {
 
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
-        self.0.size_hint()
+        let l = self.0.len();
+        (l, Some(l))
     }
 
     #[inline]

From 5edb8a28315b1edca2312df8b8974dc3ff29be51 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 19 Feb 2024 21:06:06 +0100
Subject: [PATCH 081/212] Remove mutable access

---
 src/restricted_array.rs | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/src/restricted_array.rs b/src/restricted_array.rs
index e6dc130..7e74b02 100644
--- a/src/restricted_array.rs
+++ b/src/restricted_array.rs
@@ -63,12 +63,6 @@ impl<const N: usize, T> RestrictedArray<T, N> {
         tail.split_at(self.end - self.start).0
     }
 
-    /// Returns the visible part of the array as a mutable slice.
-    pub fn as_slice_mut(&mut self) -> &mut [T] {
-        let (_, tail) = self.array.split_at_mut(self.start);
-        tail.split_at_mut(self.end - self.start).0
-    }
-
     /// Returns the index of the first element of the underlying array that's inside the visible region.
     pub const fn start(&self) -> usize {
         self.start
@@ -112,13 +106,6 @@ impl<const N: usize, T> core::ops::Index<usize> for RestrictedArray<T, N> {
     }
 }
 
-impl<const N: usize, T> core::ops::IndexMut<usize> for RestrictedArray<T, N> {
-    #[inline]
-    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
-        &mut self.as_slice_mut()[index]
-    }
-}
-
 /// Created by the [`into_iter`](RestrictedArray::into_iter) function on [`RestrictedArray`], see it for more information.
 pub struct RestrictedArrayIntoIter<const N: usize, T>(
     core::iter::Take<core::iter::Skip<core::array::IntoIter<T, N>>>,

From 8a2565f70ce311a0bd459b0a26ed597f099274d4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 22 Feb 2024 09:44:26 +0100
Subject: [PATCH 082/212] Add manual nth impl

---
 src/restricted_array.rs | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/restricted_array.rs b/src/restricted_array.rs
index 7e74b02..4ebfef2 100644
--- a/src/restricted_array.rs
+++ b/src/restricted_array.rs
@@ -124,6 +124,11 @@ impl<const N: usize, T> Iterator for RestrictedArrayIntoIter<N, T> {
         (l, Some(l))
     }
 
+    #[inline]
+    fn nth(&mut self, index: usize) -> Option<Self::Item> {
+        self.0.nth(index)
+    }
+
     #[inline]
     fn last(self) -> Option<T> {
         self.0.last()

From a54ad9492f8286cfe4f124a17eb5566e6ed9fd57 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 22 Feb 2024 09:46:23 +0100
Subject: [PATCH 083/212] Inline into_iter

---
 src/restricted_array.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/restricted_array.rs b/src/restricted_array.rs
index 4ebfef2..63aab8f 100644
--- a/src/restricted_array.rs
+++ b/src/restricted_array.rs
@@ -151,6 +151,7 @@ impl<const N: usize, T> DoubleEndedIterator for RestrictedArrayIntoIter<N, T> {
 impl<const N: usize, T> IntoIterator for RestrictedArray<T, N> {
     type IntoIter = RestrictedArrayIntoIter<N, T>;
     type Item = <RestrictedArrayIntoIter<N, T> as Iterator>::Item;
+    #[inline]
     fn into_iter(self) -> Self::IntoIter {
         let start = self.start;
         let len = self.len();

From de89b3a482165e227a47a7394363c275398e35bb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 12:56:16 +0200
Subject: [PATCH 084/212] Rename RestrictedArray, impl Index<Ranges>

---
 src/array_section.rs    | 274 ++++++++++++++++++++++++++++++++++++++++
 src/generation.rs       |  12 +-
 src/lib.rs              |   2 +-
 src/restricted_array.rs | 199 -----------------------------
 4 files changed, 281 insertions(+), 206 deletions(-)
 create mode 100644 src/array_section.rs
 delete mode 100644 src/restricted_array.rs

diff --git a/src/array_section.rs b/src/array_section.rs
new file mode 100644
index 0000000..a6f9467
--- /dev/null
+++ b/src/array_section.rs
@@ -0,0 +1,274 @@
+use core::{
+    iter::FusedIterator,
+    ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
+};
+
+/// An array where only a section of the data may be viewed,
+/// as the other data may e.g. not uphold some invariant.  
+/// When this type is compared against some other type, only
+/// data in the visible part is compared.
+#[derive(Debug, Clone, Copy, Eq)]
+pub struct ArraySection<T, const N: usize> {
+    start: usize,
+    end: usize,
+    array: [T; N],
+}
+
+impl<const N: usize, T: PartialEq<T>> PartialEq<ArraySection<T, N>> for ArraySection<T, N> {
+    /// This method tests for `self` and `other` values to be equal, and is used by `==`.  
+    /// Only compares the *visible* part of `self` against the *visible* part of `other`.
+    fn eq(&self, other: &ArraySection<T, N>) -> bool {
+        self.as_slice() == other.as_slice()
+    }
+}
+
+impl<const N: usize, T> ArraySection<T, N> {
+    /// Restrict an array so that only elements within the given range are visible.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the range of indices is out of bounds of the array.
+    pub const fn new(sub_range: Range<usize>, array: [T; N]) -> Self {
+        assert!(
+            sub_range.start < N && sub_range.end <= N,
+            "the sub-range must be in bounds"
+        );
+
+        if sub_range.start > sub_range.end {
+            Self {
+                start: 0,
+                end: 0,
+                array,
+            }
+        } else {
+            Self {
+                start: sub_range.start,
+                end: sub_range.end,
+                array,
+            }
+        }
+    }
+
+    /// Returns a reference to the full underlying array. There is no guarantee about the data
+    /// outside the section.
+    pub const fn as_full_array(&self) -> &[T; N] {
+        &self.array
+    }
+
+    /// Converts `self` into the full underlying array. There is no guarantee about the data
+    /// outside the section.
+    pub fn into_full_array(self) -> [T; N] {
+        self.array
+    }
+
+    /// Returns the visible part of the array as a slice.
+    pub const fn as_slice(&self) -> &[T] {
+        let (_, tail) = self.array.split_at(self.start);
+        tail.split_at(self.end - self.start).0
+    }
+
+    /// Returns the length of the array section.
+    pub const fn len(&self) -> usize {
+        self.as_slice().len()
+    }
+
+    /// Returns whether the array section is empty.
+    pub const fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Returns whether the section is just the entire array.
+    /// If this is `true` it is completely fine to call [`as_full_array`](RestrictedArray::as_full_array)
+    /// or [`into_full_array`](RestrictedArray::into_full_array).
+    pub const fn section_is_complete_array(&self) -> bool {
+        self.len() == N
+    }
+
+    /// Returns an iterator over the array section.
+    #[inline]
+    pub fn iter(&self) -> ArraySectionIter<'_, T> {
+        ArraySectionIter::new(self.as_slice().iter())
+    }
+}
+
+// region: Index impls
+
+impl<const N: usize, T> core::ops::Index<usize> for ArraySection<T, N> {
+    type Output = T;
+    #[inline]
+    fn index(&self, index: usize) -> &Self::Output {
+        &self.as_slice()[index]
+    }
+}
+
+macro_rules! impl_index_range {
+    ($($t:ty),+) => {
+        $(
+            impl<const N: ::core::primitive::usize, T> ::core::ops::Index<$t> for ArraySection<T, N> {
+                type Output = [T];
+                #[inline]
+                fn index(&self, index: $t) -> &Self::Output {
+                    ::core::ops::Index::index(self.as_slice(), index)
+                }
+            }
+        )+
+    };
+}
+
+impl_index_range! {Range<usize>, RangeFrom<usize>, RangeFull, RangeTo<usize>, RangeInclusive<usize>, RangeToInclusive<usize>}
+
+// endregion: Index impls
+
+// region: PartialEq impls
+impl<const N: usize, T, U> PartialEq<[U]> for ArraySection<T, N>
+where
+    U: PartialEq<T>,
+{
+    /// This method tests for `self` and `other` values to be equal, and is used by `==`.  
+    /// Only compares the *visible* part of `self` against `other`.
+    fn eq(&self, other: &[U]) -> bool {
+        other == self.as_slice()
+    }
+}
+
+impl<const N: usize, T, U> PartialEq<ArraySection<T, N>> for [U]
+where
+    U: PartialEq<T>,
+{
+    /// This method tests for `self` and `other` values to be equal, and is used by `==`.  
+    /// Only compares the *visible* part of `other` against `self`.
+    fn eq(&self, other: &ArraySection<T, N>) -> bool {
+        self == other.as_slice()
+    }
+}
+// endregion: PartialEq impls
+
+impl<const N: usize, T> AsRef<[T]> for ArraySection<T, N> {
+    fn as_ref(&self) -> &[T] {
+        self.as_slice()
+    }
+}
+
+impl<const N: usize, T> IntoIterator for ArraySection<T, N> {
+    type IntoIter = ArraySectionIntoIter<T, N>;
+    type Item = <ArraySectionIntoIter<T, N> as Iterator>::Item;
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        let start = self.start;
+        let len = self.len();
+        ArraySectionIntoIter::new(self.array.into_iter().skip(start).take(len))
+    }
+}
+
+impl<'a, const N: usize, T> IntoIterator for &'a ArraySection<T, N> {
+    type IntoIter = core::slice::Iter<'a, T>;
+    type Item = &'a <ArraySectionIntoIter<T, N> as Iterator>::Item;
+    #[inline]
+    fn into_iter(self) -> Self::IntoIter {
+        self.as_slice().iter()
+    }
+}
+
+use array_section_iter::ArraySectionIter;
+mod array_section_iter {
+    use super::FusedIterator;
+
+    #[derive(Debug, Clone)]
+    pub struct ArraySectionIter<'a, T>(core::slice::Iter<'a, T>);
+
+    impl<'a, T> ArraySectionIter<'a, T> {
+        pub const fn new(iter: core::slice::Iter<'a, T>) -> Self {
+            Self(iter)
+        }
+    }
+
+    impl<'a, T> Iterator for ArraySectionIter<'a, T> {
+        type Item = &'a T;
+        fn next(&mut self) -> Option<Self::Item> {
+            self.0.next()
+        }
+
+        fn size_hint(&self) -> (usize, Option<usize>) {
+            self.0.size_hint()
+        }
+
+        fn last(self) -> Option<Self::Item> {
+            self.0.last()
+        }
+
+        fn nth(&mut self, n: usize) -> Option<Self::Item> {
+            self.0.nth(n)
+        }
+
+        fn count(self) -> usize {
+            self.0.count()
+        }
+    }
+    impl<'a, T> DoubleEndedIterator for ArraySectionIter<'a, T> {
+        fn next_back(&mut self) -> Option<Self::Item> {
+            self.0.next_back()
+        }
+    }
+    impl<'a, T> ExactSizeIterator for ArraySectionIter<'a, T> {
+        fn len(&self) -> usize {
+            self.0.len()
+        }
+    }
+    impl<'a, T> FusedIterator for ArraySectionIter<'a, T> {}
+}
+
+use array_section_into_iter::ArraySectionIntoIter;
+mod array_section_into_iter {
+    use super::FusedIterator;
+
+    #[derive(Debug, Clone)]
+    /// Created by the [`into_iter`](RestrictedArray::into_iter) function on [`RestrictedArray`], see it for more information.
+    pub struct ArraySectionIntoIter<T, const N: usize>(
+        core::iter::Take<core::iter::Skip<core::array::IntoIter<T, N>>>,
+    );
+
+    impl<const N: usize, T> ArraySectionIntoIter<T, N> {
+        pub const fn new(
+            iter: core::iter::Take<core::iter::Skip<core::array::IntoIter<T, N>>>,
+        ) -> Self {
+            Self(iter)
+        }
+    }
+
+    impl<const N: usize, T> Iterator for ArraySectionIntoIter<T, N> {
+        type Item = T;
+        #[inline]
+        fn next(&mut self) -> Option<Self::Item> {
+            self.0.next()
+        }
+
+        #[inline]
+        fn size_hint(&self) -> (usize, Option<usize>) {
+            let l = self.0.len();
+            (l, Some(l))
+        }
+
+        #[inline]
+        fn nth(&mut self, index: usize) -> Option<Self::Item> {
+            self.0.nth(index)
+        }
+
+        #[inline]
+        fn last(self) -> Option<T> {
+            self.0.last()
+        }
+
+        #[inline]
+        fn count(self) -> usize {
+            self.0.count()
+        }
+    }
+    impl<const N: usize, T> FusedIterator for ArraySectionIntoIter<T, N> {}
+    impl<const N: usize, T> ExactSizeIterator for ArraySectionIntoIter<T, N> {}
+    impl<const N: usize, T> DoubleEndedIterator for ArraySectionIntoIter<T, N> {
+        #[inline]
+        fn next_back(&mut self) -> Option<Self::Item> {
+            self.0.next_back()
+        }
+    }
+}
diff --git a/src/generation.rs b/src/generation.rs
index d82cd1f..b5f9948 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -1,6 +1,6 @@
 use core::fmt;
 
-use crate::{restricted_array::RestrictedArray, sieve, sieving::sieve_segment, Underlying};
+use crate::{array_section::ArraySection, sieve, sieving::sieve_segment, Underlying};
 
 /// Type alias for the type returned by the segmented generation functions, that otherwise has two generics that must be the same.
 pub type SegmentedGenerationResult<const N: usize> = Result<[u64; N], SegmentedGenerationError<N>>;
@@ -195,7 +195,7 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> SegmentedGenerat
         }
         upper_limit = smallest_found_prime;
         if upper_limit <= 2 && total_primes_found < N {
-            let restricted = RestrictedArray::new(N - total_primes_found..N, primes);
+            let restricted = ArraySection::new(N - total_primes_found..N, primes);
             return Err(SegmentedGenerationError::PartialOk(restricted));
         }
     }
@@ -264,7 +264,7 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> SegmentedGenera
                     // We do not know if this is actually a prime
                     // since the base sieve does not contain information about
                     // the prime status of numbers larger than or equal to N.
-                    let restricted = RestrictedArray::new(0..total_found_primes, primes);
+                    let restricted = ArraySection::new(0..total_found_primes, primes);
                     return Err(SegmentedGenerationError::PartialOk(restricted));
                 }
                 primes[total_found_primes] = largest_found_prime;
@@ -293,12 +293,12 @@ pub enum SegmentedGenerationError<const N: usize> {
     /// the upper limit was larger than `N^2`.
     TooLargeLimit,
     /// Only a part of the output array contains prime numbers as they either exceeded `N^2` or ran out.
-    PartialOk(RestrictedArray<u64, N>),
+    PartialOk(ArraySection<u64, N>),
 }
 
 impl<const N: usize> SegmentedGenerationError<N> {
     /// Returns the partial result as a restricted array, if there is one.
-    pub const fn partial_ok(self) -> Option<RestrictedArray<u64, N>> {
+    pub const fn partial_ok(self) -> Option<ArraySection<u64, N>> {
         match self {
             Self::PartialOk(restricted_array) => Some(restricted_array),
             _ => None,
@@ -341,7 +341,7 @@ mod test {
             const P: SegmentedGenerationResult<1> = primes_geq(0);
             assert_eq!(
                 P,
-                Err(SegmentedGenerationError::PartialOk(RestrictedArray::new(
+                Err(SegmentedGenerationError::PartialOk(ArraySection::new(
                     0..0,
                     [0]
                 )))
diff --git a/src/lib.rs b/src/lib.rs
index fe646b7..6d580e7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -97,11 +97,11 @@
 // This is used since there is currently no way to be generic over types that can do arithmetic at compile time.
 type Underlying = u32;
 
+pub mod array_section;
 pub mod generation;
 mod imath;
 mod miller_rabin;
 mod other_prime;
-pub mod restricted_array;
 mod sieving;
 mod wrapper;
 
diff --git a/src/restricted_array.rs b/src/restricted_array.rs
deleted file mode 100644
index 63aab8f..0000000
--- a/src/restricted_array.rs
+++ /dev/null
@@ -1,199 +0,0 @@
-use core::{iter::FusedIterator, ops::Range};
-
-/// An array where only a section of the data may be viewed,
-/// as the other data may e.g. not uphold some invariant.  
-/// When this type is compared against some other type, only
-/// data in the visible part is compared.
-#[derive(Debug, Clone, Copy, Eq)]
-pub struct RestrictedArray<T, const N: usize> {
-    start: usize,
-    end: usize,
-    array: [T; N],
-}
-
-impl<const N: usize, T: PartialEq<T>> PartialEq<RestrictedArray<T, N>> for RestrictedArray<T, N> {
-    /// This method tests for `self` and `other` values to be equal, and is used by `==`.  
-    /// Only compares the *visible* part of `self` against the *visible* part of `other`.
-    fn eq(&self, other: &RestrictedArray<T, N>) -> bool {
-        self.as_slice() == other.as_slice()
-    }
-}
-
-impl<const N: usize, T> RestrictedArray<T, N> {
-    /// Restrict an array so that only elements within the given range are visible.
-    ///
-    /// # Panics
-    /// Panics if the range of indices is out of bounds of the array.
-    pub const fn new(sub_range: Range<usize>, array: [T; N]) -> Self {
-        assert!(
-            sub_range.start < N && sub_range.end <= N,
-            "the sub-range must be in bounds"
-        );
-
-        if sub_range.start > sub_range.end {
-            Self {
-                start: 0,
-                end: 0,
-                array,
-            }
-        } else {
-            Self {
-                start: sub_range.start,
-                end: sub_range.end,
-                array,
-            }
-        }
-    }
-
-    /// Returns a reference to the full underlying array. There is no guarantee about the data
-    /// outside the visible region.
-    pub const fn as_full_array(&self) -> &[T; N] {
-        &self.array
-    }
-
-    /// Converts `self` into the full underlying array. There is no guarantee about the data
-    /// outside the visible region.
-    pub fn into_full_array(self) -> [T; N] {
-        self.array
-    }
-
-    /// Returns the visible part of the array as a slice.
-    pub const fn as_slice(&self) -> &[T] {
-        let (_, tail) = self.array.split_at(self.start);
-        tail.split_at(self.end - self.start).0
-    }
-
-    /// Returns the index of the first element of the underlying array that's inside the visible region.
-    pub const fn start(&self) -> usize {
-        self.start
-    }
-
-    /// Returns the index of the first element of the underlying array that is
-    /// invisible again after the end of the visible part.
-    pub const fn end(&self) -> usize {
-        self.end
-    }
-
-    /// Returns the length of the visible part of the array.
-    pub const fn len(&self) -> usize {
-        self.end - self.start
-    }
-
-    /// Returns whether the visible part is empty.
-    pub const fn is_empty(&self) -> bool {
-        self.len() == 0
-    }
-
-    /// Returns whether there are no parts of the array that are invisible.
-    /// If this is `true` it is completely fine to call [`as_full_array`](RestrictedArray::as_full_array)
-    /// or [`into_full_array`](RestrictedArray::into_full_array).
-    pub const fn is_fully_visible(&self) -> bool {
-        self.len() == N
-    }
-
-    /// Returns an iterator over the visible section.
-    #[inline]
-    pub fn iter(&self) -> core::slice::Iter<'_, T> {
-        self.as_slice().iter()
-    }
-}
-
-impl<const N: usize, T> core::ops::Index<usize> for RestrictedArray<T, N> {
-    type Output = T;
-    #[inline]
-    fn index(&self, index: usize) -> &Self::Output {
-        &self.as_slice()[index]
-    }
-}
-
-/// Created by the [`into_iter`](RestrictedArray::into_iter) function on [`RestrictedArray`], see it for more information.
-pub struct RestrictedArrayIntoIter<const N: usize, T>(
-    core::iter::Take<core::iter::Skip<core::array::IntoIter<T, N>>>,
-);
-
-impl<const N: usize, T> Iterator for RestrictedArrayIntoIter<N, T> {
-    type Item = T;
-    #[inline]
-    fn next(&mut self) -> Option<Self::Item> {
-        self.0.next()
-    }
-
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let l = self.0.len();
-        (l, Some(l))
-    }
-
-    #[inline]
-    fn nth(&mut self, index: usize) -> Option<Self::Item> {
-        self.0.nth(index)
-    }
-
-    #[inline]
-    fn last(self) -> Option<T> {
-        self.0.last()
-    }
-
-    #[inline]
-    fn count(self) -> usize {
-        self.0.count()
-    }
-}
-impl<const N: usize, T> FusedIterator for RestrictedArrayIntoIter<N, T> {}
-impl<const N: usize, T> ExactSizeIterator for RestrictedArrayIntoIter<N, T> {}
-impl<const N: usize, T> DoubleEndedIterator for RestrictedArrayIntoIter<N, T> {
-    #[inline]
-    fn next_back(&mut self) -> Option<Self::Item> {
-        self.0.next_back()
-    }
-}
-
-impl<const N: usize, T> IntoIterator for RestrictedArray<T, N> {
-    type IntoIter = RestrictedArrayIntoIter<N, T>;
-    type Item = <RestrictedArrayIntoIter<N, T> as Iterator>::Item;
-    #[inline]
-    fn into_iter(self) -> Self::IntoIter {
-        let start = self.start;
-        let len = self.len();
-        RestrictedArrayIntoIter(self.array.into_iter().skip(start).take(len))
-    }
-}
-
-impl<'a, const N: usize, T> IntoIterator for &'a RestrictedArray<T, N> {
-    type IntoIter = core::slice::Iter<'a, T>;
-    type Item = &'a <RestrictedArrayIntoIter<N, T> as Iterator>::Item;
-    #[inline]
-    fn into_iter(self) -> Self::IntoIter {
-        self.as_slice().iter()
-    }
-}
-
-// region: PartialEq impls
-impl<const N: usize, T, U> PartialEq<[U]> for RestrictedArray<T, N>
-where
-    U: PartialEq<T>,
-{
-    /// This method tests for `self` and `other` values to be equal, and is used by `==`.  
-    /// Only compares the *visible* part of `self` against `other`.
-    fn eq(&self, other: &[U]) -> bool {
-        other == self.as_slice()
-    }
-}
-
-impl<const N: usize, T, U> PartialEq<RestrictedArray<T, N>> for [U]
-where
-    U: PartialEq<T>,
-{
-    /// This method tests for `self` and `other` values to be equal, and is used by `==`.  
-    /// Only compares the *visible* part of `other` against `self`.
-    fn eq(&self, other: &RestrictedArray<T, N>) -> bool {
-        self == other.as_slice()
-    }
-}
-// endregion: PartialEq impls
-
-impl<const N: usize, T> AsRef<[T]> for RestrictedArray<T, N> {
-    fn as_ref(&self) -> &[T] {
-        self.as_slice()
-    }
-}

From b476af23cd63e4c2ddb96e295d490c34bd90b91f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 13:01:29 +0200
Subject: [PATCH 085/212] minor doc and name tweaks

---
 src/array_section.rs | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index a6f9467..2bf7073 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -5,8 +5,6 @@ use core::{
 
 /// An array where only a section of the data may be viewed,
 /// as the other data may e.g. not uphold some invariant.  
-/// When this type is compared against some other type, only
-/// data in the visible part is compared.
 #[derive(Debug, Clone, Copy, Eq)]
 pub struct ArraySection<T, const N: usize> {
     start: usize,
@@ -14,9 +12,8 @@ pub struct ArraySection<T, const N: usize> {
     array: [T; N],
 }
 
+/// Only compares the data in the sections, and not the full arrays.
 impl<const N: usize, T: PartialEq<T>> PartialEq<ArraySection<T, N>> for ArraySection<T, N> {
-    /// This method tests for `self` and `other` values to be equal, and is used by `==`.  
-    /// Only compares the *visible* part of `self` against the *visible* part of `other`.
     fn eq(&self, other: &ArraySection<T, N>) -> bool {
         self.as_slice() == other.as_slice()
     }
@@ -61,7 +58,7 @@ impl<const N: usize, T> ArraySection<T, N> {
         self.array
     }
 
-    /// Returns the visible part of the array as a slice.
+    /// Returns the section of the array as a slice.
     pub const fn as_slice(&self) -> &[T] {
         let (_, tail) = self.array.split_at(self.start);
         tail.split_at(self.end - self.start).0
@@ -80,7 +77,7 @@ impl<const N: usize, T> ArraySection<T, N> {
     /// Returns whether the section is just the entire array.
     /// If this is `true` it is completely fine to call [`as_full_array`](RestrictedArray::as_full_array)
     /// or [`into_full_array`](RestrictedArray::into_full_array).
-    pub const fn section_is_complete_array(&self) -> bool {
+    pub const fn section_is_full_array(&self) -> bool {
         self.len() == N
     }
 

From b2209648ab977e8e7b0b198af68e968985a46378 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 13:02:29 +0200
Subject: [PATCH 086/212] Be explicit in impl of index<usize>

---
 src/array_section.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index 2bf7073..955be23 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -94,7 +94,7 @@ impl<const N: usize, T> core::ops::Index<usize> for ArraySection<T, N> {
     type Output = T;
     #[inline]
     fn index(&self, index: usize) -> &Self::Output {
-        &self.as_slice()[index]
+        core::ops::Index::index(self.as_slice(), index)
     }
 }
 

From 86e41cb8c0e9c59a16ea848d85bbb6ee8a5d685b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 13:03:53 +0200
Subject: [PATCH 087/212] Use arraysectioniter also for into_iter(&self)

---
 src/array_section.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index 955be23..ee0b992 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -158,11 +158,11 @@ impl<const N: usize, T> IntoIterator for ArraySection<T, N> {
 }
 
 impl<'a, const N: usize, T> IntoIterator for &'a ArraySection<T, N> {
-    type IntoIter = core::slice::Iter<'a, T>;
+    type IntoIter = ArraySectionIter<'a, T>;
     type Item = &'a <ArraySectionIntoIter<T, N> as Iterator>::Item;
     #[inline]
     fn into_iter(self) -> Self::IntoIter {
-        self.as_slice().iter()
+        ArraySectionIter::new(self.as_slice().iter())
     }
 }
 

From 824d16d4b316420eff31d0c0861d9b75d4405f1d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 13:04:44 +0200
Subject: [PATCH 088/212] Simplify impl of &self.into_iter()

---
 src/array_section.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index ee0b992..11ac353 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -159,7 +159,7 @@ impl<const N: usize, T> IntoIterator for ArraySection<T, N> {
 
 impl<'a, const N: usize, T> IntoIterator for &'a ArraySection<T, N> {
     type IntoIter = ArraySectionIter<'a, T>;
-    type Item = &'a <ArraySectionIntoIter<T, N> as Iterator>::Item;
+    type Item = <ArraySectionIter<'a, T> as Iterator>::Item;
     #[inline]
     fn into_iter(self) -> Self::IntoIter {
         ArraySectionIter::new(self.as_slice().iter())

From db284dff11201a00e8f1670a1df0482609deba3b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 13:06:33 +0200
Subject: [PATCH 089/212] Add newline before headings in docstrings

---
 src/generation.rs | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/generation.rs b/src/generation.rs
index b5f9948..556d055 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -12,6 +12,7 @@ pub type SegmentedGenerationResult<const N: usize> = Result<[u64; N], SegmentedG
 /// Uses a [segmented sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Segmented_sieve).
 ///
 /// # Example
+///
 /// ```
 /// # use const_primes::primes;
 /// const PRIMES: [u32; 10] = primes();
@@ -109,6 +110,7 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// If you want to compute primes that are larger than the input, take a look at [`primes_geq`].
 ///
 /// # Example
+///
 /// Basic usage:
 /// ```
 /// # use const_primes::generation::{SegmentedGenerationResult, primes_lt, SegmentedGenerationError};
@@ -142,6 +144,7 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// }
 /// ```
 /// # Panics
+///
 /// Panics if `N^2` does not fit in a `u64` or if `upper_limit` is larger than `N^2`. This is a compile error
 /// in const contexts:
 /// ```compile_fail
@@ -211,6 +214,7 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> SegmentedGenerat
 /// If you want to compute primes smaller than the input, take a look at [`primes_lt`].
 ///
 /// # Example
+///
 /// Basic usage:
 /// ```
 /// # use const_primes::primes_geq;
@@ -233,6 +237,7 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> SegmentedGenerat
 /// assert_eq!(PRIMES, [5, 7, 0]);
 /// ```
 /// # Panics
+///
 /// Panics if `N^2` does not fit in a `u64`.
 /// ```compile_fail
 /// # use const_primes::primes_geq;

From 08f6f806a5efea4c9aaf2180eb854554059b7b48 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 13:14:10 +0200
Subject: [PATCH 090/212] Statically assert N>0 using inline const

---
 src/lib.rs     |  1 +
 src/wrapper.rs | 12 ++++++------
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 6d580e7..a3cefdb 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -91,6 +91,7 @@
 
 #![forbid(unsafe_code)]
 #![cfg_attr(not(test), no_std)]
+#![feature(inline_const)]
 
 /// The type that `Primes<N>` stores, and `primes::<N>()`` returns. Currently `u32`.
 // Just change this to whatever unsigned primitive integer type you want and it should work as long as it has enough bits for your purposes.
diff --git a/src/wrapper.rs b/src/wrapper.rs
index 6072f48..cd0ef42 100644
--- a/src/wrapper.rs
+++ b/src/wrapper.rs
@@ -36,6 +36,7 @@ impl<const N: usize> Primes<N> {
     /// Uses a [segmented sieve of Eratosthenes](https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Segmented_sieve).
     ///
     /// # Examples
+    ///
     /// Basic usage
     /// ```
     /// # use const_primes::Primes;
@@ -54,19 +55,18 @@ impl<const N: usize> Primes<N> {
     /// assert_eq!(primes, [2, 3, 5, 7, 11]);
     /// ```
     ///
-    /// # Panics
-    ///
-    /// Panics if `N` is zero. In const contexts this will fail to compile
+    /// Fails to compile if `N` is zero.
     /// ```compile_fail
     /// # use const_primes::Primes;
     /// const NO_PRIMES: Primes<0> = Primes::new();
     /// ```
-    /// In other contexts it may panic at runtime instead.  
+    /// 
+    /// # Panics
+    /// 
     /// If any of the primes overflow a `u32` it will panic in const contexts or debug mode.
     #[must_use = "the associated method only returns a new value"]
     pub const fn new() -> Self {
-        assert!(N >= 1, "`N` must be at least 1");
-
+        const { assert!(N > 0, "`N` must be at least 1") }
         Self { primes: primes() }
     }
 

From 80e284f71cd4e4a01e5f19fd33f85fd936e3144b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 13:18:42 +0200
Subject: [PATCH 091/212] Add info about new panic behavior to type docstring

---
 src/wrapper.rs | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/wrapper.rs b/src/wrapper.rs
index cd0ef42..d5f194d 100644
--- a/src/wrapper.rs
+++ b/src/wrapper.rs
@@ -3,9 +3,10 @@ use crate::{primes, Underlying};
 // region: Primes<N>
 
 /// A wrapper around an array that consists of the first `N` primes.
-/// Can be created in const contexts, and if so it ensures that `N` is non-zero at compile time.
+/// Can be created in const contexts, and ensures that `N` is non-zero at compile time.
 ///
 /// # Examples
+///
 /// Basic usage
 /// ```
 /// # use const_primes::Primes;
@@ -60,9 +61,9 @@ impl<const N: usize> Primes<N> {
     /// # use const_primes::Primes;
     /// const NO_PRIMES: Primes<0> = Primes::new();
     /// ```
-    /// 
+    ///
     /// # Panics
-    /// 
+    ///
     /// If any of the primes overflow a `u32` it will panic in const contexts or debug mode.
     #[must_use = "the associated method only returns a new value"]
     pub const fn new() -> Self {

From 60b0865eb02c0b32641001b0c91aaf46637c8f3c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 13:32:24 +0200
Subject: [PATCH 092/212] Add space before header in docstring

---
 src/lib.rs     | 4 ++--
 src/wrapper.rs | 1 +
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index a3cefdb..0beb600 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -106,7 +106,7 @@ mod other_prime;
 mod sieving;
 mod wrapper;
 
-pub use generation::primes;
+pub use generation::{primes, primes_geq, primes_lt};
 use imath::isqrt;
 pub use miller_rabin::is_prime;
 pub use other_prime::{next_prime, previous_prime};
@@ -151,7 +151,7 @@ pub const fn prime_counts<const N: usize>() -> [usize; N] {
 mod test {
     use super::*;
 
-    use generation::{primes_lt, SegmentedGenerationResult};
+    use generation::SegmentedGenerationResult;
 
     #[test]
     fn check_primes_is_prime() {
diff --git a/src/wrapper.rs b/src/wrapper.rs
index d5f194d..673bb36 100644
--- a/src/wrapper.rs
+++ b/src/wrapper.rs
@@ -221,6 +221,7 @@ impl<const N: usize> Primes<N> {
     /// Converts `self` into an array of size `N`.
     ///
     /// # Example
+    ///
     /// Basic usage
     /// ```
     /// # use const_primes::Primes;

From 066f074289c4f13a6c8851e9714a657e4e217df6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 13:37:33 +0200
Subject: [PATCH 093/212] Add newline around headings in docstrings

---
 src/sieving.rs | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/sieving.rs b/src/sieving.rs
index 97e1e69..aae0478 100644
--- a/src/sieving.rs
+++ b/src/sieving.rs
@@ -56,6 +56,7 @@ pub(crate) const fn sieve_segment<const N: usize>(
 /// and then uses the result to sieve the output range if needed.
 ///
 /// # Examples
+///
 /// Basic usage
 /// ```
 /// # use const_primes::sieve_lt;
@@ -81,6 +82,7 @@ pub(crate) const fn sieve_segment<const N: usize>(
 /// ```
 ///
 /// # Panics
+///
 /// Panics if `upper_limit` is not in the range `[N, N^2]`. In const contexts these are compile errors:
 /// ```compile_fail
 /// # use const_primes::sieve_lt;
@@ -121,6 +123,7 @@ pub const fn sieve_lt<const N: usize>(upper_limit: u64) -> [bool; N] {
 /// Uses a sieve of Eratosthenes.
 ///
 /// # Example
+///
 /// ```
 /// # use const_primes::sieve;
 /// const PRIMALITY: [bool; 10] = sieve();
@@ -166,6 +169,7 @@ pub const fn sieve<const N: usize>() -> [bool; N] {
 /// Returns the prime status of the `N` smallest integers greater than or equal to `lower_limit`.
 ///
 /// # Example
+///
 /// Basic usage:
 /// ```
 /// # use const_primes::sieve_geq;

From c89e1252973a4c97b59b33d1b2ccb06b3daf9e74 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 13:38:31 +0200
Subject: [PATCH 094/212] Add newline around headings in docstrings

---
 src/sieving.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/sieving.rs b/src/sieving.rs
index aae0478..d116b19 100644
--- a/src/sieving.rs
+++ b/src/sieving.rs
@@ -178,6 +178,7 @@ pub const fn sieve<const N: usize>() -> [bool; N] {
 /// assert_eq!(PRIME_STATUS, [false, true, false, true, false]);
 /// ```
 /// # Panics
+/// 
 /// Panics if `N + lower_limit` is larger than or equal to `N^2`. In const contexts this is a compile error:
 /// ```compile_fail
 /// # use const_primes::sieve_geq;

From da8e1446c9cc6425fa821383e11db831b7c5cf68 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 13:42:20 +0200
Subject: [PATCH 095/212] Fail to compile in primes if N = 0

---
 src/generation.rs | 12 +++++++++---
 src/sieving.rs    |  2 +-
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 556d055..4326263 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -18,11 +18,17 @@ pub type SegmentedGenerationResult<const N: usize> = Result<[u64; N], SegmentedG
 /// const PRIMES: [u32; 10] = primes();
 /// assert_eq!(PRIMES, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]);
 /// ```
+/// Fails to compile if `N = 0`:
+/// ```compile_fail
+/// # use const_primes::primes;
+/// let primes: [u32; 0] = primes();
+/// ```
+///
 #[must_use = "the function only returns a new value"]
 pub const fn primes<const N: usize>() -> [Underlying; N] {
-    if N == 0 {
-        return [0; N];
-    } else if N == 1 {
+    const { assert!(N > 0, "`N` must be at least 1") }
+
+    if N == 1 {
         return [2; N];
     } else if N == 2 {
         let mut primes = [0; N];
diff --git a/src/sieving.rs b/src/sieving.rs
index d116b19..f2e5ff7 100644
--- a/src/sieving.rs
+++ b/src/sieving.rs
@@ -178,7 +178,7 @@ pub const fn sieve<const N: usize>() -> [bool; N] {
 /// assert_eq!(PRIME_STATUS, [false, true, false, true, false]);
 /// ```
 /// # Panics
-/// 
+///
 /// Panics if `N + lower_limit` is larger than or equal to `N^2`. In const contexts this is a compile error:
 /// ```compile_fail
 /// # use const_primes::sieve_geq;

From 73a6fb5c05a7c510e7afaae5042e94f54b813350 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 13:46:06 +0200
Subject: [PATCH 096/212] Compile fail in all sieve functions if N == 0

---
 src/generation.rs | 4 ++++
 src/sieving.rs    | 8 ++++++++
 2 files changed, 12 insertions(+)

diff --git a/src/generation.rs b/src/generation.rs
index 4326263..c27ba83 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -165,6 +165,8 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
 pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> SegmentedGenerationResult<N> {
+    const { assert!(N > 0, "`N` must be at least 1") }
+
     let n64 = N as u64;
     match (n64).checked_mul(n64) {
         Some(prod) => {
@@ -251,6 +253,8 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> SegmentedGenerat
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
 pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> SegmentedGenerationResult<N> {
+    const { assert!(N > 0, "`N` must be at least 1") }
+
     let n64 = N as u64;
     if n64.checked_mul(n64).is_none() {
         return Err(SegmentedGenerationError::TooLargeN);
diff --git a/src/sieving.rs b/src/sieving.rs
index f2e5ff7..238f5b2 100644
--- a/src/sieving.rs
+++ b/src/sieving.rs
@@ -8,6 +8,8 @@ pub(crate) const fn sieve_segment<const N: usize>(
     base_sieve: &[bool; N],
     upper_limit: u64,
 ) -> [bool; N] {
+    const { assert!(N > 0, "`N` must be at least 1") }
+
     let mut segment_sieve = [true; N];
 
     let lower_limit = upper_limit - N as u64;
@@ -94,6 +96,8 @@ pub(crate) const fn sieve_segment<const N: usize>(
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
 pub const fn sieve_lt<const N: usize>(upper_limit: u64) -> [bool; N] {
+    const { assert!(N > 0, "`N` must be at least 1") }
+
     let n64 = N as u64;
 
     // Since panics are compile time errors in const contexts
@@ -132,6 +136,8 @@ pub const fn sieve_lt<const N: usize>(upper_limit: u64) -> [bool; N] {
 /// ```
 #[must_use = "the function only returns a new value"]
 pub const fn sieve<const N: usize>() -> [bool; N] {
+    const { assert!(N > 0, "`N` must be at least 1") }
+
     let mut sieve = [true; N];
     if N > 0 {
         sieve[0] = false;
@@ -186,6 +192,8 @@ pub const fn sieve<const N: usize>() -> [bool; N] {
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
 pub const fn sieve_geq<const N: usize>(lower_limit: u64) -> [bool; N] {
+    const { assert!(N > 0, "`N` must be at least 1") }
+
     let n64 = N as u64;
 
     // Since panics are compile time errors in const contexts

From 35d086a3ece1a01c97fd3201f8d7bf192b6daec1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 13:47:14 +0200
Subject: [PATCH 097/212] Document compile fail when N=0

---
 src/sieving.rs | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/sieving.rs b/src/sieving.rs
index 238f5b2..9668954 100644
--- a/src/sieving.rs
+++ b/src/sieving.rs
@@ -2,7 +2,7 @@ use crate::isqrt;
 
 /// Uses the primalities of the first `N` integers in `base_sieve` to sieve the numbers in the range `[upper_limit - N, upper_limit)`.
 /// Assumes that the base sieve contains the prime status of the `N` fist integers. The output is only meaningful
-/// for the numbers below `N^2`.
+/// for the numbers below `N^2`. Fails to compile if `N` is 0.
 #[must_use = "the function only returns a new value and does not modify its inputs"]
 pub(crate) const fn sieve_segment<const N: usize>(
     base_sieve: &[bool; N],
@@ -57,6 +57,8 @@ pub(crate) const fn sieve_segment<const N: usize>(
 /// Uses a sieve of Eratosthenes to sieve the first `N` integers
 /// and then uses the result to sieve the output range if needed.
 ///
+///  Fails to compile if `N` is 0.
+///
 /// # Examples
 ///
 /// Basic usage
@@ -123,6 +125,7 @@ pub const fn sieve_lt<const N: usize>(upper_limit: u64) -> [bool; N] {
 }
 
 /// Returns an array of size `N` where the value at a given index indicates whether the index is prime.
+/// Fails to compile if `N` is 0.
 ///
 /// Uses a sieve of Eratosthenes.
 ///
@@ -173,6 +176,7 @@ pub const fn sieve<const N: usize>() -> [bool; N] {
 }
 
 /// Returns the prime status of the `N` smallest integers greater than or equal to `lower_limit`.
+/// Fails to compile if `N` is 0.
 ///
 /// # Example
 ///

From 7eb8d6482ee7adabcd84e970bb435ac0d21d3fdd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 13:48:30 +0200
Subject: [PATCH 098/212] Document compile fail in generation functions

---
 src/generation.rs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/generation.rs b/src/generation.rs
index c27ba83..6244d64 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -6,6 +6,7 @@ use crate::{array_section::ArraySection, sieve, sieving::sieve_segment, Underlyi
 pub type SegmentedGenerationResult<const N: usize> = Result<[u64; N], SegmentedGenerationError<N>>;
 
 /// Returns the `N` first prime numbers.
+/// Fails to compile if `N` is 0.
 ///
 /// [`Primes`](crate::Primes) might be relevant for you if you intend to later use these prime numbers for related computations.
 ///
@@ -109,6 +110,7 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 }
 
 /// Returns the `N` largest primes less than `upper_limit`.
+/// Fails to compile if `N` is 0.
 ///
 /// The return array fills from the end until either it is full or there are no more primes.
 /// If the primes run out before the array is filled the first elements will have a value of zero.
@@ -215,6 +217,7 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> SegmentedGenerat
 }
 
 /// Returns the `N` smallest primes greater than or equal to `lower_limit`.
+/// Fails to compile if `N` is 0.
 ///
 /// This function will fill the output array from index 0 and stop generating primes if they exceed `N^2`.
 /// In that case the remaining elements of the output array will be 0.

From 60c9e1c7d6a1ba746c4d651796aed55f6d598544 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 13:51:22 +0200
Subject: [PATCH 099/212] Fix compile errors of tests

---
 src/lib.rs | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 0beb600..136f1ef 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -179,11 +179,11 @@ mod test {
             };
         }
         test_to!(
-            0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
-            24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
-            46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
-            68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
-            90, 91, 92, 93, 94, 95, 96, 97, 98, 99
+            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+            25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+            47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
+            69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+            91, 92, 93, 94, 95, 96, 97, 98, 99
         );
     }
 
@@ -210,7 +210,7 @@ mod test {
             };
         }
 
-        test_prime_counts_up_to!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 50, 100);
+        test_prime_counts_up_to!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 50, 100);
     }
 
     #[test]
@@ -227,7 +227,7 @@ mod test {
             };
         }
 
-        test_to_n!(0, 1, 2, 3, 4, 5, 10, 100, 1000, 10000);
+        test_to_n!(1, 2, 3, 4, 5, 10, 100, 1000, 10000);
     }
 
     #[test]

From 57e5511bfe6ce8234479fefe6682347777d40151 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 13:54:35 +0200
Subject: [PATCH 100/212] impl Default when N>0

---
 src/wrapper.rs | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/wrapper.rs b/src/wrapper.rs
index 673bb36..b99fb5a 100644
--- a/src/wrapper.rs
+++ b/src/wrapper.rs
@@ -304,6 +304,14 @@ impl<const N: usize> Primes<N> {
     }
 }
 
+/// This statically asserts that N > 0.
+impl<const N: usize> Default for Primes<N> {
+    fn default() -> Self {
+        const { assert!(N > 0, "`N` must be at least 1") }
+        Self::new()
+    }
+}
+
 impl<const N: usize, I> core::ops::Index<I> for Primes<N>
 where
     I: core::slice::SliceIndex<[Underlying]>,

From e73fd433246177bdce8f8855ca39f17cfce19a21 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 14:32:36 +0200
Subject: [PATCH 101/212] Make primes_geq set lower_limit to 2 if it was lower

---
 src/generation.rs | 32 +++++++++++++++++---------------
 1 file changed, 17 insertions(+), 15 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 6244d64..8995ba6 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -217,7 +217,8 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> SegmentedGenerat
 }
 
 /// Returns the `N` smallest primes greater than or equal to `lower_limit`.
-/// Fails to compile if `N` is 0.
+/// Fails to compile if `N` is 0. If `lower_limit` is less than 2 this functions assumes that it is 2,
+/// since there are no primes smaller than 2.
 ///
 /// This function will fill the output array from index 0 and stop generating primes if they exceed `N^2`.
 /// In that case the remaining elements of the output array will be 0.
@@ -247,22 +248,30 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> SegmentedGenerat
 /// const PRIMES: [u64; 3] = primes_geq(5);
 /// assert_eq!(PRIMES, [5, 7, 0]);
 /// ```
-/// # Panics
+/// # Errors
 ///
-/// Panics if `N^2` does not fit in a `u64`.
-/// ```compile_fail
+/// Returns an error if `N^2` does not fit in a `u64`, or if `lower_limit` is larger or equal to `N^2`.
+/// ```
 /// # use const_primes::primes_geq;
 /// const P: [u64; u32::MAX as usize + 1] = primes_geq(0);
 /// ```
+/// ```
+/// # use const_primes::primes_geq;
+/// const P: [u64; 5] = primes_geq(26);
+/// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
 pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> SegmentedGenerationResult<N> {
     const { assert!(N > 0, "`N` must be at least 1") }
 
     let n64 = N as u64;
-    if n64.checked_mul(n64).is_none() {
+    let Some(n64_sqr) = n64.checked_mul(n64) else {
         return Err(SegmentedGenerationError::TooLargeN);
-    }
-    if lower_limit >= n64 * n64 {
+    };
+
+    // There are no primes smaller than 2, so we will always start looking at 2.
+    lower_limit = if lower_limit >= 2 { lower_limit } else { 2 };
+
+    if lower_limit >= n64_sqr {
         return Err(SegmentedGenerationError::TooLargeLimit);
     }
 
@@ -276,7 +285,6 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> SegmentedGenera
         // Move the found primes into the output vector.
         while i < N {
             if upper_sieve[i] {
-                // FIXME: BUG IDENTIFIED: THIS COULD BE 0
                 largest_found_prime = lower_limit + i as u64;
                 if largest_found_prime >= n64 * n64 {
                     // We do not know if this is actually a prime
@@ -357,13 +365,7 @@ mod test {
         }
         {
             const P: SegmentedGenerationResult<1> = primes_geq(0);
-            assert_eq!(
-                P,
-                Err(SegmentedGenerationError::PartialOk(ArraySection::new(
-                    0..0,
-                    [0]
-                )))
-            );
+            assert_eq!(P, Err(SegmentedGenerationError::TooLargeLimit),);
         }
         for prime in primes_geq::<2_000>(3_998_000)
             .unwrap_err()

From 43089c9822b223a12caa262eadd0b5a9b2b9019d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 14:36:08 +0200
Subject: [PATCH 102/212] primes_lt return error if upper_limit <= 2

---
 src/generation.rs | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 8995ba6..eaf9803 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -151,10 +151,11 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 ///     _ => panic!(),
 /// }
 /// ```
-/// # Panics
+/// # Errors
+///
+/// Returns an error if `N^2` does not fit in a `u64`,
+/// if `upper_limit` is larger than `N^2` or if `upper_limit` is smaller than or equal to 2.
 ///
-/// Panics if `N^2` does not fit in a `u64` or if `upper_limit` is larger than `N^2`. This is a compile error
-/// in const contexts:
 /// ```compile_fail
 /// # use const_primes::generation::{SegmentedGenerationResult,primes_lt};
 /// //                                       N is too large
@@ -169,6 +170,10 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> SegmentedGenerationResult<N> {
     const { assert!(N > 0, "`N` must be at least 1") }
 
+    if upper_limit <= 2 {
+        return Err(SegmentedGenerationError::TooSmallLimit);
+    }
+
     let n64 = N as u64;
     match (n64).checked_mul(n64) {
         Some(prod) => {
@@ -318,6 +323,8 @@ pub enum SegmentedGenerationError<const N: usize> {
     TooLargeN,
     /// the upper limit was larger than `N^2`.
     TooLargeLimit,
+    /// the lower limit was smaller than or equal to 2.
+    TooSmallLimit,
     /// Only a part of the output array contains prime numbers as they either exceeded `N^2` or ran out.
     PartialOk(ArraySection<u64, N>),
 }
@@ -342,6 +349,7 @@ impl<const N: usize> fmt::Display for SegmentedGenerationError<N> {
         match self {
             Self::TooLargeN => write!(f, "`N^2` did not fit in a `u64`"),
             Self::TooLargeLimit => write!(f, "the upper limit was larger than `N^2`"),
+            Self::TooSmallLimit => write!(f, "the lower limit was smaller than or equal to 2"),
             Self::PartialOk(_) => write!(f, "the sieve entered into a range it's too small for, or the primes ran out. You can access the partially completed result with the function `partial_result`"),
         }
     }

From 5bbe7a9018a81c5fa581c535e37f933494f7adad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 14:41:37 +0200
Subject: [PATCH 103/212] Specify type link for partial_ok

---
 src/generation.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/generation.rs b/src/generation.rs
index eaf9803..114b828 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -330,7 +330,7 @@ pub enum SegmentedGenerationError<const N: usize> {
 }
 
 impl<const N: usize> SegmentedGenerationError<N> {
-    /// Returns the partial result as a restricted array, if there is one.
+    /// Returns the partial result as an [`ArraySection`], if there is one.
     pub const fn partial_ok(self) -> Option<ArraySection<u64, N>> {
         match self {
             Self::PartialOk(restricted_array) => Some(restricted_array),

From 254f345a611301b7e3aeb9335b3649c3388435ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 14:43:15 +0200
Subject: [PATCH 104/212] impl Hash for ArraySection and
 SegmentedGenerationError

---
 src/array_section.rs | 2 +-
 src/generation.rs    | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index 11ac353..2830b8e 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -5,7 +5,7 @@ use core::{
 
 /// An array where only a section of the data may be viewed,
 /// as the other data may e.g. not uphold some invariant.  
-#[derive(Debug, Clone, Copy, Eq)]
+#[derive(Debug, Clone, Copy, Eq, Hash)]
 pub struct ArraySection<T, const N: usize> {
     start: usize,
     end: usize,
diff --git a/src/generation.rs b/src/generation.rs
index 114b828..482032c 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -317,7 +317,7 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> SegmentedGenera
 /// array is larger than the actual number of primes less than the given `upper_limit`.
 /// It can also be returned by [`primes_geq`] if it needs to sieve into a
 /// region of numbers that exceed the square of the size of the requested array.
-#[derive(Debug, Clone, Copy, PartialEq)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum SegmentedGenerationError<const N: usize> {
     /// `N^2`` did not fit in a `u64`.
     TooLargeN,

From 0b3c7193b552c978e2dd615b4d1576120a7e2959 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 14:47:27 +0200
Subject: [PATCH 105/212] Add start and end to ArraySection

---
 src/array_section.rs | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/array_section.rs b/src/array_section.rs
index 2830b8e..70e2fc9 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -46,6 +46,16 @@ impl<const N: usize, T> ArraySection<T, N> {
         }
     }
 
+    /// Returns the first index of the full underlying array that is part of the section.
+    pub const fn start(&self) -> usize {
+        self.start
+    }
+
+    /// Returns the first index of the full underlying array that is outside the section (to the left).
+    pub const fn end(&self) -> usize {
+        self.end
+    }
+
     /// Returns a reference to the full underlying array. There is no guarantee about the data
     /// outside the section.
     pub const fn as_full_array(&self) -> &[T; N] {

From ef2e881b8059cdf9b2dca6c5a2c913ebdc4c8e30 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 14:48:08 +0200
Subject: [PATCH 106/212] Correct left to right in docstring of end

---
 src/array_section.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index 70e2fc9..711fcae 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -51,7 +51,7 @@ impl<const N: usize, T> ArraySection<T, N> {
         self.start
     }
 
-    /// Returns the first index of the full underlying array that is outside the section (to the left).
+    /// Returns the first index of the full underlying array that is outside the section (to the right).
     pub const fn end(&self) -> usize {
         self.end
     }

From f5e44101830eccddb0f23385b79a69af82b84b2b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 14:50:29 +0200
Subject: [PATCH 107/212] Link between start and end

---
 src/array_section.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/array_section.rs b/src/array_section.rs
index 711fcae..b5d4d69 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -47,11 +47,13 @@ impl<const N: usize, T> ArraySection<T, N> {
     }
 
     /// Returns the first index of the full underlying array that is part of the section.
+    /// I.e. the section is the subrange `start ..`[`end`](ArraySection::end).
     pub const fn start(&self) -> usize {
         self.start
     }
 
     /// Returns the first index of the full underlying array that is outside the section (to the right).
+    /// I.e. the section is the subrange [`start`](ArraySection::start)`.. end`.
     pub const fn end(&self) -> usize {
         self.end
     }

From 109fe61397ded2151e959757aeb36c5478e36f1d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 14:51:25 +0200
Subject: [PATCH 108/212] Shorten core::ops::Index with use statement

---
 src/array_section.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index b5d4d69..838f2bd 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -1,6 +1,6 @@
 use core::{
     iter::FusedIterator,
-    ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
+    ops::{Index, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
 };
 
 /// An array where only a section of the data may be viewed,
@@ -102,11 +102,11 @@ impl<const N: usize, T> ArraySection<T, N> {
 
 // region: Index impls
 
-impl<const N: usize, T> core::ops::Index<usize> for ArraySection<T, N> {
+impl<const N: usize, T> Index<usize> for ArraySection<T, N> {
     type Output = T;
     #[inline]
     fn index(&self, index: usize) -> &Self::Output {
-        core::ops::Index::index(self.as_slice(), index)
+        Index::index(self.as_slice(), index)
     }
 }
 

From 37625d9fd7736d0ed16f7a19c31eb57446d15b6e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 14:51:53 +0200
Subject: [PATCH 109/212] Specify full path of ArraySection in macro

---
 src/array_section.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index 838f2bd..448fc7b 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -113,7 +113,7 @@ impl<const N: usize, T> Index<usize> for ArraySection<T, N> {
 macro_rules! impl_index_range {
     ($($t:ty),+) => {
         $(
-            impl<const N: ::core::primitive::usize, T> ::core::ops::Index<$t> for ArraySection<T, N> {
+            impl<const N: ::core::primitive::usize, T> ::core::ops::Index<$t> for $crate::array_section::ArraySection<T, N> {
                 type Output = [T];
                 #[inline]
                 fn index(&self, index: $t) -> &Self::Output {

From 4d3ce4372814cd92488827e5effe1be4b8f90fbf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 26 Apr 2024 14:53:27 +0200
Subject: [PATCH 110/212] Simplify Index<usize> imple

---
 src/array_section.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index 448fc7b..5ee39b5 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -106,7 +106,7 @@ impl<const N: usize, T> Index<usize> for ArraySection<T, N> {
     type Output = T;
     #[inline]
     fn index(&self, index: usize) -> &Self::Output {
-        Index::index(self.as_slice(), index)
+        self.as_slice().index(index)
     }
 }
 

From 4c83e566fb47a3e3d94742203f8cb77b05de42d5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 28 Apr 2024 11:16:20 +0200
Subject: [PATCH 111/212] Fixed final test, on to doctests

---
 src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/lib.rs b/src/lib.rs
index 136f1ef..a82c953 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -236,7 +236,7 @@ mod test {
             ($($n:expr),+) => {
                 $(
                     {
-                        const P: SegmentedGenerationResult<10> = primes_lt(100);
+                        const P: SegmentedGenerationResult<$n> = primes_lt(100);
                         for (i, prime) in P.unwrap().into_iter().enumerate() {
                             assert_eq!(PRECOMPUTED_PRIMES[25-$n..25][i], prime as u32);
                         }

From 1d4d07eb7ba2e09dc4de27454a4a67269d73ef79 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 28 Apr 2024 11:18:21 +0200
Subject: [PATCH 112/212] Add const assert to prime_counts

---
 src/lib.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/lib.rs b/src/lib.rs
index a82c953..5ff1963 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -114,6 +114,7 @@ pub use sieving::{sieve, sieve_geq, sieve_lt};
 pub use wrapper::Primes;
 
 /// Returns an array of size `N` where the value at a given index is how many primes are less than or equal to the index.
+/// Fails to compile if `N` is 0.
 ///
 /// Sieves primes with [`sieve`] and then counts them.
 ///
@@ -126,6 +127,7 @@ pub use wrapper::Primes;
 /// ```
 #[must_use = "the function only returns a new value"]
 pub const fn prime_counts<const N: usize>() -> [usize; N] {
+    const { assert!(N > 0, "`N` must be at least 1") }
     let mut counts = [0; N];
     if N <= 2 {
         return counts;

From 21bfd9a26d1bd4c2b8b722993e44ff3bffd14b6a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 28 Apr 2024 11:54:43 +0200
Subject: [PATCH 113/212] Fixed some doc tests

---
 src/generation.rs | 69 +++++++++++++++++++++++++++++------------------
 src/lib.rs        | 20 ++++----------
 2 files changed, 48 insertions(+), 41 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 482032c..7de964d 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -144,12 +144,7 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// ```
 /// # use const_primes::generation::{SegmentedGenerationResult, primes_lt};
 /// const PRIMES: SegmentedGenerationResult<9> = primes_lt(10);
-/// match PRIMES.err() {
-///     Some(SegmentedGenerationError::PartialOk(arr)) => {
-///         // There are only four primes less than 10:
-///         assert_eq!(arr.as_slice(), [2, 3, 5, 7]);}
-///     _ => panic!(),
-/// }
+/// assert_eq!(PRIMES.map_err(|e| e.try_as_slice()), Err(Some(&[2, 3, 5, 7])))
 /// ```
 /// # Errors
 ///
@@ -159,7 +154,7 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// ```compile_fail
 /// # use const_primes::generation::{SegmentedGenerationResult,primes_lt};
 /// //                                       N is too large
-/// const PRIMES: SegmentedGenerationResult<{u32::MAX as usize + 1}> = primes_lt(100);
+/// const PRIMES: SegmentedGenerationResult<u64::MAX as usize> = primes_lt(100);
 /// ```
 /// ```compile_fail
 /// # use const_primes::generation::{primes_lt, SegmentedGenerationResult};
@@ -234,35 +229,41 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> SegmentedGenerat
 ///
 /// Basic usage:
 /// ```
-/// # use const_primes::primes_geq;
-/// const PRIMES: [u64; 5] = primes_geq(10);
-/// assert_eq!(PRIMES, [11, 13, 17, 19, 23]);
+/// # use const_primes::{primes_geq, SegmentedGenerationResult, SegmentedGenerationError};
+/// const PRIMES: SegmentedGenerationResult<5> = primes_geq(10);
+/// assert_eq!(PRIMES?, [11, 13, 17, 19, 23]);
+/// # Ok::<(), SegmentedGenerationError<5>>(())
 /// ```
 /// Compute larger primes without starting from zero:
 /// ```
-/// # use const_primes::primes_geq;
+/// # use const_primes::{primes_geq, SegmentedGenerationResult, SegmentedGenerationError};
 /// const N: usize = 71_000;
 /// # #[allow(long_running_const_eval)]
-/// const P: [u64; N] = primes_geq(5_000_000_030);
-/// assert_eq!(P[..3], [5_000_000_039, 5_000_000_059, 5_000_000_063]);
-/// assert_eq!(P[N - 3..], [5_001_586_727, 5_001_586_729, 5_001_586_757]);
+/// const P: SegmentedGenerationResult<N> = primes_geq(5_000_000_030);
+/// assert_eq!(P?[..3], [5_000_000_039, 5_000_000_059, 5_000_000_063]);
+/// assert_eq!(P?[N - 3..], [5_001_586_727, 5_001_586_729, 5_001_586_757]);
+/// # Ok::<(), SegmentedGenerationError<N>>(())
 /// ```
 /// Only primes smaller than `N^2` will be generated:
 /// ```
-/// # use const_primes::primes_geq;
-/// const PRIMES: [u64; 3] = primes_geq(5);
-/// assert_eq!(PRIMES, [5, 7, 0]);
+/// # use const_primes::{primes_geq, SegmentedGenerationResult, SegmentedGenerationError};
+/// const PRIMES: SegmentedGenerationResult<3> = primes_geq(5);
+/// assert_eq!(PRIMES.map_err(|e| e.try_as_slice()), Err(Some([5, 7].as_slice())));
+/// # Ok::<(), SegmentedGenerationError<3>>(())
 /// ```
+///
 /// # Errors
 ///
 /// Returns an error if `N^2` does not fit in a `u64`, or if `lower_limit` is larger or equal to `N^2`.
 /// ```
-/// # use const_primes::primes_geq;
-/// const P: [u64; u32::MAX as usize + 1] = primes_geq(0);
+/// # use const_primes::{primes_geq, SegmentedGenerationResult};
+/// const P: SegmentedGenerationResult<{u32::MAX as usize + 1}> = primes_geq(0);
+/// assert!(P.is_err());
 /// ```
 /// ```
-/// # use const_primes::primes_geq;
-/// const P: [u64; 5] = primes_geq(26);
+/// # use const_primes::{primes_geq, SegmentedGenerationResult};
+/// const P: SegmentedGenerationResult<5> = primes_geq(26);
+/// assert!(P.is_err());
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
 pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> SegmentedGenerationResult<N> {
@@ -330,10 +331,26 @@ pub enum SegmentedGenerationError<const N: usize> {
 }
 
 impl<const N: usize> SegmentedGenerationError<N> {
-    /// Returns the partial result as an [`ArraySection`], if there is one.
-    pub const fn partial_ok(self) -> Option<ArraySection<u64, N>> {
+    /// Returns the partial result as a reference to an [`ArraySection`], if there is one.
+    pub const fn try_as_array_section(&self) -> Option<&ArraySection<u64, N>> {
+        match self {
+            Self::PartialOk(ref restricted_array) => Some(&restricted_array),
+            _ => None,
+        }
+    }
+
+    /// Consumes the error and returns the partial result as an [`ArraySection`], if there is one.
+    pub const fn try_into_array_section(self) -> Option<ArraySection<u64, N>> {
+        match self {
+            Self::PartialOk(ra) => Some(ra),
+            _ => None,
+        }
+    }
+
+    /// Returns the partial result as a slice if there is one.
+    pub const fn try_as_slice(&self) -> Option<&[u64]> {
         match self {
-            Self::PartialOk(restricted_array) => Some(restricted_array),
+            Self::PartialOk(ref ra) => Some(ra.as_slice()),
             _ => None,
         }
     }
@@ -375,9 +392,9 @@ mod test {
             const P: SegmentedGenerationResult<1> = primes_geq(0);
             assert_eq!(P, Err(SegmentedGenerationError::TooLargeLimit),);
         }
-        for prime in primes_geq::<2_000>(3_998_000)
+        for &prime in primes_geq::<2_000>(3_998_000)
             .unwrap_err()
-            .partial_ok()
+            .try_as_slice()
             .unwrap()
         {
             if prime == 0 {
diff --git a/src/lib.rs b/src/lib.rs
index 5ff1963..635317b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -106,7 +106,9 @@ mod other_prime;
 mod sieving;
 mod wrapper;
 
-pub use generation::{primes, primes_geq, primes_lt};
+pub use generation::{
+    primes, primes_geq, primes_lt, SegmentedGenerationError, SegmentedGenerationResult,
+};
 use imath::isqrt;
 pub use miller_rabin::is_prime;
 pub use other_prime::{next_prime, previous_prime};
@@ -153,8 +155,6 @@ pub const fn prime_counts<const N: usize>() -> [usize; N] {
 mod test {
     use super::*;
 
-    use generation::SegmentedGenerationResult;
-
     #[test]
     fn check_primes_is_prime() {
         const SET: Primes<3> = Primes::new();
@@ -255,21 +255,11 @@ mod test {
 
         assert_eq!(
             [2, 3, 5, 7],
-            primes_lt::<9>(10)
-                .err()
-                .unwrap()
-                .partial_ok()
-                .unwrap()
-                .as_slice()
+            primes_lt::<9>(10).err().unwrap().try_as_slice().unwrap()
         );
 
         assert_eq!(
-            primes_lt::<2>(3)
-                .err()
-                .unwrap()
-                .partial_ok()
-                .unwrap()
-                .as_slice(),
+            primes_lt::<2>(3).err().unwrap().try_as_slice().unwrap(),
             [2]
         );
     }

From 44d0cbdf09fcd770b2df9fc1b51dc5c8c09c831b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 28 Apr 2024 11:56:46 +0200
Subject: [PATCH 114/212] Rename SegmentedGeneration* to *

---
 src/generation.rs | 86 +++++++++++++++++++++++------------------------
 src/lib.rs        |  6 ++--
 2 files changed, 45 insertions(+), 47 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 7de964d..f23fb97 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -3,7 +3,7 @@ use core::fmt;
 use crate::{array_section::ArraySection, sieve, sieving::sieve_segment, Underlying};
 
 /// Type alias for the type returned by the segmented generation functions, that otherwise has two generics that must be the same.
-pub type SegmentedGenerationResult<const N: usize> = Result<[u64; N], SegmentedGenerationError<N>>;
+pub type Result<const N: usize> = core::result::Result<[u64; N], Error<N>>;
 
 /// Returns the `N` first prime numbers.
 /// Fails to compile if `N` is 0.
@@ -121,29 +121,29 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 ///
 /// Basic usage:
 /// ```
-/// # use const_primes::generation::{SegmentedGenerationResult, primes_lt, SegmentedGenerationError};
-/// const PRIMES: SegmentedGenerationResult<10> = primes_lt(100);
+/// # use const_primes::generation::{Result, primes_lt, Error};
+/// const PRIMES: Result<10> = primes_lt(100);
 /// assert_eq!(PRIMES?, [53, 59, 61, 67, 71, 73, 79, 83, 89, 97]);
-/// # Ok::<(), SegmentedGenerationError<10>>(())
+/// # Ok::<(), Error<10>>(())
 /// ```
 /// Compute larger primes without starting from zero:
 /// ```
-/// # use const_primes::generation::{SegmentedGenerationResult, primes_lt, SegmentedGenerationError};
+/// # use const_primes::generation::{Result, primes_lt, Error};
 /// const N: usize = 70711;
 /// # #[allow(long_running_const_eval)]
 /// // If the generation results in a completely filled array, it can be extracted like this:
-/// const BIG_PRIMES: SegmentedGenerationResult<N> = primes_lt(5_000_000_030);
+/// const BIG_PRIMES: Result<N> = primes_lt(5_000_000_030);
 ///
 /// assert_eq!(BIG_PRIMES?[..3],     [4_998_417_421, 4_998_417_427, 4_998_417_443]);
 /// assert_eq!(BIG_PRIMES?[N - 3..], [4_999_999_903, 4_999_999_937, 5_000_000_029]);
-/// # Ok::<(), SegmentedGenerationError<N>>(())
+/// # Ok::<(), Error<N>>(())
 /// ```
 /// If there are not enough primes to fill the requested array,
-/// the output will be the [`SegmentedGenerationError::PartialOk`] variant,
+/// the output will be the [`Error::PartialOk`] variant,
 /// which contains fewer primes than requested:
 /// ```
-/// # use const_primes::generation::{SegmentedGenerationResult, primes_lt};
-/// const PRIMES: SegmentedGenerationResult<9> = primes_lt(10);
+/// # use const_primes::generation::{Result, primes_lt};
+/// const PRIMES: Result<9> = primes_lt(10);
 /// assert_eq!(PRIMES.map_err(|e| e.try_as_slice()), Err(Some(&[2, 3, 5, 7])))
 /// ```
 /// # Errors
@@ -152,31 +152,31 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// if `upper_limit` is larger than `N^2` or if `upper_limit` is smaller than or equal to 2.
 ///
 /// ```compile_fail
-/// # use const_primes::generation::{SegmentedGenerationResult,primes_lt};
+/// # use const_primes::generation::{Result,primes_lt};
 /// //                                       N is too large
-/// const PRIMES: SegmentedGenerationResult<u64::MAX as usize> = primes_lt(100);
+/// const PRIMES: Result<u64::MAX as usize> = primes_lt(100);
 /// ```
 /// ```compile_fail
-/// # use const_primes::generation::{primes_lt, SegmentedGenerationResult};
+/// # use const_primes::generation::{primes_lt, Result};
 /// //                                      N              upper_limit > N^2
-/// const PRIMES: SegmentedGenerationResult<5> = primes_lt(26);
+/// const PRIMES: Result<5> = primes_lt(26);
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
-pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> SegmentedGenerationResult<N> {
+pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> Result<N> {
     const { assert!(N > 0, "`N` must be at least 1") }
 
     if upper_limit <= 2 {
-        return Err(SegmentedGenerationError::TooSmallLimit);
+        return Err(Error::TooSmallLimit);
     }
 
     let n64 = N as u64;
     match (n64).checked_mul(n64) {
         Some(prod) => {
             if upper_limit > prod {
-                return Err(SegmentedGenerationError::TooLargeLimit);
+                return Err(Error::TooLargeLimit);
             }
         }
-        None => return Err(SegmentedGenerationError::TooLargeN),
+        None => return Err(Error::TooLargeN),
     }
 
     let mut primes: [u64; N] = [0; N];
@@ -209,7 +209,7 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> SegmentedGenerat
         upper_limit = smallest_found_prime;
         if upper_limit <= 2 && total_primes_found < N {
             let restricted = ArraySection::new(N - total_primes_found..N, primes);
-            return Err(SegmentedGenerationError::PartialOk(restricted));
+            return Err(Error::PartialOk(restricted));
         }
     }
 
@@ -229,56 +229,56 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> SegmentedGenerat
 ///
 /// Basic usage:
 /// ```
-/// # use const_primes::{primes_geq, SegmentedGenerationResult, SegmentedGenerationError};
-/// const PRIMES: SegmentedGenerationResult<5> = primes_geq(10);
+/// # use const_primes::{primes_geq, Result, Error};
+/// const PRIMES: Result<5> = primes_geq(10);
 /// assert_eq!(PRIMES?, [11, 13, 17, 19, 23]);
-/// # Ok::<(), SegmentedGenerationError<5>>(())
+/// # Ok::<(), Error<5>>(())
 /// ```
 /// Compute larger primes without starting from zero:
 /// ```
-/// # use const_primes::{primes_geq, SegmentedGenerationResult, SegmentedGenerationError};
+/// # use const_primes::{primes_geq, Result, Error};
 /// const N: usize = 71_000;
 /// # #[allow(long_running_const_eval)]
-/// const P: SegmentedGenerationResult<N> = primes_geq(5_000_000_030);
+/// const P: Result<N> = primes_geq(5_000_000_030);
 /// assert_eq!(P?[..3], [5_000_000_039, 5_000_000_059, 5_000_000_063]);
 /// assert_eq!(P?[N - 3..], [5_001_586_727, 5_001_586_729, 5_001_586_757]);
-/// # Ok::<(), SegmentedGenerationError<N>>(())
+/// # Ok::<(), Error<N>>(())
 /// ```
 /// Only primes smaller than `N^2` will be generated:
 /// ```
-/// # use const_primes::{primes_geq, SegmentedGenerationResult, SegmentedGenerationError};
-/// const PRIMES: SegmentedGenerationResult<3> = primes_geq(5);
+/// # use const_primes::{primes_geq, Result, Error};
+/// const PRIMES: Result<3> = primes_geq(5);
 /// assert_eq!(PRIMES.map_err(|e| e.try_as_slice()), Err(Some([5, 7].as_slice())));
-/// # Ok::<(), SegmentedGenerationError<3>>(())
+/// # Ok::<(), Error<3>>(())
 /// ```
 ///
 /// # Errors
 ///
 /// Returns an error if `N^2` does not fit in a `u64`, or if `lower_limit` is larger or equal to `N^2`.
 /// ```
-/// # use const_primes::{primes_geq, SegmentedGenerationResult};
-/// const P: SegmentedGenerationResult<{u32::MAX as usize + 1}> = primes_geq(0);
+/// # use const_primes::{primes_geq, Result};
+/// const P: Result<{u32::MAX as usize + 1}> = primes_geq(0);
 /// assert!(P.is_err());
 /// ```
 /// ```
-/// # use const_primes::{primes_geq, SegmentedGenerationResult};
-/// const P: SegmentedGenerationResult<5> = primes_geq(26);
+/// # use const_primes::{primes_geq, Result};
+/// const P: Result<5> = primes_geq(26);
 /// assert!(P.is_err());
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
-pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> SegmentedGenerationResult<N> {
+pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> Result<N> {
     const { assert!(N > 0, "`N` must be at least 1") }
 
     let n64 = N as u64;
     let Some(n64_sqr) = n64.checked_mul(n64) else {
-        return Err(SegmentedGenerationError::TooLargeN);
+        return Err(Error::TooLargeN);
     };
 
     // There are no primes smaller than 2, so we will always start looking at 2.
     lower_limit = if lower_limit >= 2 { lower_limit } else { 2 };
 
     if lower_limit >= n64_sqr {
-        return Err(SegmentedGenerationError::TooLargeLimit);
+        return Err(Error::TooLargeLimit);
     }
 
     let mut primes = [0; N];
@@ -297,7 +297,7 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> SegmentedGenera
                     // since the base sieve does not contain information about
                     // the prime status of numbers larger than or equal to N.
                     let restricted = ArraySection::new(0..total_found_primes, primes);
-                    return Err(SegmentedGenerationError::PartialOk(restricted));
+                    return Err(Error::PartialOk(restricted));
                 }
                 primes[total_found_primes] = largest_found_prime;
                 total_found_primes += 1;
@@ -319,7 +319,7 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> SegmentedGenera
 /// It can also be returned by [`primes_geq`] if it needs to sieve into a
 /// region of numbers that exceed the square of the size of the requested array.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub enum SegmentedGenerationError<const N: usize> {
+pub enum Error<const N: usize> {
     /// `N^2`` did not fit in a `u64`.
     TooLargeN,
     /// the upper limit was larger than `N^2`.
@@ -330,7 +330,7 @@ pub enum SegmentedGenerationError<const N: usize> {
     PartialOk(ArraySection<u64, N>),
 }
 
-impl<const N: usize> SegmentedGenerationError<N> {
+impl<const N: usize> Error<N> {
     /// Returns the partial result as a reference to an [`ArraySection`], if there is one.
     pub const fn try_as_array_section(&self) -> Option<&ArraySection<u64, N>> {
         match self {
@@ -361,7 +361,7 @@ impl<const N: usize> SegmentedGenerationError<N> {
     }
 }
 
-impl<const N: usize> fmt::Display for SegmentedGenerationError<N> {
+impl<const N: usize> fmt::Display for Error<N> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
             Self::TooLargeN => write!(f, "`N^2` did not fit in a `u64`"),
@@ -381,16 +381,16 @@ mod test {
     #[test]
     fn sanity_check_primes_geq() {
         {
-            const P: SegmentedGenerationResult<5> = primes_geq(10);
+            const P: Result<5> = primes_geq(10);
             assert_eq!(P, Ok([11, 13, 17, 19, 23]));
         }
         {
-            const P: SegmentedGenerationResult<5> = primes_geq(0);
+            const P: Result<5> = primes_geq(0);
             assert_eq!(P, Ok([2, 3, 5, 7, 11]));
         }
         {
-            const P: SegmentedGenerationResult<1> = primes_geq(0);
-            assert_eq!(P, Err(SegmentedGenerationError::TooLargeLimit),);
+            const P: Result<1> = primes_geq(0);
+            assert_eq!(P, Err(Error::TooLargeLimit),);
         }
         for &prime in primes_geq::<2_000>(3_998_000)
             .unwrap_err()
diff --git a/src/lib.rs b/src/lib.rs
index 635317b..0a676c6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -106,9 +106,7 @@ mod other_prime;
 mod sieving;
 mod wrapper;
 
-pub use generation::{
-    primes, primes_geq, primes_lt, SegmentedGenerationError, SegmentedGenerationResult,
-};
+pub use generation::{primes, primes_geq, primes_lt, Error, Result};
 use imath::isqrt;
 pub use miller_rabin::is_prime;
 pub use other_prime::{next_prime, previous_prime};
@@ -238,7 +236,7 @@ mod test {
             ($($n:expr),+) => {
                 $(
                     {
-                        const P: SegmentedGenerationResult<$n> = primes_lt(100);
+                        const P: Result<$n> = primes_lt(100);
                         for (i, prime) in P.unwrap().into_iter().enumerate() {
                             assert_eq!(PRECOMPUTED_PRIMES[25-$n..25][i], prime as u32);
                         }

From 8c20088943e42ec682571789d675a541ef63e272 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 30 Apr 2024 11:32:26 +0200
Subject: [PATCH 115/212] Impl PartialOrd and Ord for ArraySection

---
 src/array_section.rs | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index 5ee39b5..8eb8979 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -1,11 +1,12 @@
 use core::{
+    cmp::Ordering,
     iter::FusedIterator,
     ops::{Index, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
 };
 
 /// An array where only a section of the data may be viewed,
 /// as the other data may e.g. not uphold some invariant.  
-#[derive(Debug, Clone, Copy, Eq, Hash)]
+#[derive(Debug, Clone, Copy, Eq, Hash, Ord)]
 pub struct ArraySection<T, const N: usize> {
     start: usize,
     end: usize,
@@ -13,9 +14,15 @@ pub struct ArraySection<T, const N: usize> {
 }
 
 /// Only compares the data in the sections, and not the full arrays.
-impl<const N: usize, T: PartialEq<T>> PartialEq<ArraySection<T, N>> for ArraySection<T, N> {
+impl<const N: usize, T: PartialEq> PartialEq<ArraySection<T, N>> for ArraySection<T, N> {
     fn eq(&self, other: &ArraySection<T, N>) -> bool {
-        self.as_slice() == other.as_slice()
+        self.as_slice().eq(other.as_slice())
+    }
+}
+
+impl<const N: usize, T: PartialOrd> PartialOrd for ArraySection<T, N> {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        self.as_slice().partial_cmp(other.as_slice())
     }
 }
 

From def01ae15d741ca07f8709f423d0d3c6e63cb417 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 30 Apr 2024 11:37:37 +0200
Subject: [PATCH 116/212] Implement non-marker traits manually for ArraySection

---
 src/array_section.rs | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index 8eb8979..108d07a 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -5,14 +5,21 @@ use core::{
 };
 
 /// An array where only a section of the data may be viewed,
-/// as the other data may e.g. not uphold some invariant.  
-#[derive(Debug, Clone, Copy, Eq, Hash, Ord)]
+/// as the other data may e.g. not uphold some invariant.
+/// The other data is not considered in comparisons, ordering or hashing.
+#[derive(Debug, Clone, Copy, Eq)]
 pub struct ArraySection<T, const N: usize> {
     start: usize,
     end: usize,
     array: [T; N],
 }
 
+impl<const N: usize, T: core::hash::Hash> core::hash::Hash for ArraySection<T, N> {
+    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
+        self.as_slice().hash(state);
+    }
+}
+
 /// Only compares the data in the sections, and not the full arrays.
 impl<const N: usize, T: PartialEq> PartialEq<ArraySection<T, N>> for ArraySection<T, N> {
     fn eq(&self, other: &ArraySection<T, N>) -> bool {
@@ -20,6 +27,12 @@ impl<const N: usize, T: PartialEq> PartialEq<ArraySection<T, N>> for ArraySectio
     }
 }
 
+impl<const N: usize, T: Ord> Ord for ArraySection<T, N> {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.as_slice().cmp(other.as_slice())
+    }
+}
+
 impl<const N: usize, T: PartialOrd> PartialOrd for ArraySection<T, N> {
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
         self.as_slice().partial_cmp(other.as_slice())

From 1e5ae57caa05c8dcae080ff54db705819a03491d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 30 Apr 2024 11:39:43 +0200
Subject: [PATCH 117/212] Import Hash and Hasher, reorder PartialOrd and Ord
 impl blocks

---
 src/array_section.rs | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index 108d07a..8c3f1ce 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -1,5 +1,6 @@
 use core::{
     cmp::Ordering,
+    hash::{Hash, Hasher},
     iter::FusedIterator,
     ops::{Index, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
 };
@@ -14,8 +15,8 @@ pub struct ArraySection<T, const N: usize> {
     array: [T; N],
 }
 
-impl<const N: usize, T: core::hash::Hash> core::hash::Hash for ArraySection<T, N> {
-    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
+impl<const N: usize, T: Hash> Hash for ArraySection<T, N> {
+    fn hash<H: Hasher>(&self, state: &mut H) {
         self.as_slice().hash(state);
     }
 }
@@ -27,18 +28,18 @@ impl<const N: usize, T: PartialEq> PartialEq<ArraySection<T, N>> for ArraySectio
     }
 }
 
-impl<const N: usize, T: Ord> Ord for ArraySection<T, N> {
-    fn cmp(&self, other: &Self) -> Ordering {
-        self.as_slice().cmp(other.as_slice())
-    }
-}
-
 impl<const N: usize, T: PartialOrd> PartialOrd for ArraySection<T, N> {
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
         self.as_slice().partial_cmp(other.as_slice())
     }
 }
 
+impl<const N: usize, T: Ord> Ord for ArraySection<T, N> {
+    fn cmp(&self, other: &Self) -> Ordering {
+        self.as_slice().cmp(other.as_slice())
+    }
+}
+
 impl<const N: usize, T> ArraySection<T, N> {
     /// Restrict an array so that only elements within the given range are visible.
     ///

From f61bd5e99bb99cbf6df559e6a6b60b4a8fd12e3a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 30 Apr 2024 11:43:35 +0200
Subject: [PATCH 118/212] #[inline all the things]

---
 src/array_section.rs | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/src/array_section.rs b/src/array_section.rs
index 8c3f1ce..b20e0a8 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -16,6 +16,7 @@ pub struct ArraySection<T, const N: usize> {
 }
 
 impl<const N: usize, T: Hash> Hash for ArraySection<T, N> {
+    #[inline]
     fn hash<H: Hasher>(&self, state: &mut H) {
         self.as_slice().hash(state);
     }
@@ -23,18 +24,21 @@ impl<const N: usize, T: Hash> Hash for ArraySection<T, N> {
 
 /// Only compares the data in the sections, and not the full arrays.
 impl<const N: usize, T: PartialEq> PartialEq<ArraySection<T, N>> for ArraySection<T, N> {
+    #[inline]
     fn eq(&self, other: &ArraySection<T, N>) -> bool {
         self.as_slice().eq(other.as_slice())
     }
 }
 
 impl<const N: usize, T: PartialOrd> PartialOrd for ArraySection<T, N> {
+    #[inline]
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
         self.as_slice().partial_cmp(other.as_slice())
     }
 }
 
 impl<const N: usize, T: Ord> Ord for ArraySection<T, N> {
+    #[inline]
     fn cmp(&self, other: &Self) -> Ordering {
         self.as_slice().cmp(other.as_slice())
     }
@@ -46,6 +50,7 @@ impl<const N: usize, T> ArraySection<T, N> {
     /// # Panics
     ///
     /// Panics if the range of indices is out of bounds of the array.
+    #[inline]
     pub const fn new(sub_range: Range<usize>, array: [T; N]) -> Self {
         assert!(
             sub_range.start < N && sub_range.end <= N,
@@ -69,40 +74,47 @@ impl<const N: usize, T> ArraySection<T, N> {
 
     /// Returns the first index of the full underlying array that is part of the section.
     /// I.e. the section is the subrange `start ..`[`end`](ArraySection::end).
+    #[inline]
     pub const fn start(&self) -> usize {
         self.start
     }
 
     /// Returns the first index of the full underlying array that is outside the section (to the right).
     /// I.e. the section is the subrange [`start`](ArraySection::start)`.. end`.
+    #[inline]
     pub const fn end(&self) -> usize {
         self.end
     }
 
     /// Returns a reference to the full underlying array. There is no guarantee about the data
     /// outside the section.
+    #[inline]
     pub const fn as_full_array(&self) -> &[T; N] {
         &self.array
     }
 
     /// Converts `self` into the full underlying array. There is no guarantee about the data
     /// outside the section.
+    #[inline]
     pub fn into_full_array(self) -> [T; N] {
         self.array
     }
 
     /// Returns the section of the array as a slice.
+    #[inline]
     pub const fn as_slice(&self) -> &[T] {
         let (_, tail) = self.array.split_at(self.start);
         tail.split_at(self.end - self.start).0
     }
 
     /// Returns the length of the array section.
+    #[inline]
     pub const fn len(&self) -> usize {
         self.as_slice().len()
     }
 
     /// Returns whether the array section is empty.
+    #[inline]
     pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
@@ -110,6 +122,7 @@ impl<const N: usize, T> ArraySection<T, N> {
     /// Returns whether the section is just the entire array.
     /// If this is `true` it is completely fine to call [`as_full_array`](RestrictedArray::as_full_array)
     /// or [`into_full_array`](RestrictedArray::into_full_array).
+    #[inline]
     pub const fn section_is_full_array(&self) -> bool {
         self.len() == N
     }

From 0985872effc8c232546d9804ed1f77589b5728a9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 30 Apr 2024 11:48:29 +0200
Subject: [PATCH 119/212] Oneliner :3

---
 src/array_section.rs | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index b20e0a8..4cb6137 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -103,8 +103,15 @@ impl<const N: usize, T> ArraySection<T, N> {
     /// Returns the section of the array as a slice.
     #[inline]
     pub const fn as_slice(&self) -> &[T] {
-        let (_, tail) = self.array.split_at(self.start);
-        tail.split_at(self.end - self.start).0
+        self.array
+            // Split &[head, section, tail] into (&[head], &[section, tail])
+            .split_at(self.start)
+            // and extract the second element of the tuple.
+            .1
+            // Split &[section, tail] into (&[section], &[tail])
+            .split_at(self.end - self.start)
+            // and extract the first element of the tuple.
+            .0
     }
 
     /// Returns the length of the array section.

From 866158bcaa2aa64d8fb28335bf3b3afe43774b3b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 30 Apr 2024 11:50:03 +0200
Subject: [PATCH 120/212] impl is_empty with slice::is_empty

---
 src/array_section.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index 4cb6137..2376f1d 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -123,7 +123,7 @@ impl<const N: usize, T> ArraySection<T, N> {
     /// Returns whether the array section is empty.
     #[inline]
     pub const fn is_empty(&self) -> bool {
-        self.len() == 0
+        self.as_slice().is_empty()
     }
 
     /// Returns whether the section is just the entire array.

From 14de1d4e44728592c65f975560b292b08a0b9cda Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 30 Apr 2024 11:53:11 +0200
Subject: [PATCH 121/212] impl AsRef<[T]> for ArraySection

---
 src/array_section.rs | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/array_section.rs b/src/array_section.rs
index 2376f1d..159ac41 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -141,6 +141,13 @@ impl<const N: usize, T> ArraySection<T, N> {
     }
 }
 
+impl<const N: usize, T> AsRef<[T]> for ArraySection<T, N> {
+    #[inline]
+    fn as_ref(&self) -> &[T] {
+        self.as_slice()
+    }
+}
+
 // region: Index impls
 
 impl<const N: usize, T> Index<usize> for ArraySection<T, N> {

From dbdbe3a63d8165b11303eb325b2a452e954555f5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 30 Apr 2024 11:54:10 +0200
Subject: [PATCH 122/212] Remove duplicate impl blocks

---
 src/array_section.rs | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index 159ac41..195c4b1 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -200,12 +200,6 @@ where
 }
 // endregion: PartialEq impls
 
-impl<const N: usize, T> AsRef<[T]> for ArraySection<T, N> {
-    fn as_ref(&self) -> &[T] {
-        self.as_slice()
-    }
-}
-
 impl<const N: usize, T> IntoIterator for ArraySection<T, N> {
     type IntoIter = ArraySectionIntoIter<T, N>;
     type Item = <ArraySectionIntoIter<T, N> as Iterator>::Item;

From aa8e06fe7d49924378ac678b5ecbae4a61c1ebef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 30 Apr 2024 11:57:08 +0200
Subject: [PATCH 123/212] Add as_full_array_mut

---
 src/array_section.rs | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/array_section.rs b/src/array_section.rs
index 195c4b1..d1df4f7 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -93,6 +93,13 @@ impl<const N: usize, T> ArraySection<T, N> {
         &self.array
     }
 
+    /// Returns a mutable reference to the full underlying array.
+    /// There is no guarantee about the data outside the section.
+    #[inline]
+    pub fn as_full_array_mut(&mut self) -> &mut [T; N] {
+        &mut self.array
+    }
+
     /// Converts `self` into the full underlying array. There is no guarantee about the data
     /// outside the section.
     #[inline]

From 2382adee84545ec848c7514d8292049aef57d434 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 30 Apr 2024 12:10:48 +0200
Subject: [PATCH 124/212] impl PartialOrd and PartialEq for different Ns

---
 src/array_section.rs | 29 ++++++++++++++++++++++++-----
 src/generation.rs    |  4 ++--
 2 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index d1df4f7..cd67347 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -7,7 +7,22 @@ use core::{
 
 /// An array where only a section of the data may be viewed,
 /// as the other data may e.g. not uphold some invariant.
+///
+/// Indexing into the `ArraySection` indices only into the section:
+/// ```
+/// # use const_primes::array_section::ArraySection;
+/// const OT: ArraySection<i32, 4> = ArraySection::new([0, 1, 2, 0], 1..3);
+/// assert_eq![OT[0], 1];
+/// assert_eq![OT[1], 2];
+/// ```
+///
 /// The other data is not considered in comparisons, ordering or hashing.
+/// ```
+/// use const_primes::array_section::ArraySection;
+/// const AS1: ArraySection<i32, 4> = ArraySection::new([1, 1, 2, 1], 1..3);
+/// const AS2: ArraySection<i32, 5> = ArraySection::new([0, 1, 2, 100, -5], 1..3);
+/// assert_eq!(AS1, AS2);
+/// ```
 #[derive(Debug, Clone, Copy, Eq)]
 pub struct ArraySection<T, const N: usize> {
     start: usize,
@@ -23,16 +38,20 @@ impl<const N: usize, T: Hash> Hash for ArraySection<T, N> {
 }
 
 /// Only compares the data in the sections, and not the full arrays.
-impl<const N: usize, T: PartialEq> PartialEq<ArraySection<T, N>> for ArraySection<T, N> {
-    #[inline]
+impl<const N: usize, const M: usize, T: PartialEq> PartialEq<ArraySection<T, N>>
+    for ArraySection<T, M>
+{
     fn eq(&self, other: &ArraySection<T, N>) -> bool {
         self.as_slice().eq(other.as_slice())
     }
 }
 
-impl<const N: usize, T: PartialOrd> PartialOrd for ArraySection<T, N> {
+/// Only checks the data in the sections, and not the full arrays.
+impl<const N: usize, const M: usize, T: PartialOrd> PartialOrd<ArraySection<T, M>>
+    for ArraySection<T, N>
+{
     #[inline]
-    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+    fn partial_cmp(&self, other: &ArraySection<T, M>) -> Option<Ordering> {
         self.as_slice().partial_cmp(other.as_slice())
     }
 }
@@ -51,7 +70,7 @@ impl<const N: usize, T> ArraySection<T, N> {
     ///
     /// Panics if the range of indices is out of bounds of the array.
     #[inline]
-    pub const fn new(sub_range: Range<usize>, array: [T; N]) -> Self {
+    pub const fn new(array: [T; N], sub_range: Range<usize>) -> Self {
         assert!(
             sub_range.start < N && sub_range.end <= N,
             "the sub-range must be in bounds"
diff --git a/src/generation.rs b/src/generation.rs
index f23fb97..0bd970a 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -208,7 +208,7 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> Result<N> {
         }
         upper_limit = smallest_found_prime;
         if upper_limit <= 2 && total_primes_found < N {
-            let restricted = ArraySection::new(N - total_primes_found..N, primes);
+            let restricted = ArraySection::new(primes, N - total_primes_found..N);
             return Err(Error::PartialOk(restricted));
         }
     }
@@ -296,7 +296,7 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> Result<N> {
                     // We do not know if this is actually a prime
                     // since the base sieve does not contain information about
                     // the prime status of numbers larger than or equal to N.
-                    let restricted = ArraySection::new(0..total_found_primes, primes);
+                    let restricted = ArraySection::new(primes, 0..total_found_primes);
                     return Err(Error::PartialOk(restricted));
                 }
                 primes[total_found_primes] = largest_found_prime;

From 4d0200f6160aa937e9d361aad9422d4cdd329a75 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 30 Apr 2024 12:42:44 +0200
Subject: [PATCH 125/212] Add examples to ArraySection

---
 src/array_section.rs | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index cd67347..4f4eb8a 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -11,17 +11,23 @@ use core::{
 /// Indexing into the `ArraySection` indices only into the section:
 /// ```
 /// # use const_primes::array_section::ArraySection;
+/// //                                                     v  v
 /// const OT: ArraySection<i32, 4> = ArraySection::new([0, 1, 2, 0], 1..3);
 /// assert_eq![OT[0], 1];
 /// assert_eq![OT[1], 2];
 /// ```
 ///
-/// The other data is not considered in comparisons, ordering or hashing.
+/// The other data is not considered in comparisons, ordering or hashing:
 /// ```
-/// use const_primes::array_section::ArraySection;
-/// const AS1: ArraySection<i32, 4> = ArraySection::new([1, 1, 2, 1], 1..3);
-/// const AS2: ArraySection<i32, 5> = ArraySection::new([0, 1, 2, 100, -5], 1..3);
+/// # use const_primes::array_section::ArraySection;
+/// //                       v  v
+/// const A1: [i32; 4] = [1, 3, 7, 1];
+/// const A2: [i32; 5] = [0, 3, 7, 100, -5];
+/// const AS1: ArraySection<i32, 4> = ArraySection::new(A1, 1..3);
+/// const AS2: ArraySection<i32, 5> = ArraySection::new(A2, 1..3);
 /// assert_eq!(AS1, AS2);
+/// assert!(A1.as_slice() > A2.as_slice());
+/// assert!(!(AS1 > AS2));
 /// ```
 #[derive(Debug, Clone, Copy, Eq)]
 pub struct ArraySection<T, const N: usize> {

From fd6c373724a8a7594bfe2f6f650481ed9a9c7174 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 30 Apr 2024 15:34:45 +0200
Subject: [PATCH 126/212] Fix rustdoc error messages

---
 src/array_section.rs | 4 ++--
 src/lib.rs           | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index 4f4eb8a..d70a3dd 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -159,8 +159,8 @@ impl<const N: usize, T> ArraySection<T, N> {
     }
 
     /// Returns whether the section is just the entire array.
-    /// If this is `true` it is completely fine to call [`as_full_array`](RestrictedArray::as_full_array)
-    /// or [`into_full_array`](RestrictedArray::into_full_array).
+    /// If this is `true` it is completely fine to call [`as_full_array`](ArraySection::as_full_array)
+    /// or [`into_full_array`](ArraySection::into_full_array).
     #[inline]
     pub const fn section_is_full_array(&self) -> bool {
         self.len() == N
diff --git a/src/lib.rs b/src/lib.rs
index 0a676c6..bf9d9b2 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -47,7 +47,7 @@
 //! ```
 //! ## Arbitrary ranges
 //!
-//! The crate provides prime generation and sieving functions with suffixes, e.g. [`primes_geq`](crate::generation::primes_geq) and [`sieve_lt`]
+//! The crate provides prime generation and sieving functions with suffixes, e.g. [`primes_geq`] and [`sieve_lt`]
 //! that can be used to work with ranges that don't start at zero.
 //! ```
 //! # use const_primes::generation::primes_geq;

From b535d9a12575a675a4584fb247b685311105e7d2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 30 Apr 2024 15:38:43 +0200
Subject: [PATCH 127/212] only do log2(n) once

---
 src/miller_rabin.rs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/miller_rabin.rs b/src/miller_rabin.rs
index c916fce..7f28ada 100644
--- a/src/miller_rabin.rs
+++ b/src/miller_rabin.rs
@@ -23,7 +23,8 @@ pub const fn is_prime(n: u64) -> bool {
         false
     } else {
         let mut candidate_factor = 5;
-        while candidate_factor <= n.ilog2() as u64 {
+        let trial_limit = n.ilog2() as u64;
+        while candidate_factor <= trial_limit {
             if n % candidate_factor == 0 || n % (candidate_factor + 2) == 0 {
                 return false;
             }

From 5e559d43b94cb2c5673261aac0afa746495288c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 30 Apr 2024 15:40:45 +0200
Subject: [PATCH 128/212] % -> mod in math

---
 src/imath.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/imath.rs b/src/imath.rs
index b600d2a..d8c11ec 100644
--- a/src/imath.rs
+++ b/src/imath.rs
@@ -19,7 +19,7 @@ pub const fn isqrt(n: u64) -> u64 {
     }
 }
 
-/// Calculates `(base ^ exp) % modulo` without overflow.
+/// Calculates `(base ^ exp) mod modulo` without overflow.
 #[must_use]
 pub const fn mod_pow(mut base: u64, mut exp: u64, modulo: u64) -> u64 {
     let mut res = 1;
@@ -37,7 +37,7 @@ pub const fn mod_pow(mut base: u64, mut exp: u64, modulo: u64) -> u64 {
     res
 }
 
-/// Calculates `(a * b) % modulo` without overflow.
+/// Calculates `(a * b) mod modulo` without overflow.
 #[must_use]
 pub const fn mod_mul(a: u64, b: u64, modulo: u64) -> u64 {
     ((a as u128 * b as u128) % modulo as u128) as u64

From 05408b02148129410cf0d8291b647962f3b6eb3b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 30 Apr 2024 16:34:51 +0200
Subject: [PATCH 129/212] Almost completely impl PrimesArray

---
 src/generation.rs | 172 +++++++++++++++++++++++++++++++++-------------
 src/lib.rs        |  18 ++---
 2 files changed, 130 insertions(+), 60 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 0bd970a..c2eef27 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -1,9 +1,12 @@
-use core::fmt;
+use core::{
+    fmt,
+    ops::{Index, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
+};
 
 use crate::{array_section::ArraySection, sieve, sieving::sieve_segment, Underlying};
 
 /// Type alias for the type returned by the segmented generation functions, that otherwise has two generics that must be the same.
-pub type Result<const N: usize> = core::result::Result<[u64; N], Error<N>>;
+pub type Result<const N: usize> = core::result::Result<PrimesArray<N>, Error<N>>;
 
 /// Returns the `N` first prime numbers.
 /// Fails to compile if `N` is 0.
@@ -209,11 +212,11 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> Result<N> {
         upper_limit = smallest_found_prime;
         if upper_limit <= 2 && total_primes_found < N {
             let restricted = ArraySection::new(primes, N - total_primes_found..N);
-            return Err(Error::PartialOk(restricted));
+            return Ok(PrimesArray::Partial(restricted));
         }
     }
 
-    Ok(primes)
+    Ok(PrimesArray::Full(primes))
 }
 
 /// Returns the `N` smallest primes greater than or equal to `lower_limit`.
@@ -231,7 +234,7 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> Result<N> {
 /// ```
 /// # use const_primes::{primes_geq, Result, Error};
 /// const PRIMES: Result<5> = primes_geq(10);
-/// assert_eq!(PRIMES?, [11, 13, 17, 19, 23]);
+/// assert_eq!(PRIMES?.as_slice(), &[11, 13, 17, 19, 23]);
 /// # Ok::<(), Error<5>>(())
 /// ```
 /// Compute larger primes without starting from zero:
@@ -240,8 +243,8 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> Result<N> {
 /// const N: usize = 71_000;
 /// # #[allow(long_running_const_eval)]
 /// const P: Result<N> = primes_geq(5_000_000_030);
-/// assert_eq!(P?[..3], [5_000_000_039, 5_000_000_059, 5_000_000_063]);
-/// assert_eq!(P?[N - 3..], [5_001_586_727, 5_001_586_729, 5_001_586_757]);
+/// assert_eq!(P?[..3], &[5_000_000_039, 5_000_000_059, 5_000_000_063]);
+/// assert_eq!(P?[N - 3..], &[5_001_586_727, 5_001_586_729, 5_001_586_757]);
 /// # Ok::<(), Error<N>>(())
 /// ```
 /// Only primes smaller than `N^2` will be generated:
@@ -297,7 +300,7 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> Result<N> {
                     // since the base sieve does not contain information about
                     // the prime status of numbers larger than or equal to N.
                     let restricted = ArraySection::new(primes, 0..total_found_primes);
-                    return Err(Error::PartialOk(restricted));
+                    return Ok(PrimesArray::Partial(restricted));
                 }
                 primes[total_found_primes] = largest_found_prime;
                 total_found_primes += 1;
@@ -310,64 +313,141 @@ pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> Result<N> {
         }
         lower_limit = largest_found_prime + 1;
     }
-    Ok(primes)
+    Ok(PrimesArray::Full(primes))
 }
 
-/// An enum describing whether the requested array could be filled completely, or only a partially.
-/// A partial array can be returned by [`primes_lt`] if the size of the requested
-/// array is larger than the actual number of primes less than the given `upper_limit`.
-/// It can also be returned by [`primes_geq`] if it needs to sieve into a
-/// region of numbers that exceed the square of the size of the requested array.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub enum Error<const N: usize> {
-    /// `N^2`` did not fit in a `u64`.
-    TooLargeN,
-    /// the upper limit was larger than `N^2`.
-    TooLargeLimit,
-    /// the lower limit was smaller than or equal to 2.
-    TooSmallLimit,
-    /// Only a part of the output array contains prime numbers as they either exceeded `N^2` or ran out.
-    PartialOk(ArraySection<u64, N>),
+#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+/// An array where potentially only a section of it contains valid prime numbers.
+pub enum PrimesArray<const N: usize> {
+    /// The entire allocated array contains prime numbers
+    Full([u64; N]),
+    /// Only a section of the allocated array contains prime numbers.
+    Partial(ArraySection<u64, N>),
 }
 
-impl<const N: usize> Error<N> {
-    /// Returns the partial result as a reference to an [`ArraySection`], if there is one.
-    pub const fn try_as_array_section(&self) -> Option<&ArraySection<u64, N>> {
+impl<const N: usize> PrimesArray<N> {
+    /// Returns a slice of all the generated prime numbers.
+    #[inline]
+    pub const fn as_slice(&self) -> &[u64] {
+        match self {
+            Self::Full(ref arr) => arr.as_slice(),
+            Self::Partial(ref arr_sec) => arr_sec.as_slice(),
+        }
+    }
+
+    /// Returns the underlying array if it is full of valid primes.
+    #[inline]
+    pub const fn full(self) -> Option<[u64; N]> {
+        match self {
+            Self::Full(arr) => Some(arr),
+            Self::Partial(_) => None,
+        }
+    }
+
+    /// Returns a reference to the underlying array if it is full of valid primes.
+    #[inline]
+    pub const fn as_full(&self) -> Option<&[u64; N]> {
         match self {
-            Self::PartialOk(ref restricted_array) => Some(&restricted_array),
-            _ => None,
+            Self::Full(ref arr) => Some(arr),
+            Self::Partial(_) => None,
         }
     }
 
-    /// Consumes the error and returns the partial result as an [`ArraySection`], if there is one.
-    pub const fn try_into_array_section(self) -> Option<ArraySection<u64, N>> {
+    /// Returns the primes as a (maybe fully populated) [`ArraySection`].
+    #[inline]
+    pub const fn into_array_section(self) -> ArraySection<u64, N> {
         match self {
-            Self::PartialOk(ra) => Some(ra),
-            _ => None,
+            Self::Partial(arr_sec) => arr_sec,
+            Self::Full(arr) => {
+                let l = arr.len();
+                ArraySection::new(arr, 0..l)
+            }
         }
     }
 
-    /// Returns the partial result as a slice if there is one.
-    pub const fn try_as_slice(&self) -> Option<&[u64]> {
+    /// Returns an [`ArraySection`] if not all of the elements
+    /// in the underlying array could be computed.
+    #[inline]
+    pub const fn partial(self) -> Option<ArraySection<u64, N>> {
         match self {
-            Self::PartialOk(ref ra) => Some(ra.as_slice()),
-            _ => None,
+            Self::Partial(arr_sec) => Some(arr_sec),
+            Self::Full(_) => None,
         }
     }
 
-    /// Returns `true` if this is the `PartialOk` variant.
-    pub const fn is_partial_ok(&self) -> bool {
-        matches!(self, Self::PartialOk(_))
+    /// Returns a reference to the [`ArraySection`] if not all elements of the underlying array
+    /// could be computed.
+    #[inline]
+    pub const fn as_partial(&self) -> Option<&ArraySection<u64, N>> {
+        match self {
+            Self::Partial(ref arr_sec) => Some(arr_sec),
+            Self::Full(_) => None,
+        }
+    }
+
+    /// Returns whether all the elements in the underlying array could be computed.
+    #[inline]
+    pub const fn is_full(&self) -> bool {
+        matches!(self, Self::Full(_))
+    }
+
+    /// Returns whether only a subset of the underlying array could be computed.
+    #[inline]
+    pub const fn is_partial(&self) -> bool {
+        matches!(self, Self::Partial(_))
     }
 }
 
+impl<const N: usize> From<PrimesArray<N>> for ArraySection<u64, N> {
+    #[inline]
+    fn from(value: PrimesArray<N>) -> Self {
+        value.into_array_section()
+    }
+}
+
+impl<const N: usize> AsRef<[u64]> for PrimesArray<N> {
+    #[inline]
+    fn as_ref(&self) -> &[u64] {
+        self.as_slice()
+    }
+}
+
+macro_rules! impl_index_range {
+    ($($n:ty),*) => {
+        $(
+            impl<const N: usize> Index<$n> for PrimesArray<N> {
+                type Output = [u64];
+                fn index(&self, index: $n) -> &Self::Output {
+                    self.as_slice().index(index)
+                }
+            }
+        )*
+    };
+}
+
+impl_index_range! {Range<usize>, RangeTo<usize>, RangeFrom<usize>, RangeToInclusive<usize>, RangeFull, RangeInclusive<usize>}
+
+/// An enum describing whether the requested array could be filled completely, or only a partially.
+/// A partial array can be returned by [`primes_lt`] if the size of the requested
+/// array is larger than the actual number of primes less than the given `upper_limit`.
+/// It can also be returned by [`primes_geq`] if it needs to sieve into a
+/// region of numbers that exceed the square of the size of the requested array.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum Error<const N: usize> {
+    /// `N^2`` did not fit in a `u64`.
+    TooLargeN,
+    /// the upper limit was larger than `N^2`.
+    TooLargeLimit,
+    /// the lower limit was smaller than or equal to 2.
+    TooSmallLimit,
+}
+
 impl<const N: usize> fmt::Display for Error<N> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
             Self::TooLargeN => write!(f, "`N^2` did not fit in a `u64`"),
             Self::TooLargeLimit => write!(f, "the upper limit was larger than `N^2`"),
             Self::TooSmallLimit => write!(f, "the lower limit was smaller than or equal to 2"),
-            Self::PartialOk(_) => write!(f, "the sieve entered into a range it's too small for, or the primes ran out. You can access the partially completed result with the function `partial_result`"),
         }
     }
 }
@@ -382,21 +462,17 @@ mod test {
     fn sanity_check_primes_geq() {
         {
             const P: Result<5> = primes_geq(10);
-            assert_eq!(P, Ok([11, 13, 17, 19, 23]));
+            assert_eq!(P.unwrap().as_slice(), [11, 13, 17, 19, 23]);
         }
         {
             const P: Result<5> = primes_geq(0);
-            assert_eq!(P, Ok([2, 3, 5, 7, 11]));
+            assert_eq!(P.unwrap().as_slice(), [2, 3, 5, 7, 11]);
         }
         {
             const P: Result<1> = primes_geq(0);
             assert_eq!(P, Err(Error::TooLargeLimit),);
         }
-        for &prime in primes_geq::<2_000>(3_998_000)
-            .unwrap_err()
-            .try_as_slice()
-            .unwrap()
-        {
+        for &prime in primes_geq::<2_000>(3_998_000).unwrap().as_slice() {
             if prime == 0 {
                 break;
             }
diff --git a/src/lib.rs b/src/lib.rs
index bf9d9b2..a2cb0f9 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -106,7 +106,7 @@ mod other_prime;
 mod sieving;
 mod wrapper;
 
-pub use generation::{primes, primes_geq, primes_lt, Error, Result};
+pub use generation::{primes, primes_geq, primes_lt, Error, PrimesArray, Result};
 use imath::isqrt;
 pub use miller_rabin::is_prime;
 pub use other_prime::{next_prime, previous_prime};
@@ -237,12 +237,12 @@ mod test {
                 $(
                     {
                         const P: Result<$n> = primes_lt(100);
-                        for (i, prime) in P.unwrap().into_iter().enumerate() {
-                            assert_eq!(PRECOMPUTED_PRIMES[25-$n..25][i], prime as u32);
+                        for (i, prime) in P.unwrap().as_slice().into_iter().enumerate() {
+                            assert_eq!(PRECOMPUTED_PRIMES[25-$n..25][i], *prime as u32);
                         }
                         assert_eq!(
                             PRECOMPUTED_PRIMES[25-$n..25],
-                            primes_lt::<$n>(100).unwrap().into_iter().map(|i|i as u32).collect::<Vec<_>>()
+                            primes_lt::<$n>(100).unwrap().as_slice().into_iter().map(|i| *i as u32).collect::<Vec<_>>()
                         );
                     }
                 )+
@@ -251,15 +251,9 @@ mod test {
 
         test_n_below_100!(10, 15, 20);
 
-        assert_eq!(
-            [2, 3, 5, 7],
-            primes_lt::<9>(10).err().unwrap().try_as_slice().unwrap()
-        );
+        assert_eq!([2, 3, 5, 7], primes_lt::<9>(10).unwrap().as_slice());
 
-        assert_eq!(
-            primes_lt::<2>(3).err().unwrap().try_as_slice().unwrap(),
-            [2]
-        );
+        assert_eq!(primes_lt::<2>(3).unwrap().as_slice(), [2]);
     }
 
     #[test]

From 8bc620c6afce7fc886a9596507f25d8b21db94dd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 30 Apr 2024 16:38:51 +0200
Subject: [PATCH 130/212] impl PartialEq with slices for PrimesArray

---
 src/generation.rs | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/src/generation.rs b/src/generation.rs
index c2eef27..acb2f41 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -398,6 +398,21 @@ impl<const N: usize> PrimesArray<N> {
     }
 }
 
+impl<const N: usize, T> PartialEq<[T]> for PrimesArray<N>
+where
+    u64: PartialEq<T>,
+{
+    fn eq(&self, other: &[T]) -> bool {
+        self.as_slice().eq(other)
+    }
+}
+
+impl<const N: usize, T: PartialEq<u64>> PartialEq<PrimesArray<N>> for [T] {
+    fn eq(&self, other: &PrimesArray<N>) -> bool {
+        self.eq(other.as_slice())
+    }
+}
+
 impl<const N: usize> From<PrimesArray<N>> for ArraySection<u64, N> {
     #[inline]
     fn from(value: PrimesArray<N>) -> Self {

From 866d9d92560231ce3a2750ccccb71caecd5a9f83 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 30 Apr 2024 16:59:53 +0200
Subject: [PATCH 131/212] Just stack overflows left

---
 src/generation.rs | 26 +++++++++++---------------
 src/lib.rs        |  7 ++++---
 2 files changed, 15 insertions(+), 18 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index acb2f41..f7e81ae 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -126,28 +126,29 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// ```
 /// # use const_primes::generation::{Result, primes_lt, Error};
 /// const PRIMES: Result<10> = primes_lt(100);
-/// assert_eq!(PRIMES?, [53, 59, 61, 67, 71, 73, 79, 83, 89, 97]);
+/// assert_eq!(PRIMES?.as_slice(), &[53, 59, 61, 67, 71, 73, 79, 83, 89, 97]);
 /// # Ok::<(), Error<10>>(())
 /// ```
 /// Compute larger primes without starting from zero:
 /// ```
 /// # use const_primes::generation::{Result, primes_lt, Error};
-/// const N: usize = 70711;
+/// const N: usize = 70_711;
 /// # #[allow(long_running_const_eval)]
 /// // If the generation results in a completely filled array, it can be extracted like this:
 /// const BIG_PRIMES: Result<N> = primes_lt(5_000_000_030);
 ///
-/// assert_eq!(BIG_PRIMES?[..3],     [4_998_417_421, 4_998_417_427, 4_998_417_443]);
-/// assert_eq!(BIG_PRIMES?[N - 3..], [4_999_999_903, 4_999_999_937, 5_000_000_029]);
+/// assert_eq!(&BIG_PRIMES?[..3],     &[4_998_417_421, 4_998_417_427, 4_998_417_443]);
+/// assert_eq!(&BIG_PRIMES?[N - 3..], &[4_999_999_903, 4_999_999_937, 5_000_000_029]);
 /// # Ok::<(), Error<N>>(())
 /// ```
 /// If there are not enough primes to fill the requested array,
-/// the output will be the [`Error::PartialOk`] variant,
+/// the output will be the [`PrimeArray::Partial`] variant,
 /// which contains fewer primes than requested:
 /// ```
-/// # use const_primes::generation::{Result, primes_lt};
+/// # use const_primes::generation::{Result, primes_lt, Error};
 /// const PRIMES: Result<9> = primes_lt(10);
-/// assert_eq!(PRIMES.map_err(|e| e.try_as_slice()), Err(Some(&[2, 3, 5, 7])))
+/// assert_eq!(PRIMES?.as_slice(), &[2, 3, 5, 7]);
+/// # Ok::<(), Error<9>>(())
 /// ```
 /// # Errors
 ///
@@ -243,15 +244,15 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> Result<N> {
 /// const N: usize = 71_000;
 /// # #[allow(long_running_const_eval)]
 /// const P: Result<N> = primes_geq(5_000_000_030);
-/// assert_eq!(P?[..3], &[5_000_000_039, 5_000_000_059, 5_000_000_063]);
-/// assert_eq!(P?[N - 3..], &[5_001_586_727, 5_001_586_729, 5_001_586_757]);
+/// assert_eq!(&P?[..3], &[5_000_000_039, 5_000_000_059, 5_000_000_063]);
+/// assert_eq!(&P?[N - 3..], &[5_001_586_727, 5_001_586_729, 5_001_586_757]);
 /// # Ok::<(), Error<N>>(())
 /// ```
 /// Only primes smaller than `N^2` will be generated:
 /// ```
 /// # use const_primes::{primes_geq, Result, Error};
 /// const PRIMES: Result<3> = primes_geq(5);
-/// assert_eq!(PRIMES.map_err(|e| e.try_as_slice()), Err(Some([5, 7].as_slice())));
+/// assert_eq!(PRIMES?.as_slice(), &[5, 7]);
 /// # Ok::<(), Error<3>>(())
 /// ```
 ///
@@ -260,11 +261,6 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> Result<N> {
 /// Returns an error if `N^2` does not fit in a `u64`, or if `lower_limit` is larger or equal to `N^2`.
 /// ```
 /// # use const_primes::{primes_geq, Result};
-/// const P: Result<{u32::MAX as usize + 1}> = primes_geq(0);
-/// assert!(P.is_err());
-/// ```
-/// ```
-/// # use const_primes::{primes_geq, Result};
 /// const P: Result<5> = primes_geq(26);
 /// assert!(P.is_err());
 /// ```
diff --git a/src/lib.rs b/src/lib.rs
index a2cb0f9..1f93efd 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -50,12 +50,13 @@
 //! The crate provides prime generation and sieving functions with suffixes, e.g. [`primes_geq`] and [`sieve_lt`]
 //! that can be used to work with ranges that don't start at zero.
 //! ```
-//! # use const_primes::generation::primes_geq;
+//! # use const_primes::generation::{primes_geq, Result, Error};
 //! const N: usize = 70722;
 //! # #[allow(long_running_const_eval)]
-//! const PRIMES_GEQ: [u64; N] = primes_geq(5_000_000_031);
+//! const PRIMES_GEQ: Result<N> = primes_geq(5_000_000_031);
 //!
-//! assert_eq!(PRIMES_GEQ[..3], [5_000_000_039, 5_000_000_059, 5_000_000_063]);
+//! assert_eq!(&PRIMES_GEQ?[..3], [5_000_000_039, 5_000_000_059, 5_000_000_063]);
+//! # Ok::<(), Error<N>>(())
 //! ```
 //! ```
 //! # use const_primes::sieve_lt;

From 8aeb16af142407cbdfbf07d7f4d42c9cd193dec5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 30 Apr 2024 17:00:24 +0200
Subject: [PATCH 132/212] Add TODO

---
 src/generation.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/generation.rs b/src/generation.rs
index f7e81ae..7de3b40 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -112,6 +112,8 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
     primes
 }
 
+// TODO: Make primes_lt and primes_geq take two generics? N and MEMORY.
+
 /// Returns the `N` largest primes less than `upper_limit`.
 /// Fails to compile if `N` is 0.
 ///

From 281882cfae8fb21bc7f7fcf345e8983606f3cf05 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 12:39:15 +0200
Subject: [PATCH 133/212] Fix primes_lt

---
 src/generation.rs | 94 ++++++++++++++++++++++++++++++-----------------
 src/lib.rs        |  8 ++--
 2 files changed, 65 insertions(+), 37 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 7de3b40..7eae59d 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -115,68 +115,75 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 // TODO: Make primes_lt and primes_geq take two generics? N and MEMORY.
 
 /// Returns the `N` largest primes less than `upper_limit`.
-/// Fails to compile if `N` is 0.
 ///
-/// The return array fills from the end until either it is full or there are no more primes.
-/// If the primes run out before the array is filled the first elements will have a value of zero.
+/// This function uses a segmented sieve of size `MEM` for computation,
+/// but only saves the `N` requested primes in the binary.
+///
+/// Set `MEM` such that `MEM*MEM >= upper_limit`.
+///
+/// Fails to compile if `N` or `MEM` is 0, if `MEM < N` or if `MEM`^2 does not fit in a u64.
+///
+/// The return array fills from the end until either it is full
+/// (in which case the function returns the [`PrimesArray::Full`] variant)
+/// or there are no more primes (in which case the function returns the [`PrimesArray::Partial`] variant).
 ///
-/// If you want to compute primes that are larger than the input, take a look at [`primes_geq`].
+/// If you want to compute primes that are larger than some limit, take a look at [`primes_geq`].
 ///
 /// # Example
 ///
 /// Basic usage:
 /// ```
 /// # use const_primes::generation::{Result, primes_lt, Error};
-/// const PRIMES: Result<10> = primes_lt(100);
-/// assert_eq!(PRIMES?.as_slice(), &[53, 59, 61, 67, 71, 73, 79, 83, 89, 97]);
-/// # Ok::<(), Error<10>>(())
+/// const PRIMES: Result<4> = primes_lt::<4, 10>(100);
+/// assert_eq!(PRIMES?, [79, 83, 89, 97]);
+/// # Ok::<(), Error<4>>(())
 /// ```
 /// Compute larger primes without starting from zero:
 /// ```
 /// # use const_primes::generation::{Result, primes_lt, Error};
-/// const N: usize = 70_711;
 /// # #[allow(long_running_const_eval)]
-/// // If the generation results in a completely filled array, it can be extracted like this:
-/// const BIG_PRIMES: Result<N> = primes_lt(5_000_000_030);
+/// const BIG_PRIMES: Result<3> = primes_lt::<3, 70_711>(5_000_000_030);
 ///
-/// assert_eq!(&BIG_PRIMES?[..3],     &[4_998_417_421, 4_998_417_427, 4_998_417_443]);
-/// assert_eq!(&BIG_PRIMES?[N - 3..], &[4_999_999_903, 4_999_999_937, 5_000_000_029]);
-/// # Ok::<(), Error<N>>(())
+/// assert_eq!(BIG_PRIMES?, [4_999_999_903, 4_999_999_937, 5_000_000_029]);
+/// # Ok::<(), Error<3>>(())
 /// ```
 /// If there are not enough primes to fill the requested array,
-/// the output will be the [`PrimeArray::Partial`] variant,
+/// the output will be the [`PrimesArray::Partial`] variant,
 /// which contains fewer primes than requested:
 /// ```
 /// # use const_primes::generation::{Result, primes_lt, Error};
-/// const PRIMES: Result<9> = primes_lt(10);
+/// const PRIMES: Result<9> = primes_lt::<9, 9>(10);
 /// assert_eq!(PRIMES?.as_slice(), &[2, 3, 5, 7]);
 /// # Ok::<(), Error<9>>(())
 /// ```
 /// # Errors
 ///
-/// Returns an error if `N^2` does not fit in a `u64`,
-/// if `upper_limit` is larger than `N^2` or if `upper_limit` is smaller than or equal to 2.
-///
-/// ```compile_fail
-/// # use const_primes::generation::{Result,primes_lt};
-/// //                                       N is too large
-/// const PRIMES: Result<u64::MAX as usize> = primes_lt(100);
+/// Returns an error if `upper_limit` is larger than `MEM`^2 or if `upper_limit` is smaller than or equal to 2.
 /// ```
-/// ```compile_fail
 /// # use const_primes::generation::{primes_lt, Result};
-/// //                                      N              upper_limit > N^2
-/// const PRIMES: Result<5> = primes_lt(26);
+/// const TOO_LARGE_LIMIT: Result<3> = primes_lt::<3, 5>(26);
+/// const TOO_SMALL_LIMIT: Result<1> = primes_lt::<1, 1>(1);
+/// assert!(TOO_LARGE_LIMIT.is_err());
+/// assert!(TOO_SMALL_LIMIT.is_err());
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
-pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> Result<N> {
-    const { assert!(N > 0, "`N` must be at least 1") }
+pub const fn primes_lt<const N: usize, const MEM: usize>(mut upper_limit: u64) -> Result<N> {
+    const {
+        assert!(N > 0, "`N` must be at least 1");
+        assert!(MEM >= N, "`MEM` must be at least as large as `N`");
+        let mem64 = MEM as u64;
+        assert!(
+            mem64.checked_mul(mem64).is_some(),
+            "`MEM`^2 must fit in a u64"
+        );
+    }
 
     if upper_limit <= 2 {
         return Err(Error::TooSmallLimit);
     }
 
-    let n64 = N as u64;
-    match (n64).checked_mul(n64) {
+    let mem64 = MEM as u64;
+    match (mem64).checked_mul(mem64) {
         Some(prod) => {
             if upper_limit > prod {
                 return Err(Error::TooLargeLimit);
@@ -188,19 +195,19 @@ pub const fn primes_lt<const N: usize>(mut upper_limit: u64) -> Result<N> {
     let mut primes: [u64; N] = [0; N];
 
     // This will be used to sieve all upper ranges.
-    let base_sieve: [bool; N] = sieve();
+    let base_sieve: [bool; MEM] = sieve();
 
     let mut total_primes_found: usize = 0;
     'generate: while total_primes_found < N {
         // This is the smallest prime we have found so far.
         let mut smallest_found_prime = primes[N - 1 - total_primes_found];
         // Sieve for primes in the segment.
-        let upper_sieve: [bool; N] = sieve_segment(&base_sieve, upper_limit);
+        let upper_sieve: [bool; MEM] = sieve_segment(&base_sieve, upper_limit);
 
         let mut i: usize = 0;
-        while i < N {
+        while i < MEM {
             // Iterate backwards through the upper sieve.
-            if upper_sieve[N - 1 - i] {
+            if upper_sieve[MEM - 1 - i] {
                 smallest_found_prime = upper_limit - 1 - i as u64;
                 // Write every found prime to the primes array.
                 primes[N - 1 - total_primes_found] = smallest_found_prime;
@@ -394,6 +401,27 @@ impl<const N: usize> PrimesArray<N> {
     pub const fn is_partial(&self) -> bool {
         matches!(self, Self::Partial(_))
     }
+
+    /// Returns the length of the populated part of the array.
+    #[inline]
+    pub const fn len(&self) -> usize {
+        self.as_slice().len()
+    }
+
+    /// Returns wether the populated part of the array is empty.
+    #[inline]
+    pub const fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+}
+
+impl<const N: usize, T> PartialEq<[T; N]> for PrimesArray<N>
+where
+    u64: PartialEq<T>,
+{
+    fn eq(&self, other: &[T; N]) -> bool {
+        self.as_slice().eq(other.as_slice())
+    }
 }
 
 impl<const N: usize, T> PartialEq<[T]> for PrimesArray<N>
diff --git a/src/lib.rs b/src/lib.rs
index 1f93efd..38718cd 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -237,13 +237,13 @@ mod test {
             ($($n:expr),+) => {
                 $(
                     {
-                        const P: Result<$n> = primes_lt(100);
+                        const P: Result<$n> = primes_lt::<$n, $n>(100);
                         for (i, prime) in P.unwrap().as_slice().into_iter().enumerate() {
                             assert_eq!(PRECOMPUTED_PRIMES[25-$n..25][i], *prime as u32);
                         }
                         assert_eq!(
                             PRECOMPUTED_PRIMES[25-$n..25],
-                            primes_lt::<$n>(100).unwrap().as_slice().into_iter().map(|i| *i as u32).collect::<Vec<_>>()
+                            primes_lt::<$n, $n>(100).unwrap().as_slice().into_iter().map(|i| *i as u32).collect::<Vec<_>>()
                         );
                     }
                 )+
@@ -252,9 +252,9 @@ mod test {
 
         test_n_below_100!(10, 15, 20);
 
-        assert_eq!([2, 3, 5, 7], primes_lt::<9>(10).unwrap().as_slice());
+        assert_eq!([2, 3, 5, 7], primes_lt::<4, 9>(10).unwrap().as_slice());
 
-        assert_eq!(primes_lt::<2>(3).unwrap().as_slice(), [2]);
+        assert_eq!(primes_lt::<1, 2>(3).unwrap().as_slice(), [2]);
     }
 
     #[test]

From c23dfd5a8b1c79485424aefedf1e1813fc7bb96a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 12:58:37 +0200
Subject: [PATCH 134/212] TODO: move only large enough primes into the array

---
 src/generation.rs | 67 +++++++++++++++++++++++++----------------------
 src/lib.rs        |  9 ++++---
 2 files changed, 41 insertions(+), 35 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 7eae59d..0974281 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -112,8 +112,6 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
     primes
 }
 
-// TODO: Make primes_lt and primes_geq take two generics? N and MEMORY.
-
 /// Returns the `N` largest primes less than `upper_limit`.
 ///
 /// This function uses a segmented sieve of size `MEM` for computation,
@@ -238,69 +236,76 @@ pub const fn primes_lt<const N: usize, const MEM: usize>(mut upper_limit: u64) -
 ///
 /// If you want to compute primes smaller than the input, take a look at [`primes_lt`].
 ///
-/// # Example
+/// # Examples
 ///
 /// Basic usage:
 /// ```
 /// # use const_primes::{primes_geq, Result, Error};
-/// const PRIMES: Result<5> = primes_geq(10);
-/// assert_eq!(PRIMES?.as_slice(), &[11, 13, 17, 19, 23]);
+/// const PRIMES: Result<5> = primes_geq::<5, 5>(10);
+/// assert_eq!(PRIMES?, [11, 13, 17, 19, 23]);
 /// # Ok::<(), Error<5>>(())
 /// ```
 /// Compute larger primes without starting from zero:
 /// ```
 /// # use const_primes::{primes_geq, Result, Error};
-/// const N: usize = 71_000;
 /// # #[allow(long_running_const_eval)]
-/// const P: Result<N> = primes_geq(5_000_000_030);
-/// assert_eq!(&P?[..3], &[5_000_000_039, 5_000_000_059, 5_000_000_063]);
-/// assert_eq!(&P?[N - 3..], &[5_001_586_727, 5_001_586_729, 5_001_586_757]);
-/// # Ok::<(), Error<N>>(())
+/// const P: Result<3> = primes_geq::<3, 71_000>(5_000_000_030);
+/// assert_eq!(P?, [5_000_000_039, 5_000_000_059, 5_000_000_063]);
+/// // assert_eq!(P?[N - 3..], &[5_001_586_727, 5_001_586_729, 5_001_586_757]);
+/// # Ok::<(), Error<3>>(())
 /// ```
-/// Only primes smaller than `N^2` will be generated:
+/// Only primes smaller than `MEM^2` will be generated:
 /// ```
 /// # use const_primes::{primes_geq, Result, Error};
-/// const PRIMES: Result<3> = primes_geq(5);
+/// const PRIMES: Result<3> = primes_geq::<3, 3>(5);
 /// assert_eq!(PRIMES?.as_slice(), &[5, 7]);
 /// # Ok::<(), Error<3>>(())
 /// ```
 ///
 /// # Errors
 ///
-/// Returns an error if `N^2` does not fit in a `u64`, or if `lower_limit` is larger or equal to `N^2`.
+/// Returns an error if `lower_limit` is larger than or equal to `MEM^2`.
 /// ```
 /// # use const_primes::{primes_geq, Result};
-/// const P: Result<5> = primes_geq(26);
-/// assert!(P.is_err());
+/// const PRIMES: Result<5> = primes_geq::<5, 5>(26);
+/// assert!(PRIMES.is_err());
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
-pub const fn primes_geq<const N: usize>(mut lower_limit: u64) -> Result<N> {
-    const { assert!(N > 0, "`N` must be at least 1") }
-
-    let n64 = N as u64;
-    let Some(n64_sqr) = n64.checked_mul(n64) else {
-        return Err(Error::TooLargeN);
-    };
+pub const fn primes_geq<const N: usize, const MEM: usize>(mut lower_limit: u64) -> Result<N> {
+    const {
+        assert!(N > 0, "`N` must be at least 1");
+        assert!(MEM >= N, "`MEM` must be at least as large as `N`");
+        let mem64 = MEM as u64;
+        assert!(
+            mem64.checked_mul(mem64).is_some(),
+            "`MEM`^2 must fit in a u64"
+        );
+    }
 
     // There are no primes smaller than 2, so we will always start looking at 2.
     lower_limit = if lower_limit >= 2 { lower_limit } else { 2 };
 
-    if lower_limit >= n64_sqr {
+    let mem64 = MEM as u64;
+    let mem_sqr = mem64 * mem64;
+
+    if lower_limit >= mem_sqr {
         return Err(Error::TooLargeLimit);
     }
 
     let mut primes = [0; N];
-    let base_sieve: [bool; N] = sieve();
+    let base_sieve: [bool; MEM] = sieve();
     let mut total_found_primes = 0;
     'generate: while total_found_primes < N {
         let mut largest_found_prime = primes[total_found_primes];
-        let upper_sieve = sieve_segment(&base_sieve, lower_limit + n64);
+        let upper_sieve = sieve_segment(&base_sieve, lower_limit + mem64);
+
         let mut i = 0;
-        // Move the found primes into the output vector.
+        // Move all large enough primes into the output array.
+        // TODO: only write large enough primes
         while i < N {
             if upper_sieve[i] {
                 largest_found_prime = lower_limit + i as u64;
-                if largest_found_prime >= n64 * n64 {
+                if largest_found_prime >= mem64 * mem64 {
                     // We do not know if this is actually a prime
                     // since the base sieve does not contain information about
                     // the prime status of numbers larger than or equal to N.
@@ -502,18 +507,18 @@ mod test {
     #[test]
     fn sanity_check_primes_geq() {
         {
-            const P: Result<5> = primes_geq(10);
+            const P: Result<5> = primes_geq::<5, 5>(10);
             assert_eq!(P.unwrap().as_slice(), [11, 13, 17, 19, 23]);
         }
         {
-            const P: Result<5> = primes_geq(0);
+            const P: Result<5> = primes_geq::<5, 5>(0);
             assert_eq!(P.unwrap().as_slice(), [2, 3, 5, 7, 11]);
         }
         {
-            const P: Result<1> = primes_geq(0);
+            const P: Result<1> = primes_geq::<1, 1>(0);
             assert_eq!(P, Err(Error::TooLargeLimit),);
         }
-        for &prime in primes_geq::<2_000>(3_998_000).unwrap().as_slice() {
+        for &prime in primes_geq::<2_000, 2_000>(3_998_000).unwrap().as_slice() {
             if prime == 0 {
                 break;
             }
diff --git a/src/lib.rs b/src/lib.rs
index 38718cd..49a779b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -51,12 +51,13 @@
 //! that can be used to work with ranges that don't start at zero.
 //! ```
 //! # use const_primes::generation::{primes_geq, Result, Error};
-//! const N: usize = 70722;
 //! # #[allow(long_running_const_eval)]
-//! const PRIMES_GEQ: Result<N> = primes_geq(5_000_000_031);
+//! // Use an array of size 70722 to sieve for primes, but only store
+//! // the three primes after 5 million and 31 in the binary.
+//! const PRIMES_GEQ: Result<3> = primes_geq::<3, 70_722>(5_000_000_031);
 //!
-//! assert_eq!(&PRIMES_GEQ?[..3], [5_000_000_039, 5_000_000_059, 5_000_000_063]);
-//! # Ok::<(), Error<N>>(())
+//! assert_eq!(PRIMES_GEQ?, [5_000_000_039, 5_000_000_059, 5_000_000_063]);
+//! # Ok::<(), Error<3>>(())
 //! ```
 //! ```
 //! # use const_primes::sieve_lt;

From 26cface222136ec54b7edebf16257a7d37514856 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 15:52:19 +0200
Subject: [PATCH 135/212] Fix primes_geq

---
 src/generation.rs | 65 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 45 insertions(+), 20 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 0974281..24d3f36 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -271,7 +271,7 @@ pub const fn primes_lt<const N: usize, const MEM: usize>(mut upper_limit: u64) -
 /// assert!(PRIMES.is_err());
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
-pub const fn primes_geq<const N: usize, const MEM: usize>(mut lower_limit: u64) -> Result<N> {
+pub const fn primes_geq<const N: usize, const MEM: usize>(lower_limit: u64) -> Result<N> {
     const {
         assert!(N > 0, "`N` must be at least 1");
         assert!(MEM >= N, "`MEM` must be at least as large as `N`");
@@ -283,7 +283,7 @@ pub const fn primes_geq<const N: usize, const MEM: usize>(mut lower_limit: u64)
     }
 
     // There are no primes smaller than 2, so we will always start looking at 2.
-    lower_limit = if lower_limit >= 2 { lower_limit } else { 2 };
+    let lower_limit = if lower_limit >= 2 { lower_limit } else { 2 };
 
     let mem64 = MEM as u64;
     let mem_sqr = mem64 * mem64;
@@ -293,35 +293,60 @@ pub const fn primes_geq<const N: usize, const MEM: usize>(mut lower_limit: u64)
     }
 
     let mut primes = [0; N];
-    let base_sieve: [bool; MEM] = sieve();
     let mut total_found_primes = 0;
+    let mut largest_found_prime = 0;
+    let base_sieve: [bool; MEM] = sieve();
+    let mut sieve_limit = lower_limit;
     'generate: while total_found_primes < N {
-        let mut largest_found_prime = primes[total_found_primes];
-        let upper_sieve = sieve_segment(&base_sieve, lower_limit + mem64);
+        let upper_sieve = sieve_segment(&base_sieve, sieve_limit + mem64);
 
         let mut i = 0;
-        // Move all large enough primes into the output array.
-        // TODO: only write large enough primes
-        while i < N {
+        while i < MEM {
             if upper_sieve[i] {
-                largest_found_prime = lower_limit + i as u64;
+                largest_found_prime = sieve_limit + i as u64;
+                // We can not know whether this is a prime since the base sieve contains no information
+                // about numbers larger than or equal to `MEM`.
                 if largest_found_prime >= mem64 * mem64 {
-                    // We do not know if this is actually a prime
-                    // since the base sieve does not contain information about
-                    // the prime status of numbers larger than or equal to N.
-                    let restricted = ArraySection::new(primes, 0..total_found_primes);
-                    return Ok(PrimesArray::Partial(restricted));
+                    return Ok(PrimesArray::Partial(ArraySection::new(
+                        primes,
+                        0..total_found_primes,
+                    )));
                 }
-                primes[total_found_primes] = largest_found_prime;
-                total_found_primes += 1;
-                if total_found_primes >= N {
-                    // We've found enough primes
-                    break 'generate;
+                if largest_found_prime >= lower_limit {
+                    primes[total_found_primes] = largest_found_prime;
+                    total_found_primes += 1;
+                    if total_found_primes >= N {
+                        // We've found enough primes.
+                        break 'generate;
+                    }
                 }
             }
             i += 1;
         }
-        lower_limit = largest_found_prime + 1;
+        sieve_limit = largest_found_prime + 1;
+
+        // let mut i = 0;
+        // // Move all large enough primes into the output array.
+        // while i < N {
+        //     if upper_sieve[i] {
+        //         largest_found_prime = lower_limit + i as u64;
+        //         if largest_found_prime >= mem64 * mem64 {
+        //             // We do not know if this is actually a prime
+        //             // since the base sieve does not contain information about
+        //             // the prime status of numbers larger than or equal to N.
+        //             let restricted = ArraySection::new(primes, 0..total_found_primes);
+        //             return Ok(PrimesArray::Partial(restricted));
+        //         }
+        //         primes[total_found_primes] = largest_found_prime;
+        //         total_found_primes += 1;
+        //         if total_found_primes >= N {
+        //             // We've found enough primes
+        //             break 'generate;
+        //         }
+        //     }
+        //     i += 1;
+        // }
+        // lower_limit = largest_found_prime + 1;
     }
     Ok(PrimesArray::Full(primes))
 }

From 1686ba8f29bf7ce3021eb9505063a2ce37d85f92 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 15:53:17 +0200
Subject: [PATCH 136/212] Comment formatting

---
 src/generation.rs | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/generation.rs b/src/generation.rs
index 24d3f36..5a577d3 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -304,7 +304,9 @@ pub const fn primes_geq<const N: usize, const MEM: usize>(lower_limit: u64) -> R
         while i < MEM {
             if upper_sieve[i] {
                 largest_found_prime = sieve_limit + i as u64;
-                // We can not know whether this is a prime since the base sieve contains no information
+
+                // We can not know whether this is actually a prime since
+                // the base sieve contains no information
                 // about numbers larger than or equal to `MEM`.
                 if largest_found_prime >= mem64 * mem64 {
                     return Ok(PrimesArray::Partial(ArraySection::new(
@@ -312,6 +314,7 @@ pub const fn primes_geq<const N: usize, const MEM: usize>(lower_limit: u64) -> R
                         0..total_found_primes,
                     )));
                 }
+
                 if largest_found_prime >= lower_limit {
                     primes[total_found_primes] = largest_found_prime;
                     total_found_primes += 1;

From b26f79cdf9f1e6fe130cdb11d5ffdfdd2a083b90 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 16:04:22 +0200
Subject: [PATCH 137/212] Rename TooLargeN to MEMSquaredOverflow

---
 src/generation.rs | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 5a577d3..1e133df 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -187,7 +187,7 @@ pub const fn primes_lt<const N: usize, const MEM: usize>(mut upper_limit: u64) -
                 return Err(Error::TooLargeLimit);
             }
         }
-        None => return Err(Error::TooLargeN),
+        None => return Err(Error::MEMSquaredOverflow),
     }
 
     let mut primes: [u64; N] = [0; N];
@@ -508,9 +508,9 @@ impl_index_range! {Range<usize>, RangeTo<usize>, RangeFrom<usize>, RangeToInclus
 /// region of numbers that exceed the square of the size of the requested array.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum Error<const N: usize> {
-    /// `N^2`` did not fit in a `u64`.
-    TooLargeN,
-    /// the upper limit was larger than `N^2`.
+    /// `MEM`^2 did not fit in a `u64`.
+    MEMSquaredOverflow,
+    /// the upper limit was larger than `MEM^2`.
     TooLargeLimit,
     /// the lower limit was smaller than or equal to 2.
     TooSmallLimit,
@@ -519,7 +519,7 @@ pub enum Error<const N: usize> {
 impl<const N: usize> fmt::Display for Error<N> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
-            Self::TooLargeN => write!(f, "`N^2` did not fit in a `u64`"),
+            Self::MEMSquaredOverflow => write!(f, "`MEM`^2 did not fit in a `u64`"),
             Self::TooLargeLimit => write!(f, "the upper limit was larger than `N^2`"),
             Self::TooSmallLimit => write!(f, "the lower limit was smaller than or equal to 2"),
         }

From b36af3fe49b16b7b8653b96e46f28a34c9aa03a2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 16:05:03 +0200
Subject: [PATCH 138/212] Correct display impl of Error for the TooLargeLimit
 variant

---
 src/generation.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/generation.rs b/src/generation.rs
index 1e133df..1d086a3 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -520,7 +520,7 @@ impl<const N: usize> fmt::Display for Error<N> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
             Self::MEMSquaredOverflow => write!(f, "`MEM`^2 did not fit in a `u64`"),
-            Self::TooLargeLimit => write!(f, "the upper limit was larger than `N^2`"),
+            Self::TooLargeLimit => write!(f, "the upper limit was larger than `MEM`^2"),
             Self::TooSmallLimit => write!(f, "the lower limit was smaller than or equal to 2"),
         }
     }

From 1f4e9be6c8aa6a8cacca686639b88e369929cc0c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 16:06:10 +0200
Subject: [PATCH 139/212] Remove ominous no guarantee text

---
 src/array_section.rs | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index d70a3dd..832b738 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -111,22 +111,19 @@ impl<const N: usize, T> ArraySection<T, N> {
         self.end
     }
 
-    /// Returns a reference to the full underlying array. There is no guarantee about the data
-    /// outside the section.
+    /// Returns a reference to the full underlying array.
     #[inline]
     pub const fn as_full_array(&self) -> &[T; N] {
         &self.array
     }
 
     /// Returns a mutable reference to the full underlying array.
-    /// There is no guarantee about the data outside the section.
     #[inline]
     pub fn as_full_array_mut(&mut self) -> &mut [T; N] {
         &mut self.array
     }
 
-    /// Converts `self` into the full underlying array. There is no guarantee about the data
-    /// outside the section.
+    /// Converts `self` into the full underlying array.
     #[inline]
     pub fn into_full_array(self) -> [T; N] {
         self.array

From 76fa4d3e3dae3b8cd2e611dd8654191df800644e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 16:08:50 +0200
Subject: [PATCH 140/212] Remove ability to edit ArraySection, the point is
 invariant preervation

---
 src/array_section.rs | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index 832b738..d9d0fb7 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -117,12 +117,6 @@ impl<const N: usize, T> ArraySection<T, N> {
         &self.array
     }
 
-    /// Returns a mutable reference to the full underlying array.
-    #[inline]
-    pub fn as_full_array_mut(&mut self) -> &mut [T; N] {
-        &mut self.array
-    }
-
     /// Converts `self` into the full underlying array.
     #[inline]
     pub fn into_full_array(self) -> [T; N] {

From b877131db59171b7aaa37d6733faa5464ff9c508 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 16:17:21 +0200
Subject: [PATCH 141/212] Fix broken doc links

---
 src/array_section.rs | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index d9d0fb7..c4e7b18 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -243,7 +243,7 @@ impl<'a, const N: usize, T> IntoIterator for &'a ArraySection<T, N> {
     }
 }
 
-use array_section_iter::ArraySectionIter;
+pub use array_section_iter::ArraySectionIter;
 mod array_section_iter {
     use super::FusedIterator;
 
@@ -251,7 +251,7 @@ mod array_section_iter {
     pub struct ArraySectionIter<'a, T>(core::slice::Iter<'a, T>);
 
     impl<'a, T> ArraySectionIter<'a, T> {
-        pub const fn new(iter: core::slice::Iter<'a, T>) -> Self {
+        pub(crate) const fn new(iter: core::slice::Iter<'a, T>) -> Self {
             Self(iter)
         }
     }
@@ -291,18 +291,18 @@ mod array_section_iter {
     impl<'a, T> FusedIterator for ArraySectionIter<'a, T> {}
 }
 
-use array_section_into_iter::ArraySectionIntoIter;
+pub use array_section_into_iter::ArraySectionIntoIter;
 mod array_section_into_iter {
     use super::FusedIterator;
 
     #[derive(Debug, Clone)]
-    /// Created by the [`into_iter`](RestrictedArray::into_iter) function on [`RestrictedArray`], see it for more information.
+    /// Created by the [`into_iter`](super::ArraySection::into_iter) function on [`ArraySection`](super::ArraySection), see it for more information.
     pub struct ArraySectionIntoIter<T, const N: usize>(
         core::iter::Take<core::iter::Skip<core::array::IntoIter<T, N>>>,
     );
 
     impl<const N: usize, T> ArraySectionIntoIter<T, N> {
-        pub const fn new(
+        pub(crate) const fn new(
             iter: core::iter::Take<core::iter::Skip<core::array::IntoIter<T, N>>>,
         ) -> Self {
             Self(iter)

From 7d4bed8fe962fe9ed94d72a95d9de3554143aa5e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 16:37:14 +0200
Subject: [PATCH 142/212] Add iter function and impl IntoIterator for
 PrimesArray

---
 src/generation.rs | 135 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 135 insertions(+)

diff --git a/src/generation.rs b/src/generation.rs
index 1d086a3..14c08be 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -446,6 +446,10 @@ impl<const N: usize> PrimesArray<N> {
     pub const fn is_empty(&self) -> bool {
         self.len() == 0
     }
+
+    pub fn iter(&self) -> PrimesArrayIter<'_> {
+        PrimesArrayIter::new(self.as_slice().iter())
+    }
 }
 
 impl<const N: usize, T> PartialEq<[T; N]> for PrimesArray<N>
@@ -501,6 +505,137 @@ macro_rules! impl_index_range {
 
 impl_index_range! {Range<usize>, RangeTo<usize>, RangeFrom<usize>, RangeToInclusive<usize>, RangeFull, RangeInclusive<usize>}
 
+impl<const N: usize> IntoIterator for PrimesArray<N> {
+    type IntoIter = PrimesArrayIntoIter<N>;
+    type Item = u64;
+    fn into_iter(self) -> Self::IntoIter {
+        PrimesArrayIntoIter::new(self)
+    }
+}
+
+impl<'a, const N: usize> IntoIterator for &'a PrimesArray<N> {
+    type IntoIter = PrimesArrayIter<'a>;
+    type Item = &'a u64;
+    fn into_iter(self) -> Self::IntoIter {
+        self.iter()
+    }
+}
+
+pub use primes_array_iter::PrimesArrayIter;
+mod primes_array_iter {
+    use core::iter::FusedIterator;
+
+    #[derive(Debug, Clone)]
+    pub struct PrimesArrayIter<'a>(core::slice::Iter<'a, u64>);
+
+    impl<'a> PrimesArrayIter<'a> {
+        pub(crate) const fn new(iter: core::slice::Iter<'a, u64>) -> Self {
+            Self(iter)
+        }
+    }
+
+    impl<'a> Iterator for PrimesArrayIter<'a> {
+        type Item = &'a u64;
+
+        #[inline]
+        fn next(&mut self) -> Option<Self::Item> {
+            self.0.next()
+        }
+
+        #[inline]
+        fn size_hint(&self) -> (usize, Option<usize>) {
+            self.0.size_hint()
+        }
+
+        #[inline]
+        fn nth(&mut self, n: usize) -> Option<Self::Item> {
+            self.0.nth(n)
+        }
+
+        #[inline]
+        fn count(self) -> usize {
+            self.0.count()
+        }
+
+        #[inline]
+        fn last(self) -> Option<Self::Item> {
+            self.0.last()
+        }
+    }
+
+    impl<'a> DoubleEndedIterator for PrimesArrayIter<'a> {
+        #[inline]
+        fn next_back(&mut self) -> Option<Self::Item> {
+            self.0.next_back()
+        }
+    }
+
+    impl<'a> ExactSizeIterator for PrimesArrayIter<'a> {
+        #[inline]
+        fn len(&self) -> usize {
+            self.0.len()
+        }
+    }
+
+    impl<'a> FusedIterator for PrimesArrayIter<'a> {}
+}
+
+pub use primes_array_into_iter::PrimesArrayIntoIter;
+mod primes_array_into_iter {
+    use core::iter::FusedIterator;
+
+    use crate::{array_section::ArraySectionIntoIter, PrimesArray};
+
+    pub struct PrimesArrayIntoIter<const N: usize>(ArraySectionIntoIter<u64, N>);
+
+    impl<const N: usize> PrimesArrayIntoIter<N> {
+        #[inline]
+        pub(crate) const fn new(primes_array: PrimesArray<N>) -> Self {
+            Self(primes_array.into_array_section().into_iter())
+        }
+    }
+
+    impl<const N: usize> Iterator for PrimesArrayIntoIter<N> {
+        type Item = u64;
+
+        #[inline]
+        fn next(&mut self) -> Option<Self::Item> {
+            self.0.next()
+        }
+
+        #[inline]
+        fn last(self) -> Option<Self::Item> {
+            self.0.last()
+        }
+
+        #[inline]
+        fn count(self) -> usize {
+            self.0.count()
+        }
+
+        #[inline]
+        fn nth(&mut self, n: usize) -> Option<Self::Item> {
+            self.0.nth(n)
+        }
+    }
+
+    impl<const N: usize> DoubleEndedIterator for PrimesArrayIntoIter<N> {
+        #[inline]
+        fn next_back(&mut self) -> Option<Self::Item> {
+            self.0.next_back()
+        }
+    }
+
+    impl<const N: usize> ExactSizeIterator for PrimesArrayIntoIter<N> {
+        #[inline]
+        fn len(&self) -> usize {
+            self.0.len()
+        }
+    }
+
+    impl<const N: usize> FusedIterator for PrimesArrayIntoIter<N> {}
+}
+
 /// An enum describing whether the requested array could be filled completely, or only a partially.
 /// A partial array can be returned by [`primes_lt`] if the size of the requested
 /// array is larger than the actual number of primes less than the given `upper_limit`.

From 25f486f79f720469fcb52e3dd3370d2951826c9d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 16:38:08 +0200
Subject: [PATCH 143/212] Remove broken const annotation

---
 src/generation.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/generation.rs b/src/generation.rs
index 14c08be..445341d 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -590,7 +590,7 @@ mod primes_array_into_iter {
 
     impl<const N: usize> PrimesArrayIntoIter<N> {
         #[inline]
-        pub(crate) const fn new(primes_array: PrimesArray<N>) -> Self {
+        pub(crate) fn new(primes_array: PrimesArray<N>) -> Self {
             Self(primes_array.into_array_section().into_iter())
         }
     }

From f15d2d780084963da996c87ab6756052a0dd0db4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 16:38:58 +0200
Subject: [PATCH 144/212] Override default size_hint for PrimesArrayIntoIter

---
 src/generation.rs | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/generation.rs b/src/generation.rs
index 445341d..e724e7d 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -603,6 +603,11 @@ mod primes_array_into_iter {
             self.0.next()
         }
 
+        #[inline]
+        fn size_hint(&self) -> (usize, Option<usize>) {
+            self.0.size_hint()
+        }
+
         #[inline]
         fn last(self) -> Option<Self::Item> {
             self.0.last()

From 69e47a159bde47eb04e31bd075c964c0dbbc9614 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 16:40:30 +0200
Subject: [PATCH 145/212] Define iterator impl region

---
 src/generation.rs | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/generation.rs b/src/generation.rs
index e724e7d..e84ce7e 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -505,6 +505,8 @@ macro_rules! impl_index_range {
 
 impl_index_range! {Range<usize>, RangeTo<usize>, RangeFrom<usize>, RangeToInclusive<usize>, RangeFull, RangeInclusive<usize>}
 
+// region: Iterator impls
+
 impl<const N: usize> IntoIterator for PrimesArray<N> {
     type IntoIter = PrimesArrayIntoIter<N>;
     type Item = u64;
@@ -641,6 +643,8 @@ mod primes_array_into_iter {
     impl<const N: usize> FusedIterator for PrimesArrayIntoIter<N> {}
 }
 
+// endregion: Iterator impls
+
 /// An enum describing whether the requested array could be filled completely, or only a partially.
 /// A partial array can be returned by [`primes_lt`] if the size of the requested
 /// array is larger than the actual number of primes less than the given `upper_limit`.

From 12e1886fb0c4d791a3b216e8f58d6a3f307846c9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 16:41:14 +0200
Subject: [PATCH 146/212] inline new PrimesArrayIter

---
 src/generation.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/generation.rs b/src/generation.rs
index e84ce7e..ceb00ea 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -531,6 +531,7 @@ mod primes_array_iter {
     pub struct PrimesArrayIter<'a>(core::slice::Iter<'a, u64>);
 
     impl<'a> PrimesArrayIter<'a> {
+        #[inline]
         pub(crate) const fn new(iter: core::slice::Iter<'a, u64>) -> Self {
             Self(iter)
         }

From a254287783e2bf1e35c42d77b7d7953341905e01 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 16:44:32 +0200
Subject: [PATCH 147/212] Make PartialEq<[T; N]> for PrimesArray symmetric

---
 src/generation.rs | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/generation.rs b/src/generation.rs
index ceb00ea..dd26066 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -476,6 +476,12 @@ impl<const N: usize, T: PartialEq<u64>> PartialEq<PrimesArray<N>> for [T] {
     }
 }
 
+impl<const N: usize, T: PartialEq<u64>> PartialEq<PrimesArray<N>> for [T; N] {
+    fn eq(&self, other: &PrimesArray<N>) -> bool {
+        self.eq(other.as_slice())
+    }
+}
+
 impl<const N: usize> From<PrimesArray<N>> for ArraySection<u64, N> {
     #[inline]
     fn from(value: PrimesArray<N>) -> Self {

From 3581ea0f7d5481427c6f29161c5c84c33f780fa9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 16:45:58 +0200
Subject: [PATCH 148/212] computed --> populated in doctext

---
 src/generation.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index dd26066..7382282 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -404,7 +404,7 @@ impl<const N: usize> PrimesArray<N> {
     }
 
     /// Returns an [`ArraySection`] if not all of the elements
-    /// in the underlying array could be computed.
+    /// in the underlying array could be populated.
     #[inline]
     pub const fn partial(self) -> Option<ArraySection<u64, N>> {
         match self {
@@ -414,7 +414,7 @@ impl<const N: usize> PrimesArray<N> {
     }
 
     /// Returns a reference to the [`ArraySection`] if not all elements of the underlying array
-    /// could be computed.
+    /// could be populated.
     #[inline]
     pub const fn as_partial(&self) -> Option<&ArraySection<u64, N>> {
         match self {

From bd61c12147a44e5274c4042552f8733e991b8d47 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 16:50:40 +0200
Subject: [PATCH 149/212] Clarify ArraySection docstring

---
 src/array_section.rs | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index c4e7b18..752f6ca 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -25,9 +25,11 @@ use core::{
 /// const A2: [i32; 5] = [0, 3, 7, 100, -5];
 /// const AS1: ArraySection<i32, 4> = ArraySection::new(A1, 1..3);
 /// const AS2: ArraySection<i32, 5> = ArraySection::new(A2, 1..3);
+///
+/// // Even though the arrays are different
+/// assert_ne!(A1.as_slice(), A2.as_slice());
+/// // The sections are the same
 /// assert_eq!(AS1, AS2);
-/// assert!(A1.as_slice() > A2.as_slice());
-/// assert!(!(AS1 > AS2));
 /// ```
 #[derive(Debug, Clone, Copy, Eq)]
 pub struct ArraySection<T, const N: usize> {

From 1f99b7758f31b3284fa187ef6a48b78cdbc4ad43 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 16:53:01 +0200
Subject: [PATCH 150/212] Add note to Hash impl

---
 src/array_section.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/array_section.rs b/src/array_section.rs
index 752f6ca..7ae055f 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -38,6 +38,7 @@ pub struct ArraySection<T, const N: usize> {
     array: [T; N],
 }
 
+/// Only hashes the data in the section, and not the full array.
 impl<const N: usize, T: Hash> Hash for ArraySection<T, N> {
     #[inline]
     fn hash<H: Hasher>(&self, state: &mut H) {

From 73981dc1be02779670aadc9a37cd609f6fbd738c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 17:04:25 +0200
Subject: [PATCH 151/212] Add fallible conversions into array for ArraySection

---
 Cargo.toml           |  3 +++
 src/array_section.rs | 37 +++++++++++++++++++++++++++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/Cargo.toml b/Cargo.toml
index 1aca1c0..b6a3134 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,6 +16,9 @@ repository = "https://github.com/JSorngard/const-primes"
 criterion = { version = "0.5", features = ["html_reports"] }
 rand = "0.8"
 
+[features]
+std = []
+
 [[bench]]
 name = "prime_benches"
 harness = false
diff --git a/src/array_section.rs b/src/array_section.rs
index 7ae055f..da0c12b 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -114,6 +114,16 @@ impl<const N: usize, T> ArraySection<T, N> {
         self.end
     }
 
+    /// Returns a reference to the full underlying array if it is fully populated.
+    #[inline]
+    pub const fn try_as_full_array(&self) -> Option<&[T; N]> {
+        if self.section_is_full_array() {
+            Some(&self.array)
+        } else {
+            None
+        }
+    }
+
     /// Returns a reference to the full underlying array.
     #[inline]
     pub const fn as_full_array(&self) -> &[T; N] {
@@ -167,6 +177,33 @@ impl<const N: usize, T> ArraySection<T, N> {
     }
 }
 
+// region: TryFrom impls
+
+#[derive(Debug, Clone, Copy)]
+pub struct TryFromArraySectionError<T, const N: usize>(ArraySection<T, N>);
+
+impl<T, const N: usize> core::fmt::Display for TryFromArraySectionError<T, N> {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(f, "the array was not fully populated")
+    }
+}
+
+#[cfg(feature = "std")]
+impl<T, const N: usize> std::error::Error for TryFromArraySectionError<T, N> {}
+
+impl<const N: usize, T> TryFrom<ArraySection<T, N>> for [T; N] {
+    type Error = TryFromArraySectionError<T, N>;
+    fn try_from(value: ArraySection<T, N>) -> Result<Self, Self::Error> {
+        if value.section_is_full_array() {
+            Ok(value.array)
+        } else {
+            Err(TryFromArraySectionError(value))
+        }
+    }
+}
+
+// endregion: TryFrom impls
+
 impl<const N: usize, T> AsRef<[T]> for ArraySection<T, N> {
     #[inline]
     fn as_ref(&self) -> &[T] {

From 98c04d71996416c5215a9d312fc4dcfd278252f8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 17:05:51 +0200
Subject: [PATCH 152/212] Add note about sections to Ord impl

---
 src/array_section.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/array_section.rs b/src/array_section.rs
index da0c12b..1e5c9cf 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -65,6 +65,7 @@ impl<const N: usize, const M: usize, T: PartialOrd> PartialOrd<ArraySection<T, M
     }
 }
 
+/// Only compares the data in the sections and not the full arrays.
 impl<const N: usize, T: Ord> Ord for ArraySection<T, N> {
     #[inline]
     fn cmp(&self, other: &Self) -> Ordering {

From e974051e3c86169bcbb1d0c0a5798813cc823e76 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Thu, 2 May 2024 17:06:37 +0200
Subject: [PATCH 153/212] Inline TryFrom stuffs

---
 src/array_section.rs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/array_section.rs b/src/array_section.rs
index 1e5c9cf..b6000e7 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -50,6 +50,7 @@ impl<const N: usize, T: Hash> Hash for ArraySection<T, N> {
 impl<const N: usize, const M: usize, T: PartialEq> PartialEq<ArraySection<T, N>>
     for ArraySection<T, M>
 {
+    #[inline]
     fn eq(&self, other: &ArraySection<T, N>) -> bool {
         self.as_slice().eq(other.as_slice())
     }
@@ -184,6 +185,7 @@ impl<const N: usize, T> ArraySection<T, N> {
 pub struct TryFromArraySectionError<T, const N: usize>(ArraySection<T, N>);
 
 impl<T, const N: usize> core::fmt::Display for TryFromArraySectionError<T, N> {
+    #[inline]
     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
         write!(f, "the array was not fully populated")
     }
@@ -194,6 +196,7 @@ impl<T, const N: usize> std::error::Error for TryFromArraySectionError<T, N> {}
 
 impl<const N: usize, T> TryFrom<ArraySection<T, N>> for [T; N] {
     type Error = TryFromArraySectionError<T, N>;
+    #[inline]
     fn try_from(value: ArraySection<T, N>) -> Result<Self, Self::Error> {
         if value.section_is_full_array() {
             Ok(value.array)

From 45280b3ae74959905f96a22373ace44db1a407da Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 3 May 2024 13:29:42 +0200
Subject: [PATCH 154/212] Reshape return type of suffixed generation functions

---
 src/array_section.rs |  55 ++++++++++++++++----
 src/generation.rs    | 117 ++++++++++++++++++++-----------------------
 src/lib.rs           |  24 ++++++---
 3 files changed, 113 insertions(+), 83 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index b6000e7..724c4b3 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -46,16 +46,6 @@ impl<const N: usize, T: Hash> Hash for ArraySection<T, N> {
     }
 }
 
-/// Only compares the data in the sections, and not the full arrays.
-impl<const N: usize, const M: usize, T: PartialEq> PartialEq<ArraySection<T, N>>
-    for ArraySection<T, M>
-{
-    #[inline]
-    fn eq(&self, other: &ArraySection<T, N>) -> bool {
-        self.as_slice().eq(other.as_slice())
-    }
-}
-
 /// Only checks the data in the sections, and not the full arrays.
 impl<const N: usize, const M: usize, T: PartialOrd> PartialOrd<ArraySection<T, M>>
     for ArraySection<T, N>
@@ -192,10 +182,12 @@ impl<T, const N: usize> core::fmt::Display for TryFromArraySectionError<T, N> {
 }
 
 #[cfg(feature = "std")]
-impl<T, const N: usize> std::error::Error for TryFromArraySectionError<T, N> {}
+impl<T: core::fmt::Debug, const N: usize> std::error::Error for TryFromArraySectionError<T, N> {}
 
+/// Converts the `ArraySection` into an array if the section is actually the entire array.
 impl<const N: usize, T> TryFrom<ArraySection<T, N>> for [T; N] {
     type Error = TryFromArraySectionError<T, N>;
+
     #[inline]
     fn try_from(value: ArraySection<T, N>) -> Result<Self, Self::Error> {
         if value.section_is_full_array() {
@@ -208,6 +200,16 @@ impl<const N: usize, T> TryFrom<ArraySection<T, N>> for [T; N] {
 
 // endregion: TryFrom impls
 
+impl<const N: usize, T> From<[T; N]> for ArraySection<T, N> {
+    fn from(value: [T; N]) -> Self {
+        Self {
+            start: 0,
+            end: N,
+            array: value,
+        }
+    }
+}
+
 impl<const N: usize, T> AsRef<[T]> for ArraySection<T, N> {
     #[inline]
     fn as_ref(&self) -> &[T] {
@@ -244,6 +246,18 @@ impl_index_range! {Range<usize>, RangeFrom<usize>, RangeFull, RangeTo<usize>, Ra
 // endregion: Index impls
 
 // region: PartialEq impls
+
+/// Only compares the sections, and not the full arrays.
+impl<const N: usize, const M: usize, T, U> PartialEq<ArraySection<T, N>> for ArraySection<U, M>
+where
+    [U]: PartialEq<[T]>,
+{
+    #[inline]
+    fn eq(&self, other: &ArraySection<T, N>) -> bool {
+        self.as_slice().eq(other.as_slice())
+    }
+}
+
 impl<const N: usize, T, U> PartialEq<[U]> for ArraySection<T, N>
 where
     U: PartialEq<T>,
@@ -265,6 +279,25 @@ where
         self == other.as_slice()
     }
 }
+
+impl<const N: usize, const M: usize, T, U> PartialEq<[T; N]> for ArraySection<U, M>
+where
+    [U]: PartialEq<[T]>,
+{
+    fn eq(&self, other: &[T; N]) -> bool {
+        self.as_slice().eq(other.as_slice())
+    }
+}
+
+impl<const N: usize, const M: usize, T, U> PartialEq<ArraySection<U, M>> for [T; N]
+where
+    [T]: PartialEq<[U]>,
+{
+    fn eq(&self, other: &ArraySection<U, M>) -> bool {
+        self.as_slice().eq(other.as_slice())
+    }
+}
+
 // endregion: PartialEq impls
 
 impl<const N: usize, T> IntoIterator for ArraySection<T, N> {
diff --git a/src/generation.rs b/src/generation.rs
index 7382282..fcf23a0 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -5,8 +5,8 @@ use core::{
 
 use crate::{array_section::ArraySection, sieve, sieving::sieve_segment, Underlying};
 
-/// Type alias for the type returned by the segmented generation functions, that otherwise has two generics that must be the same.
-pub type Result<const N: usize> = core::result::Result<PrimesArray<N>, Error<N>>;
+/// Type alias for the type returned by the segmented sieving and generation functions.
+pub type Result<const N: usize> = core::result::Result<ArraySection<u64, N>, Error>;
 
 /// Returns the `N` first prime numbers.
 /// Fails to compile if `N` is 0.
@@ -121,9 +121,8 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 ///
 /// Fails to compile if `N` or `MEM` is 0, if `MEM < N` or if `MEM`^2 does not fit in a u64.
 ///
-/// The return array fills from the end until either it is full
-/// (in which case the function returns the [`PrimesArray::Full`] variant)
-/// or there are no more primes (in which case the function returns the [`PrimesArray::Partial`] variant).
+/// The return array fills from the end until either it is full,
+/// or there are no more primes.
 ///
 /// If you want to compute primes that are larger than some limit, take a look at [`primes_geq`].
 ///
@@ -132,9 +131,11 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// Basic usage:
 /// ```
 /// # use const_primes::generation::{Result, primes_lt, Error};
+/// // Sieving up to 100 means the sieve needs to be of size sqrt(100) = 10.
+/// // However, we only save the 4 largest primes in the constant.
 /// const PRIMES: Result<4> = primes_lt::<4, 10>(100);
 /// assert_eq!(PRIMES?, [79, 83, 89, 97]);
-/// # Ok::<(), Error<4>>(())
+/// # Ok::<(), Error>(())
 /// ```
 /// Compute larger primes without starting from zero:
 /// ```
@@ -143,16 +144,18 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// const BIG_PRIMES: Result<3> = primes_lt::<3, 70_711>(5_000_000_030);
 ///
 /// assert_eq!(BIG_PRIMES?, [4_999_999_903, 4_999_999_937, 5_000_000_029]);
-/// # Ok::<(), Error<3>>(())
+/// # Ok::<(), Error>(())
 /// ```
-/// If there are not enough primes to fill the requested array,
-/// the output will be the [`PrimesArray::Partial`] variant,
-/// which contains fewer primes than requested:
+/// If the number of primes requested, `N`, is larger than
+/// the number of primes that exists below the `lower_limit` we
+/// will get a partial result of all the existing primes.
+/// Due to limitations on const evaluation this will still
+/// take up the full `N` numbers worth of memory.
 /// ```
 /// # use const_primes::generation::{Result, primes_lt, Error};
 /// const PRIMES: Result<9> = primes_lt::<9, 9>(10);
-/// assert_eq!(PRIMES?.as_slice(), &[2, 3, 5, 7]);
-/// # Ok::<(), Error<9>>(())
+/// assert_eq!(PRIMES?, [2, 3, 5, 7]);
+/// # Ok::<(), Error>(())
 /// ```
 /// # Errors
 ///
@@ -177,17 +180,17 @@ pub const fn primes_lt<const N: usize, const MEM: usize>(mut upper_limit: u64) -
     }
 
     if upper_limit <= 2 {
-        return Err(Error::TooSmallLimit);
+        return Err(Error::TooSmallLimit(upper_limit));
     }
 
     let mem64 = MEM as u64;
     match (mem64).checked_mul(mem64) {
         Some(prod) => {
             if upper_limit > prod {
-                return Err(Error::TooLargeLimit);
+                return Err(Error::TooLargeLimit(upper_limit, MEM));
             }
         }
-        None => return Err(Error::MEMSquaredOverflow),
+        None => return Err(Error::MEMSquaredOverflow(MEM)),
     }
 
     let mut primes: [u64; N] = [0; N];
@@ -219,12 +222,11 @@ pub const fn primes_lt<const N: usize, const MEM: usize>(mut upper_limit: u64) -
         }
         upper_limit = smallest_found_prime;
         if upper_limit <= 2 && total_primes_found < N {
-            let restricted = ArraySection::new(primes, N - total_primes_found..N);
-            return Ok(PrimesArray::Partial(restricted));
+            return Ok(ArraySection::new(primes, N - total_primes_found..N));
         }
     }
 
-    Ok(PrimesArray::Full(primes))
+    Ok(ArraySection::new(primes, 0..N))
 }
 
 /// Returns the `N` smallest primes greater than or equal to `lower_limit`.
@@ -243,7 +245,7 @@ pub const fn primes_lt<const N: usize, const MEM: usize>(mut upper_limit: u64) -
 /// # use const_primes::{primes_geq, Result, Error};
 /// const PRIMES: Result<5> = primes_geq::<5, 5>(10);
 /// assert_eq!(PRIMES?, [11, 13, 17, 19, 23]);
-/// # Ok::<(), Error<5>>(())
+/// # Ok::<(), Error>(())
 /// ```
 /// Compute larger primes without starting from zero:
 /// ```
@@ -251,15 +253,14 @@ pub const fn primes_lt<const N: usize, const MEM: usize>(mut upper_limit: u64) -
 /// # #[allow(long_running_const_eval)]
 /// const P: Result<3> = primes_geq::<3, 71_000>(5_000_000_030);
 /// assert_eq!(P?, [5_000_000_039, 5_000_000_059, 5_000_000_063]);
-/// // assert_eq!(P?[N - 3..], &[5_001_586_727, 5_001_586_729, 5_001_586_757]);
-/// # Ok::<(), Error<3>>(())
+/// # Ok::<(), Error>(())
 /// ```
 /// Only primes smaller than `MEM^2` will be generated:
 /// ```
 /// # use const_primes::{primes_geq, Result, Error};
 /// const PRIMES: Result<3> = primes_geq::<3, 3>(5);
 /// assert_eq!(PRIMES?.as_slice(), &[5, 7]);
-/// # Ok::<(), Error<3>>(())
+/// # Ok::<(), Error>(())
 /// ```
 ///
 /// # Errors
@@ -283,15 +284,17 @@ pub const fn primes_geq<const N: usize, const MEM: usize>(lower_limit: u64) -> R
     }
 
     // There are no primes smaller than 2, so we will always start looking at 2.
-    let lower_limit = if lower_limit >= 2 { lower_limit } else { 2 };
+    let new_lower_limit = if lower_limit >= 2 { lower_limit } else { 2 };
 
     let mem64 = MEM as u64;
     let mem_sqr = mem64 * mem64;
 
-    if lower_limit >= mem_sqr {
-        return Err(Error::TooLargeLimit);
+    if new_lower_limit >= mem_sqr {
+        return Err(Error::TooLargeLimit(lower_limit, MEM));
     }
 
+    let lower_limit = new_lower_limit;
+
     let mut primes = [0; N];
     let mut total_found_primes = 0;
     let mut largest_found_prime = 0;
@@ -309,10 +312,7 @@ pub const fn primes_geq<const N: usize, const MEM: usize>(lower_limit: u64) -> R
                 // the base sieve contains no information
                 // about numbers larger than or equal to `MEM`.
                 if largest_found_prime >= mem64 * mem64 {
-                    return Ok(PrimesArray::Partial(ArraySection::new(
-                        primes,
-                        0..total_found_primes,
-                    )));
+                    return Ok(ArraySection::new(primes, 0..total_found_primes));
                 }
 
                 if largest_found_prime >= lower_limit {
@@ -327,31 +327,9 @@ pub const fn primes_geq<const N: usize, const MEM: usize>(lower_limit: u64) -> R
             i += 1;
         }
         sieve_limit = largest_found_prime + 1;
+    }
 
-        // let mut i = 0;
-        // // Move all large enough primes into the output array.
-        // while i < N {
-        //     if upper_sieve[i] {
-        //         largest_found_prime = lower_limit + i as u64;
-        //         if largest_found_prime >= mem64 * mem64 {
-        //             // We do not know if this is actually a prime
-        //             // since the base sieve does not contain information about
-        //             // the prime status of numbers larger than or equal to N.
-        //             let restricted = ArraySection::new(primes, 0..total_found_primes);
-        //             return Ok(PrimesArray::Partial(restricted));
-        //         }
-        //         primes[total_found_primes] = largest_found_prime;
-        //         total_found_primes += 1;
-        //         if total_found_primes >= N {
-        //             // We've found enough primes
-        //             break 'generate;
-        //         }
-        //     }
-        //     i += 1;
-        // }
-        // lower_limit = largest_found_prime + 1;
-    }
-    Ok(PrimesArray::Full(primes))
+    Ok(ArraySection::new(primes, 0..N))
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -658,25 +636,36 @@ mod primes_array_into_iter {
 /// It can also be returned by [`primes_geq`] if it needs to sieve into a
 /// region of numbers that exceed the square of the size of the requested array.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub enum Error<const N: usize> {
+pub enum Error {
     /// `MEM`^2 did not fit in a `u64`.
-    MEMSquaredOverflow,
-    /// the upper limit was larger than `MEM^2`.
-    TooLargeLimit,
-    /// the lower limit was smaller than or equal to 2.
-    TooSmallLimit,
+    MEMSquaredOverflow(usize),
+    /// the limit was larger than `MEM^2`.
+    TooLargeLimit(u64, usize),
+    /// the limit was smaller than or equal to 2.
+    TooSmallLimit(u64),
 }
 
-impl<const N: usize> fmt::Display for Error<N> {
+impl fmt::Display for Error {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
-            Self::MEMSquaredOverflow => write!(f, "`MEM`^2 did not fit in a `u64`"),
-            Self::TooLargeLimit => write!(f, "the upper limit was larger than `MEM`^2"),
-            Self::TooSmallLimit => write!(f, "the lower limit was smaller than or equal to 2"),
+            Self::MEMSquaredOverflow(mem) => {
+                write!(f, "`MEM` was {mem}, and so `MEM`^2 did not fit in a `u64`")
+            }
+            Self::TooLargeLimit(limit, mem) => write!(
+                f,
+                "the limit was {limit} and `MEM` was {mem}, so the limit was larger than `MEM`^2"
+            ),
+            Self::TooSmallLimit(limit) => write!(
+                f,
+                "the limit was {limit}, which is smaller than or equal to 2"
+            ),
         }
     }
 }
 
+#[cfg(feature = "std")]
+impl<const N: usize> std::error::Error for Error<N> {}
+
 #[cfg(test)]
 mod test {
     use crate::is_prime;
@@ -695,7 +684,7 @@ mod test {
         }
         {
             const P: Result<1> = primes_geq::<1, 1>(0);
-            assert_eq!(P, Err(Error::TooLargeLimit),);
+            assert_eq!(P, Err(Error::TooLargeLimit(0, 1)));
         }
         for &prime in primes_geq::<2_000, 2_000>(3_998_000).unwrap().as_slice() {
             if prime == 0 {
diff --git a/src/lib.rs b/src/lib.rs
index 49a779b..e4b065a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -48,16 +48,21 @@
 //! ## Arbitrary ranges
 //!
 //! The crate provides prime generation and sieving functions with suffixes, e.g. [`primes_geq`] and [`sieve_lt`]
-//! that can be used to work with ranges that don't start at zero.
+//! that can be used to work with ranges that don't start at zero. They take two generics: the number of primes
+//! to store in the binary, and the size of the sieve used during const evaluation
+//! (which must be at least `isqrt(largest_encountered_number)`). This means that one can
+//! sieve up to large numbers, but doesn't need to store the entire sieve in the binary.
 //! ```
 //! # use const_primes::generation::{primes_geq, Result, Error};
+//! use const_primes::isqrt;
 //! # #[allow(long_running_const_eval)]
-//! // Use an array of size 70722 to sieve for primes, but only store
-//! // the three primes after 5 million and 31 in the binary.
-//! const PRIMES_GEQ: Result<3> = primes_geq::<3, 70_722>(5_000_000_031);
+//! // If we want the three smallest primes after 5 billion and 31 we need a large sieve
+//! // to find them without returning an error.
+//! // However, we don't need to store the entire sieve, we can just store the three primes.
+//! const PRIMES_GEQ: Result<3> = primes_geq::<3, {isqrt(5_000_000_031) as usize + 1}>(5_000_000_031);
 //!
 //! assert_eq!(PRIMES_GEQ?, [5_000_000_039, 5_000_000_059, 5_000_000_063]);
-//! # Ok::<(), Error<3>>(())
+//! # Ok::<(), Error>(())
 //! ```
 //! ```
 //! # use const_primes::sieve_lt;
@@ -90,10 +95,13 @@
 //! assert_eq!(NOSUCH, None);
 //! ```
 //! and more!
+//!
+//! # Features
+//!
+//! `std`: links the standard library and uses it to implement the [`Error`](std::error::Error) trait for the error types.
 
 #![forbid(unsafe_code)]
-#![cfg_attr(not(test), no_std)]
-#![feature(inline_const)]
+#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
 
 /// The type that `Primes<N>` stores, and `primes::<N>()`` returns. Currently `u32`.
 // Just change this to whatever unsigned primitive integer type you want and it should work as long as it has enough bits for your purposes.
@@ -109,7 +117,7 @@ mod sieving;
 mod wrapper;
 
 pub use generation::{primes, primes_geq, primes_lt, Error, PrimesArray, Result};
-use imath::isqrt;
+pub use imath::isqrt;
 pub use miller_rabin::is_prime;
 pub use other_prime::{next_prime, previous_prime};
 pub use sieving::{sieve, sieve_geq, sieve_lt};

From 25bf22d46449b653f2acdfbd57940fc49d7dc9ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 3 May 2024 15:52:33 +0200
Subject: [PATCH 155/212] Improve documentation of primes_geq

---
 src/lib.rs | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index e4b065a..51a2166 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -49,16 +49,16 @@
 //!
 //! The crate provides prime generation and sieving functions with suffixes, e.g. [`primes_geq`] and [`sieve_lt`]
 //! that can be used to work with ranges that don't start at zero. They take two generics: the number of primes
-//! to store in the binary, and the size of the sieve used during const evaluation
-//! (which must be at least `isqrt(largest_encountered_number)`). This means that one can
+//! to store in the binary, and the size of the sieve used during evaluation
+//! (which must be at least `isqrt(largest_encountered_number) + 1`). This means that one can
 //! sieve up to large numbers, but doesn't need to store the entire sieve in the binary.
 //! ```
 //! # use const_primes::generation::{primes_geq, Result, Error};
 //! use const_primes::isqrt;
 //! # #[allow(long_running_const_eval)]
-//! // If we want the three smallest primes after 5 billion and 31 we need a large sieve
-//! // to find them without returning an error.
-//! // However, we don't need to store the entire sieve, we can just store the three primes.
+//! // The sieve needs to be of size sqrt(limit) + 1,
+//! // but we don't need to store the entire sieve, we can just store the primes we want.
+//! // For the three primes after 5 billion and 31:
 //! const PRIMES_GEQ: Result<3> = primes_geq::<3, {isqrt(5_000_000_031) as usize + 1}>(5_000_000_031);
 //!
 //! assert_eq!(PRIMES_GEQ?, [5_000_000_039, 5_000_000_059, 5_000_000_063]);

From 881e2abc842012f749e9bf0aebf5f317dd90c9f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 3 May 2024 15:53:16 +0200
Subject: [PATCH 156/212] Better math notation

---
 src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/lib.rs b/src/lib.rs
index 51a2166..f6d5a8f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -56,7 +56,7 @@
 //! # use const_primes::generation::{primes_geq, Result, Error};
 //! use const_primes::isqrt;
 //! # #[allow(long_running_const_eval)]
-//! // The sieve needs to be of size sqrt(limit) + 1,
+//! // The sieve needs to be of size ceil(sqrt(limit)),
 //! // but we don't need to store the entire sieve, we can just store the primes we want.
 //! // For the three primes after 5 billion and 31:
 //! const PRIMES_GEQ: Result<3> = primes_geq::<3, {isqrt(5_000_000_031) as usize + 1}>(5_000_000_031);

From 4b1fb6adc18f6113bf29782efce714bbb06bf161 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 3 May 2024 16:02:50 +0200
Subject: [PATCH 157/212] Show usage of primes_geq

---
 src/lib.rs | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index f6d5a8f..d1d32eb 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -53,8 +53,8 @@
 //! (which must be at least `isqrt(largest_encountered_number) + 1`). This means that one can
 //! sieve up to large numbers, but doesn't need to store the entire sieve in the binary.
 //! ```
-//! # use const_primes::generation::{primes_geq, Result, Error};
-//! use const_primes::isqrt;
+//! # use const_primes::Error;
+//! use const_primes::{primes_geq, isqrt, Result};
 //! # #[allow(long_running_const_eval)]
 //! // The sieve needs to be of size ceil(sqrt(limit)),
 //! // but we don't need to store the entire sieve, we can just store the primes we want.
@@ -116,6 +116,7 @@ mod other_prime;
 mod sieving;
 mod wrapper;
 
+pub use array_section::ArraySection;
 pub use generation::{primes, primes_geq, primes_lt, Error, PrimesArray, Result};
 pub use imath::isqrt;
 pub use miller_rabin::is_prime;

From 805c05a95f4806ead8eee9d54b134b46e59597f5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 3 May 2024 16:03:56 +0200
Subject: [PATCH 158/212] Fix impl of Error for generation::Error

---
 src/generation.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/generation.rs b/src/generation.rs
index fcf23a0..3c2ada6 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -664,7 +664,7 @@ impl fmt::Display for Error {
 }
 
 #[cfg(feature = "std")]
-impl<const N: usize> std::error::Error for Error<N> {}
+impl std::error::Error for Error {}
 
 #[cfg(test)]
 mod test {

From 24448aa4c2d114c04342b28855cf9db2da1cab45 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 3 May 2024 16:06:21 +0200
Subject: [PATCH 159/212] Simplify docstring

---
 src/lib.rs | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index d1d32eb..a047a91 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -50,15 +50,13 @@
 //! The crate provides prime generation and sieving functions with suffixes, e.g. [`primes_geq`] and [`sieve_lt`]
 //! that can be used to work with ranges that don't start at zero. They take two generics: the number of primes
 //! to store in the binary, and the size of the sieve used during evaluation
-//! (which must be at least `isqrt(largest_encountered_number) + 1`). This means that one can
-//! sieve up to large numbers, but doesn't need to store the entire sieve in the binary.
+//! (which must be at least the ceiling of the square root of the largest encountered number.
+//! This means that one can sieve up to large numbers,
+//! but doesn't need to store the entire sieve in the binary.
 //! ```
 //! # use const_primes::Error;
 //! use const_primes::{primes_geq, isqrt, Result};
 //! # #[allow(long_running_const_eval)]
-//! // The sieve needs to be of size ceil(sqrt(limit)),
-//! // but we don't need to store the entire sieve, we can just store the primes we want.
-//! // For the three primes after 5 billion and 31:
 //! const PRIMES_GEQ: Result<3> = primes_geq::<3, {isqrt(5_000_000_031) as usize + 1}>(5_000_000_031);
 //!
 //! assert_eq!(PRIMES_GEQ?, [5_000_000_039, 5_000_000_059, 5_000_000_063]);

From da22f4ee55e63ed80d852f2b81dd19fd0407fe7b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 3 May 2024 17:07:44 +0200
Subject: [PATCH 160/212] close paren

---
 src/lib.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index a047a91..f63daa4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -50,16 +50,16 @@
 //! The crate provides prime generation and sieving functions with suffixes, e.g. [`primes_geq`] and [`sieve_lt`]
 //! that can be used to work with ranges that don't start at zero. They take two generics: the number of primes
 //! to store in the binary, and the size of the sieve used during evaluation
-//! (which must be at least the ceiling of the square root of the largest encountered number.
+//! (which must be at least the ceiling of the square root of the largest encountered number).
 //! This means that one can sieve up to large numbers,
 //! but doesn't need to store the entire sieve in the binary.
 //! ```
 //! # use const_primes::Error;
 //! use const_primes::{primes_geq, isqrt, Result};
 //! # #[allow(long_running_const_eval)]
-//! const PRIMES_GEQ: Result<3> = primes_geq::<3, {isqrt(5_000_000_031) as usize + 1}>(5_000_000_031);
+//! const P_GEQ: Result<3> = primes_geq::<3, {isqrt(5_000_000_031) as usize + 1}>(5_000_000_031);
 //!
-//! assert_eq!(PRIMES_GEQ?, [5_000_000_039, 5_000_000_059, 5_000_000_063]);
+//! assert_eq!(P_GEQ?, [5_000_000_039, 5_000_000_059, 5_000_000_063]);
 //! # Ok::<(), Error>(())
 //! ```
 //! ```

From 62e2e6521d94e8888496517d096c21a7f9419710 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Fri, 3 May 2024 17:10:43 +0200
Subject: [PATCH 161/212] Better format of primes_geq demo

---
 src/lib.rs | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index f63daa4..a6c7172 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -56,8 +56,10 @@
 //! ```
 //! # use const_primes::Error;
 //! use const_primes::{primes_geq, isqrt, Result};
-//! # #[allow(long_running_const_eval)]
-//! const P_GEQ: Result<3> = primes_geq::<3, {isqrt(5_000_000_031) as usize + 1}>(5_000_000_031);
+//! const NUM_PRIMES: usize = 3;
+//! const LIMIT: u64 = 5_000_000_031;
+//! const SIEVE_SIZE: usize = isqrt(LIMIT) as usize + 1;
+//! const P_GEQ: Result<NUM_PRIMES> = primes_geq::<NUM_PRIMES, SIEVE_SIZE>(LIMIT);
 //!
 //! assert_eq!(P_GEQ?, [5_000_000_039, 5_000_000_059, 5_000_000_063]);
 //! # Ok::<(), Error>(())

From 542753b82532b2f76e4732519ee605295f3d1d4b Mon Sep 17 00:00:00 2001
From: Johan <johan.sorngard@gmail.com>
Date: Fri, 3 May 2024 22:36:11 +0200
Subject: [PATCH 162/212] Solve mem problem with macro

---
 src/generation.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++++
 src/lib.rs        | 21 +++++++++++++-----
 2 files changed, 71 insertions(+), 6 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 3c2ada6..effc07c 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -229,6 +229,62 @@ pub const fn primes_lt<const N: usize, const MEM: usize>(mut upper_limit: u64) -
     Ok(ArraySection::new(primes, 0..N))
 }
 
+/// Call [`primes_geq`] and [`primes_lt`], but automatically compute the memory requirement.
+///
+/// # Example
+///
+/// ```
+/// # use const_primes::{Result, primes_where, Error};
+/// const PRIMES_GEQ: Result<3> = primes_where!(3 >= 5_000_000_031_u64);
+/// const PRIMES_LT: Result<3> = primes_where!(3 < 5_000_000_031_u64);
+/// assert_eq!(PRIMES_GEQ?, [5000000039, 5000000059, 5000000063]);
+/// assert_eq!(PRIMES_LT?, [4999999903, 4999999937, 5000000029]);
+/// # Ok::<(), Error>(())
+/// ```
+#[macro_export]
+macro_rules! primes_where {
+    ($n:literal >= $lim:literal) => {
+        $crate::primes_geq::<
+            $n,
+            {
+                (if $lim <= 1 {
+                    $lim
+                } else {
+                    let mut x0 =
+                        ::core::primitive::u64::pow(2, ::core::primitive::u64::ilog2($lim) / 2 + 1);
+                    let mut x1 = (x0 + $lim / x0) / 2;
+                    while x1 < x0 {
+                        x0 = x1;
+                        x1 = (x0 + $lim / x0) / 2;
+                    }
+                    x0
+                }) as ::core::primitive::usize
+                    + 1
+            },
+        >($lim)
+    };
+    ($n:literal < $lim:literal) => {
+        $crate::primes_lt::<
+            $n,
+            {
+                (if $lim <= 1 {
+                    $lim
+                } else {
+                    let mut x0 =
+                        ::core::primitive::u64::pow(2, ::core::primitive::u64::ilog2($lim) / 2 + 1);
+                    let mut x1 = (x0 + $lim / x0) / 2;
+                    while x1 < x0 {
+                        x0 = x1;
+                        x1 = (x0 + $lim / x0) / 2;
+                    }
+                    x0
+                }) as ::core::primitive::usize
+                    + 1
+            },
+        >($lim)
+    };
+}
+
 /// Returns the `N` smallest primes greater than or equal to `lower_limit`.
 /// Fails to compile if `N` is 0. If `lower_limit` is less than 2 this functions assumes that it is 2,
 /// since there are no primes smaller than 2.
diff --git a/src/lib.rs b/src/lib.rs
index a6c7172..64430a3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -55,15 +55,24 @@
 //! but doesn't need to store the entire sieve in the binary.
 //! ```
 //! # use const_primes::Error;
-//! use const_primes::{primes_geq, isqrt, Result};
-//! const NUM_PRIMES: usize = 3;
-//! const LIMIT: u64 = 5_000_000_031;
-//! const SIEVE_SIZE: usize = isqrt(LIMIT) as usize + 1;
-//! const P_GEQ: Result<NUM_PRIMES> = primes_geq::<NUM_PRIMES, SIEVE_SIZE>(LIMIT);
+//! use const_primes::{primes_geq, Result};
+//! // ceil(isqrt(5_000_000_031)) = 70_711
+//! const P_GEQ: Result<3> = primes_geq::<3, 70_711>(5_000_000_031);
 //!
 //! assert_eq!(P_GEQ?, [5_000_000_039, 5_000_000_059, 5_000_000_063]);
 //! # Ok::<(), Error>(())
 //! ```
+//! If you do not wish to compute the required sieve size yourself,
+//! you can use the provided macro [`primes_where!`]:
+//! ```
+//! # use const_primes::{primes_where, Result, Error};
+//! const PRIMES_OVER_100: Result<3> = primes_where!(3 >= 100);
+//! const PRIMES_UNDER_100: Result<3> = primes_where!(3 < 100);
+//!
+//! assert_eq!(PRIMES_OVER_100?, [101, 103, 107]);
+//! assert_eq!(PRIMES_UNDER_100?, [83, 89, 97]);
+//! # Ok::<(), Error>(())
+//! ```
 //! ```
 //! # use const_primes::sieve_lt;
 //! const N: usize = 70711;
@@ -118,7 +127,7 @@ mod wrapper;
 
 pub use array_section::ArraySection;
 pub use generation::{primes, primes_geq, primes_lt, Error, PrimesArray, Result};
-pub use imath::isqrt;
+use imath::isqrt;
 pub use miller_rabin::is_prime;
 pub use other_prime::{next_prime, previous_prime};
 pub use sieving::{sieve, sieve_geq, sieve_lt};

From a14ca683cf848ceda56fff04e2b429632920e8ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sat, 4 May 2024 17:37:51 +0200
Subject: [PATCH 163/212] Add primes() to const_primes!()

---
 src/generation.rs | 84 +++++++++++++++++++++++++++--------------------
 src/lib.rs        |  8 ++---
 2 files changed, 53 insertions(+), 39 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index effc07c..0d5aba9 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -229,57 +229,71 @@ pub const fn primes_lt<const N: usize, const MEM: usize>(mut upper_limit: u64) -
     Ok(ArraySection::new(primes, 0..N))
 }
 
-/// Call [`primes_geq`] and [`primes_lt`], but automatically compute the memory requirement.
+/// Same as the private const fn isqrt in the crate.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! ඞ_const_primes_isqrt {
+    ($n:ident) => {
+        if $n <= 1 {
+            $n
+        } else {
+            let mut x0 = ::core::primitive::u64::pow(2, ::core::primitive::u64::ilog2($n) / 2 + 1);
+            let mut x1 = (x0 + $n / x0) / 2;
+            while x1 < x0 {
+                x0 = x1;
+                x1 = (x0 + $n / x0) / 2;
+            }
+            x0
+        }
+    };
+}
+
+/// Call [`primes`], [`primes_geq`] and [`primes_lt`], and automatically compute the memory requirement.
 ///
 /// # Example
 ///
 /// ```
-/// # use const_primes::{Result, primes_where, Error};
-/// const PRIMES_GEQ: Result<3> = primes_where!(3 >= 5_000_000_031_u64);
-/// const PRIMES_LT: Result<3> = primes_where!(3 < 5_000_000_031_u64);
+/// # use const_primes::{Result, const_primes, Error};
+/// const PRIMES: [u32; 3] = const_primes!();
+/// const LIMIT: u64 = 5_000_000_031;
+/// const PRIMES_GEQ: Result<3> = const_primes!(3; >= LIMIT);
+/// const PRIMES_LT: Result<3> = const_primes!(3; < LIMIT);
+/// let primes = const_primes!(3);
+///
+/// assert_eq!(primes, PRIMES);
+/// assert_eq!(PRIMES, [2, 3, 5]);
 /// assert_eq!(PRIMES_GEQ?, [5000000039, 5000000059, 5000000063]);
 /// assert_eq!(PRIMES_LT?, [4999999903, 4999999937, 5000000029]);
 /// # Ok::<(), Error>(())
 /// ```
 #[macro_export]
-macro_rules! primes_where {
-    ($n:literal >= $lim:literal) => {
-        $crate::primes_geq::<
+macro_rules! const_primes {
+    () => {
+        $crate::primes()
+    };
+    ($n:expr) => {
+        $crate::primes::<
+            {
+                let mem = { $n };
+                mem
+            },
+        >()
+    };
+    ($n:expr; < $lim:expr) => {
+        $crate::primes_lt::<
             $n,
             {
-                (if $lim <= 1 {
-                    $lim
-                } else {
-                    let mut x0 =
-                        ::core::primitive::u64::pow(2, ::core::primitive::u64::ilog2($lim) / 2 + 1);
-                    let mut x1 = (x0 + $lim / x0) / 2;
-                    while x1 < x0 {
-                        x0 = x1;
-                        x1 = (x0 + $lim / x0) / 2;
-                    }
-                    x0
-                }) as ::core::primitive::usize
-                    + 1
+                let mem = { $lim };
+                $crate::ඞ_const_primes_isqrt!(mem) as ::core::primitive::usize + 1
             },
         >($lim)
     };
-    ($n:literal < $lim:literal) => {
-        $crate::primes_lt::<
+    ($n:expr; >= $lim:expr) => {
+        $crate::primes_geq::<
             $n,
             {
-                (if $lim <= 1 {
-                    $lim
-                } else {
-                    let mut x0 =
-                        ::core::primitive::u64::pow(2, ::core::primitive::u64::ilog2($lim) / 2 + 1);
-                    let mut x1 = (x0 + $lim / x0) / 2;
-                    while x1 < x0 {
-                        x0 = x1;
-                        x1 = (x0 + $lim / x0) / 2;
-                    }
-                    x0
-                }) as ::core::primitive::usize
-                    + 1
+                let mem = { $lim };
+                $crate::ඞ_const_primes_isqrt!(mem) as ::core::primitive::usize + 1
             },
         >($lim)
     };
diff --git a/src/lib.rs b/src/lib.rs
index 64430a3..e6ab20b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -63,11 +63,11 @@
 //! # Ok::<(), Error>(())
 //! ```
 //! If you do not wish to compute the required sieve size yourself,
-//! you can use the provided macro [`primes_where!`]:
+//! you can use the provided macro [`const_primes!`]:
 //! ```
-//! # use const_primes::{primes_where, Result, Error};
-//! const PRIMES_OVER_100: Result<3> = primes_where!(3 >= 100);
-//! const PRIMES_UNDER_100: Result<3> = primes_where!(3 < 100);
+//! # use const_primes::{const_primes, Result, Error};
+//! const PRIMES_OVER_100: Result<3> = const_primes!(3; >= 100);
+//! const PRIMES_UNDER_100: Result<3> = const_primes!(3; < 100);
 //!
 //! assert_eq!(PRIMES_OVER_100?, [101, 103, 107]);
 //! assert_eq!(PRIMES_UNDER_100?, [83, 89, 97]);

From ed92250e418498c62170a68f4ea19896605175bd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 08:15:12 +0200
Subject: [PATCH 164/212] Only compute MEM^2 once

---
 src/generation.rs | 28 +++++++++++-----------------
 1 file changed, 11 insertions(+), 17 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 0d5aba9..9369fc5 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -172,25 +172,22 @@ pub const fn primes_lt<const N: usize, const MEM: usize>(mut upper_limit: u64) -
     const {
         assert!(N > 0, "`N` must be at least 1");
         assert!(MEM >= N, "`MEM` must be at least as large as `N`");
+    }
+    let mem64 = const {
         let mem64 = MEM as u64;
         assert!(
             mem64.checked_mul(mem64).is_some(),
             "`MEM`^2 must fit in a u64"
         );
-    }
+        mem64
+    };
 
     if upper_limit <= 2 {
         return Err(Error::TooSmallLimit(upper_limit));
     }
 
-    let mem64 = MEM as u64;
-    match (mem64).checked_mul(mem64) {
-        Some(prod) => {
-            if upper_limit > prod {
-                return Err(Error::TooLargeLimit(upper_limit, MEM));
-            }
-        }
-        None => return Err(Error::MEMSquaredOverflow(MEM)),
+    if upper_limit > mem64 * mem64 {
+        return Err(Error::TooLargeLimit(upper_limit, MEM));
     }
 
     let mut primes: [u64; N] = [0; N];
@@ -346,19 +343,16 @@ pub const fn primes_geq<const N: usize, const MEM: usize>(lower_limit: u64) -> R
     const {
         assert!(N > 0, "`N` must be at least 1");
         assert!(MEM >= N, "`MEM` must be at least as large as `N`");
-        let mem64 = MEM as u64;
-        assert!(
-            mem64.checked_mul(mem64).is_some(),
-            "`MEM`^2 must fit in a u64"
-        );
     }
+    let (mem64, mem_sqr) = const {
+        let mem64 = MEM as u64;
+        let Some(mem_sqr) = mem64.checked_mul(mem64) else {panic!("`MEM`^2 must fit in a `u64`")};
+        (mem64, mem_sqr)
+    };
 
     // There are no primes smaller than 2, so we will always start looking at 2.
     let new_lower_limit = if lower_limit >= 2 { lower_limit } else { 2 };
 
-    let mem64 = MEM as u64;
-    let mem_sqr = mem64 * mem64;
-
     if new_lower_limit >= mem_sqr {
         return Err(Error::TooLargeLimit(lower_limit, MEM));
     }

From 6d71375a6d48cffc457a8be58fc710335464f9c5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 08:20:39 +0200
Subject: [PATCH 165/212] rustfmt let else

---
 src/generation.rs | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/generation.rs b/src/generation.rs
index 9369fc5..3275f7f 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -346,7 +346,9 @@ pub const fn primes_geq<const N: usize, const MEM: usize>(lower_limit: u64) -> R
     }
     let (mem64, mem_sqr) = const {
         let mem64 = MEM as u64;
-        let Some(mem_sqr) = mem64.checked_mul(mem64) else {panic!("`MEM`^2 must fit in a `u64`")};
+        let Some(mem_sqr) = mem64.checked_mul(mem64) else {
+            panic!("`MEM`^2 must fit in a `u64`")
+        };
         (mem64, mem_sqr)
     };
 

From 0587e03ae16bae81d6452287402ec2cf1e6ba4f0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 08:21:00 +0200
Subject: [PATCH 166/212] call index in index

---
 src/wrapper.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/wrapper.rs b/src/wrapper.rs
index b99fb5a..a73cc6a 100644
--- a/src/wrapper.rs
+++ b/src/wrapper.rs
@@ -319,7 +319,7 @@ where
     type Output = I::Output;
     #[inline]
     fn index(&self, index: I) -> &Self::Output {
-        &self.primes[index]
+        &self.primes.index(index)
     }
 }
 

From f96035c4f60ca3f01c1c03430f99d3f3e9933504 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 08:21:26 +0200
Subject: [PATCH 167/212] Impl all indexing operations with one generic impl
 instead of many expansions of a macro

---
 src/array_section.rs | 33 ++++++++-------------------------
 1 file changed, 8 insertions(+), 25 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index 724c4b3..2616fc1 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -2,7 +2,7 @@ use core::{
     cmp::Ordering,
     hash::{Hash, Hasher},
     iter::FusedIterator,
-    ops::{Index, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
+    ops::Range,
 };
 
 /// An array where only a section of the data may be viewed,
@@ -217,34 +217,17 @@ impl<const N: usize, T> AsRef<[T]> for ArraySection<T, N> {
     }
 }
 
-// region: Index impls
-
-impl<const N: usize, T> Index<usize> for ArraySection<T, N> {
-    type Output = T;
+impl<const N: usize, T, I> core::ops::Index<I> for ArraySection<T, N>
+where
+    I: core::slice::SliceIndex<[T]>,
+{
+    type Output = I::Output;
     #[inline]
-    fn index(&self, index: usize) -> &Self::Output {
-        self.as_slice().index(index)
+    fn index(&self, index: I) -> &Self::Output {
+        &self.as_slice().index(index)
     }
 }
 
-macro_rules! impl_index_range {
-    ($($t:ty),+) => {
-        $(
-            impl<const N: ::core::primitive::usize, T> ::core::ops::Index<$t> for $crate::array_section::ArraySection<T, N> {
-                type Output = [T];
-                #[inline]
-                fn index(&self, index: $t) -> &Self::Output {
-                    ::core::ops::Index::index(self.as_slice(), index)
-                }
-            }
-        )+
-    };
-}
-
-impl_index_range! {Range<usize>, RangeFrom<usize>, RangeFull, RangeTo<usize>, RangeInclusive<usize>, RangeToInclusive<usize>}
-
-// endregion: Index impls
-
 // region: PartialEq impls
 
 /// Only compares the sections, and not the full arrays.

From 8bce044d18d47528eb4c7fa3c49df56a7712aff1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 08:22:41 +0200
Subject: [PATCH 168/212] use statement, and remove where

---
 src/array_section.rs | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index 2616fc1..3b0341d 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -2,7 +2,8 @@ use core::{
     cmp::Ordering,
     hash::{Hash, Hasher},
     iter::FusedIterator,
-    ops::Range,
+    ops::{Index, Range},
+    slice::SliceIndex,
 };
 
 /// An array where only a section of the data may be viewed,
@@ -217,10 +218,7 @@ impl<const N: usize, T> AsRef<[T]> for ArraySection<T, N> {
     }
 }
 
-impl<const N: usize, T, I> core::ops::Index<I> for ArraySection<T, N>
-where
-    I: core::slice::SliceIndex<[T]>,
-{
+impl<const N: usize, T, I: SliceIndex<[T]>> Index<I> for ArraySection<T, N> {
     type Output = I::Output;
     #[inline]
     fn index(&self, index: I) -> &Self::Output {

From 4b3f21b98861b7bc9b1f7788b44e8e27e64f95fd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 08:26:15 +0200
Subject: [PATCH 169/212] inline more trivial things

---
 src/array_section.rs | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index 3b0341d..0a841a1 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -202,6 +202,7 @@ impl<const N: usize, T> TryFrom<ArraySection<T, N>> for [T; N] {
 // endregion: TryFrom impls
 
 impl<const N: usize, T> From<[T; N]> for ArraySection<T, N> {
+    #[inline]
     fn from(value: [T; N]) -> Self {
         Self {
             start: 0,
@@ -228,7 +229,6 @@ impl<const N: usize, T, I: SliceIndex<[T]>> Index<I> for ArraySection<T, N> {
 
 // region: PartialEq impls
 
-/// Only compares the sections, and not the full arrays.
 impl<const N: usize, const M: usize, T, U> PartialEq<ArraySection<T, N>> for ArraySection<U, M>
 where
     [U]: PartialEq<[T]>,
@@ -243,8 +243,7 @@ impl<const N: usize, T, U> PartialEq<[U]> for ArraySection<T, N>
 where
     U: PartialEq<T>,
 {
-    /// This method tests for `self` and `other` values to be equal, and is used by `==`.  
-    /// Only compares the *visible* part of `self` against `other`.
+    #[inline]
     fn eq(&self, other: &[U]) -> bool {
         other == self.as_slice()
     }
@@ -254,8 +253,7 @@ impl<const N: usize, T, U> PartialEq<ArraySection<T, N>> for [U]
 where
     U: PartialEq<T>,
 {
-    /// This method tests for `self` and `other` values to be equal, and is used by `==`.  
-    /// Only compares the *visible* part of `other` against `self`.
+    #[inline]
     fn eq(&self, other: &ArraySection<T, N>) -> bool {
         self == other.as_slice()
     }
@@ -265,6 +263,7 @@ impl<const N: usize, const M: usize, T, U> PartialEq<[T; N]> for ArraySection<U,
 where
     [U]: PartialEq<[T]>,
 {
+    #[inline]
     fn eq(&self, other: &[T; N]) -> bool {
         self.as_slice().eq(other.as_slice())
     }
@@ -274,6 +273,7 @@ impl<const N: usize, const M: usize, T, U> PartialEq<ArraySection<U, M>> for [T;
 where
     [T]: PartialEq<[U]>,
 {
+    #[inline]
     fn eq(&self, other: &ArraySection<U, M>) -> bool {
         self.as_slice().eq(other.as_slice())
     }

From 4d99fc01e92970839cc7b73362d05cff85b47072 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 08:27:48 +0200
Subject: [PATCH 170/212] Clearer variable name in example

---
 src/array_section.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index 0a841a1..ac95b63 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -13,9 +13,9 @@ use core::{
 /// ```
 /// # use const_primes::array_section::ArraySection;
 /// //                                                     v  v
-/// const OT: ArraySection<i32, 4> = ArraySection::new([0, 1, 2, 0], 1..3);
-/// assert_eq![OT[0], 1];
-/// assert_eq![OT[1], 2];
+/// const AS: ArraySection<i32, 4> = ArraySection::new([0, 1, 2, 0], 1..3);
+/// assert_eq![AS[0], 1];
+/// assert_eq![AS[1], 2];
 /// ```
 ///
 /// The other data is not considered in comparisons, ordering or hashing:

From 250fe929af885fb70e42d65250fa1675b29e33fe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 08:45:59 +0200
Subject: [PATCH 171/212] impl From<TryFromArraySectionError> for ArraySection

---
 src/array_section.rs | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/src/array_section.rs b/src/array_section.rs
index ac95b63..1198b7a 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -172,9 +172,17 @@ impl<const N: usize, T> ArraySection<T, N> {
 
 // region: TryFrom impls
 
+/// Returned by `TryFrom<ArraySection<T, N>> for [T; N]` if the [`ArraySection`] was not fully valid.
+/// Contains the original [`ArraySection`], which can be retrieved via the [`array_section`](TryFromArraySectionError::array_section) function.
 #[derive(Debug, Clone, Copy)]
 pub struct TryFromArraySectionError<T, const N: usize>(ArraySection<T, N>);
 
+impl<T, const N: usize> TryFromArraySectionError<T, N> {
+    fn array_section(self) -> ArraySection<T, N> {
+        self.0
+    }
+}
+
 impl<T, const N: usize> core::fmt::Display for TryFromArraySectionError<T, N> {
     #[inline]
     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
@@ -185,6 +193,12 @@ impl<T, const N: usize> core::fmt::Display for TryFromArraySectionError<T, N> {
 #[cfg(feature = "std")]
 impl<T: core::fmt::Debug, const N: usize> std::error::Error for TryFromArraySectionError<T, N> {}
 
+impl<T, const N: usize> From<TryFromArraySectionError<T, N>> for ArraySection<T, N> {
+    fn from(value: TryFromArraySectionError<T, N>) -> Self {
+        value.0
+    }
+}
+
 /// Converts the `ArraySection` into an array if the section is actually the entire array.
 impl<const N: usize, T> TryFrom<ArraySection<T, N>> for [T; N] {
     type Error = TryFromArraySectionError<T, N>;

From 8e9c2ceea61138f542b573b019cb604a116d3680 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 08:46:34 +0200
Subject: [PATCH 172/212] it must be pub

---
 src/array_section.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index 1198b7a..900bdea 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -178,7 +178,7 @@ impl<const N: usize, T> ArraySection<T, N> {
 pub struct TryFromArraySectionError<T, const N: usize>(ArraySection<T, N>);
 
 impl<T, const N: usize> TryFromArraySectionError<T, N> {
-    fn array_section(self) -> ArraySection<T, N> {
+    pub fn array_section(self) -> ArraySection<T, N> {
         self.0
     }
 }

From 345f637e167b29a2243c5efb580e15daee82d321 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 08:47:04 +0200
Subject: [PATCH 173/212] Add docstring to array_section

---
 src/array_section.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/array_section.rs b/src/array_section.rs
index 900bdea..e68e02c 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -178,6 +178,7 @@ impl<const N: usize, T> ArraySection<T, N> {
 pub struct TryFromArraySectionError<T, const N: usize>(ArraySection<T, N>);
 
 impl<T, const N: usize> TryFromArraySectionError<T, N> {
+    /// Returns the original [`ArraySection`].
     pub fn array_section(self) -> ArraySection<T, N> {
         self.0
     }

From 4ef0691543c655c151a41720535dd3de21dd5574 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 08:48:16 +0200
Subject: [PATCH 174/212] clarity in docstring

---
 src/array_section.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index e68e02c..b199606 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -172,7 +172,7 @@ impl<const N: usize, T> ArraySection<T, N> {
 
 // region: TryFrom impls
 
-/// Returned by `TryFrom<ArraySection<T, N>> for [T; N]` if the [`ArraySection`] was not fully valid.
+/// Returned by `TryFrom<ArraySection<T, N>> for [T; N]` if the [`ArraySection`] was not the full array.
 /// Contains the original [`ArraySection`], which can be retrieved via the [`array_section`](TryFromArraySectionError::array_section) function.
 #[derive(Debug, Clone, Copy)]
 pub struct TryFromArraySectionError<T, const N: usize>(ArraySection<T, N>);

From 97ea44498487b9c9977c2a9b1406ef99680d3cbe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 08:48:55 +0200
Subject: [PATCH 175/212] Remove double doc-links

---
 src/array_section.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index b199606..0effc41 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -173,7 +173,7 @@ impl<const N: usize, T> ArraySection<T, N> {
 // region: TryFrom impls
 
 /// Returned by `TryFrom<ArraySection<T, N>> for [T; N]` if the [`ArraySection`] was not the full array.
-/// Contains the original [`ArraySection`], which can be retrieved via the [`array_section`](TryFromArraySectionError::array_section) function.
+/// Contains the original `ArraySection`, which can be retrieved via the [`array_section`](TryFromArraySectionError::array_section) function.
 #[derive(Debug, Clone, Copy)]
 pub struct TryFromArraySectionError<T, const N: usize>(ArraySection<T, N>);
 

From 0064cdba6da8ab04f2b115422949fc92c1c14ccd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 08:53:05 +0200
Subject: [PATCH 176/212] impl into_full_array_const for ArraySection

---
 src/array_section.rs | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/src/array_section.rs b/src/array_section.rs
index 0effc41..7afa4b7 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -124,6 +124,9 @@ impl<const N: usize, T> ArraySection<T, N> {
     }
 
     /// Converts `self` into the full underlying array.
+    ///
+    /// If you wish to use this in const context the destructor of `T` must be trivial,
+    /// use [`into_full_array_const`](ArraySection::into_full_array_const)
     #[inline]
     pub fn into_full_array(self) -> [T; N] {
         self.array
@@ -170,6 +173,13 @@ impl<const N: usize, T> ArraySection<T, N> {
     }
 }
 
+impl<T: Copy, const N: usize> ArraySection<T, N> {
+    /// Converts `self` into the full underlying array.
+    pub const fn into_full_array_const(self) -> [T; N] {
+        self.array
+    }
+}
+
 // region: TryFrom impls
 
 /// Returned by `TryFrom<ArraySection<T, N>> for [T; N]` if the [`ArraySection`] was not the full array.

From 6f6aad5e89fe6e64bd98d432c9c095db4e0151f4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 08:57:24 +0200
Subject: [PATCH 177/212] rename ArraySection::new range argument

---
 src/array_section.rs | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index 7afa4b7..a7c3cd7 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -72,13 +72,13 @@ impl<const N: usize, T> ArraySection<T, N> {
     ///
     /// Panics if the range of indices is out of bounds of the array.
     #[inline]
-    pub const fn new(array: [T; N], sub_range: Range<usize>) -> Self {
+    pub const fn new(array: [T; N], section: Range<usize>) -> Self {
         assert!(
-            sub_range.start < N && sub_range.end <= N,
+            section.start < N && section.end <= N,
             "the sub-range must be in bounds"
         );
 
-        if sub_range.start > sub_range.end {
+        if section.start > section.end {
             Self {
                 start: 0,
                 end: 0,
@@ -86,8 +86,8 @@ impl<const N: usize, T> ArraySection<T, N> {
             }
         } else {
             Self {
-                start: sub_range.start,
-                end: sub_range.end,
+                start: section.start,
+                end: section.end,
                 array,
             }
         }

From ad524303ec780eb86d502c550bc9385b20ca5a3d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 08:59:57 +0200
Subject: [PATCH 178/212] Simplify doctest

---
 src/generation.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/generation.rs b/src/generation.rs
index 3275f7f..82e4a24 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -326,7 +326,7 @@ macro_rules! const_primes {
 /// ```
 /// # use const_primes::{primes_geq, Result, Error};
 /// const PRIMES: Result<3> = primes_geq::<3, 3>(5);
-/// assert_eq!(PRIMES?.as_slice(), &[5, 7]);
+/// assert_eq!(PRIMES?, [5, 7]);
 /// # Ok::<(), Error>(())
 /// ```
 ///

From 0ee8c807f50c752623d9d28035386528fdc7206b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 09:04:47 +0200
Subject: [PATCH 179/212] Clarify what the result type is in doctests

---
 src/generation.rs | 36 ++++++++++++++++++------------------
 src/lib.rs        | 10 +++++-----
 2 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 82e4a24..23c9baa 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -130,18 +130,18 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 ///
 /// Basic usage:
 /// ```
-/// # use const_primes::generation::{Result, primes_lt, Error};
+/// # use const_primes::generation::{primes_lt, Error};
 /// // Sieving up to 100 means the sieve needs to be of size sqrt(100) = 10.
 /// // However, we only save the 4 largest primes in the constant.
-/// const PRIMES: Result<4> = primes_lt::<4, 10>(100);
+/// const PRIMES: const_primes::Result<4> = primes_lt::<4, 10>(100);
 /// assert_eq!(PRIMES?, [79, 83, 89, 97]);
 /// # Ok::<(), Error>(())
 /// ```
 /// Compute larger primes without starting from zero:
 /// ```
-/// # use const_primes::generation::{Result, primes_lt, Error};
+/// # use const_primes::generation::{primes_lt, Error};
 /// # #[allow(long_running_const_eval)]
-/// const BIG_PRIMES: Result<3> = primes_lt::<3, 70_711>(5_000_000_030);
+/// const BIG_PRIMES: const_primes::Result<3> = primes_lt::<3, 70_711>(5_000_000_030);
 ///
 /// assert_eq!(BIG_PRIMES?, [4_999_999_903, 4_999_999_937, 5_000_000_029]);
 /// # Ok::<(), Error>(())
@@ -152,8 +152,8 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// Due to limitations on const evaluation this will still
 /// take up the full `N` numbers worth of memory.
 /// ```
-/// # use const_primes::generation::{Result, primes_lt, Error};
-/// const PRIMES: Result<9> = primes_lt::<9, 9>(10);
+/// # use const_primes::generation::{primes_lt, Error};
+/// const PRIMES: const_primes::Result<9> = primes_lt::<9, 9>(10);
 /// assert_eq!(PRIMES?, [2, 3, 5, 7]);
 /// # Ok::<(), Error>(())
 /// ```
@@ -161,9 +161,9 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 ///
 /// Returns an error if `upper_limit` is larger than `MEM`^2 or if `upper_limit` is smaller than or equal to 2.
 /// ```
-/// # use const_primes::generation::{primes_lt, Result};
-/// const TOO_LARGE_LIMIT: Result<3> = primes_lt::<3, 5>(26);
-/// const TOO_SMALL_LIMIT: Result<1> = primes_lt::<1, 1>(1);
+/// # use const_primes::generation::primes_lt;
+/// const TOO_LARGE_LIMIT: const_primes::Result<3> = primes_lt::<3, 5>(26);
+/// const TOO_SMALL_LIMIT: const_primes::Result<1> = primes_lt::<1, 1>(1);
 /// assert!(TOO_LARGE_LIMIT.is_err());
 /// assert!(TOO_SMALL_LIMIT.is_err());
 /// ```
@@ -250,11 +250,11 @@ macro_rules! ඞ_const_primes_isqrt {
 /// # Example
 ///
 /// ```
-/// # use const_primes::{Result, const_primes, Error};
+/// # use const_primes::{const_primes, Error};
 /// const PRIMES: [u32; 3] = const_primes!();
 /// const LIMIT: u64 = 5_000_000_031;
-/// const PRIMES_GEQ: Result<3> = const_primes!(3; >= LIMIT);
-/// const PRIMES_LT: Result<3> = const_primes!(3; < LIMIT);
+/// const PRIMES_GEQ: const_primes::Result<3> = const_primes!(3; >= LIMIT);
+/// const PRIMES_LT: const_primes::Result<3> = const_primes!(3; < LIMIT);
 /// let primes = const_primes!(3);
 ///
 /// assert_eq!(primes, PRIMES);
@@ -309,23 +309,23 @@ macro_rules! const_primes {
 ///
 /// Basic usage:
 /// ```
-/// # use const_primes::{primes_geq, Result, Error};
-/// const PRIMES: Result<5> = primes_geq::<5, 5>(10);
+/// # use const_primes::{primes_geq, Error};
+/// const PRIMES: const_primes::Result<5> = primes_geq::<5, 5>(10);
 /// assert_eq!(PRIMES?, [11, 13, 17, 19, 23]);
 /// # Ok::<(), Error>(())
 /// ```
 /// Compute larger primes without starting from zero:
 /// ```
-/// # use const_primes::{primes_geq, Result, Error};
+/// # use const_primes::{primes_geq, Error};
 /// # #[allow(long_running_const_eval)]
-/// const P: Result<3> = primes_geq::<3, 71_000>(5_000_000_030);
+/// const P: const_primes::Result<3> = primes_geq::<3, 71_000>(5_000_000_030);
 /// assert_eq!(P?, [5_000_000_039, 5_000_000_059, 5_000_000_063]);
 /// # Ok::<(), Error>(())
 /// ```
 /// Only primes smaller than `MEM^2` will be generated:
 /// ```
-/// # use const_primes::{primes_geq, Result, Error};
-/// const PRIMES: Result<3> = primes_geq::<3, 3>(5);
+/// # use const_primes::{primes_geq, Error};
+/// const PRIMES: const_primes::Result<3> = primes_geq::<3, 3>(5);
 /// assert_eq!(PRIMES?, [5, 7]);
 /// # Ok::<(), Error>(())
 /// ```
diff --git a/src/lib.rs b/src/lib.rs
index e6ab20b..a793152 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -55,9 +55,9 @@
 //! but doesn't need to store the entire sieve in the binary.
 //! ```
 //! # use const_primes::Error;
-//! use const_primes::{primes_geq, Result};
+//! use const_primes::primes_geq;
 //! // ceil(isqrt(5_000_000_031)) = 70_711
-//! const P_GEQ: Result<3> = primes_geq::<3, 70_711>(5_000_000_031);
+//! const P_GEQ: const_primes::Result<3> = primes_geq::<3, 70_711>(5_000_000_031);
 //!
 //! assert_eq!(P_GEQ?, [5_000_000_039, 5_000_000_059, 5_000_000_063]);
 //! # Ok::<(), Error>(())
@@ -65,9 +65,9 @@
 //! If you do not wish to compute the required sieve size yourself,
 //! you can use the provided macro [`const_primes!`]:
 //! ```
-//! # use const_primes::{const_primes, Result, Error};
-//! const PRIMES_OVER_100: Result<3> = const_primes!(3; >= 100);
-//! const PRIMES_UNDER_100: Result<3> = const_primes!(3; < 100);
+//! # use const_primes::{const_primes, Error};
+//! const PRIMES_OVER_100: const_primes::Result<3> = const_primes!(3; >= 100);
+//! const PRIMES_UNDER_100: const_primes::Result<3> = const_primes!(3; < 100);
 //!
 //! assert_eq!(PRIMES_OVER_100?, [101, 103, 107]);
 //! assert_eq!(PRIMES_UNDER_100?, [83, 89, 97]);

From bfcd802acc11cccebdc9ce9b1743da11329a4a67 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 09:05:43 +0200
Subject: [PATCH 180/212] remove i

---
 src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/lib.rs b/src/lib.rs
index a793152..d136def 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -56,7 +56,7 @@
 //! ```
 //! # use const_primes::Error;
 //! use const_primes::primes_geq;
-//! // ceil(isqrt(5_000_000_031)) = 70_711
+//! // ceil(sqrt(5_000_000_031)) = 70_711
 //! const P_GEQ: const_primes::Result<3> = primes_geq::<3, 70_711>(5_000_000_031);
 //!
 //! assert_eq!(P_GEQ?, [5_000_000_039, 5_000_000_059, 5_000_000_063]);

From 48ab2316b909229416ae3baf94dcbc97c06a8643 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 09:06:35 +0200
Subject: [PATCH 181/212] 31 -> 63

---
 src/lib.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/lib.rs b/src/lib.rs
index d136def..cb6fa08 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -56,7 +56,7 @@
 //! ```
 //! # use const_primes::Error;
 //! use const_primes::primes_geq;
-//! // ceil(sqrt(5_000_000_031)) = 70_711
+//! // ceil(sqrt(5_000_000_063)) = 70_711
 //! const P_GEQ: const_primes::Result<3> = primes_geq::<3, 70_711>(5_000_000_031);
 //!
 //! assert_eq!(P_GEQ?, [5_000_000_039, 5_000_000_059, 5_000_000_063]);

From 1b340581dbbb00e56b3427a371708869a1b86112 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 09:11:12 +0200
Subject: [PATCH 182/212] Simplify module structure

---
 src/generation.rs | 8 ++++----
 src/lib.rs        | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 23c9baa..f792755 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -130,7 +130,7 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 ///
 /// Basic usage:
 /// ```
-/// # use const_primes::generation::{primes_lt, Error};
+/// # use const_primes::{primes_lt, Error};
 /// // Sieving up to 100 means the sieve needs to be of size sqrt(100) = 10.
 /// // However, we only save the 4 largest primes in the constant.
 /// const PRIMES: const_primes::Result<4> = primes_lt::<4, 10>(100);
@@ -139,7 +139,7 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// ```
 /// Compute larger primes without starting from zero:
 /// ```
-/// # use const_primes::generation::{primes_lt, Error};
+/// # use const_primes::{primes_lt, Error};
 /// # #[allow(long_running_const_eval)]
 /// const BIG_PRIMES: const_primes::Result<3> = primes_lt::<3, 70_711>(5_000_000_030);
 ///
@@ -152,7 +152,7 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// Due to limitations on const evaluation this will still
 /// take up the full `N` numbers worth of memory.
 /// ```
-/// # use const_primes::generation::{primes_lt, Error};
+/// # use const_primes::{primes_lt, Error};
 /// const PRIMES: const_primes::Result<9> = primes_lt::<9, 9>(10);
 /// assert_eq!(PRIMES?, [2, 3, 5, 7]);
 /// # Ok::<(), Error>(())
@@ -161,7 +161,7 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 ///
 /// Returns an error if `upper_limit` is larger than `MEM`^2 or if `upper_limit` is smaller than or equal to 2.
 /// ```
-/// # use const_primes::generation::primes_lt;
+/// # use const_primes::primes_lt;
 /// const TOO_LARGE_LIMIT: const_primes::Result<3> = primes_lt::<3, 5>(26);
 /// const TOO_SMALL_LIMIT: const_primes::Result<1> = primes_lt::<1, 1>(1);
 /// assert!(TOO_LARGE_LIMIT.is_err());
diff --git a/src/lib.rs b/src/lib.rs
index cb6fa08..46322aa 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -118,7 +118,7 @@
 type Underlying = u32;
 
 pub mod array_section;
-pub mod generation;
+mod generation;
 mod imath;
 mod miller_rabin;
 mod other_prime;

From deebe76788e69afffe81b439d76053ab5e4341ca Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 09:16:56 +0200
Subject: [PATCH 183/212] Remove PrimesArray

---
 src/generation.rs | 303 +---------------------------------------------
 src/lib.rs        |   2 +-
 2 files changed, 2 insertions(+), 303 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index f792755..3478d1e 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -1,7 +1,4 @@
-use core::{
-    fmt,
-    ops::{Index, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
-};
+use core::fmt;
 
 use crate::{array_section::ArraySection, sieve, sieving::sieve_segment, Underlying};
 
@@ -398,304 +395,6 @@ pub const fn primes_geq<const N: usize, const MEM: usize>(lower_limit: u64) -> R
     Ok(ArraySection::new(primes, 0..N))
 }
 
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-/// An array where potentially only a section of it contains valid prime numbers.
-pub enum PrimesArray<const N: usize> {
-    /// The entire allocated array contains prime numbers
-    Full([u64; N]),
-    /// Only a section of the allocated array contains prime numbers.
-    Partial(ArraySection<u64, N>),
-}
-
-impl<const N: usize> PrimesArray<N> {
-    /// Returns a slice of all the generated prime numbers.
-    #[inline]
-    pub const fn as_slice(&self) -> &[u64] {
-        match self {
-            Self::Full(ref arr) => arr.as_slice(),
-            Self::Partial(ref arr_sec) => arr_sec.as_slice(),
-        }
-    }
-
-    /// Returns the underlying array if it is full of valid primes.
-    #[inline]
-    pub const fn full(self) -> Option<[u64; N]> {
-        match self {
-            Self::Full(arr) => Some(arr),
-            Self::Partial(_) => None,
-        }
-    }
-
-    /// Returns a reference to the underlying array if it is full of valid primes.
-    #[inline]
-    pub const fn as_full(&self) -> Option<&[u64; N]> {
-        match self {
-            Self::Full(ref arr) => Some(arr),
-            Self::Partial(_) => None,
-        }
-    }
-
-    /// Returns the primes as a (maybe fully populated) [`ArraySection`].
-    #[inline]
-    pub const fn into_array_section(self) -> ArraySection<u64, N> {
-        match self {
-            Self::Partial(arr_sec) => arr_sec,
-            Self::Full(arr) => {
-                let l = arr.len();
-                ArraySection::new(arr, 0..l)
-            }
-        }
-    }
-
-    /// Returns an [`ArraySection`] if not all of the elements
-    /// in the underlying array could be populated.
-    #[inline]
-    pub const fn partial(self) -> Option<ArraySection<u64, N>> {
-        match self {
-            Self::Partial(arr_sec) => Some(arr_sec),
-            Self::Full(_) => None,
-        }
-    }
-
-    /// Returns a reference to the [`ArraySection`] if not all elements of the underlying array
-    /// could be populated.
-    #[inline]
-    pub const fn as_partial(&self) -> Option<&ArraySection<u64, N>> {
-        match self {
-            Self::Partial(ref arr_sec) => Some(arr_sec),
-            Self::Full(_) => None,
-        }
-    }
-
-    /// Returns whether all the elements in the underlying array could be computed.
-    #[inline]
-    pub const fn is_full(&self) -> bool {
-        matches!(self, Self::Full(_))
-    }
-
-    /// Returns whether only a subset of the underlying array could be computed.
-    #[inline]
-    pub const fn is_partial(&self) -> bool {
-        matches!(self, Self::Partial(_))
-    }
-
-    /// Returns the length of the populated part of the array.
-    #[inline]
-    pub const fn len(&self) -> usize {
-        self.as_slice().len()
-    }
-
-    /// Returns wether the populated part of the array is empty.
-    #[inline]
-    pub const fn is_empty(&self) -> bool {
-        self.len() == 0
-    }
-
-    pub fn iter(&self) -> PrimesArrayIter<'_> {
-        PrimesArrayIter::new(self.as_slice().iter())
-    }
-}
-
-impl<const N: usize, T> PartialEq<[T; N]> for PrimesArray<N>
-where
-    u64: PartialEq<T>,
-{
-    fn eq(&self, other: &[T; N]) -> bool {
-        self.as_slice().eq(other.as_slice())
-    }
-}
-
-impl<const N: usize, T> PartialEq<[T]> for PrimesArray<N>
-where
-    u64: PartialEq<T>,
-{
-    fn eq(&self, other: &[T]) -> bool {
-        self.as_slice().eq(other)
-    }
-}
-
-impl<const N: usize, T: PartialEq<u64>> PartialEq<PrimesArray<N>> for [T] {
-    fn eq(&self, other: &PrimesArray<N>) -> bool {
-        self.eq(other.as_slice())
-    }
-}
-
-impl<const N: usize, T: PartialEq<u64>> PartialEq<PrimesArray<N>> for [T; N] {
-    fn eq(&self, other: &PrimesArray<N>) -> bool {
-        self.eq(other.as_slice())
-    }
-}
-
-impl<const N: usize> From<PrimesArray<N>> for ArraySection<u64, N> {
-    #[inline]
-    fn from(value: PrimesArray<N>) -> Self {
-        value.into_array_section()
-    }
-}
-
-impl<const N: usize> AsRef<[u64]> for PrimesArray<N> {
-    #[inline]
-    fn as_ref(&self) -> &[u64] {
-        self.as_slice()
-    }
-}
-
-macro_rules! impl_index_range {
-    ($($n:ty),*) => {
-        $(
-            impl<const N: usize> Index<$n> for PrimesArray<N> {
-                type Output = [u64];
-                fn index(&self, index: $n) -> &Self::Output {
-                    self.as_slice().index(index)
-                }
-            }
-        )*
-    };
-}
-
-impl_index_range! {Range<usize>, RangeTo<usize>, RangeFrom<usize>, RangeToInclusive<usize>, RangeFull, RangeInclusive<usize>}
-
-// region: Iterator impls
-
-impl<const N: usize> IntoIterator for PrimesArray<N> {
-    type IntoIter = PrimesArrayIntoIter<N>;
-    type Item = u64;
-    fn into_iter(self) -> Self::IntoIter {
-        PrimesArrayIntoIter::new(self)
-    }
-}
-
-impl<'a, const N: usize> IntoIterator for &'a PrimesArray<N> {
-    type IntoIter = PrimesArrayIter<'a>;
-    type Item = &'a u64;
-    fn into_iter(self) -> Self::IntoIter {
-        self.iter()
-    }
-}
-
-pub use primes_array_iter::PrimesArrayIter;
-mod primes_array_iter {
-    use core::iter::FusedIterator;
-
-    #[derive(Debug, Clone)]
-    pub struct PrimesArrayIter<'a>(core::slice::Iter<'a, u64>);
-
-    impl<'a> PrimesArrayIter<'a> {
-        #[inline]
-        pub(crate) const fn new(iter: core::slice::Iter<'a, u64>) -> Self {
-            Self(iter)
-        }
-    }
-
-    impl<'a> Iterator for PrimesArrayIter<'a> {
-        type Item = &'a u64;
-
-        #[inline]
-        fn next(&mut self) -> Option<Self::Item> {
-            self.0.next()
-        }
-
-        #[inline]
-        fn size_hint(&self) -> (usize, Option<usize>) {
-            self.0.size_hint()
-        }
-
-        #[inline]
-        fn nth(&mut self, n: usize) -> Option<Self::Item> {
-            self.0.nth(n)
-        }
-
-        #[inline]
-        fn count(self) -> usize {
-            self.0.count()
-        }
-
-        #[inline]
-        fn last(self) -> Option<Self::Item> {
-            self.0.last()
-        }
-    }
-
-    impl<'a> DoubleEndedIterator for PrimesArrayIter<'a> {
-        #[inline]
-        fn next_back(&mut self) -> Option<Self::Item> {
-            self.0.next_back()
-        }
-    }
-
-    impl<'a> ExactSizeIterator for PrimesArrayIter<'a> {
-        #[inline]
-        fn len(&self) -> usize {
-            self.0.len()
-        }
-    }
-
-    impl<'a> FusedIterator for PrimesArrayIter<'a> {}
-}
-
-pub use primes_array_into_iter::PrimesArrayIntoIter;
-mod primes_array_into_iter {
-    use core::iter::FusedIterator;
-
-    use crate::{array_section::ArraySectionIntoIter, PrimesArray};
-
-    pub struct PrimesArrayIntoIter<const N: usize>(ArraySectionIntoIter<u64, N>);
-
-    impl<const N: usize> PrimesArrayIntoIter<N> {
-        #[inline]
-        pub(crate) fn new(primes_array: PrimesArray<N>) -> Self {
-            Self(primes_array.into_array_section().into_iter())
-        }
-    }
-
-    impl<const N: usize> Iterator for PrimesArrayIntoIter<N> {
-        type Item = u64;
-
-        #[inline]
-        fn next(&mut self) -> Option<Self::Item> {
-            self.0.next()
-        }
-
-        #[inline]
-        fn size_hint(&self) -> (usize, Option<usize>) {
-            self.0.size_hint()
-        }
-
-        #[inline]
-        fn last(self) -> Option<Self::Item> {
-            self.0.last()
-        }
-
-        #[inline]
-        fn count(self) -> usize {
-            self.0.count()
-        }
-
-        #[inline]
-        fn nth(&mut self, n: usize) -> Option<Self::Item> {
-            self.0.nth(n)
-        }
-    }
-
-    impl<const N: usize> DoubleEndedIterator for PrimesArrayIntoIter<N> {
-        #[inline]
-        fn next_back(&mut self) -> Option<Self::Item> {
-            self.0.next_back()
-        }
-    }
-
-    impl<const N: usize> ExactSizeIterator for PrimesArrayIntoIter<N> {
-        #[inline]
-        fn len(&self) -> usize {
-            self.0.len()
-        }
-    }
-
-    impl<const N: usize> FusedIterator for PrimesArrayIntoIter<N> {}
-}
-
-// endregion: Iterator impls
-
 /// An enum describing whether the requested array could be filled completely, or only a partially.
 /// A partial array can be returned by [`primes_lt`] if the size of the requested
 /// array is larger than the actual number of primes less than the given `upper_limit`.
diff --git a/src/lib.rs b/src/lib.rs
index 46322aa..07a437c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -126,7 +126,7 @@ mod sieving;
 mod wrapper;
 
 pub use array_section::ArraySection;
-pub use generation::{primes, primes_geq, primes_lt, Error, PrimesArray, Result};
+pub use generation::{primes, primes_geq, primes_lt, Error, Result};
 use imath::isqrt;
 pub use miller_rabin::is_prime;
 pub use other_prime::{next_prime, previous_prime};

From cf139081063d2e9538acf926dcc5047337b556d5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 09:21:22 +0200
Subject: [PATCH 184/212] more docstrings

---
 src/array_section.rs | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/array_section.rs b/src/array_section.rs
index a7c3cd7..42a2e43 100644
--- a/src/array_section.rs
+++ b/src/array_section.rs
@@ -1,3 +1,5 @@
+//! Contains the definition of [`ArraySection`] as well as related types.
+
 use core::{
     cmp::Ordering,
     hash::{Hash, Hasher},
@@ -182,7 +184,8 @@ impl<T: Copy, const N: usize> ArraySection<T, N> {
 
 // region: TryFrom impls
 
-/// Returned by `TryFrom<ArraySection<T, N>> for [T; N]` if the [`ArraySection`] was not the full array.
+/// Returned when a `TryFrom` conversion of an [`ArraySection`] into an array fails.
+/// 
 /// Contains the original `ArraySection`, which can be retrieved via the [`array_section`](TryFromArraySectionError::array_section) function.
 #[derive(Debug, Clone, Copy)]
 pub struct TryFromArraySectionError<T, const N: usize>(ArraySection<T, N>);
@@ -330,6 +333,7 @@ pub use array_section_iter::ArraySectionIter;
 mod array_section_iter {
     use super::FusedIterator;
 
+    /// Created by the [`iter`](super::ArraySection::iter) function on [`ArraySection`](super::ArraySection), see it for more information.
     #[derive(Debug, Clone)]
     pub struct ArraySectionIter<'a, T>(core::slice::Iter<'a, T>);
 

From 43c8eae308ab34110ce29bd9b1056d0e3a24faa5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 10:24:38 +0200
Subject: [PATCH 185/212] Split ArraySection into its own crate

---
 Cargo.toml           |   1 +
 src/array_section.rs | 435 -------------------------------------------
 src/generation.rs    |   4 +-
 src/lib.rs           |   2 -
 4 files changed, 4 insertions(+), 438 deletions(-)
 delete mode 100644 src/array_section.rs

diff --git a/Cargo.toml b/Cargo.toml
index b6a3134..769af06 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,6 +11,7 @@ repository = "https://github.com/JSorngard/const-primes"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+array-section = "0.1.0"
 
 [dev-dependencies]
 criterion = { version = "0.5", features = ["html_reports"] }
diff --git a/src/array_section.rs b/src/array_section.rs
deleted file mode 100644
index 42a2e43..0000000
--- a/src/array_section.rs
+++ /dev/null
@@ -1,435 +0,0 @@
-//! Contains the definition of [`ArraySection`] as well as related types.
-
-use core::{
-    cmp::Ordering,
-    hash::{Hash, Hasher},
-    iter::FusedIterator,
-    ops::{Index, Range},
-    slice::SliceIndex,
-};
-
-/// An array where only a section of the data may be viewed,
-/// as the other data may e.g. not uphold some invariant.
-///
-/// Indexing into the `ArraySection` indices only into the section:
-/// ```
-/// # use const_primes::array_section::ArraySection;
-/// //                                                     v  v
-/// const AS: ArraySection<i32, 4> = ArraySection::new([0, 1, 2, 0], 1..3);
-/// assert_eq![AS[0], 1];
-/// assert_eq![AS[1], 2];
-/// ```
-///
-/// The other data is not considered in comparisons, ordering or hashing:
-/// ```
-/// # use const_primes::array_section::ArraySection;
-/// //                       v  v
-/// const A1: [i32; 4] = [1, 3, 7, 1];
-/// const A2: [i32; 5] = [0, 3, 7, 100, -5];
-/// const AS1: ArraySection<i32, 4> = ArraySection::new(A1, 1..3);
-/// const AS2: ArraySection<i32, 5> = ArraySection::new(A2, 1..3);
-///
-/// // Even though the arrays are different
-/// assert_ne!(A1.as_slice(), A2.as_slice());
-/// // The sections are the same
-/// assert_eq!(AS1, AS2);
-/// ```
-#[derive(Debug, Clone, Copy, Eq)]
-pub struct ArraySection<T, const N: usize> {
-    start: usize,
-    end: usize,
-    array: [T; N],
-}
-
-/// Only hashes the data in the section, and not the full array.
-impl<const N: usize, T: Hash> Hash for ArraySection<T, N> {
-    #[inline]
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        self.as_slice().hash(state);
-    }
-}
-
-/// Only checks the data in the sections, and not the full arrays.
-impl<const N: usize, const M: usize, T: PartialOrd> PartialOrd<ArraySection<T, M>>
-    for ArraySection<T, N>
-{
-    #[inline]
-    fn partial_cmp(&self, other: &ArraySection<T, M>) -> Option<Ordering> {
-        self.as_slice().partial_cmp(other.as_slice())
-    }
-}
-
-/// Only compares the data in the sections and not the full arrays.
-impl<const N: usize, T: Ord> Ord for ArraySection<T, N> {
-    #[inline]
-    fn cmp(&self, other: &Self) -> Ordering {
-        self.as_slice().cmp(other.as_slice())
-    }
-}
-
-impl<const N: usize, T> ArraySection<T, N> {
-    /// Restrict an array so that only elements within the given range are visible.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the range of indices is out of bounds of the array.
-    #[inline]
-    pub const fn new(array: [T; N], section: Range<usize>) -> Self {
-        assert!(
-            section.start < N && section.end <= N,
-            "the sub-range must be in bounds"
-        );
-
-        if section.start > section.end {
-            Self {
-                start: 0,
-                end: 0,
-                array,
-            }
-        } else {
-            Self {
-                start: section.start,
-                end: section.end,
-                array,
-            }
-        }
-    }
-
-    /// Returns the first index of the full underlying array that is part of the section.
-    /// I.e. the section is the subrange `start ..`[`end`](ArraySection::end).
-    #[inline]
-    pub const fn start(&self) -> usize {
-        self.start
-    }
-
-    /// Returns the first index of the full underlying array that is outside the section (to the right).
-    /// I.e. the section is the subrange [`start`](ArraySection::start)`.. end`.
-    #[inline]
-    pub const fn end(&self) -> usize {
-        self.end
-    }
-
-    /// Returns a reference to the full underlying array if it is fully populated.
-    #[inline]
-    pub const fn try_as_full_array(&self) -> Option<&[T; N]> {
-        if self.section_is_full_array() {
-            Some(&self.array)
-        } else {
-            None
-        }
-    }
-
-    /// Returns a reference to the full underlying array.
-    #[inline]
-    pub const fn as_full_array(&self) -> &[T; N] {
-        &self.array
-    }
-
-    /// Converts `self` into the full underlying array.
-    ///
-    /// If you wish to use this in const context the destructor of `T` must be trivial,
-    /// use [`into_full_array_const`](ArraySection::into_full_array_const)
-    #[inline]
-    pub fn into_full_array(self) -> [T; N] {
-        self.array
-    }
-
-    /// Returns the section of the array as a slice.
-    #[inline]
-    pub const fn as_slice(&self) -> &[T] {
-        self.array
-            // Split &[head, section, tail] into (&[head], &[section, tail])
-            .split_at(self.start)
-            // and extract the second element of the tuple.
-            .1
-            // Split &[section, tail] into (&[section], &[tail])
-            .split_at(self.end - self.start)
-            // and extract the first element of the tuple.
-            .0
-    }
-
-    /// Returns the length of the array section.
-    #[inline]
-    pub const fn len(&self) -> usize {
-        self.as_slice().len()
-    }
-
-    /// Returns whether the array section is empty.
-    #[inline]
-    pub const fn is_empty(&self) -> bool {
-        self.as_slice().is_empty()
-    }
-
-    /// Returns whether the section is just the entire array.
-    /// If this is `true` it is completely fine to call [`as_full_array`](ArraySection::as_full_array)
-    /// or [`into_full_array`](ArraySection::into_full_array).
-    #[inline]
-    pub const fn section_is_full_array(&self) -> bool {
-        self.len() == N
-    }
-
-    /// Returns an iterator over the array section.
-    #[inline]
-    pub fn iter(&self) -> ArraySectionIter<'_, T> {
-        ArraySectionIter::new(self.as_slice().iter())
-    }
-}
-
-impl<T: Copy, const N: usize> ArraySection<T, N> {
-    /// Converts `self` into the full underlying array.
-    pub const fn into_full_array_const(self) -> [T; N] {
-        self.array
-    }
-}
-
-// region: TryFrom impls
-
-/// Returned when a `TryFrom` conversion of an [`ArraySection`] into an array fails.
-/// 
-/// Contains the original `ArraySection`, which can be retrieved via the [`array_section`](TryFromArraySectionError::array_section) function.
-#[derive(Debug, Clone, Copy)]
-pub struct TryFromArraySectionError<T, const N: usize>(ArraySection<T, N>);
-
-impl<T, const N: usize> TryFromArraySectionError<T, N> {
-    /// Returns the original [`ArraySection`].
-    pub fn array_section(self) -> ArraySection<T, N> {
-        self.0
-    }
-}
-
-impl<T, const N: usize> core::fmt::Display for TryFromArraySectionError<T, N> {
-    #[inline]
-    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
-        write!(f, "the array was not fully populated")
-    }
-}
-
-#[cfg(feature = "std")]
-impl<T: core::fmt::Debug, const N: usize> std::error::Error for TryFromArraySectionError<T, N> {}
-
-impl<T, const N: usize> From<TryFromArraySectionError<T, N>> for ArraySection<T, N> {
-    fn from(value: TryFromArraySectionError<T, N>) -> Self {
-        value.0
-    }
-}
-
-/// Converts the `ArraySection` into an array if the section is actually the entire array.
-impl<const N: usize, T> TryFrom<ArraySection<T, N>> for [T; N] {
-    type Error = TryFromArraySectionError<T, N>;
-
-    #[inline]
-    fn try_from(value: ArraySection<T, N>) -> Result<Self, Self::Error> {
-        if value.section_is_full_array() {
-            Ok(value.array)
-        } else {
-            Err(TryFromArraySectionError(value))
-        }
-    }
-}
-
-// endregion: TryFrom impls
-
-impl<const N: usize, T> From<[T; N]> for ArraySection<T, N> {
-    #[inline]
-    fn from(value: [T; N]) -> Self {
-        Self {
-            start: 0,
-            end: N,
-            array: value,
-        }
-    }
-}
-
-impl<const N: usize, T> AsRef<[T]> for ArraySection<T, N> {
-    #[inline]
-    fn as_ref(&self) -> &[T] {
-        self.as_slice()
-    }
-}
-
-impl<const N: usize, T, I: SliceIndex<[T]>> Index<I> for ArraySection<T, N> {
-    type Output = I::Output;
-    #[inline]
-    fn index(&self, index: I) -> &Self::Output {
-        &self.as_slice().index(index)
-    }
-}
-
-// region: PartialEq impls
-
-impl<const N: usize, const M: usize, T, U> PartialEq<ArraySection<T, N>> for ArraySection<U, M>
-where
-    [U]: PartialEq<[T]>,
-{
-    #[inline]
-    fn eq(&self, other: &ArraySection<T, N>) -> bool {
-        self.as_slice().eq(other.as_slice())
-    }
-}
-
-impl<const N: usize, T, U> PartialEq<[U]> for ArraySection<T, N>
-where
-    U: PartialEq<T>,
-{
-    #[inline]
-    fn eq(&self, other: &[U]) -> bool {
-        other == self.as_slice()
-    }
-}
-
-impl<const N: usize, T, U> PartialEq<ArraySection<T, N>> for [U]
-where
-    U: PartialEq<T>,
-{
-    #[inline]
-    fn eq(&self, other: &ArraySection<T, N>) -> bool {
-        self == other.as_slice()
-    }
-}
-
-impl<const N: usize, const M: usize, T, U> PartialEq<[T; N]> for ArraySection<U, M>
-where
-    [U]: PartialEq<[T]>,
-{
-    #[inline]
-    fn eq(&self, other: &[T; N]) -> bool {
-        self.as_slice().eq(other.as_slice())
-    }
-}
-
-impl<const N: usize, const M: usize, T, U> PartialEq<ArraySection<U, M>> for [T; N]
-where
-    [T]: PartialEq<[U]>,
-{
-    #[inline]
-    fn eq(&self, other: &ArraySection<U, M>) -> bool {
-        self.as_slice().eq(other.as_slice())
-    }
-}
-
-// endregion: PartialEq impls
-
-impl<const N: usize, T> IntoIterator for ArraySection<T, N> {
-    type IntoIter = ArraySectionIntoIter<T, N>;
-    type Item = <ArraySectionIntoIter<T, N> as Iterator>::Item;
-    #[inline]
-    fn into_iter(self) -> Self::IntoIter {
-        let start = self.start;
-        let len = self.len();
-        ArraySectionIntoIter::new(self.array.into_iter().skip(start).take(len))
-    }
-}
-
-impl<'a, const N: usize, T> IntoIterator for &'a ArraySection<T, N> {
-    type IntoIter = ArraySectionIter<'a, T>;
-    type Item = <ArraySectionIter<'a, T> as Iterator>::Item;
-    #[inline]
-    fn into_iter(self) -> Self::IntoIter {
-        ArraySectionIter::new(self.as_slice().iter())
-    }
-}
-
-pub use array_section_iter::ArraySectionIter;
-mod array_section_iter {
-    use super::FusedIterator;
-
-    /// Created by the [`iter`](super::ArraySection::iter) function on [`ArraySection`](super::ArraySection), see it for more information.
-    #[derive(Debug, Clone)]
-    pub struct ArraySectionIter<'a, T>(core::slice::Iter<'a, T>);
-
-    impl<'a, T> ArraySectionIter<'a, T> {
-        pub(crate) const fn new(iter: core::slice::Iter<'a, T>) -> Self {
-            Self(iter)
-        }
-    }
-
-    impl<'a, T> Iterator for ArraySectionIter<'a, T> {
-        type Item = &'a T;
-        fn next(&mut self) -> Option<Self::Item> {
-            self.0.next()
-        }
-
-        fn size_hint(&self) -> (usize, Option<usize>) {
-            self.0.size_hint()
-        }
-
-        fn last(self) -> Option<Self::Item> {
-            self.0.last()
-        }
-
-        fn nth(&mut self, n: usize) -> Option<Self::Item> {
-            self.0.nth(n)
-        }
-
-        fn count(self) -> usize {
-            self.0.count()
-        }
-    }
-    impl<'a, T> DoubleEndedIterator for ArraySectionIter<'a, T> {
-        fn next_back(&mut self) -> Option<Self::Item> {
-            self.0.next_back()
-        }
-    }
-    impl<'a, T> ExactSizeIterator for ArraySectionIter<'a, T> {
-        fn len(&self) -> usize {
-            self.0.len()
-        }
-    }
-    impl<'a, T> FusedIterator for ArraySectionIter<'a, T> {}
-}
-
-pub use array_section_into_iter::ArraySectionIntoIter;
-mod array_section_into_iter {
-    use super::FusedIterator;
-
-    #[derive(Debug, Clone)]
-    /// Created by the [`into_iter`](super::ArraySection::into_iter) function on [`ArraySection`](super::ArraySection), see it for more information.
-    pub struct ArraySectionIntoIter<T, const N: usize>(
-        core::iter::Take<core::iter::Skip<core::array::IntoIter<T, N>>>,
-    );
-
-    impl<const N: usize, T> ArraySectionIntoIter<T, N> {
-        pub(crate) const fn new(
-            iter: core::iter::Take<core::iter::Skip<core::array::IntoIter<T, N>>>,
-        ) -> Self {
-            Self(iter)
-        }
-    }
-
-    impl<const N: usize, T> Iterator for ArraySectionIntoIter<T, N> {
-        type Item = T;
-        #[inline]
-        fn next(&mut self) -> Option<Self::Item> {
-            self.0.next()
-        }
-
-        #[inline]
-        fn size_hint(&self) -> (usize, Option<usize>) {
-            let l = self.0.len();
-            (l, Some(l))
-        }
-
-        #[inline]
-        fn nth(&mut self, index: usize) -> Option<Self::Item> {
-            self.0.nth(index)
-        }
-
-        #[inline]
-        fn last(self) -> Option<T> {
-            self.0.last()
-        }
-
-        #[inline]
-        fn count(self) -> usize {
-            self.0.count()
-        }
-    }
-    impl<const N: usize, T> FusedIterator for ArraySectionIntoIter<T, N> {}
-    impl<const N: usize, T> ExactSizeIterator for ArraySectionIntoIter<T, N> {}
-    impl<const N: usize, T> DoubleEndedIterator for ArraySectionIntoIter<T, N> {
-        #[inline]
-        fn next_back(&mut self) -> Option<Self::Item> {
-            self.0.next_back()
-        }
-    }
-}
diff --git a/src/generation.rs b/src/generation.rs
index 3478d1e..0811af5 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -1,6 +1,8 @@
 use core::fmt;
 
-use crate::{array_section::ArraySection, sieve, sieving::sieve_segment, Underlying};
+use array_section::ArraySection;
+
+use crate::{sieve, sieving::sieve_segment, Underlying};
 
 /// Type alias for the type returned by the segmented sieving and generation functions.
 pub type Result<const N: usize> = core::result::Result<ArraySection<u64, N>, Error>;
diff --git a/src/lib.rs b/src/lib.rs
index 07a437c..2e1c7d8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -117,7 +117,6 @@
 // This is used since there is currently no way to be generic over types that can do arithmetic at compile time.
 type Underlying = u32;
 
-pub mod array_section;
 mod generation;
 mod imath;
 mod miller_rabin;
@@ -125,7 +124,6 @@ mod other_prime;
 mod sieving;
 mod wrapper;
 
-pub use array_section::ArraySection;
 pub use generation::{primes, primes_geq, primes_lt, Error, Result};
 use imath::isqrt;
 pub use miller_rabin::is_prime;

From 61fd56a60865b196ac2b40ed11db95d86d33009d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Sun, 5 May 2024 15:52:02 +0200
Subject: [PATCH 186/212] Docstring formatting

---
 src/lib.rs | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 2e1c7d8..b7d0403 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -51,8 +51,7 @@
 //! that can be used to work with ranges that don't start at zero. They take two generics: the number of primes
 //! to store in the binary, and the size of the sieve used during evaluation
 //! (which must be at least the ceiling of the square root of the largest encountered number).
-//! This means that one can sieve up to large numbers,
-//! but doesn't need to store the entire sieve in the binary.
+//! This means that one can sieve to large numbers, but doesn't need to store the entire sieve in the binary.
 //! ```
 //! # use const_primes::Error;
 //! use const_primes::primes_geq;

From d64b58cb0bfaf0f60004fd72c5fb073d737dc3f8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 6 May 2024 10:30:13 +0200
Subject: [PATCH 187/212] Add note of runtime use to const_primes!

---
 src/generation.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/generation.rs b/src/generation.rs
index 0811af5..89cf453 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -254,7 +254,9 @@ macro_rules! ඞ_const_primes_isqrt {
 /// const LIMIT: u64 = 5_000_000_031;
 /// const PRIMES_GEQ: const_primes::Result<3> = const_primes!(3; >= LIMIT);
 /// const PRIMES_LT: const_primes::Result<3> = const_primes!(3; < LIMIT);
+/// // Can also be used at runtime:
 /// let primes = const_primes!(3);
+/// let hmm = const_primes!(3; >= 100);
 ///
 /// assert_eq!(primes, PRIMES);
 /// assert_eq!(PRIMES, [2, 3, 5]);

From 96973ab41d94d27d1bc6a03472ea3f2c1fe14e56 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 6 May 2024 10:32:06 +0200
Subject: [PATCH 188/212] improve docstring

---
 src/generation.rs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/generation.rs b/src/generation.rs
index 89cf453..bb4232c 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -256,10 +256,11 @@ macro_rules! ඞ_const_primes_isqrt {
 /// const PRIMES_LT: const_primes::Result<3> = const_primes!(3; < LIMIT);
 /// // Can also be used at runtime:
 /// let primes = const_primes!(3);
-/// let hmm = const_primes!(3; >= 100);
+/// let primes_geq = const_primes!(3; >= LIMIT)?;
 ///
 /// assert_eq!(primes, PRIMES);
 /// assert_eq!(PRIMES, [2, 3, 5]);
+/// assert_eq!(PRIMES_GEQ?, primes_geq);
 /// assert_eq!(PRIMES_GEQ?, [5000000039, 5000000059, 5000000063]);
 /// assert_eq!(PRIMES_LT?, [4999999903, 4999999937, 5000000029]);
 /// # Ok::<(), Error>(())

From c6a2eef6c66ec112c67787f10c674b7d8e9a4fc3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 6 May 2024 13:22:16 +0200
Subject: [PATCH 189/212] Add categories 'Mathematics' and 'No standard
 library::no dynamic allocation'

---
 Cargo.toml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Cargo.toml b/Cargo.toml
index 769af06..ecc39ea 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,6 +5,7 @@ version = "0.4.8"
 edition = "2021"
 license = "MIT OR Apache-2.0"
 keywords = ["primes", "const"]
+categories = ["mathematics", "no-std::no-alloc"]
 description = "Generate and work with prime numbers in const contexts"
 repository = "https://github.com/JSorngard/const-primes"
 

From c3177f5c4a8b96682bd8563eeedd76ff9b2b714c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 6 May 2024 13:29:05 +0200
Subject: [PATCH 190/212] Add alloc features

---
 Cargo.toml | 3 ++-
 src/lib.rs | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/Cargo.toml b/Cargo.toml
index ecc39ea..86f1471 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,7 +19,8 @@ criterion = { version = "0.5", features = ["html_reports"] }
 rand = "0.8"
 
 [features]
-std = []
+std = ["array-section/std", "alloc"]
+alloc = ["array-section/alloc"]
 
 [[bench]]
 name = "prime_benches"
diff --git a/src/lib.rs b/src/lib.rs
index b7d0403..aed009b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -107,6 +107,7 @@
 //! # Features
 //!
 //! `std`: links the standard library and uses it to implement the [`Error`](std::error::Error) trait for the error types.
+//! `alloc`: enables conversion of the type returned by [`primes_geq`] and [`primes_lt`] into [`Vec`]s and [`Box`]ed slices.
 
 #![forbid(unsafe_code)]
 #![cfg_attr(all(not(test), not(feature = "std")), no_std)]

From eb94512aedc50718948fec4d8e24b22de16640bb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 6 May 2024 13:38:09 +0200
Subject: [PATCH 191/212] Update README.md

---
 README.md | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/README.md b/README.md
index e10b91a..a7ba367 100644
--- a/README.md
+++ b/README.md
@@ -50,11 +50,13 @@ assert_eq!(PRIME_STATUS, [false, false, true, true, false, true, false, true, fa
 
 ## Arbitrary ranges
 The crate provides prime generation and sieving functions with suffixes, e.g. `primes_geq` and `sieve_lt`
-that can be used to work with ranges that don't start at zero.
+that can be used to work with ranges that don't start at zero. They take two generics: the number of elements
+to store in the binary and the size of the sieve used during evaluation. The sieve size must be the cieling
+of the square root of the largest encountered value:
 ```rust
-const N: usize = 70722;
-const PRIMES_GEQ: [u64; N] = primes_geq(5_000_000_031);
-assert_eq!(PRIMES_GEQ[..3], [5_000_000_039, 5_000_000_059, 5_000_000_063]);
+//                              ceil(sqrt(5_000_000_063)) = 70_711
+const PRIMES_GEQ: const_primes::Result<3> = primes_geq::<3, 70_711>(5_000_000_031);
+assert_eq!(PRIMES_GEQ?, [5_000_000_039, 5_000_000_059, 5_000_000_063]);
 ```
 ```rust
 const N: usize = 70711;
@@ -62,9 +64,7 @@ const PRIME_STATUS_LT: [bool; N] = sieve_lt(5_000_000_031);
 //                                    5_000_000_028  5_000_000_029  5_000_000_030
 assert_eq!(PRIME_STATUS_LT[N - 3..], [false,         true,          false]);
 ```
-Unfortunately the output array must be large enough to contain the prime sieve, which scales with
-the square root of largest relavant number, which is why the examples use a size of over 70000 even though
-they're only interested in three numbers.
+The sieving functions have yet to be modified for two generics, and must save the entire sieve in the binary.
 ## Other functionality
 Use `is_prime` to test whether a given number is prime:
 ```rust

From 4af54542c8b9eba575a9149e85b509189d8d24bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 6 May 2024 13:39:51 +0200
Subject: [PATCH 192/212] Add features to README

---
 README.md  | 5 +++++
 src/lib.rs | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index a7ba367..5b38ac5 100644
--- a/README.md
+++ b/README.md
@@ -83,6 +83,11 @@ assert_eq!(NOSUCH, None);
 ```
 and more!
 
+## Features
+
+`std`: derives the `Error` trait for the error types.
+`alloc`: enables conversion of the type returned by [`primes_geq`] and [`primes_lt`] into [`Vec`]s and [`Box`]ed slices.
+
 ## License
 
 Licensed under either of
diff --git a/src/lib.rs b/src/lib.rs
index aed009b..c0b8c94 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -106,7 +106,7 @@
 //!
 //! # Features
 //!
-//! `std`: links the standard library and uses it to implement the [`Error`](std::error::Error) trait for the error types.
+//! `std`: derives the [`Error`](std::error::Error) trait for the error types.
 //! `alloc`: enables conversion of the type returned by [`primes_geq`] and [`primes_lt`] into [`Vec`]s and [`Box`]ed slices.
 
 #![forbid(unsafe_code)]

From 0d7dabcd4cca20725b70782ac9fbb51ff4cf43e2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 6 May 2024 13:40:03 +0200
Subject: [PATCH 193/212] newline

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 5b38ac5..c52ce32 100644
--- a/README.md
+++ b/README.md
@@ -85,7 +85,7 @@ and more!
 
 ## Features
 
-`std`: derives the `Error` trait for the error types.
+`std`: derives the `Error` trait for the error types.  
 `alloc`: enables conversion of the type returned by [`primes_geq`] and [`primes_lt`] into [`Vec`]s and [`Box`]ed slices.
 
 ## License

From de8dd9efb54f4fc9a15231f1909c05eb3e20b942 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 6 May 2024 13:40:48 +0200
Subject: [PATCH 194/212] The readme can't doclink

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index c52ce32..d7b73dd 100644
--- a/README.md
+++ b/README.md
@@ -86,7 +86,7 @@ and more!
 ## Features
 
 `std`: derives the `Error` trait for the error types.  
-`alloc`: enables conversion of the type returned by [`primes_geq`] and [`primes_lt`] into [`Vec`]s and [`Box`]ed slices.
+`alloc`: enables conversion of the type returned by `primes_geq` and `primes_lt` into `Vec`s and `Box`ed slices.
 
 ## License
 

From 7b55a59d883824ec5726bf052ceb9ac69057d0af Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 6 May 2024 16:42:56 +0200
Subject: [PATCH 195/212] Ignore rust-toolchain.toml, I just want my vscode to
 stop yelling at me

---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index 4fffb2f..482c89d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 /target
 /Cargo.lock
+rust-toolchain.toml
\ No newline at end of file

From d189cb6ad62ad48eb5e99951502b111e4dc19346 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Mon, 6 May 2024 16:54:10 +0200
Subject: [PATCH 196/212] fix benchmark code

---
 benches/prime_benches.rs | 12 +++++-------
 src/sieving.rs           |  2 +-
 2 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/benches/prime_benches.rs b/benches/prime_benches.rs
index 21c2cdf..3794bb1 100644
--- a/benches/prime_benches.rs
+++ b/benches/prime_benches.rs
@@ -1,7 +1,4 @@
-use const_primes::{
-    generation::{primes_geq, primes_lt},
-    is_prime, primes, sieve, sieve_geq, sieve_lt,
-};
+use const_primes::{is_prime, primes, primes_geq, primes_lt, sieve, sieve_geq, sieve_lt};
 use criterion::{criterion_group, criterion_main, BatchSize, Criterion, Throughput};
 use rand::prelude::*;
 use std::hint::black_box;
@@ -14,20 +11,21 @@ fn benchmarks(c: &mut Criterion) {
             b.iter(|| black_box(primes::<N>()))
         });
         prime_generation.bench_function(format!("{N} primes < 100000000"), |b| {
-            b.iter(|| black_box(primes_lt::<N>(100000000)))
+            b.iter(|| black_box(primes_lt::<N, N>(100000000)))
         });
         prime_generation.bench_function(format!("{N} primes >= 99990000"), |b| {
-            b.iter(|| black_box(primes_geq::<N>(99990000)))
+            b.iter(|| black_box(primes_geq::<N, N>(99990000)))
         });
     }
 
     {
         const N: u64 = 10_000;
+        let mut rng = StdRng::seed_from_u64(1234567890);
         let mut primality_testing = c.benchmark_group("primality testing");
         primality_testing.throughput(Throughput::Elements(N));
         primality_testing.bench_function(format!("is_prime on {N} random numbers"), |b| {
             b.iter_batched(
-                || (0..N).map(|_| random()).collect::<Vec<u64>>(),
+                || (0..N).map(|_| rng.gen()).collect::<Vec<u64>>(),
                 |data| {
                     for number in data.iter() {
                         black_box(is_prime(*number));
diff --git a/src/sieving.rs b/src/sieving.rs
index 9668954..3476c65 100644
--- a/src/sieving.rs
+++ b/src/sieving.rs
@@ -209,7 +209,7 @@ pub const fn sieve_geq<const N: usize>(lower_limit: u64) -> [bool; N] {
     };
     if let Some(n_sqr) = n64.checked_mul(n64) {
         assert!(
-            upper_limit < n_sqr,
+            upper_limit <= n_sqr,
             "`lower_limit + N` must be less than or equal to `N^2`"
         );
     } else {

From 472ee923336366c8cf2211dd1aa8a9af3380907f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 7 May 2024 12:01:01 +0200
Subject: [PATCH 197/212] Simplify API

---
 Cargo.toml        |   9 +--
 src/generation.rs | 146 ++++++++++++++++++++++------------------------
 src/lib.rs        |  21 +++----
 src/sieving.rs    |   4 +-
 4 files changed, 83 insertions(+), 97 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml
index 86f1471..d8f4fbf 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,18 +9,13 @@ categories = ["mathematics", "no-std::no-alloc"]
 description = "Generate and work with prime numbers in const contexts"
 repository = "https://github.com/JSorngard/const-primes"
 
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-array-section = "0.1.0"
-
 [dev-dependencies]
 criterion = { version = "0.5", features = ["html_reports"] }
 rand = "0.8"
 
 [features]
-std = ["array-section/std", "alloc"]
-alloc = ["array-section/alloc"]
+std = [ "alloc"]
+alloc = []
 
 [[bench]]
 name = "prime_benches"
diff --git a/src/generation.rs b/src/generation.rs
index bb4232c..18e73e0 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -1,12 +1,7 @@
 use core::fmt;
 
-use array_section::ArraySection;
-
 use crate::{sieve, sieving::sieve_segment, Underlying};
 
-/// Type alias for the type returned by the segmented sieving and generation functions.
-pub type Result<const N: usize> = core::result::Result<ArraySection<u64, N>, Error>;
-
 /// Returns the `N` first prime numbers.
 /// Fails to compile if `N` is 0.
 ///
@@ -132,61 +127,60 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// # use const_primes::{primes_lt, Error};
 /// // Sieving up to 100 means the sieve needs to be of size sqrt(100) = 10.
 /// // However, we only save the 4 largest primes in the constant.
-/// const PRIMES: const_primes::Result<4> = primes_lt::<4, 10>(100);
-/// assert_eq!(PRIMES?, [79, 83, 89, 97]);
-/// # Ok::<(), Error>(())
+/// const PRIMES: [u64;4] = match primes_lt::<4, 10>(100) {Ok(ps) => ps, Err(_) => panic!()};
+/// assert_eq!(PRIMES, [79, 83, 89, 97]);
 /// ```
 /// Compute larger primes without starting from zero:
 /// ```
 /// # use const_primes::{primes_lt, Error};
 /// # #[allow(long_running_const_eval)]
-/// const BIG_PRIMES: const_primes::Result<3> = primes_lt::<3, 70_711>(5_000_000_030);
+/// const BIG_PRIMES: Result<[u64; 3], Error> = primes_lt::<3, 70_711>(5_000_000_030);
 ///
 /// assert_eq!(BIG_PRIMES?, [4_999_999_903, 4_999_999_937, 5_000_000_029]);
 /// # Ok::<(), Error>(())
 /// ```
+/// # Errors
+///
 /// If the number of primes requested, `N`, is larger than
 /// the number of primes that exists below the `lower_limit` we
-/// will get a partial result of all the existing primes.
-/// Due to limitations on const evaluation this will still
-/// take up the full `N` numbers worth of memory.
+/// will get an error:
 /// ```
 /// # use const_primes::{primes_lt, Error};
-/// const PRIMES: const_primes::Result<9> = primes_lt::<9, 9>(10);
-/// assert_eq!(PRIMES?, [2, 3, 5, 7]);
-/// # Ok::<(), Error>(())
+/// const PRIMES: Result<[u64; 9], Error> = primes_lt::<9, 9>(10);
+/// assert_eq!(PRIMES, Err(Error::OutOfPrimes));
 /// ```
-/// # Errors
 ///
-/// Returns an error if `upper_limit` is larger than `MEM`^2 or if `upper_limit` is smaller than or equal to 2.
+/// We will also get an error if `upper_limit` is larger than `MEM`^2 or if `upper_limit` is smaller than or equal to 2.
 /// ```
-/// # use const_primes::primes_lt;
-/// const TOO_LARGE_LIMIT: const_primes::Result<3> = primes_lt::<3, 5>(26);
-/// const TOO_SMALL_LIMIT: const_primes::Result<1> = primes_lt::<1, 1>(1);
+/// # use const_primes::{primes_lt, Error};
+/// const TOO_LARGE_LIMIT: Result<[u64; 3], Error> = primes_lt::<3, 5>(26);
+/// const TOO_SMALL_LIMIT: Result<[u64 ;1], Error> = primes_lt::<1, 1>(1);
 /// assert!(TOO_LARGE_LIMIT.is_err());
 /// assert!(TOO_SMALL_LIMIT.is_err());
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
-pub const fn primes_lt<const N: usize, const MEM: usize>(mut upper_limit: u64) -> Result<N> {
+pub const fn primes_lt<const N: usize, const MEM: usize>(
+    mut upper_limit: u64,
+) -> Result<[u64; N], Error> {
     const {
         assert!(N > 0, "`N` must be at least 1");
         assert!(MEM >= N, "`MEM` must be at least as large as `N`");
     }
-    let mem64 = const {
+    let mem_sqr = const {
         let mem64 = MEM as u64;
-        assert!(
-            mem64.checked_mul(mem64).is_some(),
-            "`MEM`^2 must fit in a u64"
-        );
-        mem64
+        let mem_sqr = match mem64.checked_mul(mem64) {
+            Some(prod) => prod,
+            None => panic!("`MEM`^2 must fit in a u64"),
+        };
+        mem_sqr
     };
 
     if upper_limit <= 2 {
         return Err(Error::TooSmallLimit(upper_limit));
     }
 
-    if upper_limit > mem64 * mem64 {
-        return Err(Error::TooLargeLimit(upper_limit, MEM));
+    if upper_limit > mem_sqr {
+        return Err(Error::TooLargeLimit(upper_limit, mem_sqr));
     }
 
     let mut primes: [u64; N] = [0; N];
@@ -218,11 +212,12 @@ pub const fn primes_lt<const N: usize, const MEM: usize>(mut upper_limit: u64) -
         }
         upper_limit = smallest_found_prime;
         if upper_limit <= 2 && total_primes_found < N {
-            return Ok(ArraySection::new(primes, N - total_primes_found..N));
+            return Err(Error::OutOfPrimes);
+            //return Err(ArraySection::new(primes, N - total_primes_found..N));
         }
     }
 
-    Ok(ArraySection::new(primes, 0..N))
+    Ok(primes)
 }
 
 /// Same as the private const fn isqrt in the crate.
@@ -252,17 +247,17 @@ macro_rules! ඞ_const_primes_isqrt {
 /// # use const_primes::{const_primes, Error};
 /// const PRIMES: [u32; 3] = const_primes!();
 /// const LIMIT: u64 = 5_000_000_031;
-/// const PRIMES_GEQ: const_primes::Result<3> = const_primes!(3; >= LIMIT);
-/// const PRIMES_LT: const_primes::Result<3> = const_primes!(3; < LIMIT);
+/// const PRIMES_GEQ: Result<[u64; 3], Error> = const_primes!(3; >= LIMIT);
+/// const PRIMES_LT: Result<[u64; 3], Error> = const_primes!(3; < LIMIT);
 /// // Can also be used at runtime:
 /// let primes = const_primes!(3);
-/// let primes_geq = const_primes!(3; >= LIMIT)?;
+/// let primes_geq = const_primes!(3; >= LIMIT);
 ///
 /// assert_eq!(primes, PRIMES);
 /// assert_eq!(PRIMES, [2, 3, 5]);
-/// assert_eq!(PRIMES_GEQ?, primes_geq);
-/// assert_eq!(PRIMES_GEQ?, [5000000039, 5000000059, 5000000063]);
-/// assert_eq!(PRIMES_LT?, [4999999903, 4999999937, 5000000029]);
+/// assert_eq!(PRIMES_GEQ, primes_geq);
+/// assert_eq!(PRIMES_GEQ, Ok([5000000039, 5000000059, 5000000063]));
+/// assert_eq!(PRIMES_LT, Ok([4999999903, 4999999937, 5000000029]));
 /// # Ok::<(), Error>(())
 /// ```
 #[macro_export]
@@ -311,37 +306,38 @@ macro_rules! const_primes {
 ///
 /// Basic usage:
 /// ```
-/// # use const_primes::{primes_geq, Error};
-/// const PRIMES: const_primes::Result<5> = primes_geq::<5, 5>(10);
-/// assert_eq!(PRIMES?, [11, 13, 17, 19, 23]);
-/// # Ok::<(), Error>(())
+/// use const_primes::{primes_geq, Error};
+/// const PRIMES: [u64; 5] = match primes_geq::<5, 5>(10) {Ok(ps) => ps, Err(_) => panic!()};
+/// assert_eq!(PRIMES, [11, 13, 17, 19, 23]);
 /// ```
 /// Compute larger primes without starting from zero:
 /// ```
 /// # use const_primes::{primes_geq, Error};
 /// # #[allow(long_running_const_eval)]
-/// const P: const_primes::Result<3> = primes_geq::<3, 71_000>(5_000_000_030);
+/// const P: Result<[u64; 3], Error> = primes_geq::<3, 71_000>(5_000_000_030);
 /// assert_eq!(P?, [5_000_000_039, 5_000_000_059, 5_000_000_063]);
 /// # Ok::<(), Error>(())
 /// ```
-/// Only primes smaller than `MEM^2` will be generated:
+/// # Errors
+///
+/// Only primes smaller than `MEM^2` can be generated, so if the sieve
+/// encounters a number larger than that it results in an error:
 /// ```
 /// # use const_primes::{primes_geq, Error};
-/// const PRIMES: const_primes::Result<3> = primes_geq::<3, 3>(5);
-/// assert_eq!(PRIMES?, [5, 7]);
-/// # Ok::<(), Error>(())
+/// const PRIMES: Result<[u64; 3], Error> = primes_geq::<3, 3>(5);
+/// assert!(matches!(PRIMES, Err(Error::SieveOverrun(_))));
 /// ```
 ///
-/// # Errors
-///
 /// Returns an error if `lower_limit` is larger than or equal to `MEM^2`.
 /// ```
-/// # use const_primes::{primes_geq, Result};
-/// const PRIMES: Result<5> = primes_geq::<5, 5>(26);
+/// # use const_primes::{primes_geq, Error};
+/// const PRIMES: Result<[u64; 5], Error> = primes_geq::<5, 5>(26);
 /// assert!(PRIMES.is_err());
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
-pub const fn primes_geq<const N: usize, const MEM: usize>(lower_limit: u64) -> Result<N> {
+pub const fn primes_geq<const N: usize, const MEM: usize>(
+    lower_limit: u64,
+) -> Result<[u64; N], Error> {
     const {
         assert!(N > 0, "`N` must be at least 1");
         assert!(MEM >= N, "`MEM` must be at least as large as `N`");
@@ -358,7 +354,7 @@ pub const fn primes_geq<const N: usize, const MEM: usize>(lower_limit: u64) -> R
     let new_lower_limit = if lower_limit >= 2 { lower_limit } else { 2 };
 
     if new_lower_limit >= mem_sqr {
-        return Err(Error::TooLargeLimit(lower_limit, MEM));
+        return Err(Error::TooLargeLimit(lower_limit, mem_sqr));
     }
 
     let lower_limit = new_lower_limit;
@@ -378,9 +374,9 @@ pub const fn primes_geq<const N: usize, const MEM: usize>(lower_limit: u64) -> R
 
                 // We can not know whether this is actually a prime since
                 // the base sieve contains no information
-                // about numbers larger than or equal to `MEM`.
-                if largest_found_prime >= mem64 * mem64 {
-                    return Ok(ArraySection::new(primes, 0..total_found_primes));
+                // about numbers larger than or equal to `MEM`^2.
+                if largest_found_prime >= mem_sqr {
+                    return Err(Error::SieveOverrun(largest_found_prime));
                 }
 
                 if largest_found_prime >= lower_limit {
@@ -397,38 +393,39 @@ pub const fn primes_geq<const N: usize, const MEM: usize>(lower_limit: u64) -> R
         sieve_limit = largest_found_prime + 1;
     }
 
-    Ok(ArraySection::new(primes, 0..N))
+    Ok(primes)
 }
 
-/// An enum describing whether the requested array could be filled completely, or only a partially.
-/// A partial array can be returned by [`primes_lt`] if the size of the requested
-/// array is larger than the actual number of primes less than the given `upper_limit`.
-/// It can also be returned by [`primes_geq`] if it needs to sieve into a
-/// region of numbers that exceed the square of the size of the requested array.
+/// The error returned by [`primes_lt`] and [`primes_geq`] if the input
+/// is invalid or does not work to produce the requested primes.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum Error {
-    /// `MEM`^2 did not fit in a `u64`.
-    MEMSquaredOverflow(usize),
     /// the limit was larger than `MEM^2`.
-    TooLargeLimit(u64, usize),
+    TooLargeLimit(u64, u64),
     /// the limit was smaller than or equal to 2.
     TooSmallLimit(u64),
+    /// encountered a number larger than `MEM`^2.
+    SieveOverrun(u64),
+    /// ran out of primes.
+    OutOfPrimes,
 }
 
 impl fmt::Display for Error {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
-            Self::MEMSquaredOverflow(mem) => {
-                write!(f, "`MEM` was {mem}, and so `MEM`^2 did not fit in a `u64`")
-            }
-            Self::TooLargeLimit(limit, mem) => write!(
+            Self::TooLargeLimit(limit, mem_sqr) => write!(
                 f,
-                "the limit was {limit} and `MEM` was {mem}, so the limit was larger than `MEM`^2"
+                "the limit ({limit}) was larger than `MEM`^2 ({mem_sqr})"
             ),
             Self::TooSmallLimit(limit) => write!(
                 f,
                 "the limit was {limit}, which is smaller than or equal to 2"
             ),
+            Self::SieveOverrun(number) => write!(
+                f,
+                "encountered the number {number} which would have needed `MEM` to be at least {} to sieve", crate::imath::isqrt(*number) + 1
+            ),
+            Self::OutOfPrimes => write!(f, "ran out of primes before the array was filled"),
         }
     }
 }
@@ -445,21 +442,18 @@ mod test {
     #[test]
     fn sanity_check_primes_geq() {
         {
-            const P: Result<5> = primes_geq::<5, 5>(10);
+            const P: Result<[u64; 5], Error> = primes_geq::<5, 5>(10);
             assert_eq!(P.unwrap().as_slice(), [11, 13, 17, 19, 23]);
         }
         {
-            const P: Result<5> = primes_geq::<5, 5>(0);
+            const P: Result<[u64; 5], Error> = primes_geq::<5, 5>(0);
             assert_eq!(P.unwrap().as_slice(), [2, 3, 5, 7, 11]);
         }
         {
-            const P: Result<1> = primes_geq::<1, 1>(0);
+            const P: Result<[u64; 1], Error> = primes_geq::<1, 1>(0);
             assert_eq!(P, Err(Error::TooLargeLimit(0, 1)));
         }
-        for &prime in primes_geq::<2_000, 2_000>(3_998_000).unwrap().as_slice() {
-            if prime == 0 {
-                break;
-            }
+        for &prime in primes_geq::<2_000, 2_008>(3_998_000).unwrap().as_slice() {
             assert!(is_prime(prime));
         }
     }
diff --git a/src/lib.rs b/src/lib.rs
index c0b8c94..435c197 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -53,24 +53,21 @@
 //! (which must be at least the ceiling of the square root of the largest encountered number).
 //! This means that one can sieve to large numbers, but doesn't need to store the entire sieve in the binary.
 //! ```
-//! # use const_primes::Error;
-//! use const_primes::primes_geq;
+//! use const_primes::{primes_geq, Error};
 //! // ceil(sqrt(5_000_000_063)) = 70_711
-//! const P_GEQ: const_primes::Result<3> = primes_geq::<3, 70_711>(5_000_000_031);
+//! const P_GEQ: Result<[u64; 3], Error> = primes_geq::<3, 70_711>(5_000_000_031);
 //!
-//! assert_eq!(P_GEQ?, [5_000_000_039, 5_000_000_059, 5_000_000_063]);
-//! # Ok::<(), Error>(())
+//! assert_eq!(P_GEQ, Ok([5_000_000_039, 5_000_000_059, 5_000_000_063]));
 //! ```
 //! If you do not wish to compute the required sieve size yourself,
 //! you can use the provided macro [`const_primes!`]:
 //! ```
 //! # use const_primes::{const_primes, Error};
-//! const PRIMES_OVER_100: const_primes::Result<3> = const_primes!(3; >= 100);
-//! const PRIMES_UNDER_100: const_primes::Result<3> = const_primes!(3; < 100);
+//! const PRIMES_OVER_100: Result<[u64; 3], Error> = const_primes!(3; >= 100);
+//! const PRIMES_UNDER_100: Result<[u64; 3], Error> = const_primes!(3; < 100);
 //!
-//! assert_eq!(PRIMES_OVER_100?, [101, 103, 107]);
-//! assert_eq!(PRIMES_UNDER_100?, [83, 89, 97]);
-//! # Ok::<(), Error>(())
+//! assert_eq!(PRIMES_OVER_100, Ok([101, 103, 107]));
+//! assert_eq!(PRIMES_UNDER_100, Ok([83, 89, 97]));
 //! ```
 //! ```
 //! # use const_primes::sieve_lt;
@@ -124,7 +121,7 @@ mod other_prime;
 mod sieving;
 mod wrapper;
 
-pub use generation::{primes, primes_geq, primes_lt, Error, Result};
+pub use generation::{primes, primes_geq, primes_lt, Error};
 use imath::isqrt;
 pub use miller_rabin::is_prime;
 pub use other_prime::{next_prime, previous_prime};
@@ -254,7 +251,7 @@ mod test {
             ($($n:expr),+) => {
                 $(
                     {
-                        const P: Result<$n> = primes_lt::<$n, $n>(100);
+                        const P: Result<[u64; $n], Error> = primes_lt::<$n, $n>(100);
                         for (i, prime) in P.unwrap().as_slice().into_iter().enumerate() {
                             assert_eq!(PRECOMPUTED_PRIMES[25-$n..25][i], *prime as u32);
                         }
diff --git a/src/sieving.rs b/src/sieving.rs
index 3476c65..aa0e861 100644
--- a/src/sieving.rs
+++ b/src/sieving.rs
@@ -189,10 +189,10 @@ pub const fn sieve<const N: usize>() -> [bool; N] {
 /// ```
 /// # Panics
 ///
-/// Panics if `N + lower_limit` is larger than or equal to `N^2`. In const contexts this is a compile error:
+/// Panics if `N + lower_limit` is larger than to `N^2`. In const contexts this is a compile error:
 /// ```compile_fail
 /// # use const_primes::sieve_geq;
-/// const P: [bool; 5] = sieve_geq(20);
+/// const P: [bool; 5] = sieve_geq(21);
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
 pub const fn sieve_geq<const N: usize>(lower_limit: u64) -> [bool; N] {

From 11a52e96f05b2d3dab36376262b64625ac6f701e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 7 May 2024 12:33:39 +0200
Subject: [PATCH 198/212] Use heuristic to estimate geq memory requirements

---
 src/generation.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/generation.rs b/src/generation.rs
index 18e73e0..9c60bf6 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -287,7 +287,7 @@ macro_rules! const_primes {
             $n,
             {
                 let mem = { $lim };
-                $crate::ඞ_const_primes_isqrt!(mem) as ::core::primitive::usize + 1
+                $crate::ඞ_const_primes_isqrt!(mem) as ::core::primitive::usize + 1 + { $n }
             },
         >($lim)
     };

From 2f63369cbf29e2c97f6ff48f672da0430a6fa76c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 7 May 2024 12:39:54 +0200
Subject: [PATCH 199/212] const_primes! -> primes_segment!

---
 src/generation.rs | 28 ++++++----------------------
 src/lib.rs        |  8 ++++----
 2 files changed, 10 insertions(+), 26 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 9c60bf6..66db981 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -239,40 +239,24 @@ macro_rules! ඞ_const_primes_isqrt {
     };
 }
 
-/// Call [`primes`], [`primes_geq`] and [`primes_lt`], and automatically compute the memory requirement.
+/// Call [`primes_geq`] and [`primes_lt`], and automatically compute the memory requirement.
 ///
 /// # Example
 ///
 /// ```
-/// # use const_primes::{const_primes, Error};
-/// const PRIMES: [u32; 3] = const_primes!();
+/// # use const_primes::{primes_segment, Error};
 /// const LIMIT: u64 = 5_000_000_031;
-/// const PRIMES_GEQ: Result<[u64; 3], Error> = const_primes!(3; >= LIMIT);
-/// const PRIMES_LT: Result<[u64; 3], Error> = const_primes!(3; < LIMIT);
+/// const PRIMES_GEQ: Result<[u64; 3], Error> = primes_segment!(3; >= LIMIT);
+/// const PRIMES_LT: Result<[u64; 3], Error> = primes_segment!(3; < LIMIT);
 /// // Can also be used at runtime:
-/// let primes = const_primes!(3);
-/// let primes_geq = const_primes!(3; >= LIMIT);
+/// let primes_geq = primes_segment!(3; >= LIMIT);
 ///
-/// assert_eq!(primes, PRIMES);
-/// assert_eq!(PRIMES, [2, 3, 5]);
 /// assert_eq!(PRIMES_GEQ, primes_geq);
 /// assert_eq!(PRIMES_GEQ, Ok([5000000039, 5000000059, 5000000063]));
 /// assert_eq!(PRIMES_LT, Ok([4999999903, 4999999937, 5000000029]));
-/// # Ok::<(), Error>(())
 /// ```
 #[macro_export]
-macro_rules! const_primes {
-    () => {
-        $crate::primes()
-    };
-    ($n:expr) => {
-        $crate::primes::<
-            {
-                let mem = { $n };
-                mem
-            },
-        >()
-    };
+macro_rules! primes_segment {
     ($n:expr; < $lim:expr) => {
         $crate::primes_lt::<
             $n,
diff --git a/src/lib.rs b/src/lib.rs
index 435c197..8ad8992 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -60,11 +60,11 @@
 //! assert_eq!(P_GEQ, Ok([5_000_000_039, 5_000_000_059, 5_000_000_063]));
 //! ```
 //! If you do not wish to compute the required sieve size yourself,
-//! you can use the provided macro [`const_primes!`]:
+//! you can use the provided macro [`primes_segment!`]:
 //! ```
-//! # use const_primes::{const_primes, Error};
-//! const PRIMES_OVER_100: Result<[u64; 3], Error> = const_primes!(3; >= 100);
-//! const PRIMES_UNDER_100: Result<[u64; 3], Error> = const_primes!(3; < 100);
+//! # use const_primes::{primes_segment, Error};
+//! const PRIMES_OVER_100: Result<[u64; 3], Error> = primes_segment!(3; >= 100);
+//! const PRIMES_UNDER_100: Result<[u64; 3], Error> = primes_segment!(3; < 100);
 //!
 //! assert_eq!(PRIMES_OVER_100, Ok([101, 103, 107]));
 //! assert_eq!(PRIMES_UNDER_100, Ok([83, 89, 97]));

From eb0b14ec141a2994277e74d196c6f27dae684a09 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 7 May 2024 12:44:48 +0200
Subject: [PATCH 200/212] Add test to primes_segment

---
 src/generation.rs | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/generation.rs b/src/generation.rs
index 66db981..85b3780 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -441,4 +441,16 @@ mod test {
             assert!(is_prime(prime));
         }
     }
+
+    #[test]
+    fn check_primes_segment() {
+        const P_GEQ: Result<[u64; 10], Error> = primes_segment!(10; >= 1000);
+        const P_LT: Result<[u64; 10], Error> = primes_segment!(10; < 1000);
+
+        assert_eq!(
+            P_GEQ,
+            Ok([1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061])
+        );
+        assert_eq!(P_LT, Ok([937, 941, 947, 953, 967, 971, 977, 983, 991, 997]));
+    }
 }

From 8be89a40735f2bbd43aa8952789d98edd7ba41f0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 7 May 2024 12:47:18 +0200
Subject: [PATCH 201/212] Simplify test code

---
 src/generation.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 85b3780..9433403 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -427,11 +427,11 @@ mod test {
     fn sanity_check_primes_geq() {
         {
             const P: Result<[u64; 5], Error> = primes_geq::<5, 5>(10);
-            assert_eq!(P.unwrap().as_slice(), [11, 13, 17, 19, 23]);
+            assert_eq!(P, Ok([11, 13, 17, 19, 23]));
         }
         {
             const P: Result<[u64; 5], Error> = primes_geq::<5, 5>(0);
-            assert_eq!(P.unwrap().as_slice(), [2, 3, 5, 7, 11]);
+            assert_eq!(P, Ok([2, 3, 5, 7, 11]));
         }
         {
             const P: Result<[u64; 1], Error> = primes_geq::<1, 1>(0);

From b4599d94bcb15fdf9e3332ebe29538202359d99e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 7 May 2024 12:49:14 +0200
Subject: [PATCH 202/212] Add note about overestimating sieve size

---
 src/lib.rs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/lib.rs b/src/lib.rs
index 8ad8992..0d393c5 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -69,6 +69,8 @@
 //! assert_eq!(PRIMES_OVER_100, Ok([101, 103, 107]));
 //! assert_eq!(PRIMES_UNDER_100, Ok([83, 89, 97]));
 //! ```
+//! it may, however, overestimate the required sieve size.
+//!
 //! ```
 //! # use const_primes::sieve_lt;
 //! const N: usize = 70711;

From e13fdaeb53e92d4d7fce83877a8d11de317aa4bd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 7 May 2024 12:59:40 +0200
Subject: [PATCH 203/212] Clarify docstirng

---
 src/generation.rs | 16 +++++-----------
 src/lib.rs        | 12 ++++++------
 2 files changed, 11 insertions(+), 17 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 9433403..b59e709 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -115,9 +115,6 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 ///
 /// Fails to compile if `N` or `MEM` is 0, if `MEM < N` or if `MEM`^2 does not fit in a u64.
 ///
-/// The return array fills from the end until either it is full,
-/// or there are no more primes.
-///
 /// If you want to compute primes that are larger than some limit, take a look at [`primes_geq`].
 ///
 /// # Example
@@ -281,10 +278,7 @@ macro_rules! primes_segment {
 /// Fails to compile if `N` is 0. If `lower_limit` is less than 2 this functions assumes that it is 2,
 /// since there are no primes smaller than 2.
 ///
-/// This function will fill the output array from index 0 and stop generating primes if they exceed `N^2`.
-/// In that case the remaining elements of the output array will be 0.
-///
-/// If you want to compute primes smaller than the input, take a look at [`primes_lt`].
+/// If you want to compute primes smaller than some limit, take a look at [`primes_lt`].
 ///
 /// # Examples
 ///
@@ -384,13 +378,13 @@ pub const fn primes_geq<const N: usize, const MEM: usize>(
 /// is invalid or does not work to produce the requested primes.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum Error {
-    /// the limit was larger than `MEM^2`.
+    /// The limit was larger than `MEM^2`.
     TooLargeLimit(u64, u64),
-    /// the limit was smaller than or equal to 2.
+    /// The limit was smaller than or equal to 2.
     TooSmallLimit(u64),
-    /// encountered a number larger than `MEM`^2.
+    /// Encountered a number larger than `MEM`^2.
     SieveOverrun(u64),
-    /// ran out of primes.
+    /// Ran out of primes.
     OutOfPrimes,
 }
 
diff --git a/src/lib.rs b/src/lib.rs
index 0d393c5..6cd9b10 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -47,17 +47,17 @@
 //! ```
 //! ## Arbitrary ranges
 //!
-//! The crate provides prime generation and sieving functions with suffixes, e.g. [`primes_geq`] and [`sieve_lt`]
+//! The crate provides prime generation and sieving functions with suffixes, e.g. [`primes_lt`] and [`sieve_geq`]
 //! that can be used to work with ranges that don't start at zero. They take two generics: the number of primes
 //! to store in the binary, and the size of the sieve used during evaluation
 //! (which must be at least the ceiling of the square root of the largest encountered number).
 //! This means that one can sieve to large numbers, but doesn't need to store the entire sieve in the binary.
 //! ```
-//! use const_primes::{primes_geq, Error};
-//! // ceil(sqrt(5_000_000_063)) = 70_711
-//! const P_GEQ: Result<[u64; 3], Error> = primes_geq::<3, 70_711>(5_000_000_031);
+//! use const_primes::{primes_lt, Error, isqrt};
+//! const LIMIT: u64 = 5_000_000_031;
+//! const PRIMES_LT: Result<[u64; 3], Error> = primes_lt::<3, {isqrt(LIMIT) as usize + 1}>(LIMIT);
 //!
-//! assert_eq!(P_GEQ, Ok([5_000_000_039, 5_000_000_059, 5_000_000_063]));
+//! assert_eq!(PRIMES_LT, Ok([4_999_999_903, 4_999_999_937, 5_000_000_029]));
 //! ```
 //! If you do not wish to compute the required sieve size yourself,
 //! you can use the provided macro [`primes_segment!`]:
@@ -124,7 +124,7 @@ mod sieving;
 mod wrapper;
 
 pub use generation::{primes, primes_geq, primes_lt, Error};
-use imath::isqrt;
+pub use imath::isqrt;
 pub use miller_rabin::is_prime;
 pub use other_prime::{next_prime, previous_prime};
 pub use sieving::{sieve, sieve_geq, sieve_lt};

From 4c557e78926f7f87e3460816e069b0ebf473cef3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 7 May 2024 13:21:27 +0200
Subject: [PATCH 204/212] move 3 into const N

---
 src/lib.rs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/lib.rs b/src/lib.rs
index 6cd9b10..6c0df6c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -55,7 +55,8 @@
 //! ```
 //! use const_primes::{primes_lt, Error, isqrt};
 //! const LIMIT: u64 = 5_000_000_031;
-//! const PRIMES_LT: Result<[u64; 3], Error> = primes_lt::<3, {isqrt(LIMIT) as usize + 1}>(LIMIT);
+//! const N: usize = 3;
+//! const PRIMES_LT: Result<[u64; N], Error> = primes_lt::<N, {isqrt(LIMIT) as usize + 1}>(LIMIT);
 //!
 //! assert_eq!(PRIMES_LT, Ok([4_999_999_903, 4_999_999_937, 5_000_000_029]));
 //! ```

From 4ddcaddeab85e415d03d7a9c757276e5af78d913 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 7 May 2024 13:23:37 +0200
Subject: [PATCH 205/212] use isqrt in primes_segment!

---
 src/generation.rs | 23 ++---------------------
 1 file changed, 2 insertions(+), 21 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index b59e709..0306b59 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -217,25 +217,6 @@ pub const fn primes_lt<const N: usize, const MEM: usize>(
     Ok(primes)
 }
 
-/// Same as the private const fn isqrt in the crate.
-#[doc(hidden)]
-#[macro_export]
-macro_rules! ඞ_const_primes_isqrt {
-    ($n:ident) => {
-        if $n <= 1 {
-            $n
-        } else {
-            let mut x0 = ::core::primitive::u64::pow(2, ::core::primitive::u64::ilog2($n) / 2 + 1);
-            let mut x1 = (x0 + $n / x0) / 2;
-            while x1 < x0 {
-                x0 = x1;
-                x1 = (x0 + $n / x0) / 2;
-            }
-            x0
-        }
-    };
-}
-
 /// Call [`primes_geq`] and [`primes_lt`], and automatically compute the memory requirement.
 ///
 /// # Example
@@ -259,7 +240,7 @@ macro_rules! primes_segment {
             $n,
             {
                 let mem = { $lim };
-                $crate::ඞ_const_primes_isqrt!(mem) as ::core::primitive::usize + 1
+                $crate::isqrt(mem) as ::core::primitive::usize + 1
             },
         >($lim)
     };
@@ -268,7 +249,7 @@ macro_rules! primes_segment {
             $n,
             {
                 let mem = { $lim };
-                $crate::ඞ_const_primes_isqrt!(mem) as ::core::primitive::usize + 1 + { $n }
+                $crate::isqrt(mem) as ::core::primitive::usize + 1 + { $n }
             },
         >($lim)
     };

From 3c5c687cbcb915091f35fe2b0c9222899f581f75 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 7 May 2024 13:25:23 +0200
Subject: [PATCH 206/212] and -> or

---
 src/generation.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/generation.rs b/src/generation.rs
index 0306b59..288dea8 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -217,7 +217,7 @@ pub const fn primes_lt<const N: usize, const MEM: usize>(
     Ok(primes)
 }
 
-/// Call [`primes_geq`] and [`primes_lt`], and automatically compute the memory requirement.
+/// Call [`primes_geq`] or [`primes_lt`], and automatically compute the memory requirement.
 ///
 /// # Example
 ///

From 2185d55d5651d17bf3e8e03806e9e4459ac1bc7e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 7 May 2024 13:28:56 +0200
Subject: [PATCH 207/212] Clearer error in docstring of primes_geq

---
 src/generation.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 288dea8..d84cc4d 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -287,11 +287,11 @@ macro_rules! primes_segment {
 /// assert!(matches!(PRIMES, Err(Error::SieveOverrun(_))));
 /// ```
 ///
-/// Returns an error if `lower_limit` is larger than or equal to `MEM^2`.
+/// Also returns an error if `lower_limit` is larger than or equal to `MEM^2`:
 /// ```
 /// # use const_primes::{primes_geq, Error};
 /// const PRIMES: Result<[u64; 5], Error> = primes_geq::<5, 5>(26);
-/// assert!(PRIMES.is_err());
+/// assert!(matches!(PRIMES, Err(Error::TooLargeLimit(_, _))));
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
 pub const fn primes_geq<const N: usize, const MEM: usize>(

From 9f69a8fcc9095d01b588f840033a1987bacb569b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 7 May 2024 13:35:52 +0200
Subject: [PATCH 208/212] docstring tweaks of primes_lt

---
 src/generation.rs | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index d84cc4d..b9a214c 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -122,28 +122,30 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// Basic usage:
 /// ```
 /// # use const_primes::{primes_lt, Error};
-/// // Sieving up to 100 means the sieve needs to be of size sqrt(100) = 10.
+/// // Sieving up to 100 means the sieve needs to be of size ceil(sqrt(100)) = 10.
 /// // However, we only save the 4 largest primes in the constant.
 /// const PRIMES: [u64;4] = match primes_lt::<4, 10>(100) {Ok(ps) => ps, Err(_) => panic!()};
 /// assert_eq!(PRIMES, [79, 83, 89, 97]);
 /// ```
-/// Compute larger primes without starting from zero:
+/// Compute larger primes:
 /// ```
 /// # use const_primes::{primes_lt, Error};
+/// use const_primes::isqrt;
+/// const LIMIT: u64 = 5_000_000_030;
 /// # #[allow(long_running_const_eval)]
-/// const BIG_PRIMES: Result<[u64; 3], Error> = primes_lt::<3, 70_711>(5_000_000_030);
+/// const BIG_PRIMES: Result<[u64; 3], Error> = primes_lt::<3, {isqrt(LIMIT) as usize + 1}>(LIMIT);
 ///
-/// assert_eq!(BIG_PRIMES?, [4_999_999_903, 4_999_999_937, 5_000_000_029]);
-/// # Ok::<(), Error>(())
+/// assert_eq!(BIG_PRIMES, Ok([4_999_999_903, 4_999_999_937, 5_000_000_029]));
 /// ```
 /// # Errors
 ///
 /// If the number of primes requested, `N`, is larger than
-/// the number of primes that exists below the `lower_limit` we
+/// the number of primes that exists below the `upper_limit` we
 /// will get an error:
 /// ```
 /// # use const_primes::{primes_lt, Error};
-/// const PRIMES: Result<[u64; 9], Error> = primes_lt::<9, 9>(10);
+/// const N: usize = 9;
+/// const PRIMES: Result<[u64; N], Error> = primes_lt::<N, N>(10);
 /// assert_eq!(PRIMES, Err(Error::OutOfPrimes));
 /// ```
 ///
@@ -152,8 +154,8 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
 /// # use const_primes::{primes_lt, Error};
 /// const TOO_LARGE_LIMIT: Result<[u64; 3], Error> = primes_lt::<3, 5>(26);
 /// const TOO_SMALL_LIMIT: Result<[u64 ;1], Error> = primes_lt::<1, 1>(1);
-/// assert!(TOO_LARGE_LIMIT.is_err());
-/// assert!(TOO_SMALL_LIMIT.is_err());
+/// assert!(matches!(TOO_LARGE_LIMIT, Err(Error::TooLargeLimit(_, _))));
+/// assert!(matches!(TOO_SMALL_LIMIT, Err(Error::TooSmallLimit(_))));
 /// ```
 #[must_use = "the function only returns a new value and does not modify its input"]
 pub const fn primes_lt<const N: usize, const MEM: usize>(

From a7f8aaa6a9bf6fd4663c7c2317ec5703d8dabdad Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 7 May 2024 13:36:20 +0200
Subject: [PATCH 209/212] Force nightly for now

---
 .gitignore          | 3 +--
 rust-toolchain.toml | 2 ++
 2 files changed, 3 insertions(+), 2 deletions(-)
 create mode 100644 rust-toolchain.toml

diff --git a/.gitignore b/.gitignore
index 482c89d..2ebc5ea 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,2 @@
 /target
-/Cargo.lock
-rust-toolchain.toml
\ No newline at end of file
+/Cargo.lock
\ No newline at end of file
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
new file mode 100644
index 0000000..271800c
--- /dev/null
+++ b/rust-toolchain.toml
@@ -0,0 +1,2 @@
+[toolchain]
+channel = "nightly"
\ No newline at end of file

From 1d7b69c268a8e16cc78103a5b2de9201a2aefaf9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 7 May 2024 13:48:55 +0200
Subject: [PATCH 210/212] All hail clippy

---
 src/generation.rs | 5 ++---
 src/wrapper.rs    | 2 +-
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index b9a214c..17bf84f 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -167,11 +167,10 @@ pub const fn primes_lt<const N: usize, const MEM: usize>(
     }
     let mem_sqr = const {
         let mem64 = MEM as u64;
-        let mem_sqr = match mem64.checked_mul(mem64) {
+        match mem64.checked_mul(mem64) {
             Some(prod) => prod,
             None => panic!("`MEM`^2 must fit in a u64"),
-        };
-        mem_sqr
+        }
     };
 
     if upper_limit <= 2 {
diff --git a/src/wrapper.rs b/src/wrapper.rs
index 5fb3cd0..8781115 100644
--- a/src/wrapper.rs
+++ b/src/wrapper.rs
@@ -325,7 +325,7 @@ where
     type Output = I::Output;
     #[inline]
     fn index(&self, index: I) -> &Self::Output {
-        &self.primes.index(index)
+        self.primes.index(index)
     }
 }
 

From 64ba7c9f6b34fe5e2aaf815e5f6c58a94812b831 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 7 May 2024 13:50:00 +0200
Subject: [PATCH 211/212] Remove commented line

---
 src/generation.rs | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/generation.rs b/src/generation.rs
index 17bf84f..116cb39 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -211,7 +211,6 @@ pub const fn primes_lt<const N: usize, const MEM: usize>(
         upper_limit = smallest_found_prime;
         if upper_limit <= 2 && total_primes_found < N {
             return Err(Error::OutOfPrimes);
-            //return Err(ArraySection::new(primes, N - total_primes_found..N));
         }
     }
 

From f820bba453b336cdee5a949d3f49edfa8a21b049 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <jsorngard@gmail.com>
Date: Tue, 7 May 2024 14:01:58 +0200
Subject: [PATCH 212/212] primes_geq docstring tweaks

---
 src/generation.rs | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/src/generation.rs b/src/generation.rs
index 116cb39..f773702 100644
--- a/src/generation.rs
+++ b/src/generation.rs
@@ -266,15 +266,19 @@ macro_rules! primes_segment {
 /// Basic usage:
 /// ```
 /// use const_primes::{primes_geq, Error};
-/// const PRIMES: [u64; 5] = match primes_geq::<5, 5>(10) {Ok(ps) => ps, Err(_) => panic!()};
-/// assert_eq!(PRIMES, [11, 13, 17, 19, 23]);
+/// // Compute 5 primes larger than 40. The largest will be 59, so `MEM` needs to be at least 8.
+/// const PRIMES: [u64; 5] = match primes_geq::<5, 8>(40) {Ok(ps) => ps, Err(_) => panic!()};
+/// assert_eq!(PRIMES, [41, 43, 47, 53, 59]);
 /// ```
-/// Compute larger primes without starting from zero:
+/// Estimate the size of `MEM` using the square root of the limit (and some extra, proportional to `N`):
 /// ```
 /// # use const_primes::{primes_geq, Error};
+/// use const_primes::isqrt;
+/// const N: usize = 3;
+/// const LIMIT: u64 = 5_000_000_030;
 /// # #[allow(long_running_const_eval)]
-/// const P: Result<[u64; 3], Error> = primes_geq::<3, 71_000>(5_000_000_030);
-/// assert_eq!(P?, [5_000_000_039, 5_000_000_059, 5_000_000_063]);
+/// const PRIMES_GEQ: Result<[u64; N], Error> = primes_geq::<N, {isqrt(LIMIT) as usize + 1 + N}>(LIMIT);
+/// assert_eq!(PRIMES_GEQ, Ok([5_000_000_039, 5_000_000_059, 5_000_000_063]));
 /// # Ok::<(), Error>(())
 /// ```
 /// # Errors