Skip to content

Commit

Permalink
Convert static assertions to panics
Browse files Browse the repository at this point in the history
  • Loading branch information
JSorngard committed May 8, 2024
1 parent 6a39862 commit c6b4395
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 39 deletions.
27 changes: 14 additions & 13 deletions src/generation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,18 @@ use crate::{sieve, sieving::sieve_segment, Underlying};
/// const PRIMES: [u32; 10] = primes();
/// assert_eq!(PRIMES, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]);
/// ```
/// Fails to compile if `N = 0`:
///
/// # Panics
///
/// Panics if `N = 0`. In const contexts, this is a compile error:
/// ```compile_fail
/// # use const_primes::primes;
/// let primes: [u32; 0] = primes();
/// const PRIMES: [u32; 0] = primes();
/// ```
///
#[must_use = "the function only returns a new value"]
pub const fn primes<const N: usize>() -> [Underlying; N] {
const { assert!(N > 0, "`N` must be at least 1") }
assert!(N > 0, "`N` must be at least 1");

if N == 1 {
return [2; N];
Expand Down Expand Up @@ -166,11 +169,10 @@ pub const fn primes<const N: usize>() -> [Underlying; N] {
pub const fn primes_lt<const N: usize, const MEM: usize>(
mut upper_limit: u64,
) -> Result<[u64; N], GenerationError> {
const {
assert!(N > 0, "`N` must be at least 1");
assert!(MEM >= N, "`MEM` must be at least as large as `N`");
}
let mem_sqr = const {
assert!(N > 0, "`N` must be at least 1");
assert!(MEM >= N, "`MEM` must be at least as large as `N`");

let mem_sqr = {
let mem64 = MEM as u64;
match mem64.checked_mul(mem64) {
Some(prod) => prod,
Expand Down Expand Up @@ -321,11 +323,10 @@ macro_rules! primes_segment {
pub const fn primes_geq<const N: usize, const MEM: usize>(
lower_limit: u64,
) -> Result<[u64; N], GenerationError> {
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_sqr) = 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_sqr) = {
let mem64 = MEM as u64;
let Some(mem_sqr) = mem64.checked_mul(mem64) else {
panic!("`MEM`^2 must fit in a `u64`")
Expand Down
8 changes: 6 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,20 +123,24 @@ pub use sieving::{sieve, sieve_geq, sieve_lt, SieveError};
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.
///
/// # Example
///
/// Basic usage
/// ```
/// # use const_primes::prime_counts;
/// const COUNTS: [usize; 10] = prime_counts();
/// assert_eq!(COUNTS, [0, 0, 1, 2, 2, 3, 3, 4, 4, 4]);
/// ```
///
/// # Panics
///
/// Panics if `N` is 0. In const contexts this is a compile error.
#[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") }
assert!(N > 0, "`N` must be at least 1");
let mut counts = [0; N];
if N <= 2 {
return counts;
Expand Down
44 changes: 27 additions & 17 deletions src/sieving.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ 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`. Fails to compile if `N` is 0.
///
/// # Panics
///
/// Panics 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],
upper_limit: u64,
) -> [bool; N] {
const { assert!(N > 0, "`N` must be at least 1") }
assert!(N > 0, "`N` must be at least 1");

let mut segment_sieve = [true; N];

Expand Down Expand Up @@ -55,8 +59,6 @@ pub(crate) const fn sieve_segment<const N: usize>(
/// `MEM` must be large enough for the sieve to be able to determine the prime status of all numbers in the requested range,
/// that is: `MEM`^2 must be at least as large as `upper_limit`.
///
/// Fails to compile if `N` is 0, or if `MEM` is smaller than `N`.
///
/// If you just want the prime status of the first `N` integers, see [`sieve`], and if you want the prime status of
/// the integers above some number, see [`sieve_geq`].
///
Expand Down Expand Up @@ -110,16 +112,19 @@ pub(crate) const fn sieve_segment<const N: usize>(
/// const PS: Result<[bool; 5], SieveError> = sieve_lt::<5, 5>(4);
/// assert_eq!(PS, Err(SieveError::TooSmallLimit));
/// ```
///
/// # Panics
///
/// Panics if `N` is 0, if `MEM` is smaller than `N`, or if `MEM`^2 does not fit in a `u64`.
/// In const contexts this is a compile error.
#[must_use = "the function only returns a new value and does not modify its input"]
pub const fn sieve_lt<const N: usize, const MEM: usize>(
upper_limit: u64,
) -> Result<[bool; N], SieveError> {
const {
assert!(N > 0, "`N` must be at least 1");
assert!(MEM >= N, "`MEM` must be at least as large as `N`");
}
assert!(N > 0, "`N` must be at least 1");
assert!(MEM >= N, "`MEM` must be at least as large as `N`");

let mem_sqr = const {
let mem_sqr = {
let mem64 = MEM as u64;
match mem64.checked_mul(mem64) {
Some(prod) => prod,
Expand Down Expand Up @@ -158,7 +163,6 @@ pub const fn sieve_lt<const N: usize, const MEM: usize>(
}

/// 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.
///
/// # Example
///
Expand All @@ -168,9 +172,13 @@ pub const fn sieve_lt<const N: usize, const MEM: usize>(
/// // 0 1 2 3 4 5 6 7 8 9
/// assert_eq!(PRIMALITY, [false, false, true, true, false, true, false, true, false, false]);
/// ```
///
/// # Panics
///
/// Panics if `N` is 0. In const contexts this is a compile error.
#[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") }
assert!(N > 0, "`N` must be at least 1");

let mut sieve = [true; N];
if N > 0 {
Expand Down Expand Up @@ -236,8 +244,6 @@ impl std::error::Error for SieveError {}
/// `MEM` must be large enough for the sieve to be able to determine the prime status of all numbers in the requested range,
/// that is `MEM`^2 must be larger than `lower_limit + N`.
///
/// Fails to compile if `N` is 0, or if `MEM` is smaller than `N`.
///
/// If you just want the prime status of the first N integers, see [`sieve`], and if you want the
/// prime status of the integers below some number, see [`sieve_lt`].
///
Expand Down Expand Up @@ -280,15 +286,19 @@ impl std::error::Error for SieveError {}
/// assert_eq!(P1, Err(SieveError::TooLargeTotal));
/// assert_eq!(P2, Err(SieveError::TotalDoesntFitU64));
/// ```
///
/// # Panics
///
/// Panics if `N` is 0, if `MEM` is smaller than `N`, or if `MEM`^2 does not fit in a `u64`.
/// In const contexts this is a compile error.
#[must_use = "the function only returns a new value and does not modify its input"]
pub const fn sieve_geq<const N: usize, const MEM: usize>(
lower_limit: u64,
) -> Result<[bool; N], SieveError> {
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_sqr) = 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_sqr) = {
let mem64 = MEM as u64;
match mem64.checked_mul(mem64) {
Some(prod) => (mem64, prod),
Expand Down
14 changes: 7 additions & 7 deletions src/wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,18 @@ impl<const N: usize> Primes<N> {
/// assert_eq!(primes, [2, 3, 5, 7, 11]);
/// ```
///
/// Fails to compile if `N` is zero.
/// # Panics
///
/// Panics if `N` is zero. In const contexts this is a compile error.
/// ```compile_fail
/// # 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 {
const { assert!(N > 0, "`N` must be at least 1") }
assert!(N > 0, "`N` must be at least 1");
Self { primes: primes() }
}

Expand Down Expand Up @@ -310,11 +310,11 @@ impl<const N: usize> Primes<N> {
}
}

/// This statically asserts that N > 0.
/// Panics if `N` is 0.
impl<const N: usize> Default for Primes<N> {
fn default() -> Self {
const { assert!(N > 0, "`N` must be at least 1") }
Self::new()
assert!(N > 0, "`N` must be at least 1");
Self { primes: primes() }

Check warning on line 317 in src/wrapper.rs

View check run for this annotation

Codecov / codecov/patch

src/wrapper.rs#L316-L317

Added lines #L316 - L317 were not covered by tests
}
}

Expand Down

0 comments on commit c6b4395

Please sign in to comment.