calc_rational

CLI calculator for rational numbers.
git clone https://git.philomathiclife.com/repos/calc_rational
Log | Files | Refs | README

commit 36a5f22255497cd55e078d59055aaac0f8a6713b
parent 084504bed2163a48fb2f08aaa841fa52e451d1e0
Author: Zack Newman <zack@philomathiclife.com>
Date:   Mon, 23 Jun 2025 13:17:43 -0600

more lints

Diffstat:
MCargo.toml | 33++++++++++++++++++++++++++++++---
Msrc/cache.rs | 1+
Msrc/lending_iterator.rs | 4++--
Msrc/lib.rs | 173++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Msrc/main.rs | 10++++++++++
5 files changed, 145 insertions(+), 76 deletions(-)

diff --git a/Cargo.toml b/Cargo.toml @@ -10,7 +10,7 @@ name = "calc_rational" readme = "README.md" repository = "https://git.philomathiclife.com/repos/calc_rational/" rust-version = "1.87.0" -version = "2.3.0" +version = "2.4.0" [lib] name = "calc_lib" @@ -21,18 +21,45 @@ name = "calc" path = "src/main.rs" [lints.rust] -unknown_lints = { level = "deny", priority = -1 } +ambiguous_negative_literals = { level = "deny", priority = -1 } +closure_returning_async_block = { level = "deny", priority = -1 } +deref_into_dyn_supertrait = { level = "deny", priority = -1 } +ffi_unwind_calls = { level = "deny", priority = -1 } future_incompatible = { level = "deny", priority = -1 } +impl_trait_redundant_captures = { level = "deny", priority = -1 } +keyword-idents = { level = "deny", priority = -1 } let_underscore = { level = "deny", priority = -1 } +linker_messages = { level = "deny", priority = -1 } +macro_use_extern_crate = { level = "deny", priority = -1 } +meta_variable_misuse = { level = "deny", priority = -1 } +missing_copy_implementations = { level = "deny", priority = -1 } +missing_debug_implementations = { level = "deny", priority = -1 } missing_docs = { level = "deny", priority = -1 } +non_ascii_idents = { level = "deny", priority = -1 } nonstandard_style = { level = "deny", priority = -1 } +redundant_imports = { level = "deny", priority = -1 } +redundant_lifetimes = { level = "deny", priority = -1 } refining_impl_trait = { level = "deny", priority = -1 } rust_2018_compatibility = { level = "deny", priority = -1 } rust_2018_idioms = { level = "deny", priority = -1 } rust_2021_compatibility = { level = "deny", priority = -1 } rust_2024_compatibility = { level = "deny", priority = -1 } +single_use_lifetimes = { level = "deny", priority = -1 } +trivial_casts = { level = "deny", priority = -1 } +trivial_numeric_casts = { level = "deny", priority = -1 } +unit_bindings = { level = "deny", priority = -1 } +unknown_lints = { level = "deny", priority = -1 } +unnameable_types = { level = "deny", priority = -1 } +unreachable_pub = { level = "deny", priority = -1 } unsafe_code = { level = "deny", priority = -1 } +unstable_features = { level = "deny", priority = -1 } unused = { level = "deny", priority = -1 } +unused_crate_dependencies = { level = "deny", priority = -1 } +unused_import_braces = { level = "deny", priority = -1 } +unused_lifetimes = { level = "deny", priority = -1 } +unused_qualifications = { level = "deny", priority = -1 } +unused_results = { level = "deny", priority = -1 } +variant_size_differences = { level = "deny", priority = -1 } warnings = { level = "deny", priority = -1 } [lints.clippy] @@ -70,7 +97,7 @@ num-bigint = { version = "0.4.6", default-features = false } num-integer = { version = "0.1.46", default-features = false } num-rational = { version = "0.4.2", default-features = false, features = ["num-bigint"] } num-traits = { version = "0.2.19", default-features = false } -priv_sep = { version = "3.0.0-alpha.1", default-features = false, optional = true } +priv_sep = { version = "3.0.0-alpha.1.1", default-features = false, optional = true } rand = { version = "0.9.1", default-features = false, features = ["thread_rng"], optional = true } diff --git a/src/cache.rs b/src/cache.rs @@ -2,6 +2,7 @@ use core::ops::Index; /// A cache of `N` `T`s. When the cache is filled up, /// a new entry overwrites the oldest entry. `Cache<T, N>` /// cannot be expanded or shrunk. +#[derive(Debug)] pub struct Cache<T, const N: usize> { /// The cache of `T`s. vals: [T; N], diff --git a/src/lending_iterator.rs b/src/lending_iterator.rs @@ -31,7 +31,7 @@ pub trait LendingIterator { #[inline] fn advance_by(&mut self, n: usize) -> Result<(), usize> { for i in 0..n { - self.lend_next().ok_or(i)?; + drop(self.lend_next().ok_or(i)?); } Ok(()) } @@ -99,7 +99,7 @@ where #[inline] fn advance_by(&mut self, n: usize) -> Result<(), usize> { for i in 0..n { - self.lend_next().ok_or(i)?; + drop(self.lend_next().ok_or(i)?); } Ok(()) } diff --git a/src/lib.rs b/src/lib.rs @@ -144,6 +144,8 @@ use num_rational::Ratio; #[cfg(feature = "rand")] use num_traits::ToPrimitive as _; use num_traits::{Inv as _, Pow as _}; +#[cfg(feature = "priv_sep")] +use priv_sep as _; #[cfg_attr(docsrs, doc(cfg(feature = "rand")))] #[cfg(feature = "rand")] pub use rand; @@ -382,6 +384,7 @@ impl Display for O<'_> { /// Size of [`Evaluator::cache`]. const CACHE_SIZE: usize = 8; /// Evaluates the supplied input. +#[derive(Debug)] pub struct Evaluator<'input, 'cache, 'prev, 'scratch, 'rand> { /// The input to be evaluated. utf8: &'input [u8], @@ -403,6 +406,7 @@ pub struct Evaluator<'input, 'cache, 'prev, 'scratch, 'rand> { _rng: PhantomData<fn() -> &'rand ()>, } #[allow( + single_use_lifetimes, clippy::allow_attributes, clippy::elidable_lifetime_names, reason = "unify rand and not rand" @@ -1134,6 +1138,7 @@ impl<'input, 'cache, 'prev, 'scratch, 'rand> Evaluator<'input, 'cache, 'prev, 's /// Reads data from `R` passing each line to an [`Evaluator`] to be evaluated. #[cfg_attr(docsrs, doc(cfg(feature = "std")))] #[cfg(feature = "std")] +#[derive(Debug)] pub struct EvalIter<R> { /// Reader that contains input data. reader: R, @@ -1244,8 +1249,8 @@ where .map_or_else( |e| Some(Err(E::LangErr(e))), |o| match o { - O::Empty(_) | O::Eval(_) | O::Store(_) => Some(Ok(o)), - O::Exit => None, + Empty(_) | Eval(_) | Store(_) => Some(Ok(o)), + Exit => None, }, ) } @@ -1265,7 +1270,7 @@ mod tests { .evaluate() .unwrap() { - O::Empty(o) => o.is_none(), + Empty(o) => o.is_none(), _ => false, } ); @@ -1627,12 +1632,16 @@ mod tests { // Successfully extract previous expression. let mut prev = None; let mut cache = Cache::new(); - Evaluator::new(b"1\n", &mut cache, &mut prev, &mut Vec::new()) - .evaluate() - .unwrap(); - Evaluator::new(b" s \r\n", &mut cache, &mut prev, &mut Vec::new()) - .evaluate() - .unwrap(); + drop( + Evaluator::new(b"1\n", &mut cache, &mut prev, &mut Vec::new()) + .evaluate() + .unwrap(), + ); + drop( + Evaluator::new(b" s \r\n", &mut cache, &mut prev, &mut Vec::new()) + .evaluate() + .unwrap(), + ); assert!( Evaluator::new(b"@", &mut cache, &mut prev, &mut Vec::new()) .get_recall() @@ -1698,12 +1707,16 @@ mod tests { _ => false, } ); - Evaluator::new(b"2\r\n", &mut cache, &mut prev, &mut Vec::new()) - .evaluate() - .unwrap(); - Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new()) - .evaluate() - .unwrap(); + drop( + Evaluator::new(b"2\r\n", &mut cache, &mut prev, &mut Vec::new()) + .evaluate() + .unwrap(), + ); + drop( + Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new()) + .evaluate() + .unwrap(), + ); // Stored values correct. assert!( Evaluator::new(b"@", &mut cache, &mut prev, &mut Vec::new()) @@ -1732,12 +1745,16 @@ mod tests { let mut v = vec![0, b'\n']; for i in b'3'..=b'8' { v[0] = i; - Evaluator::new(v.as_slice(), &mut cache, &mut prev, &mut Vec::new()) - .evaluate() - .unwrap(); - Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new()) - .evaluate() - .unwrap(); + drop( + Evaluator::new(v.as_slice(), &mut cache, &mut prev, &mut Vec::new()) + .evaluate() + .unwrap(), + ); + drop( + Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new()) + .evaluate() + .unwrap(), + ); } v[0] = b'@'; for i in b'1'..=b'8' { @@ -1762,12 +1779,16 @@ mod tests { .unwrap() == Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![8]))) ); - Evaluator::new(b"9\r\n", &mut cache, &mut prev, &mut Vec::new()) - .evaluate() - .unwrap(); - Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new()) - .evaluate() - .unwrap(); + drop( + Evaluator::new(b"9\r\n", &mut cache, &mut prev, &mut Vec::new()) + .evaluate() + .unwrap(), + ); + drop( + Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new()) + .evaluate() + .unwrap(), + ); // Oldest value is overwritten; all others remain. for i in b'1'..=b'8' { v[1] = i; @@ -2186,13 +2207,17 @@ mod tests { #[cfg(not(feature = "rand"))] let mut cache = Cache::new(); #[cfg(not(feature = "rand"))] - Evaluator::new(b"1\n", &mut cache, &mut prev, &mut Vec::new()) - .evaluate() - .unwrap(); + drop( + Evaluator::new(b"1\n", &mut cache, &mut prev, &mut Vec::new()) + .evaluate() + .unwrap(), + ); #[cfg(not(feature = "rand"))] - Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new()) - .evaluate() - .unwrap(); + drop( + Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new()) + .evaluate() + .unwrap(), + ); #[cfg(not(feature = "rand"))] assert!( Evaluator::new(b"@", &mut cache, &mut prev, &mut Vec::new()) @@ -2245,12 +2270,16 @@ mod tests { ); let mut prev = None; let mut cache = Cache::new(); - Evaluator::new(b"3\n", &mut cache, &mut prev, &mut Vec::new()) - .evaluate() - .unwrap(); - Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new()) - .evaluate() - .unwrap(); + drop( + Evaluator::new(b"3\n", &mut cache, &mut prev, &mut Vec::new()) + .evaluate() + .unwrap(), + ); + drop( + Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new()) + .evaluate() + .unwrap(), + ); assert!( Evaluator::new(b"@!", &mut cache, &mut prev, &mut Vec::new()) .get_fact() @@ -3004,7 +3033,7 @@ mod tests { .evaluate() .unwrap() { - O::Exit => true, + Exit => true, _ => false, } ); @@ -3017,7 +3046,7 @@ mod tests { .evaluate() .unwrap() { - O::Exit => true, + Exit => true, _ => false, }); assert!( @@ -3025,7 +3054,7 @@ mod tests { .evaluate() .unwrap() { - O::Exit => true, + Exit => true, _ => false, } ); @@ -3034,7 +3063,7 @@ mod tests { .evaluate() .unwrap() { - O::Exit => true, + Exit => true, _ => false, } ); @@ -3052,7 +3081,7 @@ mod tests { .evaluate() .unwrap() { - O::Exit => true, + Exit => true, _ => false, } ); @@ -3079,7 +3108,7 @@ mod tests { .evaluate() .unwrap() { - O::Exit => true, + Exit => true, _ => false, } ); @@ -3089,16 +3118,18 @@ mod tests { fn store() { let mut prev = None; let mut cache = Cache::new(); - Evaluator::new(b"1\n", &mut cache, &mut prev, &mut Vec::new()) - .evaluate() - .unwrap(); + drop( + Evaluator::new(b"1\n", &mut cache, &mut prev, &mut Vec::new()) + .evaluate() + .unwrap(), + ); assert!(cache.is_empty()); assert!( match Evaluator::new(b"s\n", &mut cache, &mut prev, &mut Vec::new()) .evaluate() .unwrap() { - O::Store(o) => + Store(o) => o.as_ref().unwrap() == &Ratio::from_integer(BigInt::from_biguint( Sign::Plus, @@ -3121,7 +3152,7 @@ mod tests { .evaluate() .unwrap() { - O::Eval(i) => + Eval(i) => i == &Ratio::from_integer(BigInt::from_biguint( Sign::Plus, BigUint::new(vec![3]) @@ -3134,7 +3165,7 @@ mod tests { .evaluate() .unwrap() { - O::Store(o) => + Store(o) => o.as_ref().unwrap() == &Ratio::from_integer(BigInt::from_biguint( Sign::Plus, @@ -3148,7 +3179,7 @@ mod tests { .evaluate() .unwrap() { - O::Eval(i) => + Eval(i) => i == &Ratio::new( BigInt::from_biguint(Sign::Plus, BigUint::new(vec![11])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2])) @@ -3161,7 +3192,7 @@ mod tests { .evaluate() .unwrap() { - O::Store(o) => + Store(o) => o == &Some(Ratio::new( BigInt::from_biguint(Sign::Plus, BigUint::new(vec![11])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![2])) @@ -3174,7 +3205,7 @@ mod tests { .evaluate() .unwrap() { - O::Eval(i) => + Eval(i) => i == &Ratio::new( BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1771561])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![64])) @@ -3187,7 +3218,7 @@ mod tests { .evaluate() .unwrap() { - O::Store(o) => + Store(o) => o == &Some(Ratio::new( BigInt::from_biguint(Sign::Plus, BigUint::new(vec![1771561])), BigInt::from_biguint(Sign::Plus, BigUint::new(vec![64])) @@ -3197,7 +3228,7 @@ mod tests { ); // Verified with Wolfram Alpha. assert!(match Evaluator::new(b" \t 1 + (2 * |(7.98\t - 12/7)|) / 4!^@3!^|1-3|\t \n", &mut cache, &mut prev, &mut exp).evaluate().unwrap() { - O::Eval(i) => i == &Ratio::from_str("2841328814244153299237884950647090899374680152474331/2841328814244153299237884950647090899374680152473600").unwrap(), + Eval(i) => i == &Ratio::from_str("2841328814244153299237884950647090899374680152474331/2841328814244153299237884950647090899374680152473600").unwrap(), _ => false, }); assert!(match Evaluator::new( @@ -3209,7 +3240,7 @@ mod tests { .evaluate() .unwrap() { - O::Eval(i) => + Eval(i) => i == &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![6]))), _ => false, }); @@ -3222,7 +3253,7 @@ mod tests { .evaluate() .unwrap() { - O::Eval(i) => + Eval(i) => i == &Ratio::from_integer(BigInt::from_biguint(Sign::Plus, BigUint::new(vec![64]))), _ => false, }); @@ -3231,7 +3262,7 @@ mod tests { .evaluate() .unwrap() { - O::Eval(i) => + Eval(i) => i == &Ratio::from_integer(BigInt::from_biguint( Sign::Plus, BigUint::new(vec![9]) @@ -3278,7 +3309,7 @@ mod tests { .evaluate() .unwrap() { - O::Empty(o) => + Empty(o) => o == &Some(Ratio::from_integer(BigInt::from_biguint( Sign::Plus, BigUint::new(vec![9]) @@ -3296,7 +3327,7 @@ mod tests { .evaluate() .unwrap() { - O::Empty(o) => *o == prev, + Empty(o) => *o == prev, _ => false, } ); @@ -3305,7 +3336,7 @@ mod tests { .evaluate() .unwrap() { - O::Empty(o) => *o == prev, + Empty(o) => *o == prev, _ => false, } ); @@ -3325,7 +3356,7 @@ mod tests { Self { data, err: true } } } - impl<'a> Read for Reader<'a> { + impl Read for Reader<'_> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { if self.err { self.err = false; @@ -3337,7 +3368,7 @@ mod tests { } } } - impl<'a> BufRead for Reader<'a> { + impl BufRead for Reader<'_> { fn fill_buf(&mut self) -> io::Result<&[u8]> { if self.err { self.err = false; @@ -3358,33 +3389,33 @@ mod tests { _ => false, }); assert!(match iter.lend_next().unwrap().unwrap() { - O::Eval(r) => r.numer().to_i32().unwrap() == 3, + Eval(r) => r.numer().to_i32().unwrap() == 3, _ => false, }); assert!(match iter.lend_next().unwrap().unwrap() { - O::Eval(r) => r.numer().to_i32().unwrap() == 4, + Eval(r) => r.numer().to_i32().unwrap() == 4, _ => false, }); assert!(match iter.lend_next().unwrap().unwrap() { - O::Empty(r) => r.as_ref().unwrap().numer().to_i32().unwrap() == 4, + Empty(r) => r.as_ref().unwrap().numer().to_i32().unwrap() == 4, _ => false, }); assert!(iter.lend_next().is_none()); assert!(match iter.lend_next().unwrap().unwrap() { - O::Eval(r) => r.numer().to_i32().unwrap() == 5, + Eval(r) => r.numer().to_i32().unwrap() == 5, _ => false, }); assert!(match iter.lend_next().unwrap().unwrap() { - O::Store(r) => r.as_ref().unwrap().numer().to_i32().unwrap() == 5, + Store(r) => r.as_ref().unwrap().numer().to_i32().unwrap() == 5, _ => false, }); assert!(match iter.lend_next().unwrap().unwrap() { - O::Eval(r) => r.is_integer(), + Eval(r) => r.is_integer(), _ => false, }); assert!(match iter.lend_next().unwrap().unwrap_err() { E::LangErr(e) => match e { - LangErr::MissingTerm(_) => true, + MissingTerm(_) => true, _ => false, }, _ => false, diff --git a/src/main.rs b/src/main.rs @@ -1,12 +1,22 @@ //! # `calc` //! //! Consult [`README.md`](https://crates.io/crates/calc_rational). +#[cfg(not(feature = "std"))] +use calc_lib as _; #[cfg(feature = "std")] use calc_lib::{EvalIter, lending_iterator::LendingIterator as _}; #[cfg(feature = "std")] use core::fmt::{self, Display, Formatter}; +use num_bigint as _; +use num_integer as _; +use num_rational as _; +use num_traits as _; +#[cfg(all(feature = "priv_sep", not(target_os = "openbsd")))] +use priv_sep as _; #[cfg(all(feature = "priv_sep", target_os = "openbsd"))] use priv_sep::{Promise, Promises}; +#[cfg(feature = "rand")] +use rand as _; #[cfg(feature = "std")] use std::{ error,