From e7d58f673ff9515af11169cd92b6b341d6e8c13f Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Mon, 13 Nov 2023 17:37:25 +0100 Subject: [PATCH] seq: simplify and use new printf implementation --- src/uu/seq/src/extendedbigdecimal.rs | 54 +---- src/uu/seq/src/extendedbigint.rs | 214 ------------------ src/uu/seq/src/number.rs | 70 +----- src/uu/seq/src/numberparse.rs | 127 ++++------- src/uu/seq/src/seq.rs | 167 +++----------- src/uucore/src/lib/features/format/mod.rs | 4 +- .../src/lib/features/format/num_format.rs | 24 +- src/uucore/src/lib/features/format/spec.rs | 13 +- 8 files changed, 104 insertions(+), 569 deletions(-) delete mode 100644 src/uu/seq/src/extendedbigint.rs diff --git a/src/uu/seq/src/extendedbigdecimal.rs b/src/uu/seq/src/extendedbigdecimal.rs index 388046ba3..ecd460ceb 100644 --- a/src/uu/seq/src/extendedbigdecimal.rs +++ b/src/uu/seq/src/extendedbigdecimal.rs @@ -25,13 +25,8 @@ use std::fmt::Display; use std::ops::Add; use bigdecimal::BigDecimal; -use num_bigint::BigInt; -use num_bigint::ToBigInt; -use num_traits::One; use num_traits::Zero; -use crate::extendedbigint::ExtendedBigInt; - #[derive(Debug, Clone)] pub enum ExtendedBigDecimal { /// Arbitrary precision floating point number. @@ -72,53 +67,14 @@ pub enum ExtendedBigDecimal { Nan, } -/// The smallest integer greater than or equal to this number. -fn ceil(x: BigDecimal) -> BigInt { - if x.is_integer() { - // Unwrapping the Option because it always returns Some - x.to_bigint().unwrap() - } else { - (x + BigDecimal::one().half()).round(0).to_bigint().unwrap() - } -} - -/// The largest integer less than or equal to this number. -fn floor(x: BigDecimal) -> BigInt { - if x.is_integer() { - // Unwrapping the Option because it always returns Some - x.to_bigint().unwrap() - } else { - (x - BigDecimal::one().half()).round(0).to_bigint().unwrap() - } -} - impl ExtendedBigDecimal { - /// The smallest integer greater than or equal to this number. - pub fn ceil(self) -> ExtendedBigInt { - match self { - Self::BigDecimal(x) => ExtendedBigInt::BigInt(ceil(x)), - other => From::from(other), - } + #[cfg(test)] + pub fn zero() -> Self { + Self::BigDecimal(1.into()) } - /// The largest integer less than or equal to this number. - pub fn floor(self) -> ExtendedBigInt { - match self { - Self::BigDecimal(x) => ExtendedBigInt::BigInt(floor(x)), - other => From::from(other), - } - } -} - -impl From for ExtendedBigDecimal { - fn from(big_int: ExtendedBigInt) -> Self { - match big_int { - ExtendedBigInt::BigInt(n) => Self::BigDecimal(BigDecimal::from(n)), - ExtendedBigInt::Infinity => Self::Infinity, - ExtendedBigInt::MinusInfinity => Self::MinusInfinity, - ExtendedBigInt::MinusZero => Self::MinusZero, - ExtendedBigInt::Nan => Self::Nan, - } + pub fn one() -> Self { + Self::BigDecimal(1.into()) } } diff --git a/src/uu/seq/src/extendedbigint.rs b/src/uu/seq/src/extendedbigint.rs deleted file mode 100644 index 6828fba2d..000000000 --- a/src/uu/seq/src/extendedbigint.rs +++ /dev/null @@ -1,214 +0,0 @@ -// This file is part of the uutils coreutils package. -// -// For the full copyright and license information, please view the LICENSE -// file that was distributed with this source code. -// spell-checker:ignore bigint extendedbigint extendedbigdecimal -//! An arbitrary precision integer that can also represent infinity, NaN, etc. -//! -//! Usually infinity, NaN, and negative zero are only represented for -//! floating point numbers. The [`ExtendedBigInt`] enumeration provides -//! a representation of those things with the set of integers. The -//! finite values are stored as [`BigInt`] instances. -//! -//! # Examples -//! -//! Addition works for [`ExtendedBigInt`] as it does for floats. For -//! example, adding infinity to any finite value results in infinity: -//! -//! ```rust,ignore -//! let summand1 = ExtendedBigInt::BigInt(BigInt::zero()); -//! let summand2 = ExtendedBigInt::Infinity; -//! assert_eq!(summand1 + summand2, ExtendedBigInt::Infinity); -//! ``` -use std::cmp::Ordering; -use std::fmt::Display; -use std::ops::Add; - -use num_bigint::BigInt; -use num_bigint::ToBigInt; -use num_traits::One; -use num_traits::Zero; - -use crate::extendedbigdecimal::ExtendedBigDecimal; - -#[derive(Debug, Clone)] -pub enum ExtendedBigInt { - BigInt(BigInt), - Infinity, - MinusInfinity, - MinusZero, - Nan, -} - -impl ExtendedBigInt { - /// The integer number one. - pub fn one() -> Self { - // We would like to implement `num_traits::One`, but it requires - // a multiplication implementation, and we don't want to - // implement that here. - Self::BigInt(BigInt::one()) - } -} - -impl From for ExtendedBigInt { - fn from(big_decimal: ExtendedBigDecimal) -> Self { - match big_decimal { - // TODO When can this fail? - ExtendedBigDecimal::BigDecimal(x) => Self::BigInt(x.to_bigint().unwrap()), - ExtendedBigDecimal::Infinity => Self::Infinity, - ExtendedBigDecimal::MinusInfinity => Self::MinusInfinity, - ExtendedBigDecimal::MinusZero => Self::MinusZero, - ExtendedBigDecimal::Nan => Self::Nan, - } - } -} - -impl Display for ExtendedBigInt { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::BigInt(n) => n.fmt(f), - Self::Infinity => f32::INFINITY.fmt(f), - Self::MinusInfinity => f32::NEG_INFINITY.fmt(f), - Self::MinusZero => "-0".fmt(f), - Self::Nan => "nan".fmt(f), - } - } -} - -impl Zero for ExtendedBigInt { - fn zero() -> Self { - Self::BigInt(BigInt::zero()) - } - fn is_zero(&self) -> bool { - match self { - Self::BigInt(n) => n.is_zero(), - Self::MinusZero => true, - _ => false, - } - } -} - -impl Add for ExtendedBigInt { - type Output = Self; - - fn add(self, other: Self) -> Self { - match (self, other) { - (Self::BigInt(m), Self::BigInt(n)) => Self::BigInt(m.add(n)), - (Self::BigInt(_), Self::MinusInfinity) => Self::MinusInfinity, - (Self::BigInt(_), Self::Infinity) => Self::Infinity, - (Self::BigInt(_), Self::Nan) => Self::Nan, - (Self::BigInt(m), Self::MinusZero) => Self::BigInt(m), - (Self::Infinity, Self::BigInt(_)) => Self::Infinity, - (Self::Infinity, Self::Infinity) => Self::Infinity, - (Self::Infinity, Self::MinusZero) => Self::Infinity, - (Self::Infinity, Self::MinusInfinity) => Self::Nan, - (Self::Infinity, Self::Nan) => Self::Nan, - (Self::MinusInfinity, Self::BigInt(_)) => Self::MinusInfinity, - (Self::MinusInfinity, Self::MinusInfinity) => Self::MinusInfinity, - (Self::MinusInfinity, Self::MinusZero) => Self::MinusInfinity, - (Self::MinusInfinity, Self::Infinity) => Self::Nan, - (Self::MinusInfinity, Self::Nan) => Self::Nan, - (Self::Nan, _) => Self::Nan, - (Self::MinusZero, other) => other, - } - } -} - -impl PartialEq for ExtendedBigInt { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Self::BigInt(m), Self::BigInt(n)) => m.eq(n), - (Self::BigInt(_), Self::MinusInfinity) => false, - (Self::BigInt(_), Self::Infinity) => false, - (Self::BigInt(_), Self::Nan) => false, - (Self::BigInt(_), Self::MinusZero) => false, - (Self::Infinity, Self::BigInt(_)) => false, - (Self::Infinity, Self::Infinity) => true, - (Self::Infinity, Self::MinusZero) => false, - (Self::Infinity, Self::MinusInfinity) => false, - (Self::Infinity, Self::Nan) => false, - (Self::MinusInfinity, Self::BigInt(_)) => false, - (Self::MinusInfinity, Self::Infinity) => false, - (Self::MinusInfinity, Self::MinusZero) => false, - (Self::MinusInfinity, Self::MinusInfinity) => true, - (Self::MinusInfinity, Self::Nan) => false, - (Self::Nan, _) => false, - (Self::MinusZero, Self::BigInt(_)) => false, - (Self::MinusZero, Self::Infinity) => false, - (Self::MinusZero, Self::MinusZero) => true, - (Self::MinusZero, Self::MinusInfinity) => false, - (Self::MinusZero, Self::Nan) => false, - } - } -} - -impl PartialOrd for ExtendedBigInt { - fn partial_cmp(&self, other: &Self) -> Option { - match (self, other) { - (Self::BigInt(m), Self::BigInt(n)) => m.partial_cmp(n), - (Self::BigInt(_), Self::MinusInfinity) => Some(Ordering::Greater), - (Self::BigInt(_), Self::Infinity) => Some(Ordering::Less), - (Self::BigInt(_), Self::Nan) => None, - (Self::BigInt(m), Self::MinusZero) => m.partial_cmp(&BigInt::zero()), - (Self::Infinity, Self::BigInt(_)) => Some(Ordering::Greater), - (Self::Infinity, Self::Infinity) => Some(Ordering::Equal), - (Self::Infinity, Self::MinusZero) => Some(Ordering::Greater), - (Self::Infinity, Self::MinusInfinity) => Some(Ordering::Greater), - (Self::Infinity, Self::Nan) => None, - (Self::MinusInfinity, Self::BigInt(_)) => Some(Ordering::Less), - (Self::MinusInfinity, Self::Infinity) => Some(Ordering::Less), - (Self::MinusInfinity, Self::MinusZero) => Some(Ordering::Less), - (Self::MinusInfinity, Self::MinusInfinity) => Some(Ordering::Equal), - (Self::MinusInfinity, Self::Nan) => None, - (Self::Nan, _) => None, - (Self::MinusZero, Self::BigInt(n)) => BigInt::zero().partial_cmp(n), - (Self::MinusZero, Self::Infinity) => Some(Ordering::Less), - (Self::MinusZero, Self::MinusZero) => Some(Ordering::Equal), - (Self::MinusZero, Self::MinusInfinity) => Some(Ordering::Greater), - (Self::MinusZero, Self::Nan) => None, - } - } -} - -#[cfg(test)] -mod tests { - - use num_bigint::BigInt; - use num_traits::Zero; - - use crate::extendedbigint::ExtendedBigInt; - - #[test] - fn test_addition_infinity() { - let summand1 = ExtendedBigInt::BigInt(BigInt::zero()); - let summand2 = ExtendedBigInt::Infinity; - assert_eq!(summand1 + summand2, ExtendedBigInt::Infinity); - } - - #[test] - fn test_addition_minus_infinity() { - let summand1 = ExtendedBigInt::BigInt(BigInt::zero()); - let summand2 = ExtendedBigInt::MinusInfinity; - assert_eq!(summand1 + summand2, ExtendedBigInt::MinusInfinity); - } - - #[test] - fn test_addition_nan() { - let summand1 = ExtendedBigInt::BigInt(BigInt::zero()); - let summand2 = ExtendedBigInt::Nan; - let sum = summand1 + summand2; - match sum { - ExtendedBigInt::Nan => (), - _ => unreachable!(), - } - } - - #[test] - fn test_display() { - assert_eq!(format!("{}", ExtendedBigInt::BigInt(BigInt::zero())), "0"); - assert_eq!(format!("{}", ExtendedBigInt::MinusZero), "-0"); - assert_eq!(format!("{}", ExtendedBigInt::Infinity), "inf"); - assert_eq!(format!("{}", ExtendedBigInt::MinusInfinity), "-inf"); - assert_eq!(format!("{}", ExtendedBigInt::Nan), "nan"); - } -} diff --git a/src/uu/seq/src/number.rs b/src/uu/seq/src/number.rs index 85bc327ff..4da1146ef 100644 --- a/src/uu/seq/src/number.rs +++ b/src/uu/seq/src/number.rs @@ -12,70 +12,6 @@ use num_traits::Zero; use crate::extendedbigdecimal::ExtendedBigDecimal; -use crate::extendedbigint::ExtendedBigInt; - -/// An integral or floating point number. -#[derive(Debug, PartialEq)] -pub enum Number { - Int(ExtendedBigInt), - Float(ExtendedBigDecimal), -} - -impl Number { - /// Decide whether this number is zero (either positive or negative). - pub fn is_zero(&self) -> bool { - // We would like to implement `num_traits::Zero`, but it - // requires an addition implementation, and we don't want to - // implement that here. - match self { - Self::Int(n) => n.is_zero(), - Self::Float(x) => x.is_zero(), - } - } - - /// Convert this number into an `ExtendedBigDecimal`. - pub fn into_extended_big_decimal(self) -> ExtendedBigDecimal { - match self { - Self::Int(n) => ExtendedBigDecimal::from(n), - Self::Float(x) => x, - } - } - - /// The integer number one. - pub fn one() -> Self { - // We would like to implement `num_traits::One`, but it requires - // a multiplication implementation, and we don't want to - // implement that here. - Self::Int(ExtendedBigInt::one()) - } - - /// Round this number towards the given other number. - /// - /// If `other` is greater, then round up. If `other` is smaller, - /// then round down. - pub fn round_towards(self, other: &ExtendedBigInt) -> ExtendedBigInt { - match self { - // If this number is already an integer, it is already - // rounded to the nearest integer in the direction of - // `other`. - Self::Int(num) => num, - // Otherwise, if this number is a float, we need to decide - // whether `other` is larger or smaller than it, and thus - // whether to round up or round down, respectively. - Self::Float(num) => { - let other: ExtendedBigDecimal = From::from(other.clone()); - if other > num { - num.ceil() - } else { - // If they are equal, then `self` is already an - // integer, so calling `floor()` does no harm and - // will just return that integer anyway. - num.floor() - } - } - } - } -} /// A number with a specified number of integer and fractional digits. /// @@ -87,13 +23,13 @@ impl Number { /// You can get an instance of this struct by calling [`str::parse`]. #[derive(Debug)] pub struct PreciseNumber { - pub number: Number, + pub number: ExtendedBigDecimal, pub num_integral_digits: usize, pub num_fractional_digits: usize, } impl PreciseNumber { - pub fn new(number: Number, num_integral_digits: usize, num_fractional_digits: usize) -> Self { + pub fn new(number: ExtendedBigDecimal, num_integral_digits: usize, num_fractional_digits: usize) -> Self { Self { number, num_integral_digits, @@ -106,7 +42,7 @@ impl PreciseNumber { // We would like to implement `num_traits::One`, but it requires // a multiplication implementation, and we don't want to // implement that here. - Self::new(Number::one(), 1, 0) + Self::new(ExtendedBigDecimal::one(), 1, 0) } /// Decide whether this number is zero (either positive or negative). diff --git a/src/uu/seq/src/numberparse.rs b/src/uu/seq/src/numberparse.rs index 3f4b21395..a82d1e887 100644 --- a/src/uu/seq/src/numberparse.rs +++ b/src/uu/seq/src/numberparse.rs @@ -16,8 +16,6 @@ use num_traits::Num; use num_traits::Zero; use crate::extendedbigdecimal::ExtendedBigDecimal; -use crate::extendedbigint::ExtendedBigInt; -use crate::number::Number; use crate::number::PreciseNumber; /// An error returned when parsing a number fails. @@ -29,8 +27,8 @@ pub enum ParseNumberError { } /// Decide whether a given string and its parsed `BigInt` is negative zero. -fn is_minus_zero_int(s: &str, n: &BigInt) -> bool { - s.starts_with('-') && n == &BigInt::zero() +fn is_minus_zero_int(s: &str, n: &BigDecimal) -> bool { + s.starts_with('-') && n == &BigDecimal::zero() } /// Decide whether a given string and its parsed `BigDecimal` is negative zero. @@ -53,19 +51,19 @@ fn is_minus_zero_float(s: &str, x: &BigDecimal) -> bool { /// assert_eq!(actual, expected); /// ``` fn parse_no_decimal_no_exponent(s: &str) -> Result { - match s.parse::() { + match s.parse::() { Ok(n) => { // If `s` is '-0', then `parse()` returns `BigInt::zero()`, // but we need to return `Number::MinusZeroInt` instead. if is_minus_zero_int(s, &n) { Ok(PreciseNumber::new( - Number::Int(ExtendedBigInt::MinusZero), + ExtendedBigDecimal::MinusZero, s.len(), 0, )) } else { Ok(PreciseNumber::new( - Number::Int(ExtendedBigInt::BigInt(n)), + ExtendedBigDecimal::BigDecimal(n), s.len(), 0, )) @@ -79,7 +77,7 @@ fn parse_no_decimal_no_exponent(s: &str) -> Result return Err(ParseNumberError::Nan), _ => return Err(ParseNumberError::Float), }; - Ok(PreciseNumber::new(Number::Float(float_val), 0, 0)) + Ok(PreciseNumber::new(float_val, 0, 0)) } } } @@ -125,13 +123,13 @@ fn parse_exponent_no_decimal(s: &str, j: usize) -> Result Result() + .parse::() .map_err(|_| ParseNumberError::Float)?; Ok(PreciseNumber::new( - Number::Int(ExtendedBigInt::BigInt(n)), + ExtendedBigDecimal::BigDecimal(n), num_integral_digits, num_fractional_digits, )) } } else if is_minus_zero_float(s, &val) { Ok(PreciseNumber::new( - Number::Float(ExtendedBigDecimal::MinusZero), + ExtendedBigDecimal::MinusZero, num_integral_digits, num_fractional_digits, )) } else { Ok(PreciseNumber::new( - Number::Float(ExtendedBigDecimal::BigDecimal(val)), + ExtendedBigDecimal::BigDecimal(val), num_integral_digits, num_fractional_digits, )) @@ -303,20 +301,17 @@ fn parse_hexadecimal(s: &str) -> Result { } let num = BigInt::from_str_radix(s, 16).map_err(|_| ParseNumberError::Hex)?; + let num = BigDecimal::from(num); - match (is_neg, num == BigInt::zero()) { - (true, true) => Ok(PreciseNumber::new( - Number::Int(ExtendedBigInt::MinusZero), - 2, - 0, - )), + match (is_neg, num == BigDecimal::zero()) { + (true, true) => Ok(PreciseNumber::new(ExtendedBigDecimal::MinusZero, 2, 0)), (true, false) => Ok(PreciseNumber::new( - Number::Int(ExtendedBigInt::BigInt(-num)), + ExtendedBigDecimal::BigDecimal(-num), 0, 0, )), (false, _) => Ok(PreciseNumber::new( - Number::Int(ExtendedBigInt::BigInt(num)), + ExtendedBigDecimal::BigDecimal(num), 0, 0, )), @@ -364,19 +359,14 @@ impl FromStr for PreciseNumber { #[cfg(test)] mod tests { - use bigdecimal::BigDecimal; - use num_bigint::BigInt; - use num_traits::Zero; use crate::extendedbigdecimal::ExtendedBigDecimal; - use crate::extendedbigint::ExtendedBigInt; - use crate::number::Number; use crate::number::PreciseNumber; use crate::numberparse::ParseNumberError; /// Convenience function for parsing a [`Number`] and unwrapping. - fn parse(s: &str) -> Number { + fn parse(s: &str) -> ExtendedBigDecimal { s.parse::().unwrap().number } @@ -392,40 +382,37 @@ mod tests { #[test] fn test_parse_minus_zero_int() { - assert_eq!(parse("-0e0"), Number::Int(ExtendedBigInt::MinusZero)); - assert_eq!(parse("-0e-0"), Number::Int(ExtendedBigInt::MinusZero)); - assert_eq!(parse("-0e1"), Number::Int(ExtendedBigInt::MinusZero)); - assert_eq!(parse("-0e+1"), Number::Int(ExtendedBigInt::MinusZero)); - assert_eq!(parse("-0.0e1"), Number::Int(ExtendedBigInt::MinusZero)); - assert_eq!(parse("-0x0"), Number::Int(ExtendedBigInt::MinusZero)); + assert_eq!(parse("-0e0"), ExtendedBigDecimal::MinusZero); + assert_eq!(parse("-0e-0"), ExtendedBigDecimal::MinusZero); + assert_eq!(parse("-0e1"), ExtendedBigDecimal::MinusZero); + assert_eq!(parse("-0e+1"), ExtendedBigDecimal::MinusZero); + assert_eq!(parse("-0.0e1"), ExtendedBigDecimal::MinusZero); + assert_eq!(parse("-0x0"), ExtendedBigDecimal::MinusZero); } #[test] fn test_parse_minus_zero_float() { - assert_eq!(parse("-0.0"), Number::Float(ExtendedBigDecimal::MinusZero)); - assert_eq!(parse("-0e-1"), Number::Float(ExtendedBigDecimal::MinusZero)); - assert_eq!( - parse("-0.0e-1"), - Number::Float(ExtendedBigDecimal::MinusZero) - ); + assert_eq!(parse("-0.0"), ExtendedBigDecimal::MinusZero); + assert_eq!(parse("-0e-1"), ExtendedBigDecimal::MinusZero); + assert_eq!(parse("-0.0e-1"), ExtendedBigDecimal::MinusZero); } #[test] fn test_parse_big_int() { - assert_eq!(parse("0"), Number::Int(ExtendedBigInt::zero())); - assert_eq!(parse("0.1e1"), Number::Int(ExtendedBigInt::one())); + assert_eq!(parse("0"), ExtendedBigDecimal::zero()); + assert_eq!(parse("0.1e1"), ExtendedBigDecimal::one()); assert_eq!( parse("1.0e1"), - Number::Int(ExtendedBigInt::BigInt("10".parse::().unwrap())) + ExtendedBigDecimal::BigDecimal("10".parse::().unwrap()) ); } #[test] fn test_parse_hexadecimal_big_int() { - assert_eq!(parse("0x0"), Number::Int(ExtendedBigInt::zero())); + assert_eq!(parse("0x0"), ExtendedBigDecimal::zero()); assert_eq!( parse("0x10"), - Number::Int(ExtendedBigInt::BigInt("16".parse::().unwrap())) + ExtendedBigDecimal::BigDecimal("16".parse::().unwrap()) ); } @@ -433,56 +420,34 @@ mod tests { fn test_parse_big_decimal() { assert_eq!( parse("0.0"), - Number::Float(ExtendedBigDecimal::BigDecimal( - "0.0".parse::().unwrap() - )) + ExtendedBigDecimal::BigDecimal("0.0".parse::().unwrap()) ); assert_eq!( parse(".0"), - Number::Float(ExtendedBigDecimal::BigDecimal( - "0.0".parse::().unwrap() - )) + ExtendedBigDecimal::BigDecimal("0.0".parse::().unwrap()) ); assert_eq!( parse("1.0"), - Number::Float(ExtendedBigDecimal::BigDecimal( - "1.0".parse::().unwrap() - )) + ExtendedBigDecimal::BigDecimal("1.0".parse::().unwrap()) ); assert_eq!( parse("10e-1"), - Number::Float(ExtendedBigDecimal::BigDecimal( - "1.0".parse::().unwrap() - )) + ExtendedBigDecimal::BigDecimal("1.0".parse::().unwrap()) ); assert_eq!( parse("-1e-3"), - Number::Float(ExtendedBigDecimal::BigDecimal( - "-0.001".parse::().unwrap() - )) + ExtendedBigDecimal::BigDecimal("-0.001".parse::().unwrap()) ); } #[test] fn test_parse_inf() { - assert_eq!(parse("inf"), Number::Float(ExtendedBigDecimal::Infinity)); - assert_eq!( - parse("infinity"), - Number::Float(ExtendedBigDecimal::Infinity) - ); - assert_eq!(parse("+inf"), Number::Float(ExtendedBigDecimal::Infinity)); - assert_eq!( - parse("+infinity"), - Number::Float(ExtendedBigDecimal::Infinity) - ); - assert_eq!( - parse("-inf"), - Number::Float(ExtendedBigDecimal::MinusInfinity) - ); - assert_eq!( - parse("-infinity"), - Number::Float(ExtendedBigDecimal::MinusInfinity) - ); + assert_eq!(parse("inf"), ExtendedBigDecimal::Infinity); + assert_eq!(parse("infinity"), ExtendedBigDecimal::Infinity); + assert_eq!(parse("+inf"), ExtendedBigDecimal::Infinity); + assert_eq!(parse("+infinity"), ExtendedBigDecimal::Infinity); + assert_eq!(parse("-inf"), ExtendedBigDecimal::MinusInfinity); + assert_eq!(parse("-infinity"), ExtendedBigDecimal::MinusInfinity); } #[test] diff --git a/src/uu/seq/src/seq.rs b/src/uu/seq/src/seq.rs index bb4d5414e..a987405ce 100644 --- a/src/uu/seq/src/seq.rs +++ b/src/uu/seq/src/seq.rs @@ -3,24 +3,21 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. // spell-checker:ignore (ToDO) istr chiter argptr ilen extendedbigdecimal extendedbigint numberparse -use std::io::{stdout, Write}; +use std::io::{stdout, ErrorKind, Write}; use clap::{crate_version, Arg, ArgAction, Command}; -use num_traits::{Zero, ToPrimitive}; +use num_traits::{ToPrimitive, Zero}; -use uucore::error::UResult; -use uucore::format::{printf, FormatArgument, Format, num_format}; +use uucore::error::{FromIo, UResult}; +use uucore::format::{num_format, Format}; use uucore::{format_usage, help_about, help_usage}; mod error; mod extendedbigdecimal; -mod extendedbigint; mod number; mod numberparse; use crate::error::SeqError; use crate::extendedbigdecimal::ExtendedBigDecimal; -use crate::extendedbigint::ExtendedBigInt; -use crate::number::Number; use crate::number::PreciseNumber; const ABOUT: &str = help_about!("seq.md"); @@ -41,11 +38,6 @@ struct SeqOptions<'a> { format: Option<&'a str>, } -/// A range of integers. -/// -/// The elements are (first, increment, last). -type RangeInt = (ExtendedBigInt, ExtendedBigInt, ExtendedBigInt); - /// A range of floats. /// /// The elements are (first, increment, last). @@ -116,53 +108,26 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { .num_fractional_digits .max(increment.num_fractional_digits); - let result = match (first.number, increment.number, last.number) { - (Number::Int(first), Number::Int(increment), last) => { - let last = last.round_towards(&first); - let format = match options.format { - Some(f) => { - let f = Format::::parse(f)?; - Some(f) - } - None => None, - }; - print_seq_integers( - (first, increment, last), - &options.separator, - &options.terminator, - options.equal_width, - padding, - format, - ) - } - (first, increment, last) => { - let format = match options.format { - Some(f) => { - let f = Format::::parse(f)?; - Some(f) - } - None => None, - }; - print_seq( - ( - first.into_extended_big_decimal(), - increment.into_extended_big_decimal(), - last.into_extended_big_decimal(), - ), - largest_dec, - &options.separator, - &options.terminator, - options.equal_width, - padding, - format, - ) + let format = match options.format { + Some(f) => { + let f = Format::::parse(f)?; + Some(f) } + None => None, }; + let result = print_seq( + (first.number, increment.number, last.number), + largest_dec, + &options.separator, + &options.terminator, + options.equal_width, + padding, + format, + ); match result { Ok(_) => Ok(()), - _ => todo!(), - // Err(err) if err.kind() == ErrorKind::BrokenPipe => Ok(()), - // Err(e) => Err(e.map_err_context(|| "write error".into())), + Err(err) if err.kind() == ErrorKind::BrokenPipe => Ok(()), + Err(e) => Err(e.map_err_context(|| "write error".into())), } } @@ -230,28 +195,6 @@ fn write_value_float( write!(writer, "{value_as_str}") } -/// Write a big int formatted according to the given parameters. -fn write_value_int( - writer: &mut impl Write, - value: &ExtendedBigInt, - width: usize, - pad: bool, -) -> std::io::Result<()> { - let value_as_str = if pad { - if *value == ExtendedBigInt::MinusZero { - format!("{value:00width$}") - } - } else { - format!("{value}") - }; - write!(writer, "{value_as_str}") -} - -// TODO `print_seq()` and `print_seq_integers()` are nearly identical, -// they could be refactored into a single more general function. - /// Floating point based code path fn print_seq( range: RangeFloat, @@ -261,12 +204,16 @@ fn print_seq( pad: bool, padding: usize, format: Option>, -) -> UResult<()> { +) -> std::io::Result<()> { let stdout = stdout(); let mut stdout = stdout.lock(); let (first, increment, last) = range; let mut value = first; - let padding = if pad { padding + 1 + largest_dec } else { 0 }; + let padding = if pad { + padding + if largest_dec > 0 { largest_dec + 1 } else { 0 } + } else { + 0 + }; let mut is_first_iteration = true; while !done_printing(&value, &increment, &last) { if !is_first_iteration { @@ -307,65 +254,3 @@ fn print_seq( stdout.flush()?; Ok(()) } - -/// Print an integer sequence. -/// -/// This function prints a sequence of integers defined by `range`, -/// which defines the first integer, last integer, and increment of the -/// range. The `separator` is inserted between each integer and -/// `terminator` is inserted at the end. -/// -/// The `pad` parameter indicates whether to pad numbers to the width -/// given in `padding`. -/// -/// If `is_first_minus_zero` is `true`, then the `first` parameter is -/// printed as if it were negative zero, even though no such number -/// exists as an integer (negative zero only exists for floating point -/// numbers). Only set this to `true` if `first` is actually zero. -fn print_seq_integers( - range: RangeInt, - separator: &str, - terminator: &str, - pad: bool, - padding: usize, - format: Option>, -) -> UResult<()> { - let stdout = stdout(); - let mut stdout = stdout.lock(); - let (first, increment, last) = range; - let mut value = first; - let mut is_first_iteration = true; - while !done_printing(&value, &increment, &last) { - if !is_first_iteration { - write!(stdout, "{separator}")?; - } - // If there was an argument `-f FORMAT`, then use that format - // template instead of the default formatting strategy. - // - // The `printf()` function takes in the template and - // the current value and writes the result to `stdout`. - // - // TODO See similar comment about formatting in `print_seq()`. - match &format { - Some(f) => { - let int = match &value { - ExtendedBigInt::BigInt(bi) => bi.to_i64().unwrap(), - ExtendedBigInt::Infinity => todo!(), - ExtendedBigInt::MinusInfinity => todo!(), - ExtendedBigInt::MinusZero => todo!(), - ExtendedBigInt::Nan => todo!(), - }; - f.fmt(&mut stdout, int)?; - } - None => write_value_int(&mut stdout, &value, padding, pad)?, - } - // TODO Implement augmenting addition. - value = value + increment.clone(); - is_first_iteration = false; - } - - if !is_first_iteration { - write!(stdout, "{terminator}")?; - } - Ok(()) -} diff --git a/src/uucore/src/lib/features/format/mod.rs b/src/uucore/src/lib/features/format/mod.rs index 48151be98..d6500b20c 100644 --- a/src/uucore/src/lib/features/format/mod.rs +++ b/src/uucore/src/lib/features/format/mod.rs @@ -115,7 +115,7 @@ fn parse_iter(fmt: &[u8]) -> impl Iterator { let spec = match Spec::parse(&mut rest) { Some(spec) => spec, - None => return Some(Err(FormatError::SpecError)), + None => return Some(Err(dbg!(FormatError::SpecError))), }; Some(Ok(FormatItem::Spec(spec))) } @@ -230,7 +230,7 @@ impl Format { for item in &mut iter { match item? { FormatItem::Spec(_) => { - return Err(FormatError::SpecError); + return Err(dbg!(FormatError::SpecError)); } FormatItem::Text(t) => suffix.extend_from_slice(&t), FormatItem::Char(c) => suffix.push(c), diff --git a/src/uucore/src/lib/features/format/num_format.rs b/src/uucore/src/lib/features/format/num_format.rs index fd010bdc0..046249a13 100644 --- a/src/uucore/src/lib/features/format/num_format.rs +++ b/src/uucore/src/lib/features/format/num_format.rs @@ -13,14 +13,14 @@ pub trait Formatter { Self: Sized; } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum UnsignedIntVariant { Decimal, Octal(Prefix), Hexadecimal(Case, Prefix), } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum FloatVariant { Decimal, @@ -29,32 +29,32 @@ pub enum FloatVariant { Hexadecimal, } -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Case { Lowercase, Uppercase, } -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Prefix { No, Yes, } -#[derive(Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum ForceDecimal { No, Yes, } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum PositiveSign { None, Plus, Space, } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum NumberAlignment { Left, RightSpace, @@ -93,7 +93,7 @@ impl Formatter for SignedInt { alignment, } = s else { - return Err(FormatError::SpecError); + return Err(dbg!(FormatError::SpecError)); }; let width = match width { @@ -152,7 +152,7 @@ impl Formatter for UnsignedInt { alignment, } = s else { - return Err(FormatError::SpecError); + return Err(dbg!(FormatError::SpecError)); }; let width = match width { @@ -241,19 +241,19 @@ impl Formatter for Float { precision, } = s else { - return Err(FormatError::SpecError); + return Err(dbg!(FormatError::SpecError)); }; let width = match width { Some(CanAsterisk::Fixed(x)) => x, None => 0, - Some(CanAsterisk::Asterisk) => return Err(FormatError::SpecError), + Some(CanAsterisk::Asterisk) => return Err(dbg!(FormatError::SpecError)), }; let precision = match precision { Some(CanAsterisk::Fixed(x)) => x, None => 0, - Some(CanAsterisk::Asterisk) => return Err(FormatError::SpecError), + Some(CanAsterisk::Asterisk) => return Err(dbg!(FormatError::SpecError)), }; Ok(Self { diff --git a/src/uucore/src/lib/features/format/spec.rs b/src/uucore/src/lib/features/format/spec.rs index 9c53669fa..abc9b7a87 100644 --- a/src/uucore/src/lib/features/format/spec.rs +++ b/src/uucore/src/lib/features/format/spec.rs @@ -9,6 +9,7 @@ use super::{ }; use std::{fmt::Display, io::Write}; +#[derive(Debug)] pub enum Spec { Char { width: Option>, @@ -41,7 +42,7 @@ pub enum Spec { /// Precision and width specified might use an asterisk to indicate that they are /// determined by an argument. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum CanAsterisk { Fixed(T), Asterisk, @@ -99,6 +100,7 @@ impl Spec { let width = eat_asterisk_or_number(rest); let precision = if let Some(b'.') = rest.get(0) { + *rest = &rest[1..]; Some(eat_asterisk_or_number(rest).unwrap_or(CanAsterisk::Fixed(0))) } else { None @@ -134,7 +136,9 @@ impl Spec { *rest = &rest[1..]; } - Some(match rest.get(0)? { + let type_spec = rest.get(0)?; + *rest = &rest[1..]; + Some(match type_spec { b'c' => Spec::Char { width, align_left: minus, @@ -208,7 +212,10 @@ impl Spec { (false, false) => PositiveSign::None, }, }, - _ => return None, + x => { + dbg!("{:b}", x); + return dbg!(None) + }, }) }