diff --git a/Cargo.toml b/Cargo.toml index 1d42f78..8bd94b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,10 +5,9 @@ authors = ["Timothy J. Warren "] edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] - [features] default = ["std"] alloc = [] std = ["alloc"] + +[dependencies] diff --git a/justfile b/justfile index 37654bd..cef1053 100644 --- a/justfile +++ b/justfile @@ -13,6 +13,14 @@ clean: rm -f cobertura.xml rm -f coverage.html +# Check code syntax +check: + cargo check + +# Generate API docs +docs: + cargo doc + # Check code style lint: cargo clippy @@ -21,6 +29,11 @@ lint: fmt: cargo +nightly fmt +# Automatically fix some code syntax/style issues +fix: + cargo fix --allow-dirty --allow-staged + just fmt + # Run the normal tests test: cargo test diff --git a/src/bigint.rs b/src/bigint.rs index d3c4ee2..7d6ee5b 100644 --- a/src/bigint.rs +++ b/src/bigint.rs @@ -1,4 +1,9 @@ //! \[WIP\] Arbitrarily large integers +mod compare; +mod from; +pub use compare::*; +pub use from::*; + use crate::num::FracOp; use crate::num::Sign::{self, Negative, Positive}; @@ -26,7 +31,7 @@ pub struct BigInt { /// Create a [`BigInt`](bigint/struct.BigInt.html) type with signed or unsigned number literals #[macro_export] -macro_rules! big_int { +macro_rules! bint { ($w:literal) => { $crate::bigint::BigInt::new($w) }; @@ -44,27 +49,6 @@ impl Default for BigInt { } } -impl From for BigInt { - fn from(n: usize) -> Self { - Self { - inner: vec![n], - sign: Sign::default(), - } - } -} - -impl From<&str> for BigInt { - fn from(s: &str) -> Self { - Self::from_str(s, 10) - } -} - -impl From for BigInt { - fn from(s: String) -> Self { - Self::from_str(&s, 10) - } -} - impl BigInt { /// Create a new Bigint, of value 0 /// @@ -492,155 +476,6 @@ impl PartialOrd for BigInt { } } -macro_rules! impl_from_smaller { - ($(($s: ty, $u: ty)),* ) => { - $( - impl From<$s> for BigInt { - /// Create a `BigInt` from a signed integer primitive - fn from(n: $s) -> Self { - let sign = if n < 0 { Sign::Negative } else { Sign::Positive }; - let n = n.abs(); - let raw: usize = <$s>::try_into(n).unwrap(); - - Self { - inner: vec![raw], - sign, - } - } - } - - impl From<$u> for BigInt { - /// Create a `BigInt` from an unsigned integer primitive - fn from(n: $u) -> Self { - let mut new = Self::empty(); - new.inner.push(n as usize); - - new - } - } - )* - } -} - -macro_rules! impl_from_larger { - ($(($s: ty, $u: ty)),* ) => { - $( - impl From<$s> for BigInt { - /// Create a `BigInt` from a signed integer primitive - fn from(n: $s) -> Self { - let target_radix: $s = (usize::MAX as $s) + 1; - let sign = if n < 0 { Sign::Negative } else { Sign::Positive }; - let n = n.abs(); - - let mut quotient = n / target_radix; - let mut rem = n % target_radix; - - if quotient == 0 { - Self::from(rem as usize) - } else { - let mut inner: Vec = vec![rem as usize]; - - loop { - rem = quotient % target_radix; - quotient /= target_radix; - - inner.push(rem as usize); - - if (quotient == 0) { - break; - } - } - - BigInt { - inner, - sign, - } - } - } - } - - impl From<$u> for BigInt { - /// Create a `BigInt` from an unsigned integer primitive - fn from(n: $u) -> Self { - let target_radix: $u = (usize::MAX as $u) + 1; - - let mut quotient = n / target_radix; - let mut rem = n % target_radix; - - if quotient == 0 { - Self::from(rem as usize) - } else { - let mut inner: Vec = vec![rem as usize]; - - loop { - rem = quotient % target_radix; - quotient /= target_radix; - - inner.push(rem as usize); - - if (quotient == 0) { - break; - } - } - - BigInt { - inner, - sign: Sign::Positive - } - } - } - } - )* - }; -} - -macro_rules! impl_ord_literal { - ($($prim: ty),+) => { - $( - impl PartialEq<$prim> for BigInt { - #[must_use] - fn eq(&self, other: &$prim) -> bool { - self == &BigInt::new(*other) - } - } - - impl PartialEq for $prim { - #[must_use] - fn eq(&self, other: &BigInt) -> bool { - &BigInt::new(*self) == other - } - } - - impl PartialOrd<$prim> for BigInt { - #[must_use] - fn partial_cmp(&self, other: &$prim) -> Option { - self.partial_cmp(&BigInt::new(*other)) - } - } - - impl PartialOrd for $prim { - #[must_use] - fn partial_cmp(&self, other: &BigInt) -> Option { - (&BigInt::new(*self)).partial_cmp(other) - } - } - )+ - }; -} - -#[cfg(target_pointer_width = "32")] -impl_from_larger!((i64, u64), (i128, u128)); -#[cfg(target_pointer_width = "32")] -impl_from_smaller!((i8, u8), (i16, u16), (i32, u32)); - -#[cfg(target_pointer_width = "64")] -impl_from_larger!((i128, u128)); -#[cfg(target_pointer_width = "64")] -impl_from_smaller!((i8, u8), (i16, u16), (i32, u32), (i64, u64)); - -// Implement PartialEq and PartialOrd to compare against BigInt values -impl_ord_literal!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); - #[cfg(test)] #[cfg(not(tarpaulin_include))] mod tests { @@ -657,11 +492,11 @@ mod tests { #[test] fn test_macro() { - let a = big_int!(75); + let a = bint!(75); let b = BigInt::new(75); assert_eq!(a, b); - let a = big_int!(-75); + let a = bint!(-75); let b = BigInt::new(-75); assert_eq!(a, b); } @@ -733,13 +568,10 @@ mod tests { #[test] fn test_sub() { let a = BigInt::new(usize::MAX); - let b = BigInt::new(core::u16::MAX); + let b = BigInt::new(u16::MAX); let diff = a - b; - assert_eq!( - diff.clone().inner[0], - usize::MAX - core::u16::MAX as usize - ); + assert_eq!(diff.clone().inner[0], usize::MAX - u16::MAX as usize); assert_eq!(diff.inner.len(), 1); let a = BigInt::new(5); @@ -912,10 +744,10 @@ mod tests { assert_eq!(c.partial_cmp(&b), Some(Ordering::Less)); assert_eq!(b.partial_cmp(&c), Some(Ordering::Greater)); - assert!(big_int!(-32) < big_int!(3)); - assert!(big_int!(3) > big_int!(-32)); - assert!(big_int!(152) > big_int!(132)); - assert_eq!(big_int!(123), big_int!(123)); + assert!(bint!(-32) < bint!(3)); + assert!(bint!(3) > bint!(-32)); + assert!(bint!(152) > bint!(132)); + assert_eq!(bint!(123), bint!(123)); } #[test] diff --git a/src/bigint/compare.rs b/src/bigint/compare.rs new file mode 100644 index 0000000..9f03ae6 --- /dev/null +++ b/src/bigint/compare.rs @@ -0,0 +1,47 @@ +#[cfg(all(feature = "alloc", not(feature = "std")))] +extern crate alloc; +#[cfg(all(feature = "alloc", not(feature = "std")))] +use alloc::string::*; +#[cfg(all(feature = "alloc", not(feature = "std")))] +use alloc::vec::*; +use core::cmp::{Ordering, PartialEq, PartialOrd}; +use core::prelude::v1::*; + +use super::BigInt; + +macro_rules! impl_ord_literal { + ($($prim: ty),+) => { + $( + impl PartialEq<$prim> for BigInt { + #[must_use] + fn eq(&self, other: &$prim) -> bool { + self == &BigInt::new(*other) + } + } + + impl PartialEq for $prim { + #[must_use] + fn eq(&self, other: &BigInt) -> bool { + &BigInt::new(*self) == other + } + } + + impl PartialOrd<$prim> for BigInt { + #[must_use] + fn partial_cmp(&self, other: &$prim) -> Option { + self.partial_cmp(&BigInt::new(*other)) + } + } + + impl PartialOrd for $prim { + #[must_use] + fn partial_cmp(&self, other: &BigInt) -> Option { + (&BigInt::new(*self)).partial_cmp(other) + } + } + )+ + }; +} + +// Implement PartialEq and PartialOrd to compare against BigInt values +impl_ord_literal!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); diff --git a/src/bigint/from.rs b/src/bigint/from.rs new file mode 100644 index 0000000..5fa1feb --- /dev/null +++ b/src/bigint/from.rs @@ -0,0 +1,172 @@ +use crate::num::Sign::{self}; + +#[cfg(all(feature = "alloc", not(feature = "std")))] +extern crate alloc; +#[cfg(all(feature = "alloc", not(feature = "std")))] +use alloc::string::*; +#[cfg(all(feature = "alloc", not(feature = "std")))] +use alloc::vec::*; +use core::convert::TryInto; +use core::prelude::v1::*; +#[cfg(feature = "std")] +use std::prelude::v1::*; + +use super::BigInt; + +macro_rules! impl_from_smaller { + ($(($s: ty, $u: ty)),* ) => { + $( + impl From<$s> for BigInt { + /// Create a `BigInt` from a signed integer primitive + fn from(n: $s) -> Self { + let sign = if n < 0 { Sign::Negative } else { Sign::Positive }; + let n = n.abs(); + let raw: usize = <$s>::try_into(n).unwrap(); + + Self { + inner: vec![raw], + sign, + } + } + } + + impl From<$u> for BigInt { + /// Create a `BigInt` from an unsigned integer primitive + fn from(n: $u) -> Self { + let mut new = Self::empty(); + new.inner.push(n as usize); + + new + } + } + )* + } +} + +macro_rules! impl_from_larger { + ($(($s: ty, $u: ty)),* ) => { + $( + impl From<$s> for BigInt { + /// Create a `BigInt` from a signed integer primitive + fn from(n: $s) -> Self { + let target_radix: $s = (usize::MAX as $s) + 1; + let sign = if n < 0 { Sign::Negative } else { Sign::Positive }; + let n = n.abs(); + + let mut quotient = n / target_radix; + let mut rem = n % target_radix; + + if quotient == 0 { + Self::from(rem as usize) + } else { + let mut inner: Vec = vec![rem as usize]; + + loop { + rem = quotient % target_radix; + quotient /= target_radix; + + inner.push(rem as usize); + + if (quotient == 0) { + break; + } + } + + BigInt { + inner, + sign, + } + } + } + } + + impl From<$u> for BigInt { + /// Create a `BigInt` from an unsigned integer primitive + fn from(n: $u) -> Self { + let target_radix: $u = (usize::MAX as $u) + 1; + + let mut quotient = n / target_radix; + let mut rem = n % target_radix; + + if quotient == 0 { + Self::from(rem as usize) + } else { + let mut inner: Vec = vec![rem as usize]; + + loop { + rem = quotient % target_radix; + quotient /= target_radix; + + inner.push(rem as usize); + + if (quotient == 0) { + break; + } + } + + BigInt { + inner, + sign: Sign::Positive + } + } + } + } + )* + }; +} + +#[cfg(target_pointer_width = "16")] +impl_from_larger!((i32, u32), (i64, u64), (i128, u128)); +#[cfg(target_pointer_width = "16")] +impl_from_smaller!((i8, u8), (i16, u16)); + +#[cfg(target_pointer_width = "32")] +impl_from_larger!((i64, u64), (i128, u128)); +#[cfg(target_pointer_width = "32")] +impl_from_smaller!((i8, u8), (i16, u16), (i32, u32)); + +#[cfg(target_pointer_width = "64")] +impl_from_larger!((i128, u128)); +#[cfg(target_pointer_width = "64")] +impl_from_smaller!((i8, u8), (i16, u16), (i32, u32), (i64, u64)); + +#[cfg(target_pointer_width = "128")] +impl_from_smaller!((i8, u8), (i16, u16), (i32, u32), (i64, u64), (i128, u128)); + +impl From for BigInt { + fn from(n: usize) -> Self { + Self { + inner: vec![n], + sign: Sign::default(), + } + } +} + +impl From for BigInt { + fn from(n: isize) -> Self { + let sign = if n < 0 { + Sign::Negative + } else { + Sign::Positive + }; + let n = n.abs(); + let raw: usize = isize::try_into(n).expect("Unable to convert isize value into usize."); + + Self { + inner: vec![raw], + sign, + } + } +} + +impl From<&str> for BigInt { + fn from(s: &str) -> Self { + Self::from_str(s, 10) + } +} + +impl From for BigInt { + fn from(s: String) -> Self { + Self::from_str(&s, 10) + } +}