zfc

Library for sets according to ZFC.
git clone https://git.philomathiclife.com/repos/zfc
Log | Files | Refs | README

commit 4731e52ae651bf5404fe0f24597f763de7664ed5
parent 177519dba61a589d3970c1ccdb4dfd0d2a79ad3f
Author: Zack Newman <zack@philomathiclife.com>
Date:   Fri,  6 Sep 2024 10:16:08 -0600

update deps. address lints

Diffstat:
MCargo.toml | 33+++++++++++++--------------------
MREADME.md | 34+++++++++++++++++++++++-----------
Dbuild.rs | 12------------
Msrc/lib.rs | 128++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
4 files changed, 114 insertions(+), 93 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Zack Newman <zack@philomathiclife.com>"] categories = ["mathematics", "no-std"] -description = "Trait that represents a set according to Zermelo–Fraenkel set theory with the axiom of choice (ZFC)" +description = "Trait that represents a set according to Zermelo–Fraenkel set theory with the axiom of choice (ZFC)." documentation = "https://docs.rs/zfc/latest/zfc/" edition = "2021" keywords = ["math", "set", "zfc"] @@ -9,29 +9,22 @@ license = "MIT OR Apache-2.0" name = "zfc" readme = "README.md" repository = "https://git.philomathiclife.com/repos/zfc/" -version = "0.3.2" +rust-version = "1.81.0" +version = "0.4.0" -[lib] -name = "zfc" -path = "src/lib.rs" - -[build-dependencies] -rustc_version = "0.4.0" - -[features] -std = [] - -[dependencies] -num-bigint = { version = "0.4.4", default-features = false } +[badges] +maintenance = { status = "actively-developed" } [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] -[badges] -maintenance = { status = "actively-developed" } +[dependencies] +num-bigint = { version = "0.4.6", default-features = false } -[profile.release] -lto = true -panic = 'abort' -strip = true + +### FEATURES ################################################################# + +[features] +# Provide Set implementation for HashSet. +std = [] diff --git a/README.md b/README.md @@ -1,11 +1,23 @@ -# `zfc` - -`zfc` is a library for sets according to [Zermelo–Fraenkel set theory with the axiom of choice (ZFC)](https://en.wikipedia.org/wiki/Zermelo%E2%80%93Fraenkel_set_theory). - -## Status - -This package will be actively maintained until it is deemed “feature complete”. - -The crates are only tested on the `x86_64-unknown-linux-gnu` and `x86_64-unknown-openbsd` targets, but -they should work on any [Tier 1 with Host Tools](https://doc.rust-lang.org/beta/rustc/platform-support.html) -target. +# `zfc` + +`zfc` is a library for sets according to +[Zermelo–Fraenkel set theory with the axiom of choice (ZFC)](https://en.wikipedia.org/wiki/Zermelo%E2%80%93Fraenkel_set_theory). + +## License + +Licensed under either of + +* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0). +* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT). + +at your option. + +## Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, +as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. + +### Status + +The crate is only tested on `x86_64-unknown-linux-gnu` and `x86_64-unknown-openbsd` targets, but it should work +on most platforms. diff --git a/build.rs b/build.rs @@ -1,12 +0,0 @@ -use rustc_version::{version_meta, Channel}; - -fn main() { - // Set cfg flags depending on release channel - let channel = match version_meta().unwrap().channel { - Channel::Stable => "CHANNEL_STABLE", - Channel::Beta => "CHANNEL_BETA", - Channel::Nightly => "CHANNEL_NIGHTLY", - Channel::Dev => "CHANNEL_DEV", - }; - println!("cargo:rustc-cfg={}", channel) -} diff --git a/src/lib.rs b/src/lib.rs @@ -1,13 +1,16 @@ //! # `zfc` //! -//! `zfc` is a library for sets according to [Zermelo–Fraenkel set theory with the axiom of choice (ZFC)](https://en.wikipedia.org/wiki/Zermelo%E2%80%93Fraenkel_set_theory). -#![cfg_attr(all(doc, CHANNEL_NIGHTLY), feature(doc_auto_cfg))] +//! `zfc` is a library for sets according to +//! [Zermelo–Fraenkel set theory with the axiom of choice (ZFC)](https://en.wikipedia.org/wiki/Zermelo%E2%80%93Fraenkel_set_theory). +#![cfg_attr(docsrs, feature(doc_cfg))] #![no_std] #![deny( + unknown_lints, future_incompatible, let_underscore, missing_docs, nonstandard_style, + refining_impl_trait, rust_2018_compatibility, rust_2018_idioms, rust_2021_compatibility, @@ -26,25 +29,28 @@ clippy::style, clippy::suspicious )] -#![allow( - clippy::arithmetic_side_effects, +#![expect( clippy::blanket_clippy_restriction_lints, + clippy::exhaustive_enums, clippy::exhaustive_structs, clippy::implicit_return, + clippy::min_ident_chars, clippy::missing_trait_methods, clippy::ref_patterns, - clippy::single_char_lifetime_names + clippy::single_char_lifetime_names, + reason = "noisy, opinionated, and likely doesn't prevent bugs or improve APIs" )] extern crate alloc; -use alloc::collections::BTreeSet; +use alloc::{collections::BTreeSet, vec::Vec}; use core::borrow::Borrow; use core::cmp::Ordering; +use core::error::Error; use core::fmt::{self, Display, Formatter}; use core::ops::{Range, RangeInclusive, Sub}; +pub use num_bigint; use num_bigint::BigUint; /// Represents the quantity of elements in a [`Set`]. #[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] -#[allow(clippy::exhaustive_enums)] pub enum Cardinality { /// The contained `BigUint` represents the quantity of elements in a finite `Set`. Finite(BigUint), @@ -145,7 +151,6 @@ impl Cardinality { } } impl Display for Cardinality { - #[allow(clippy::min_ident_chars)] #[inline] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match *self { @@ -155,7 +160,6 @@ impl Display for Cardinality { } } impl fmt::Debug for Cardinality { - #[allow(clippy::min_ident_chars)] #[inline] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { <Self as Display>::fmt(self, f) @@ -291,34 +295,29 @@ impl PartialOrd<BigUint> for Cardinality { Some(self.cmp_biguint(other)) } } -/// Error returned when attempting to create a -/// [`BoundedCardinality`] from a pair of [`BigUint`]s -/// or [`Cardinality`]s such that the upper bound -/// is strictly less than the lower bound. +/// Error returned when attempting to create a [`BoundedCardinality`] from a pair of [`BigUint`]s +/// or [`Cardinality`]s such that the upper bound is strictly less than the lower bound. #[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct BoundedErr; impl Display for BoundedErr { - #[allow(clippy::min_ident_chars)] #[inline] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_str("upper bound is greater than lower bound") } } -/// Error returned when attempting to create a -/// [`Cardinality`] from a [`BoundedCardinality`] such that +impl Error for BoundedErr {} +/// Error returned when attempting to create a [`Cardinality`] from a [`BoundedCardinality`] such that /// the lower bound is less than the upper bound. #[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct CardinalityErr; impl Display for CardinalityErr { - #[allow(clippy::min_ident_chars)] #[inline] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_str("lower bound of the BoundedCardinality is less than the upper bound") } } -/// Contains a lower and upper bound -/// [`Cardinality`] used to bound the cardinality -/// of a [`Set`]. +impl Error for CardinalityErr {} +/// Contains a lower and upper bound [`Cardinality`] used to bound the cardinality of a [`Set`]. #[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct BoundedCardinality { /// Lower bound. @@ -328,6 +327,7 @@ pub struct BoundedCardinality { } impl BoundedCardinality { /// Creates an instance of `BoundedCardinality`. + /// /// Returns `None` iff `lower > upper`. #[inline] #[must_use] @@ -338,8 +338,7 @@ impl BoundedCardinality { Some(Self { lower, upper }) } } - /// Creates an instance of `BoundedCardinality` with the lower and upper bounds - /// both set to `exact`. + /// Creates an instance of `BoundedCardinality` with the lower and upper bounds both set to `exact`. #[inline] #[must_use] pub fn new_exact(exact: Cardinality) -> Self { @@ -348,9 +347,9 @@ impl BoundedCardinality { upper: exact, } } - /// Creates an instance of `BoundedCardinality` - /// with the lower and upper bounds as `Cardinality::Finite` + /// Creates an instance of `BoundedCardinality` with the lower and upper bounds as `Cardinality::Finite` /// of their respective values. + /// /// Returns `None` iff `lower > upper`. #[inline] #[must_use] @@ -364,8 +363,7 @@ impl BoundedCardinality { }) } } - /// Creates an instance of `BoundedCardinality` - /// with the lower and upper bounds as `Cardinality::Finite(exact)`. + /// Creates an instance of `BoundedCardinality` with the lower and upper bounds as `Cardinality::Finite(exact)`. #[inline] #[must_use] pub fn from_biguint_exact(exact: BigUint) -> Self { @@ -374,26 +372,30 @@ impl BoundedCardinality { upper: Cardinality::Finite(exact), } } - /// Creates an instance of `BoundedCardinality` - /// without verifying `lower <= upper`. + /// Creates an instance of `BoundedCardinality` without verifying `lower <= upper`. /// /// # Safety /// /// `lower <= upper`. - #[allow(unsafe_code)] + #[expect( + unsafe_code, + reason = "when literal values are used, code can reasonably bypass checks" + )] #[inline] #[must_use] pub const unsafe fn new_unsafe(lower: Cardinality, upper: Cardinality) -> Self { Self { lower, upper } } - /// Creates an instance of `BoundedCardinality` - /// with the lower and upper bounds as `Cardinality::Finite` + /// Creates an instance of `BoundedCardinality` with the lower and upper bounds as `Cardinality::Finite` /// of their respective values without verifying `lower <= upper`. /// /// # Safety /// /// `lower <= upper`. - #[allow(unsafe_code)] + #[expect( + unsafe_code, + reason = "when literal values are used, code can reasonably bypass checks" + )] #[inline] #[must_use] pub const unsafe fn from_biguint_unsafe(lower: BigUint, upper: BigUint) -> Self { @@ -464,14 +466,12 @@ impl BoundedCardinality { } } impl Display for BoundedCardinality { - #[allow(clippy::min_ident_chars)] #[inline] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "({}, {})", self.lower, self.upper) } } impl fmt::Debug for BoundedCardinality { - #[allow(clippy::min_ident_chars)] #[inline] fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { <Self as Display>::fmt(self, f) @@ -518,11 +518,15 @@ impl From<BoundedCardinality> for (BigUint, BigUint) { (value.lower.into(), value.upper.into()) } } -/// Represents a set according to [Zermelo–Fraenkel set theory with the axiom of choice (ZFC)](https://en.wikipedia.org/wiki/Zermelo%E2%80%93Fraenkel_set_theory). -/// Note that elements in a `Set` must not be distinguishable by order or frequency, so care must be taken in its implementation if the implementing type -/// exposes an API that distinguishes between the order or frequency of `Elem` (e.g., [`Vec<T>`](https://doc.rust-lang.org/alloc/vec/struct.Vec.html) where `Elem` = `T`). +/// Represents a set according to +/// [Zermelo–Fraenkel set theory with the axiom of choice (ZFC)](https://en.wikipedia.org/wiki/Zermelo%E2%80%93Fraenkel_set_theory). +/// +/// Note that elements in a `Set` must not be distinguishable by order or frequency, so care must be taken in its +/// implementation if the implementing type exposes an API that distinguishes between the order or frequency of +/// `Elem` (e.g., [`Vec<T>`](https://doc.rust-lang.org/alloc/vec/struct.Vec.html) where `Elem` = `T`). pub trait Set { /// The elements that make up the set. + /// /// Per ZFC, this must not be the same type as `Self` nor a recursive type based on `Self`. type Elem: Eq + ?Sized; /// Returns the cardinality of `self` if it is known exactly. @@ -687,13 +691,29 @@ where for<'a, 'b> <&'a T as Sub<&'b T>>::Output: Into<BigUint>, { type Elem = T; + #[expect( + clippy::arithmetic_side_effects, + reason = "we need to calculate the cardinality, and we avoid underflow" + )] #[inline] fn cardinality(&self) -> Option<Cardinality> { - Some(Cardinality::Finite((&self.end - &self.start).into())) + Some(Cardinality::Finite(if self.end >= self.start { + (&self.end - &self.start).into() + } else { + BigUint::new(Vec::new()) + })) } + #[expect( + clippy::arithmetic_side_effects, + reason = "we need to calculate the cardinality, and we avoid underflow" + )] #[inline] fn bounded_cardinality(&self) -> BoundedCardinality { - let card = Cardinality::Finite((&self.end - &self.start).into()); + let card = Cardinality::Finite(if self.end >= self.start { + (&self.end - &self.start).into() + } else { + BigUint::new(Vec::new()) + }); BoundedCardinality { lower: card.clone(), upper: card, @@ -726,16 +746,29 @@ where for<'a, 'b> <&'a T as Sub<&'b T>>::Output: Into<BigUint>, { type Elem = T; + #[expect( + clippy::arithmetic_side_effects, + reason = "we need to calculate the cardinality, and we avoid underflow. Overflow is no worry since we use BigUint." + )] #[inline] fn cardinality(&self) -> Option<Cardinality> { - Some(Cardinality::Finite( - (self.end() - self.start()).into() + BigUint::new(alloc::vec![1]), - )) + Some(Cardinality::Finite(if self.end() >= self.start() { + (self.end() - self.start()).into() + BigUint::new(alloc::vec![1]) + } else { + BigUint::new(Vec::new()) + })) } + #[expect( + clippy::arithmetic_side_effects, + reason = "we need to calculate the cardinality, and we avoid underflow. Overflow is no worry since we use BigUint." + )] #[inline] fn bounded_cardinality(&self) -> BoundedCardinality { - let card = - Cardinality::Finite((self.end() - self.start()).into() + BigUint::new(alloc::vec![1])); + let card = Cardinality::Finite(if self.end() >= self.start() { + (self.end() - self.start()).into() + BigUint::new(alloc::vec![1]) + } else { + BigUint::new(Vec::new()) + }); BoundedCardinality { lower: card.clone(), upper: card, @@ -768,8 +801,7 @@ use core::hash::{BuildHasher, Hash}; #[cfg(feature = "std")] use std::collections::HashSet; #[cfg(feature = "std")] -use std::error::Error; -#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl<T, S> Set for HashSet<T, S> where T: Eq + Hash, @@ -804,7 +836,3 @@ where self.len() <= val.len() && self.intersection(val).count() == val.len() } } -#[cfg(feature = "std")] -impl Error for BoundedErr {} -#[cfg(feature = "std")] -impl Error for CardinalityErr {}