From 4fd623a0666e8d59d3a9bd4e76ef1c6457df4f1d Mon Sep 17 00:00:00 2001 From: dracarys18 Date: Sat, 20 Apr 2024 21:56:45 +0530 Subject: [PATCH 1/6] fix: dont round off floats while formatting --- tests/formatting.rs | 111 ++++++++++++++++----------------- time/src/formatting/iso8601.rs | 6 +- time/src/formatting/mod.rs | 37 +++++++++-- 3 files changed, 91 insertions(+), 63 deletions(-) diff --git a/tests/formatting.rs b/tests/formatting.rs index e54a9f618..01903fdad 100644 --- a/tests/formatting.rs +++ b/tests/formatting.rs @@ -3,6 +3,7 @@ use std::io; use time::format_description::well_known::iso8601::{DateKind, OffsetPrecision, TimePrecision}; use time::format_description::well_known::{iso8601, Iso8601, Rfc2822, Rfc3339}; use time::format_description::{self, BorrowedFormatItem, OwnedFormatItem}; +use time::formatting::FloatNum; use time::macros::{date, datetime, format_description as fd, offset, time}; use time::{OffsetDateTime, Time}; @@ -109,12 +110,10 @@ fn iso_8601() -> time::Result<()> { }; } - assert!( - std::panic::catch_unwind(|| { - let _unused = datetime!(2021-01-02 03:04:05 UTC).format(&Iso8601::PARSING); - }) - .is_err() - ); + assert!(std::panic::catch_unwind(|| { + let _unused = datetime!(2021-01-02 03:04:05 UTC).format(&Iso8601::PARSING); + }) + .is_err()); assert_eq!( datetime!(-123_456-01-02 03:04:05 UTC).format( &Iso8601::< @@ -266,20 +265,16 @@ fn format_time() -> time::Result<()> { time!(13:02:03.456_789_012).format(format_description)?, output ); - assert!( - time!(13:02:03.456_789_012) - .format_into(&mut io::sink(), format_description) - .is_ok() - ); + assert!(time!(13:02:03.456_789_012) + .format_into(&mut io::sink(), format_description) + .is_ok()); assert_eq!( time!(13:02:03.456_789_012).format(&OwnedFormatItem::from(format_description))?, output ); - assert!( - time!(13:02:03.456_789_012) - .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) - .is_ok() - ); + assert!(time!(13:02:03.456_789_012) + .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) + .is_ok()); } assert_eq!( @@ -376,20 +371,16 @@ fn format_date() -> time::Result<()> { for &(format_description, output) in &format_output { assert_eq!(date!(2019 - 12 - 31).format(format_description)?, output); - assert!( - date!(2019 - 12 - 31) - .format_into(&mut io::sink(), format_description) - .is_ok() - ); + assert!(date!(2019 - 12 - 31) + .format_into(&mut io::sink(), format_description) + .is_ok()); assert_eq!( date!(2019 - 12 - 31).format(&OwnedFormatItem::from(format_description))?, output ); - assert!( - date!(2019 - 12 - 31) - .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) - .is_ok() - ); + assert!(date!(2019 - 12 - 31) + .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) + .is_ok()); } Ok(()) @@ -437,20 +428,16 @@ fn format_offset() -> time::Result<()> { for &(value, format_description, output) in &value_format_output { assert_eq!(value.format(format_description)?, output); - assert!( - value - .format_into(&mut io::sink(), format_description) - .is_ok() - ); + assert!(value + .format_into(&mut io::sink(), format_description) + .is_ok()); assert_eq!( value.format(&OwnedFormatItem::from(format_description))?, output ); - assert!( - value - .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) - .is_ok() - ); + assert!(value + .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) + .is_ok()); } Ok(()) @@ -480,20 +467,16 @@ fn format_pdt() -> time::Result<()> { datetime!(1970-01-01 0:00).format(format_description)?, "1970-01-01 00:00:00.0" ); - assert!( - datetime!(1970-01-01 0:00) - .format_into(&mut io::sink(), format_description) - .is_ok() - ); + assert!(datetime!(1970-01-01 0:00) + .format_into(&mut io::sink(), format_description) + .is_ok()); assert_eq!( datetime!(1970-01-01 0:00).format(&OwnedFormatItem::from(format_description))?, "1970-01-01 00:00:00.0" ); - assert!( - datetime!(1970-01-01 0:00) - .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) - .is_ok() - ); + assert!(datetime!(1970-01-01 0:00) + .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) + .is_ok()); Ok(()) } @@ -521,20 +504,16 @@ fn format_odt() -> time::Result<()> { datetime!(1970-01-01 0:00 UTC).format(&format_description)?, "1970-01-01 00:00:00.0 +00:00:00" ); - assert!( - datetime!(1970-01-01 0:00 UTC) - .format_into(&mut io::sink(), &format_description) - .is_ok() - ); + assert!(datetime!(1970-01-01 0:00 UTC) + .format_into(&mut io::sink(), &format_description) + .is_ok()); assert_eq!( datetime!(1970-01-01 0:00 UTC).format(&OwnedFormatItem::from(&format_description))?, "1970-01-01 00:00:00.0 +00:00:00" ); - assert!( - datetime!(1970-01-01 0:00 UTC) - .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) - .is_ok() - ); + assert!(datetime!(1970-01-01 0:00 UTC) + .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) + .is_ok()); Ok(()) } @@ -785,3 +764,23 @@ fn unix_timestamp() -> time::Result<()> { Ok(()) } + +#[test] +fn test_float_formatting() -> time::Result<()> { + let num: FloatNum = 2.99999999.into(); + let width = 3; + + // Less than digits after decimal places + let precision = 3; + assert_eq!(format!("{num:0>width$.precision$}"), "2.999"); + + // More than digits after decimal places + let precision = 10; + assert_eq!(format!("{num:0>width$.precision$}"), "2.9999999900"); + + // Equal digits after decimal places + let precision = 8; + assert_eq!(format!("{num:0>width$.precision$}"), "2.99999999"); + + Ok(()) +} diff --git a/time/src/formatting/iso8601.rs b/time/src/formatting/iso8601.rs index ee49d7d89..cd0604b4e 100644 --- a/time/src/formatting/iso8601.rs +++ b/time/src/formatting/iso8601.rs @@ -90,7 +90,7 @@ pub(super) fn format_time( + (minutes as f64) / Minute::per(Hour) as f64 + (seconds as f64) / Second::per(Hour) as f64 + (nanoseconds as f64) / Nanosecond::per(Hour) as f64; - format_float(output, hours, 2, decimal_digits)?; + format_float(output, hours.into(), 2, decimal_digits)?; } TimePrecision::Minute { decimal_digits } => { bytes += format_number_pad_zero::<2>(output, hours)?; @@ -98,7 +98,7 @@ pub(super) fn format_time( let minutes = (minutes as f64) + (seconds as f64) / Second::per(Minute) as f64 + (nanoseconds as f64) / Nanosecond::per(Minute) as f64; - bytes += format_float(output, minutes, 2, decimal_digits)?; + bytes += format_float(output, minutes.into(), 2, decimal_digits)?; } TimePrecision::Second { decimal_digits } => { bytes += format_number_pad_zero::<2>(output, hours)?; @@ -106,7 +106,7 @@ pub(super) fn format_time( bytes += format_number_pad_zero::<2>(output, minutes)?; bytes += write_if(output, Iso8601::::USE_SEPARATORS, b":")?; let seconds = (seconds as f64) + (nanoseconds as f64) / Nanosecond::per(Second) as f64; - bytes += format_float(output, seconds, 2, decimal_digits)?; + bytes += format_float(output, seconds.into(), 2, decimal_digits)?; } } diff --git a/time/src/formatting/mod.rs b/time/src/formatting/mod.rs index b57c15222..20467ca34 100644 --- a/time/src/formatting/mod.rs +++ b/time/src/formatting/mod.rs @@ -2,7 +2,7 @@ pub(crate) mod formattable; mod iso8601; -use core::num::NonZeroU8; +use core::{fmt, num::NonZeroU8}; use std::io; use num_conv::prelude::*; @@ -40,6 +40,31 @@ const WEEKDAY_NAMES: [&[u8]; 7] = [ b"Sunday", ]; +/// Wrapper struct for f64 with custom Display formatter +#[derive(Debug, Clone, Copy)] +pub struct FloatNum(f64); + +impl From for FloatNum { + fn from(num: f64) -> Self { + Self(num) + } +} + +impl core::fmt::Display for FloatNum { + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + if let Some(precision) = fmt.precision() { + let precision: i32 = precision.try_into().map_err(|_| fmt::Error)?; + + // Truncate the decimal points up to the precision + let trunc_num = 10.0_f64.powi(precision); + let num_to_format = f64::trunc(self.0 * trunc_num) / trunc_num; + + return num_to_format.fmt(fmt); + } + self.0.fmt(fmt) + } +} + /// Write all bytes to the output, returning the number of bytes written. pub(crate) fn write(output: &mut impl io::Write, bytes: &[u8]) -> io::Result { output.write_all(bytes)?; @@ -48,7 +73,11 @@ pub(crate) fn write(output: &mut impl io::Write, bytes: &[u8]) -> io::Result io::Result { - if pred { write(output, bytes) } else { Ok(0) } + if pred { + write(output, bytes) + } else { + Ok(0) + } } /// If `pred` is true, write `true_bytes` to the output. Otherwise, write `false_bytes`. @@ -67,7 +96,7 @@ pub(crate) fn write_if_else( /// with zeroes to the left if necessary. pub(crate) fn format_float( output: &mut impl io::Write, - value: f64, + value: FloatNum, digits_before_decimal: u8, digits_after_decimal: Option, ) -> io::Result { @@ -79,7 +108,7 @@ pub(crate) fn format_float( Ok(width) } None => { - let value = value.trunc() as u64; + let value = value.0.trunc() as u64; let width = digits_before_decimal.extend(); write!(output, "{value:0>width$}")?; Ok(width) From 31542f3c0622e7ea29300fbe3eb85687a73d868f Mon Sep 17 00:00:00 2001 From: dracarys18 Date: Sat, 20 Apr 2024 22:03:49 +0530 Subject: [PATCH 2/6] chore: fmt --- time/src/formatting/mod.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/time/src/formatting/mod.rs b/time/src/formatting/mod.rs index 20467ca34..7fa45c932 100644 --- a/time/src/formatting/mod.rs +++ b/time/src/formatting/mod.rs @@ -2,7 +2,8 @@ pub(crate) mod formattable; mod iso8601; -use core::{fmt, num::NonZeroU8}; +use core::fmt; +use core::num::NonZeroU8; use std::io; use num_conv::prelude::*; @@ -73,11 +74,7 @@ pub(crate) fn write(output: &mut impl io::Write, bytes: &[u8]) -> io::Result io::Result { - if pred { - write(output, bytes) - } else { - Ok(0) - } + if pred { write(output, bytes) } else { Ok(0) } } /// If `pred` is true, write `true_bytes` to the output. Otherwise, write `false_bytes`. From 6eaffca327aaf15cb0bcd83ae060c1abc864d223 Mon Sep 17 00:00:00 2001 From: dracarys18 Date: Mon, 22 Apr 2024 12:27:50 +0530 Subject: [PATCH 3/6] chore: dont do implicit return --- time/src/formatting/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/time/src/formatting/mod.rs b/time/src/formatting/mod.rs index 7fa45c932..40e6c4e54 100644 --- a/time/src/formatting/mod.rs +++ b/time/src/formatting/mod.rs @@ -60,9 +60,10 @@ impl core::fmt::Display for FloatNum { let trunc_num = 10.0_f64.powi(precision); let num_to_format = f64::trunc(self.0 * trunc_num) / trunc_num; - return num_to_format.fmt(fmt); + num_to_format.fmt(fmt) + } else { + self.0.fmt(fmt) } - self.0.fmt(fmt) } } From ff0c1aeefb903305a989b162c14a54844b69daf8 Mon Sep 17 00:00:00 2001 From: dracarys18 Date: Mon, 22 Apr 2024 12:29:52 +0530 Subject: [PATCH 4/6] chore: revert formatting on tests --- tests/formatting.rs | 91 ++++++++++++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 35 deletions(-) diff --git a/tests/formatting.rs b/tests/formatting.rs index 01903fdad..101f62c3f 100644 --- a/tests/formatting.rs +++ b/tests/formatting.rs @@ -3,7 +3,6 @@ use std::io; use time::format_description::well_known::iso8601::{DateKind, OffsetPrecision, TimePrecision}; use time::format_description::well_known::{iso8601, Iso8601, Rfc2822, Rfc3339}; use time::format_description::{self, BorrowedFormatItem, OwnedFormatItem}; -use time::formatting::FloatNum; use time::macros::{date, datetime, format_description as fd, offset, time}; use time::{OffsetDateTime, Time}; @@ -110,10 +109,12 @@ fn iso_8601() -> time::Result<()> { }; } - assert!(std::panic::catch_unwind(|| { - let _unused = datetime!(2021-01-02 03:04:05 UTC).format(&Iso8601::PARSING); - }) - .is_err()); + assert!( + std::panic::catch_unwind(|| { + let _unused = datetime!(2021-01-02 03:04:05 UTC).format(&Iso8601::PARSING); + }) + .is_err() + ); assert_eq!( datetime!(-123_456-01-02 03:04:05 UTC).format( &Iso8601::< @@ -265,16 +266,20 @@ fn format_time() -> time::Result<()> { time!(13:02:03.456_789_012).format(format_description)?, output ); - assert!(time!(13:02:03.456_789_012) - .format_into(&mut io::sink(), format_description) - .is_ok()); + assert!( + time!(13:02:03.456_789_012) + .format_into(&mut io::sink(), format_description) + .is_ok() + ); assert_eq!( time!(13:02:03.456_789_012).format(&OwnedFormatItem::from(format_description))?, output ); - assert!(time!(13:02:03.456_789_012) - .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) - .is_ok()); + assert!( + time!(13:02:03.456_789_012) + .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) + .is_ok() + ); } assert_eq!( @@ -371,16 +376,20 @@ fn format_date() -> time::Result<()> { for &(format_description, output) in &format_output { assert_eq!(date!(2019 - 12 - 31).format(format_description)?, output); - assert!(date!(2019 - 12 - 31) - .format_into(&mut io::sink(), format_description) - .is_ok()); + assert!( + date!(2019 - 12 - 31) + .format_into(&mut io::sink(), format_description) + .is_ok() + ); assert_eq!( date!(2019 - 12 - 31).format(&OwnedFormatItem::from(format_description))?, output ); - assert!(date!(2019 - 12 - 31) - .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) - .is_ok()); + assert!( + date!(2019 - 12 - 31) + .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) + .is_ok() + ); } Ok(()) @@ -428,16 +437,20 @@ fn format_offset() -> time::Result<()> { for &(value, format_description, output) in &value_format_output { assert_eq!(value.format(format_description)?, output); - assert!(value - .format_into(&mut io::sink(), format_description) - .is_ok()); + assert!( + value + .format_into(&mut io::sink(), format_description) + .is_ok() + ); assert_eq!( value.format(&OwnedFormatItem::from(format_description))?, output ); - assert!(value - .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) - .is_ok()); + assert!( + value + .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) + .is_ok() + ); } Ok(()) @@ -467,16 +480,20 @@ fn format_pdt() -> time::Result<()> { datetime!(1970-01-01 0:00).format(format_description)?, "1970-01-01 00:00:00.0" ); - assert!(datetime!(1970-01-01 0:00) - .format_into(&mut io::sink(), format_description) - .is_ok()); + assert!( + datetime!(1970-01-01 0:00) + .format_into(&mut io::sink(), format_description) + .is_ok() + ); assert_eq!( datetime!(1970-01-01 0:00).format(&OwnedFormatItem::from(format_description))?, "1970-01-01 00:00:00.0" ); - assert!(datetime!(1970-01-01 0:00) - .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) - .is_ok()); + assert!( + datetime!(1970-01-01 0:00) + .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) + .is_ok() + ); Ok(()) } @@ -504,16 +521,20 @@ fn format_odt() -> time::Result<()> { datetime!(1970-01-01 0:00 UTC).format(&format_description)?, "1970-01-01 00:00:00.0 +00:00:00" ); - assert!(datetime!(1970-01-01 0:00 UTC) - .format_into(&mut io::sink(), &format_description) - .is_ok()); + assert!( + datetime!(1970-01-01 0:00 UTC) + .format_into(&mut io::sink(), &format_description) + .is_ok() + ); assert_eq!( datetime!(1970-01-01 0:00 UTC).format(&OwnedFormatItem::from(&format_description))?, "1970-01-01 00:00:00.0 +00:00:00" ); - assert!(datetime!(1970-01-01 0:00 UTC) - .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) - .is_ok()); + assert!( + datetime!(1970-01-01 0:00 UTC) + .format_into(&mut io::sink(), &OwnedFormatItem::from(format_description)) + .is_ok() + ); Ok(()) } From dacd1e4d9f858ef13df9cc1434240fd19f044aa8 Mon Sep 17 00:00:00 2001 From: dracarys18 Date: Mon, 22 Apr 2024 12:34:05 +0530 Subject: [PATCH 5/6] chore: fix import --- tests/formatting.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/formatting.rs b/tests/formatting.rs index 101f62c3f..7877b4a70 100644 --- a/tests/formatting.rs +++ b/tests/formatting.rs @@ -5,6 +5,7 @@ use time::format_description::well_known::{iso8601, Iso8601, Rfc2822, Rfc3339}; use time::format_description::{self, BorrowedFormatItem, OwnedFormatItem}; use time::macros::{date, datetime, format_description as fd, offset, time}; use time::{OffsetDateTime, Time}; +use time::formatting::FloatNum; #[test] fn rfc_2822() -> time::Result<()> { From 50bbfabfbe941033077d2b98213a7b99b7a4a803 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Wed, 29 May 2024 01:54:20 -0400 Subject: [PATCH 6/6] Rework bug fix to avoid exposing internals --- tests/formatting.rs | 42 +++++++++++++++++----------------- time/src/formatting/iso8601.rs | 6 ++--- time/src/formatting/mod.rs | 36 ++++++----------------------- 3 files changed, 31 insertions(+), 53 deletions(-) diff --git a/tests/formatting.rs b/tests/formatting.rs index 7877b4a70..6cb403b74 100644 --- a/tests/formatting.rs +++ b/tests/formatting.rs @@ -1,11 +1,11 @@ use std::io; +use std::num::NonZeroU8; use time::format_description::well_known::iso8601::{DateKind, OffsetPrecision, TimePrecision}; use time::format_description::well_known::{iso8601, Iso8601, Rfc2822, Rfc3339}; use time::format_description::{self, BorrowedFormatItem, OwnedFormatItem}; use time::macros::{date, datetime, format_description as fd, offset, time}; use time::{OffsetDateTime, Time}; -use time::formatting::FloatNum; #[test] fn rfc_2822() -> time::Result<()> { @@ -227,6 +227,26 @@ fn iso_8601() -> time::Result<()> { Ok(()) } +#[test] +fn iso_8601_issue_678() -> time::Result<()> { + macro_rules! assert_format_config { + ($formatted:literal $(, $($config:tt)+)?) => { + assert_eq!( + datetime!(2021-01-02 03:04:05.999_999_999 UTC).format( + &Iso8601::<{ iso8601::Config::DEFAULT$($($config)+)?.encode() }> + )?, + $formatted + ); + }; + } + + assert_format_config!("2021-01-02T03:04:05.999999999Z", .set_time_precision(TimePrecision::Second { decimal_digits: NonZeroU8::new(9) })); + assert_format_config!("2021-01-02T03:04:05.999999Z", .set_time_precision(TimePrecision::Second { decimal_digits: NonZeroU8::new(6) })); + assert_format_config!("2021-01-02T03:04:05.999Z", .set_time_precision(TimePrecision::Second { decimal_digits: NonZeroU8::new(3) })); + + Ok(()) +} + #[test] fn format_time() -> time::Result<()> { let format_output = [ @@ -786,23 +806,3 @@ fn unix_timestamp() -> time::Result<()> { Ok(()) } - -#[test] -fn test_float_formatting() -> time::Result<()> { - let num: FloatNum = 2.99999999.into(); - let width = 3; - - // Less than digits after decimal places - let precision = 3; - assert_eq!(format!("{num:0>width$.precision$}"), "2.999"); - - // More than digits after decimal places - let precision = 10; - assert_eq!(format!("{num:0>width$.precision$}"), "2.9999999900"); - - // Equal digits after decimal places - let precision = 8; - assert_eq!(format!("{num:0>width$.precision$}"), "2.99999999"); - - Ok(()) -} diff --git a/time/src/formatting/iso8601.rs b/time/src/formatting/iso8601.rs index cd0604b4e..ee49d7d89 100644 --- a/time/src/formatting/iso8601.rs +++ b/time/src/formatting/iso8601.rs @@ -90,7 +90,7 @@ pub(super) fn format_time( + (minutes as f64) / Minute::per(Hour) as f64 + (seconds as f64) / Second::per(Hour) as f64 + (nanoseconds as f64) / Nanosecond::per(Hour) as f64; - format_float(output, hours.into(), 2, decimal_digits)?; + format_float(output, hours, 2, decimal_digits)?; } TimePrecision::Minute { decimal_digits } => { bytes += format_number_pad_zero::<2>(output, hours)?; @@ -98,7 +98,7 @@ pub(super) fn format_time( let minutes = (minutes as f64) + (seconds as f64) / Second::per(Minute) as f64 + (nanoseconds as f64) / Nanosecond::per(Minute) as f64; - bytes += format_float(output, minutes.into(), 2, decimal_digits)?; + bytes += format_float(output, minutes, 2, decimal_digits)?; } TimePrecision::Second { decimal_digits } => { bytes += format_number_pad_zero::<2>(output, hours)?; @@ -106,7 +106,7 @@ pub(super) fn format_time( bytes += format_number_pad_zero::<2>(output, minutes)?; bytes += write_if(output, Iso8601::::USE_SEPARATORS, b":")?; let seconds = (seconds as f64) + (nanoseconds as f64) / Nanosecond::per(Second) as f64; - bytes += format_float(output, seconds.into(), 2, decimal_digits)?; + bytes += format_float(output, seconds, 2, decimal_digits)?; } } diff --git a/time/src/formatting/mod.rs b/time/src/formatting/mod.rs index 40e6c4e54..f5a6de58e 100644 --- a/time/src/formatting/mod.rs +++ b/time/src/formatting/mod.rs @@ -2,7 +2,7 @@ pub(crate) mod formattable; mod iso8601; -use core::fmt; + use core::num::NonZeroU8; use std::io; @@ -41,32 +41,6 @@ const WEEKDAY_NAMES: [&[u8]; 7] = [ b"Sunday", ]; -/// Wrapper struct for f64 with custom Display formatter -#[derive(Debug, Clone, Copy)] -pub struct FloatNum(f64); - -impl From for FloatNum { - fn from(num: f64) -> Self { - Self(num) - } -} - -impl core::fmt::Display for FloatNum { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - if let Some(precision) = fmt.precision() { - let precision: i32 = precision.try_into().map_err(|_| fmt::Error)?; - - // Truncate the decimal points up to the precision - let trunc_num = 10.0_f64.powi(precision); - let num_to_format = f64::trunc(self.0 * trunc_num) / trunc_num; - - num_to_format.fmt(fmt) - } else { - self.0.fmt(fmt) - } - } -} - /// Write all bytes to the output, returning the number of bytes written. pub(crate) fn write(output: &mut impl io::Write, bytes: &[u8]) -> io::Result { output.write_all(bytes)?; @@ -94,19 +68,23 @@ pub(crate) fn write_if_else( /// with zeroes to the left if necessary. pub(crate) fn format_float( output: &mut impl io::Write, - value: FloatNum, + value: f64, digits_before_decimal: u8, digits_after_decimal: Option, ) -> io::Result { match digits_after_decimal { Some(digits_after_decimal) => { + // Truncate the decimal points up to the precision + let trunc_num = 10_f64.powi(digits_after_decimal.get().cast_signed().extend()); + let value = f64::trunc(value * trunc_num) / trunc_num; + let digits_after_decimal = digits_after_decimal.get().extend(); let width = digits_before_decimal.extend::() + 1 + digits_after_decimal; write!(output, "{value:0>width$.digits_after_decimal$}")?; Ok(width) } None => { - let value = value.0.trunc() as u64; + let value = value.trunc() as u64; let width = digits_before_decimal.extend(); write!(output, "{value:0>width$}")?; Ok(width)