From ff3159d7320fb81bfa6f1acd23a64758f6d06403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johanna=20S=C3=B6rng=C3=A5rd?= <44257381+JSorngard@users.noreply.github.com> Date: Thu, 12 Sep 2024 22:38:42 +0200 Subject: [PATCH] Add feature `rkyv` that derives the traits from the `rkyv` crate for `Primes` (#66) * Add feature `rklyv` that derives the traits from the `rkyv` crate for `Primes`. Removes the impl of the comparison and ordering traits, as all instances of the type are the same. * cargo fmt * Add `rkyv` feature docs * cargo fmt * Add test of zerocopy::AsBytes impl --- CHANGELOG.md | 8 +++ Cargo.lock | 80 ++++++++++++++++++++++++++++ Cargo.toml | 6 ++- README.md | 3 ++ src/cache/mod.rs | 132 +++++++++++++++-------------------------------- src/generate.rs | 7 +-- src/lib.rs | 14 ++++- src/sieve.rs | 7 +-- 8 files changed, 159 insertions(+), 98 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18c66ae..827c48a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,11 @@ This file contains the changes to the crate since version 0.4.8. from `core`. The crate is thus always `no_std` compatible. If the `serde` feature is enabled the crate uses the [`serde_arrays`](https://crates.io/crates/serde_arrays) crate to serialize the type, and that crate in turn uses the standard library. +- Removed the implementations of `PartialEq`, `Eq`, `PartialOrd`, and `Ord` from + `Primes`. To perform comparisons of the numbers in the struct with arrays or + slices you can call `as_array` or `as_slice`. The reson for the removal is that + every instance of `Primes` for a given `N` is the same, which means that + comparisons and orderings are pointless, since `N` is part of the type signature. These changes mean that the MSRV of the crate is increased from 1.67.1 to 1.81.0. @@ -18,6 +23,9 @@ These changes mean that the MSRV of the crate is increased from 1.67.1 to 1.81.0 - Added the `zerocopy` feature that derives the `AsBytes` trait from the [`zerocopy`](https://crates.io/crates/zerocopy) crate for the `Primes` struct. +- Added the `rkyv` feature that derives the `Serialize`, `Deserialize`, and `Archive` + traits from the [`rkyv`](https://crates.io/crates/rkyv) crate for the `Primes` + struct. ## 0.8.7 diff --git a/Cargo.lock b/Cargo.lock index 5082709..fc5db85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -105,6 +105,7 @@ version = "0.9.0" dependencies = [ "criterion", "rand", + "rkyv", "serde", "serde_arrays", "zerocopy", @@ -252,6 +253,26 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "munge" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64142d38c84badf60abf06ff9bd80ad2174306a5b11bd4706535090a30a419df" +dependencies = [ + "munge_macro", +] + +[[package]] +name = "munge_macro" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb5c1d8184f13f7d0ccbeeca0def2f9a181bce2624302793005f5ca8aa62e5e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -310,6 +331,26 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "ptr_meta" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9e76f66d3f9606f44e45598d155cb13ecf09f4a28199e48daf8c8fc937ea90" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "quote" version = "1.0.37" @@ -319,6 +360,15 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rancor" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf5f7161924b9d1cea0e4cabc97c372cea92b5f927fc13c6bca67157a0ad947" +dependencies = [ + "ptr_meta", +] + [[package]] name = "rand" version = "0.8.5" @@ -383,6 +433,36 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +[[package]] +name = "rend" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc8d57aa48e8477046d7d6296d920a1f50bbbaf45047ec46c52f6d6cccea7ef7" + +[[package]] +name = "rkyv" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a1dfb7c03271e31aad881e521cfe25bda0206ee94b1af152957f4f49e25ee23" +dependencies = [ + "munge", + "ptr_meta", + "rancor", + "rend", + "rkyv_derive", +] + +[[package]] +name = "rkyv_derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa3ca4a30c576aeb76aea84370da286f74d12d32029da8caec3d53b5a36a7539" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "ryu" version = "1.0.18" diff --git a/Cargo.toml b/Cargo.toml index f27efbb..0793aa3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,19 +13,23 @@ repository = "https://github.com/JSorngard/const-primes/" serde = { version = "1.0", default-features = false, features = ["derive"], optional = true } serde_arrays = { version = "0.1.0", optional = true } zerocopy = { version = "0.7", default-features = false, features = ["derive"], optional = true } +rkyv = { version = "0.8.1", default-features = false, optional = true } [dev-dependencies] criterion = { version = "0.5", features = ["html_reports"] } rand = { version = "0.8", default-features = false, features = ["small_rng"] } [features] -# Derives the `Serialize` and `Deserialize` traits from [`serde`](https://crates.io/crates/serde) for the `Primes` struct, as well as a few others. +# Derives the `Serialize` and `Deserialize` traits from the [`serde`](https://crates.io/crates/serde) crate for the `Primes` struct, as well as a few others. # Uses the [`serde_arrays`](https://crates.io/crates/serde_arrays) crate to do this, and that crate uses the standard library. serde = ["dep:serde", "dep:serde_arrays"] # Derives the `AsBytes` trait from the [`zerocopy`](https://crates.io/crates/zerocopy) crate for the `Primes` struct. zerocopy = ["dep:zerocopy"] +# Derives the `Serialize`, `Deserialize`, and `Archive` traits from the [`rkyv`](https://crates.io/crates/rkyv) crate for the `Primes` struct. +rkyv = ["dep:rkyv"] + [package.metadata.docs.rs] # Document all features. all-features = true diff --git a/README.md b/README.md index 230ddb7..efb3adf 100644 --- a/README.md +++ b/README.md @@ -125,6 +125,9 @@ crate to do this, and that crate uses the standard library. `zerocopy`: derives the `AsBytes` trait from [`zerocopy`](https://crates.io/crates/zerocopy) for the `Primes` struct. +`rkyv`: derives the `Serialize`, `Deserialize`, and `Archive` traits from the +[`rkyv`](https://crates.io/crates/rkyv) crate for the [`Primes`] struct. + ## License Licensed under either of diff --git a/src/cache/mod.rs b/src/cache/mod.rs index 09a5315..8488709 100644 --- a/src/cache/mod.rs +++ b/src/cache/mod.rs @@ -22,14 +22,17 @@ use serde::{Deserialize, Serialize}; /// /// # Examples /// -/// Basic usage +/// Basic usage: +/// /// ``` /// # use const_primes::Primes; /// const PRIMES: Primes<3> = Primes::new(); /// assert_eq!(PRIMES[2], 5); -/// assert_eq!(PRIMES, [2, 3, 5]); +/// assert_eq!(PRIMES.as_array(), &[2, 3, 5]); /// ``` -/// Reuse sieved primes for other computations +/// +/// Reuse sieved primes for other computations: +/// /// ``` /// # use const_primes::Primes; /// const CACHE: Primes<100> = Primes::new(); @@ -43,9 +46,13 @@ use serde::{Deserialize, Serialize}; /// assert_eq!(CACHE.is_prime(1000), None); /// assert_eq!(CACHE.count_primes_leq(1000), None); /// ``` -#[derive(Debug, Clone, Copy, Eq, Ord, Hash)] +#[derive(Debug, Clone, Copy, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "zerocopy", derive(zerocopy::AsBytes))] +#[cfg_attr( + feature = "rkyv", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) +)] #[repr(transparent)] pub struct Primes( #[cfg_attr(feature = "serde", serde(with = "serde_arrays"))] [Underlying; N], @@ -58,31 +65,38 @@ impl Primes { /// /// # Examples /// - /// Basic usage + /// Basic usage: + /// /// ``` /// # use const_primes::Primes; /// const PRIMES: Primes<3> = Primes::new(); - /// assert_eq!(PRIMES, [2, 3, 5]); + /// assert_eq!(PRIMES.as_array(), &[2, 3, 5]); /// ``` + /// /// Determine `N` through type inference + /// /// ``` /// # use const_primes::Primes; - /// assert_eq!(Primes::new(), [2, 3, 5, 7, 11]); + /// assert_eq!(Primes::new().as_array(), &[2, 3, 5, 7, 11]); /// ``` + /// /// Specify `N` manually + /// /// ``` /// # use const_primes::Primes; /// let primes = Primes::<5>::new(); - /// assert_eq!(primes, [2, 3, 5, 7, 11]); + /// assert_eq!(primes.as_array(), &[2, 3, 5, 7, 11]); /// ``` /// /// # Panics /// /// Panics if `N` is 0, which is a compile error in const contexts: + /// /// ```compile_fail /// # use const_primes::Primes; /// const NO_PRIMES: Primes<0> = Primes::new(); /// ``` + /// /// This is always a compile error instead of a panic if the `const_assert` feature is enabled. /// /// If any of the primes overflow a `u32` it will panic in const contexts or debug mode. @@ -98,7 +112,8 @@ impl Primes { /// /// # Example /// - /// Basic usage + /// Basic usage: + /// /// ``` /// # use const_primes::Primes; /// const PRIMES: Primes<100> = Primes::new(); @@ -131,6 +146,7 @@ impl Primes { /// # Example /// /// Basic usage: + /// /// ``` /// # use const_primes::Primes; /// const CACHE: Primes<100> = Primes::new(); @@ -169,6 +185,7 @@ impl Primes { /// # Examples /// /// Basic usage: + /// /// ``` /// # use const_primes::Primes; /// // Contains the primes [2, 3, 5] @@ -176,14 +193,18 @@ impl Primes { /// /// assert_eq!(CACHE.prime_factorization(15).collect::>(), &[(3, 1), (5, 1)]); /// ``` + /// /// The second element of the returned tuples is the multiplicity of the prime in the number: + /// /// ``` /// # use const_primes::Primes; /// # const CACHE: Primes<3> = Primes::new(); /// // 1024 = 2^10 /// assert_eq!(CACHE.prime_factorization(1024).next(), Some((2, 10))); /// ``` + /// /// 294 has 7 as a prime factor, but 7 is not in the cache: + /// /// ``` /// # use const_primes::Primes; /// # const CACHE: Primes<3> = Primes::new(); @@ -220,7 +241,9 @@ impl Primes { /// assert_eq!(CACHE.prime_factors(3*5).collect::>(), &[3, 5]); /// assert_eq!(CACHE.prime_factors(2*2*2*2*3).collect::>(), &[2, 3]); /// ``` + /// /// 294 has 7 as a prime factor, but 7 is not in the cache: + /// /// ``` /// # use const_primes::Primes; /// # const CACHE: Primes<3> = Primes::new(); @@ -314,6 +337,7 @@ impl Primes { /// # Example /// /// Basic usage: + /// /// ``` /// # use const_primes::Primes; /// // [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] @@ -353,7 +377,8 @@ impl Primes { /// /// # Example /// - /// Basic usage + /// Basic usage: + /// /// ``` /// # use const_primes::Primes; /// const PRIMES: [u32; 5] = Primes::new().into_array(); @@ -384,6 +409,7 @@ impl Primes { /// # Example /// /// Basic usage: + /// /// ``` /// # use const_primes::Primes; /// const PRIMES: Primes<10> = Primes::new(); @@ -405,7 +431,8 @@ impl Primes { /// /// # Example /// - /// Basic usage + /// Basic usage: + /// /// ``` /// # use const_primes::Primes; /// const PRIMES: Primes<5> = Primes::new(); @@ -426,7 +453,8 @@ impl Primes { /// /// # Example /// - /// Basic usage + /// Basic usage: + /// /// ``` /// # use const_primes::Primes; /// const PRIMES: Primes<5> = Primes::new(); @@ -445,6 +473,8 @@ impl Primes { /// /// # Example /// + /// Basic usage: + /// /// ``` /// # use const_primes::Primes; /// const PRIMES: Primes<5> = Primes::new(); @@ -484,6 +514,7 @@ impl Primes { /// The number 2450 is equal to 2\*5\*5\*7\*7. /// If the cache does not contain 7 the function runs out of primes after 5, /// and can not finish the computation: + /// /// ``` /// # use const_primes::{Primes, cache::PartialTotient}; /// // Contains the primes [2, 3, 5] @@ -610,64 +641,6 @@ impl<'a, const N: usize> IntoIterator for &'a Primes { // endregion: IntoIterator -// region: PartialEq - -impl> PartialEq for Primes { - #[inline] - fn eq(&self, other: &T) -> bool { - other == &self.0 - } -} - -impl PartialEq> for [Underlying; N] { - #[inline] - fn eq(&self, other: &Primes) -> bool { - self == &other.0 - } -} - -impl PartialEq> for &[Underlying] { - #[inline] - fn eq(&self, other: &Primes) -> bool { - self == &other.0 - } -} - -impl PartialEq<[Underlying]> for Primes { - #[inline] - fn eq(&self, other: &[Underlying]) -> bool { - self.0 == other - } -} - -// endregion: PartialEq - -// region: PartialOrd - -use core::cmp::Ordering; -impl> PartialOrd for Primes { - #[inline] - fn partial_cmp(&self, other: &T) -> Option { - other.partial_cmp(&self.0) - } -} - -impl PartialOrd> for [Underlying; N] { - #[inline] - fn partial_cmp(&self, other: &Primes) -> Option { - other.0.partial_cmp(self) - } -} - -impl PartialOrd> for &[Underlying] { - #[inline] - fn partial_cmp(&self, other: &Primes) -> Option { - other.0.as_slice().partial_cmp(self) - } -} - -// endregion: PartialOrd - // endregion: Primes #[cfg(test)] @@ -678,30 +651,11 @@ mod test { // region: TraitImpls - #[test] - fn partial_eq_impl() { - const P1: Primes<3> = Primes::new(); - macro_rules! partial_eq_check { - ($($t:ident),+) => { - $( - assert_eq!(P1, $t); - assert_eq!(&P1, &$t); - assert_eq!(&$t, &P1); - assert_eq!($t, P1); - )+ - }; - } - let v = [2, 3, 5]; - let s = v.as_slice(); - partial_eq_check!(v, s); - } - #[test] fn verify_impl_from_primes_traits() { const N: usize = 10; const P: Primes = Primes::new(); let p: [Underlying; N] = P.into(); - assert_eq!(P, p); assert_eq!(p, P.as_ref()); assert_eq!( P.as_array(), diff --git a/src/generate.rs b/src/generate.rs index de49df6..35b45d5 100644 --- a/src/generate.rs +++ b/src/generate.rs @@ -432,11 +432,12 @@ pub const fn primes_geq( /// The error returned by [`primes_lt`] and [`primes_geq`] if the input /// is invalid or does not work to produce the requested primes. -/// -/// Only implements the [`Error`](core::error::Error) trait -/// if the `std` feature is enabled. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr( + feature = "rkyv", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) +)] pub enum GenerationError { /// The limit was larger than or equal to `MEM^2`. TooSmallSieveSize, diff --git a/src/lib.rs b/src/lib.rs index 6433e8b..1b8f871 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,10 +105,12 @@ //! //! # Features //! -//! `serde`: derives the [`Serialize`](serde::Serialize) and [`Deserialize`](serde::Deserialize) traits from [`serde`] for the [`Primes`] struct, as well as a few others. +//! `serde`: derives the [`Serialize`](serde::Serialize) and [`Deserialize`](serde::Deserialize) traits from the [`serde`] crte for the [`Primes`] struct, as well as a few others. //! Uses the [`serde_arrays`](https://docs.rs/serde_arrays/0.1.0) crate to do this, and that crate uses the standard library. //! -//! `zerocopy`: derives the [`AsBytes`](zerocopy::AsBytes) trait from [`zerocopy`] for the [`Primes`] struct. +//! `zerocopy`: derives the [`AsBytes`](zerocopy::AsBytes) trait from the [`zerocopy`] crate for the [`Primes`] struct. +//! +//! `rkyv`: derives the [`Serialize`](rkyv::Serialize), [`Deserialize`](rkyv::Deserialize), and [`Archive`](rkyv::Archive) traits from the [`rkyv`] crate for the [`Primes`] struct. #![forbid(unsafe_code)] #![no_std] @@ -322,6 +324,14 @@ mod test { } } + #[cfg(feature = "zerocopy")] + #[test] + fn test_as_bytes() { + use zerocopy::AsBytes; + const P: Primes<3> = Primes::new(); + assert_eq!(P.as_bytes(), &[2, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0]); + } + // region: test data #[rustfmt::skip] diff --git a/src/sieve.rs b/src/sieve.rs index 0353676..26eddfc 100644 --- a/src/sieve.rs +++ b/src/sieve.rs @@ -249,11 +249,12 @@ pub const fn sieve() -> [bool; N] { /// The error returned by [`sieve_lt`] and [`sieve_geq`] if the input /// is invalid or does not work to sieve the requested range. -/// -/// Only implements the [`Error`](core::error::Error) trait -/// if the `std` feature is enabled. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr( + feature = "rkyv", + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) +)] pub enum SieveError { /// The limit was less than or equal to `N` (for `sieve_lt`). TooSmallLimit,