use crate::{
error::{IntegerErrors, NumeraErrors, NumeraResult},
number::integer::prime::all::{is_prime, PRIMES_U16, PRIMES_U8},
};
use core::fmt;
#[cfg(not(feature = "std"))]
use crate::number::integer::prime::fns::nth_prime;
#[cfg(feature = "std")]
use {
crate::number::integer::prime::fns::{is_prime_sieve, nth_prime_sieve},
devela::convert::az::CheckedAs,
primal_sieve::Sieve,
};
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Prime8(pub(crate) u8);
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Prime16(pub(crate) u16);
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Prime32(pub(crate) u32);
#[cfg_attr(
not(feature = "std"),
doc = "This is calculated using the *prime number theorem* formula."
)]
#[cfg_attr(
feature = "std",
doc = "This is calculated using the [*prime number theorem*][0]
<span class='stab portability'
title='Available on crate feature `std` only'><code>std</code></span>
formula."
)]
#[cfg_attr(feature = "std", doc = "\n\n[0]: crate::all::prime_number_theorem")]
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Prime64(pub(crate) u64);
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Prime128(pub(crate) u128);
impl fmt::Display for Prime8 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Display for Prime16 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Display for Prime32 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Display for Prime64 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Display for Prime128 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Debug for Prime8 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "P8({})", self.0)
}
}
impl fmt::Debug for Prime16 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "P16({})", self.0)
}
}
impl fmt::Debug for Prime32 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "P32({})", self.0)
}
}
impl fmt::Debug for Prime64 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "P64({})", self.0)
}
}
impl fmt::Debug for Prime128 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "P128({})", self.0)
}
}
impl Prime8 {
#[inline]
pub fn new(value: u8) -> NumeraResult<Self> {
if is_prime(value.into()) {
Ok(Prime8(value))
} else {
Err(IntegerErrors::NotPrime.into())
}
}
#[inline]
pub const fn new_nth(nth: u8) -> NumeraResult<Self> {
match nth {
0..=53 => Ok(Self(PRIMES_U8[nth as usize])),
_ => Err(NumeraErrors::Integer(IntegerErrors::Overflow)),
}
}
#[inline]
#[cfg(all(debug_assertions, not(feature = "safe")))]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "not(safe)")))]
pub unsafe fn new_unchecked(value: u8) -> Self {
debug_assert![is_prime(value.into())];
Self(value)
}
#[inline]
#[cfg(all(not(debug_assertions), not(feature = "safe")))]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "not(safe)")))]
pub const unsafe fn new_unchecked(value: u8) -> Self {
Self(value)
}
pub fn pi(&self) -> usize {
for (i, &p) in PRIMES_U8.iter().enumerate() {
if p == self.0 {
return i + 1;
}
}
return 54;
}
}
impl Prime16 {
#[inline]
pub fn new(value: u16) -> NumeraResult<Self> {
if is_prime(value.into()) {
Ok(Prime16(value))
} else {
Err(IntegerErrors::NotPrime.into())
}
}
#[inline]
pub const fn new_nth(nth: u16) -> NumeraResult<Self> {
match nth {
#[allow(clippy::cast_possible_truncation)]
0..=53 => Ok(Self(PRIMES_U8[nth as usize] as u16)),
54..=6541 => Ok(Self(PRIMES_U16[(nth - 54) as usize])),
_ => Err(NumeraErrors::Integer(IntegerErrors::Overflow)),
}
}
#[inline]
#[cfg(all(debug_assertions, not(feature = "safe")))]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "not(safe)")))]
pub unsafe fn new_unchecked(value: u16) -> Self {
debug_assert![is_prime(value.into())];
Self(value)
}
#[inline]
#[cfg(all(not(debug_assertions), not(feature = "safe")))]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "not(safe)")))]
pub const unsafe fn new_unchecked(value: u16) -> Self {
Self(value)
}
pub fn pi(&self) -> usize {
if self.0 < u16::from(u8::MAX) {
for (i, &p) in PRIMES_U8.iter().enumerate() {
if u16::from(p) == self.0 {
return i + 1;
}
}
} else {
for (i, &p) in PRIMES_U16.iter().enumerate() {
if p == self.0 {
return i + 55;
}
}
}
return 6_542;
}
}
impl Prime32 {
#[inline]
#[cfg(not(feature = "std"))]
pub fn new(value: u32) -> NumeraResult<Self> {
if is_prime(value) {
Ok(Prime32(value))
} else {
Err(IntegerErrors::NotPrime.into())
}
}
#[inline]
#[cfg(feature = "std")]
pub fn new(value: u32) -> NumeraResult<Self> {
if is_prime_sieve(value.checked_as::<usize>().ok_or(IntegerErrors::Overflow)?) {
Ok(Prime32(value))
} else {
Err(IntegerErrors::NotPrime.into())
}
}
#[inline]
pub fn new_nth(nth: u32) -> NumeraResult<Self> {
match nth {
#[allow(clippy::cast_possible_truncation)]
0..=53 => Ok(Self(u32::from(PRIMES_U8[nth as usize]))),
#[allow(clippy::cast_possible_truncation)]
54..=6_541 => Ok(Self(u32::from(PRIMES_U16[nth as usize - 54]))),
6_542..=203_280_220 => {
#[cfg(feature = "std")]
{
use crate::all::ConstUpperBounded;
#[allow(clippy::cast_possible_truncation)]
return Ok(Self(
nth_prime_sieve(nth as usize, u32::from(Prime32::MAX) as usize) as u32,
));
}
#[cfg(not(feature = "std"))]
return Ok(Self(nth_prime(nth)));
}
_ => Err(NumeraErrors::Integer(IntegerErrors::Overflow)),
}
}
#[inline]
#[cfg(all(debug_assertions, not(feature = "safe"), feature = "std"))]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "not(safe)")))]
pub unsafe fn new_unchecked(value: u32) -> Self {
debug_assert![is_prime_sieve(value.checked_as::<usize>().unwrap())];
Self(value)
}
#[inline]
#[cfg(all(not(debug_assertions), not(feature = "safe")))]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "not(safe)")))]
pub const unsafe fn new_unchecked(value: u32) -> Self {
Self(value)
}
#[cfg(feature = "std")]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "std")))]
pub fn pi(&self) -> usize {
if self.0 < u32::from(u8::MAX) {
for (i, &p) in PRIMES_U8.iter().enumerate() {
if u32::from(p) == self.0 {
return i + 1;
}
}
} else if self.0 < u32::from(u16::MAX) {
for (i, &p) in PRIMES_U16.iter().enumerate() {
if u32::from(p) == self.0 {
return i + 55;
}
}
} else {
#[cfg(feature = "std")]
{
let sieve = Sieve::new(self.0 as usize);
return sieve.prime_pi(self.0 as usize);
}
#[cfg(not(feature = "std"))]
{
nth_prime(core::num::NonZeroU32::new(self.0).unwrap())
}
}
return 203_280_221;
}
}
impl Prime64 {
#[inline]
#[cfg(feature = "std")]
pub fn new(value: u64) -> NumeraResult<Self> {
if is_prime_sieve(value.checked_as::<usize>().ok_or(IntegerErrors::Overflow)?) {
Ok(Prime64(value))
} else {
Err(IntegerErrors::NotPrime.into())
}
}
#[inline]
pub fn new_nth(nth: u64) -> NumeraResult<Self> {
match nth {
#[allow(clippy::cast_possible_truncation)]
0..=53 => Ok(Self(u64::from(PRIMES_U8[(nth as u8) as usize]))),
#[allow(clippy::cast_possible_truncation)]
54..=6_541 => Ok(Self(u64::from(PRIMES_U16[(nth as u16 - 54) as usize]))),
6_542..=203_280_220 => {
#[cfg(feature = "std")]
{
use crate::all::ConstUpperBounded;
#[allow(clippy::cast_possible_truncation)]
return Ok(Self(
nth_prime_sieve(nth as usize, u32::from(Prime32::MAX) as usize) as u64,
));
}
#[cfg(not(feature = "std"))]
#[allow(clippy::cast_possible_truncation)]
return Ok(Self(u64::from(nth_prime(nth as u32))));
}
203_280_221..=425_656_284_035_217_742 => {
Err(NumeraErrors::NotImplemented) }
_ => Err(NumeraErrors::Integer(IntegerErrors::Overflow)),
}
}
#[inline]
#[cfg(all(debug_assertions, not(feature = "safe"), feature = "std"))]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "not(safe)")))]
pub unsafe fn new_unchecked(value: u64) -> Self {
debug_assert![is_prime_sieve(value.checked_as::<usize>().unwrap())];
Self(value)
}
#[inline]
#[cfg(all(not(debug_assertions), not(feature = "safe")))]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "not(safe)")))]
pub const unsafe fn new_unchecked(value: u64) -> Self {
Self(value)
}
#[cfg(feature = "std")]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "std")))]
pub fn pi(&self) -> usize {
if self.0 < u64::from(u8::MAX) {
for (i, &p) in PRIMES_U8.iter().enumerate() {
if u64::from(p) == self.0 {
return i + 1;
}
}
} else if self.0 < u64::from(u16::MAX) {
for (i, &p) in PRIMES_U16.iter().enumerate() {
if u64::from(p) == self.0 {
return i + 55;
}
}
} else {
#[cfg(feature = "std")]
{
let value = usize::try_from(self.0).expect("usize overflow");
let sieve = Sieve::new(value);
return sieve.prime_pi(value);
}
#[cfg(not(feature = "std"))]
{
nth_prime(core::num::NonZeroU64::new(self.0).unwrap())
}
}
#[allow(overflowing_literals)] return 425_656_284_035_217_743;
}
}
impl Prime128 {
#[inline]
#[cfg(feature = "std")]
pub fn new(value: u128) -> NumeraResult<Self> {
if is_prime_sieve(value.checked_as::<usize>().ok_or(IntegerErrors::Overflow)?) {
Ok(Prime128(value))
} else {
Err(IntegerErrors::NotPrime.into())
}
}
#[inline]
#[allow(clippy::match_same_arms)]
pub fn new_nth(nth: u128) -> NumeraResult<Self> {
match nth {
#[allow(clippy::cast_possible_truncation)]
0..=53 => Ok(Self(u128::from(PRIMES_U8[(nth as u8) as usize]))),
#[allow(clippy::cast_possible_truncation)]
54..=6_541 => Ok(Self(u128::from(PRIMES_U16[(nth as u16 - 54) as usize]))),
6_542..=203_280_220 => {
#[cfg(feature = "std")]
{
use crate::all::ConstUpperBounded;
return Ok(Self(
nth_prime_sieve(nth as usize, u32::from(Prime32::MAX) as usize) as u128,
));
}
#[cfg(not(feature = "std"))]
#[allow(clippy::cast_possible_truncation)]
return Ok(Self(u128::from(nth_prime(nth as u32))));
}
203_280_221..=425_656_284_035_217_742 => {
Err(NumeraErrors::NotImplemented) }
425_656_284_035_217_743..=3_835_341_275_459_348_115_779_911_081_237_938_175 => {
Err(NumeraErrors::NotImplemented) }
_ => Err(NumeraErrors::Integer(IntegerErrors::Overflow)),
}
}
#[inline]
#[cfg(all(debug_assertions, not(feature = "safe"), feature = "std"))]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "not(safe)")))]
pub unsafe fn new_unchecked(value: u128) -> Self {
debug_assert![is_prime_sieve(value.checked_as::<usize>().unwrap())];
Self(value)
}
#[inline]
#[cfg(all(not(debug_assertions), not(feature = "safe")))]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "not(safe)")))]
pub const unsafe fn new_unchecked(value: u128) -> Self {
Self(value)
}
#[cfg(feature = "std")]
#[cfg_attr(feature = "nightly", doc(cfg(feature = "std")))]
pub fn pi(&self) -> usize {
if self.0 < u128::from(u8::MAX) {
for (i, &p) in PRIMES_U8.iter().enumerate() {
if u128::from(p) == self.0 {
return i + 1;
}
}
} else if self.0 < u128::from(u16::MAX) {
for (i, &p) in PRIMES_U16.iter().enumerate() {
if u128::from(p) == self.0 {
return i + 55;
}
}
} else {
#[cfg(feature = "std")]
{
let sieve = Sieve::new(self.0 as usize);
return sieve.prime_pi(self.0 as usize);
}
#[cfg(not(feature = "std"))]
{
nth_prime(core::num::NonZeroU128::new(self.0).unwrap()) }
}
return usize::MAX;
}
}