diff --git a/crates/typst-cli/src/download.rs b/crates/typst-cli/src/download.rs index 3e3d8294d..ca1e539d4 100644 --- a/crates/typst-cli/src/download.rs +++ b/crates/typst-cli/src/download.rs @@ -5,7 +5,7 @@ use std::time::{Duration, Instant}; use codespan_reporting::term; use codespan_reporting::term::termcolor::WriteColor; -use typst::utils::format; +use typst::utils::format_duration; use typst_kit::download::{DownloadState, Downloader, Progress}; use crate::terminal::{self, TermOut}; @@ -62,9 +62,7 @@ pub fn display_download_progress( let total_downloaded = as_bytes_unit(state.total_downloaded); let speed_h = as_throughput_unit(speed); - let elapsed = format::time_starting_with_seconds( - &Instant::now().saturating_duration_since(state.start_time), - ); + let elapsed = Instant::now().saturating_duration_since(state.start_time); match state.content_len { Some(content_len) => { @@ -72,20 +70,26 @@ pub fn display_download_progress( let remaining = content_len - state.total_downloaded; let download_size = as_bytes_unit(content_len); - let eta = - format::time_starting_with_seconds(&Duration::from_secs(if speed == 0 { - 0 - } else { - (remaining / speed) as u64 - })); + let eta = Duration::from_secs(if speed == 0 { + 0 + } else { + (remaining / speed) as u64 + }); + writeln!( out, - "{total_downloaded} / {download_size} ({percent:3.0} %) {speed_h} in {elapsed} ETA: {eta}", + "{total_downloaded} / {download_size} ({percent:3.0} %) \ + {speed_h} in {elapsed} ETA: {eta}", + elapsed = format_duration(elapsed), + eta = format_duration(eta), )?; } None => writeln!( out, - "Total downloaded: {total_downloaded} Speed: {speed_h} Elapsed: {elapsed}", + "Total downloaded: {total_downloaded} \ + Speed: {speed_h} \ + Elapsed: {elapsed}", + elapsed = format_duration(elapsed), )?, }; Ok(()) diff --git a/crates/typst-cli/src/watch.rs b/crates/typst-cli/src/watch.rs index eb437ffdd..f3ca329b8 100644 --- a/crates/typst-cli/src/watch.rs +++ b/crates/typst-cli/src/watch.rs @@ -11,7 +11,7 @@ use ecow::eco_format; use notify::{Event, RecommendedWatcher, RecursiveMode, Watcher as _}; use same_file::is_same_file; use typst::diag::{bail, StrResult}; -use typst::utils::format; +use typst::utils::format_duration; use crate::args::{CompileCommand, Input, Output}; use crate::compile::compile_once; @@ -296,18 +296,14 @@ impl Status { } fn message(&self) -> String { - match self { + match *self { Self::Compiling => "compiling ...".into(), Self::Success(duration) => { - format!( - "compiled successfully in {}", - format::time_starting_with_milliseconds(duration, 2) - ) + format!("compiled successfully in {}", format_duration(duration)) + } + Self::PartialSuccess(duration) => { + format!("compiled with warnings in {}", format_duration(duration)) } - Self::PartialSuccess(duration) => format!( - "compiled with warnings in {}", - format::time_starting_with_milliseconds(duration, 2) - ), Self::Error => "compiled with errors".into(), } } diff --git a/crates/typst-ide/src/tooltip.rs b/crates/typst-ide/src/tooltip.rs index 02fb3ec62..532cda396 100644 --- a/crates/typst-ide/src/tooltip.rs +++ b/crates/typst-ide/src/tooltip.rs @@ -8,7 +8,7 @@ use typst::foundations::{repr, Capturer, CastInfo, Repr, Value}; use typst::layout::Length; use typst::model::Document; use typst::syntax::{ast, LinkedNode, Side, Source, SyntaxKind}; -use typst::utils::{round_2, Numeric}; +use typst::utils::{round_with_precision, Numeric}; use typst::World; use crate::{analyze_expr, analyze_labels, plain_docs_sentence, summarize_font_family}; @@ -142,10 +142,10 @@ fn length_tooltip(length: Length) -> Option { length.em.is_zero().then(|| { Tooltip::Code(eco_format!( "{}pt = {}mm = {}cm = {}in", - round_2(length.abs.to_pt()), - round_2(length.abs.to_mm()), - round_2(length.abs.to_cm()), - round_2(length.abs.to_inches()) + round_with_precision(length.abs.to_pt(), 2), + round_with_precision(length.abs.to_mm(), 2), + round_with_precision(length.abs.to_cm(), 2), + round_with_precision(length.abs.to_inches(), 2), )) }) } diff --git a/crates/typst-utils/src/duration.rs b/crates/typst-utils/src/duration.rs new file mode 100644 index 000000000..883482489 --- /dev/null +++ b/crates/typst-utils/src/duration.rs @@ -0,0 +1,94 @@ +use std::fmt::{self, Display, Formatter, Write}; +use std::time::Duration; + +use super::round_with_precision; + +/// Formats a duration with a precision suitable for human display. +pub fn format_duration(duration: Duration) -> impl Display { + DurationDisplay(duration) +} + +/// Displays a `Duration`. +struct DurationDisplay(Duration); + +impl Display for DurationDisplay { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let mut space = false; + macro_rules! piece { + ($($tts:tt)*) => { + if std::mem::replace(&mut space, true) { + f.write_char(' ')?; + } + write!(f, $($tts)*)?; + }; + } + + let secs = self.0.as_secs(); + let (mins, secs) = (secs / 60, (secs % 60)); + let (hours, mins) = (mins / 60, (mins % 60)); + let (days, hours) = ((hours / 24), (hours % 24)); + + if days > 0 { + piece!("{days} d"); + } + + if hours > 0 { + piece!("{hours} h"); + } + + if mins > 0 { + piece!("{mins} min"); + } + + // No need to display anything more than minutes at this point. + if days > 0 || hours > 0 { + return Ok(()); + } + + let order = |exp| 1000u64.pow(exp); + let nanos = secs * order(3) + self.0.subsec_nanos() as u64; + let fract = |exp| round_with_precision(nanos as f64 / order(exp) as f64, 2); + + if nanos == 0 || self.0 > Duration::from_secs(1) { + // For durations > 5 min, we drop the fractional part. + if self.0 > Duration::from_secs(300) { + piece!("{secs} s"); + } else { + piece!("{} s", fract(3)); + } + } else if self.0 > Duration::from_millis(1) { + piece!("{} ms", fract(2)); + } else if self.0 > Duration::from_micros(1) { + piece!("{} µs", fract(1)); + } else { + piece!("{} ns", fract(0)); + } + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[track_caller] + fn test(duration: Duration, expected: &str) { + assert_eq!(format_duration(duration).to_string(), expected); + } + + #[test] + fn test_format_duration() { + test(Duration::from_secs(1000000), "11 d 13 h 46 min"); + test(Duration::from_secs(3600 * 24), "1 d"); + test(Duration::from_secs(3600), "1 h"); + test(Duration::from_secs(3600 + 240), "1 h 4 min"); + test(Duration::from_secs_f64(364.77), "6 min 4 s"); + test(Duration::from_secs_f64(264.776), "4 min 24.78 s"); + test(Duration::from_secs(3), "3 s"); + test(Duration::from_secs_f64(2.8492), "2.85 s"); + test(Duration::from_micros(734), "734 µs"); + test(Duration::from_micros(294816), "294.82 ms"); + test(Duration::from_nanos(1), "1 ns"); + } +} diff --git a/crates/typst-utils/src/format.rs b/crates/typst-utils/src/format.rs deleted file mode 100644 index 36c6bb50a..000000000 --- a/crates/typst-utils/src/format.rs +++ /dev/null @@ -1,256 +0,0 @@ -//! Different formatting functions. - -use std::time::Duration; - -/// Returns value with `n` digits after floating point where `n` is `precision`. -/// Standard rounding rules apply (if `n+1`th digit >= 5, round up). -/// -/// If rounding the `value` will have no effect (e.g., it's infinite or NaN), -/// returns `value` unchanged. -/// -/// # Examples -/// -/// ``` -/// # use typst_utils::format::round_with_precision; -/// let rounded = round_with_precision(-0.56553, 2); -/// assert_eq!(-0.57, rounded); -/// ``` -pub fn round_with_precision(value: f64, precision: u8) -> f64 { - // Don't attempt to round the float if that wouldn't have any effect. - // This includes infinite or NaN values, as well as integer values - // with a filled mantissa (which can't have a fractional part). - // Rounding with a precision larger than the amount of digits that can be - // effectively represented would also be a no-op. Given that, the check - // below ensures we won't proceed if `|value| >= 2^53` or if - // `precision >= 15`, which also ensures the multiplication by `offset` - // won't return `inf`, since `2^53 * 10^15` (larger than any possible - // `value * offset` multiplication) does not. - if value.is_infinite() - || value.is_nan() - || value.abs() >= (1_i64 << f64::MANTISSA_DIGITS) as f64 - || precision as u32 >= f64::DIGITS - { - return value; - } - let offset = 10_f64.powi(precision.into()); - assert!((value * offset).is_finite(), "{value} * {offset} is not finite!"); - (value * offset).round() / offset -} - -/// Returns `(days, hours, minutes, seconds, milliseconds, microseconds)`. -fn get_duration_parts(duration: &Duration) -> (u64, u8, u8, u8, u16, u16) { - // In practice we probably don't need nanoseconds. - let micros = duration.as_micros(); - let (millis, micros) = (micros / 1000, (micros % 1000) as u16); - let (sec, millis) = (millis / 1000, (millis % 1000) as u16); - let (mins, sec) = (sec / 60, (sec % 60) as u8); - let (hours, mins) = (mins / 60, (mins % 60) as u8); - let (days, hours) = ((hours / 24) as u64, (hours % 24) as u8); - (days, hours, mins, sec, millis, micros) -} - -/// Format string using `days`, `hours`, `minutes`, `seconds`. -fn format_dhms(days: u64, hours: u8, minutes: u8, seconds: u8) -> String { - match (days, hours, minutes, seconds) { - (0, 0, 0, s) => format!("{s:2} s"), - (0, 0, m, s) => format!("{m:2} m {s:2} s"), - (0, h, m, s) => format!("{h:2} h {m:2} m {s:2} s"), - (d, h, m, s) => format!("{d:3} d {h:2} h {m:2} m {s:2} s"), - } -} - -/// Format string starting with number of seconds and going bigger from there. -/// -/// # Examples -/// -/// ``` -/// # use std::time::Duration; -/// # use typst_utils::format::time_starting_with_seconds; -/// let duration1 = time_starting_with_seconds(&Duration::from_secs(0)); -/// assert_eq!(" 0 s", &duration1); -/// -/// let duration2 = time_starting_with_seconds(&Duration::from_secs( -/// 24 * 60 * 60 * 100 + // days -/// 60 * 60 * 10 + // hours -/// 60 * 10 + // minutes -/// 10 // seconds -/// )); -/// assert_eq!("100 d 10 h 10 m 10 s", &duration2); -/// ``` -pub fn time_starting_with_seconds(duration: &Duration) -> String { - let (days, hours, minutes, seconds, _, _) = get_duration_parts(duration); - format_dhms(days, hours, minutes, seconds) -} - -/// Format string starting with number of milliseconds and going bigger -/// from there. `precision` is how many digits of microseconds -/// from floating point to the right will be preserved (with rounding). -/// Keep in mind that this function will always remove all trailing zeros -/// for microseconds. -/// -/// Note: if duration is 1 second or longer, then output will be identical -/// to [time_starting_with_seconds], which also means that precision, -/// number of milliseconds and microseconds will not be used. -/// -/// # Examples -/// -/// ``` -/// # use std::time::Duration; -/// # use typst_utils::format::time_starting_with_milliseconds; -/// let duration1 = time_starting_with_milliseconds(&Duration::from_micros( -/// 123 * 1000 + // milliseconds -/// 456 // microseconds -/// ), 2); -/// assert_eq!("123.46 ms", &duration1); -/// -/// let duration2 = time_starting_with_milliseconds(&Duration::from_micros( -/// 123 * 1000 // milliseconds -/// ), 2); -/// assert_eq!("123 ms", &duration2); -/// -/// let duration3 = time_starting_with_milliseconds(&Duration::from_secs(1), 2); -/// assert_eq!(" 1 s", &duration3); -/// ``` -pub fn time_starting_with_milliseconds(duration: &Duration, precision: u8) -> String { - let (d, h, m, s, ms, mcs) = get_duration_parts(duration); - match (d, h, m, s) { - (0, 0, 0, 0) => { - let ms_mcs = ms as f64 + mcs as f64 / 1000.0; - format!("{} ms", round_with_precision(ms_mcs, precision)) - } - (d, h, m, s) => format_dhms(d, h, m, s), - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_round_with_precision_0() { - let round = |value| round_with_precision(value, 0); - assert_eq!(0.0, round(0.0)); - assert_eq!(-0.0, round(-0.0)); - assert_eq!(0.0, round(0.4)); - assert_eq!(-0.0, round(-0.4)); - assert_eq!(1.0, round(0.56453)); - assert_eq!(-1.0, round(-0.56453)); - } - - #[test] - fn test_round_with_precision_1() { - let round = |value| round_with_precision(value, 1); - assert_eq!(0.0, round(0.0)); - assert_eq!(-0.0, round(-0.0)); - assert_eq!(0.4, round(0.4)); - assert_eq!(-0.4, round(-0.4)); - assert_eq!(0.4, round(0.44)); - assert_eq!(-0.4, round(-0.44)); - assert_eq!(0.6, round(0.56453)); - assert_eq!(-0.6, round(-0.56453)); - assert_eq!(1.0, round(0.96453)); - assert_eq!(-1.0, round(-0.96453)); - } - - #[test] - fn test_round_with_precision_2() { - let round = |value| round_with_precision(value, 2); - assert_eq!(0.0, round(0.0)); - assert_eq!(-0.0, round(-0.0)); - assert_eq!(0.4, round(0.4)); - assert_eq!(-0.4, round(-0.4)); - assert_eq!(0.44, round(0.44)); - assert_eq!(-0.44, round(-0.44)); - assert_eq!(0.44, round(0.444)); - assert_eq!(-0.44, round(-0.444)); - assert_eq!(0.57, round(0.56553)); - assert_eq!(-0.57, round(-0.56553)); - assert_eq!(1.0, round(0.99553)); - assert_eq!(-1.0, round(-0.99553)); - } - - #[test] - fn test_round_with_precision_fuzzy() { - let round = |value| round_with_precision(value, 0); - assert_eq!(f64::INFINITY, round(f64::INFINITY)); - assert_eq!(f64::NEG_INFINITY, round(f64::NEG_INFINITY)); - assert!(round(f64::NAN).is_nan()); - - let max_int = (1_i64 << f64::MANTISSA_DIGITS) as f64; - let f64_digits = f64::DIGITS as u8; - - // max - assert_eq!(max_int, round(max_int)); - assert_eq!(0.123456, round_with_precision(0.123456, f64_digits)); - assert_eq!(max_int, round_with_precision(max_int, f64_digits)); - - // max - 1 - assert_eq!(max_int - 1f64, round(max_int - 1f64)); - assert_eq!(0.123456, round_with_precision(0.123456, f64_digits - 1)); - assert_eq!(max_int - 1f64, round_with_precision(max_int - 1f64, f64_digits)); - assert_eq!(max_int, round_with_precision(max_int, f64_digits - 1)); - assert_eq!(max_int - 1f64, round_with_precision(max_int - 1f64, f64_digits - 1)); - } - - fn duration_from_milli_micro(milliseconds: u16, microseconds: u16) -> Duration { - let microseconds = microseconds as u64; - let milliseconds = 1000 * milliseconds as u64; - Duration::from_micros(milliseconds + microseconds) - } - - #[test] - fn test_time_starting_with_seconds() { - let f = |duration| time_starting_with_seconds(&duration); - fn duration(days: u16, hours: u8, minutes: u8, seconds: u8) -> Duration { - let seconds = seconds as u64; - let minutes = 60 * minutes as u64; - let hours = 60 * 60 * hours as u64; - let days = 24 * 60 * 60 * days as u64; - Duration::from_secs(days + hours + minutes + seconds) - } - assert_eq!(" 0 s", &f(duration(0, 0, 0, 0))); - assert_eq!("59 s", &f(duration(0, 0, 0, 59))); - assert_eq!(" 1 m 12 s", &f(duration(0, 0, 1, 12))); - assert_eq!("59 m 0 s", &f(duration(0, 0, 59, 0))); - assert_eq!(" 5 h 1 m 2 s", &f(duration(0, 5, 1, 2))); - assert_eq!(" 1 d 0 h 0 m 0 s", &f(duration(1, 0, 0, 0))); - assert_eq!(" 69 d 0 h 0 m 0 s", &f(duration(69, 0, 0, 0))); - assert_eq!("100 d 10 h 10 m 10 s", &f(duration(100, 10, 10, 10))); - } - - #[test] - fn test_time_as_ms_with_precision_1() { - let f = |duration| time_starting_with_milliseconds(&duration, 1); - let duration = duration_from_milli_micro; - assert_eq!("123.5 ms", &f(duration(123, 456))); - assert_eq!("123.5 ms", &f(duration(123, 455))); - assert_eq!("123.4 ms", &f(duration(123, 445))); - assert_eq!("123.4 ms", &f(duration(123, 440))); - assert_eq!("123.1 ms", &f(duration(123, 100))); - assert_eq!("123 ms", &f(duration(123, 0))); - } - - #[test] - fn test_time_as_ms_with_precision_2() { - let f = |duration| time_starting_with_milliseconds(&duration, 2); - let duration = duration_from_milli_micro; - assert_eq!("123.46 ms", &f(duration(123, 456))); - assert_eq!("123.46 ms", &f(duration(123, 455))); - assert_eq!("123.45 ms", &f(duration(123, 454))); - assert_eq!("123.45 ms", &f(duration(123, 450))); - assert_eq!("123.1 ms", &f(duration(123, 100))); - assert_eq!("123 ms", &f(duration(123, 0))); - } - - #[test] - fn test_time_as_ms_with_precision_3() { - let f = |duration| time_starting_with_milliseconds(&duration, 3); - let duration = duration_from_milli_micro; - assert_eq!("123.456 ms", &f(duration(123, 456))); - assert_eq!("123.455 ms", &f(duration(123, 455))); - assert_eq!("123.454 ms", &f(duration(123, 454))); - assert_eq!("123.45 ms", &f(duration(123, 450))); - assert_eq!("123.1 ms", &f(duration(123, 100))); - assert_eq!("123 ms", &f(duration(123, 0))); - } -} diff --git a/crates/typst-utils/src/lib.rs b/crates/typst-utils/src/lib.rs index 35f1f142a..77581860e 100644 --- a/crates/typst-utils/src/lib.rs +++ b/crates/typst-utils/src/lib.rs @@ -1,20 +1,23 @@ //! Utilities for Typst. pub mod fat; -pub mod format; #[macro_use] mod macros; mod bitset; mod deferred; +mod duration; mod hash; mod pico; +mod round; mod scalar; pub use self::bitset::{BitSet, SmallBitSet}; pub use self::deferred::Deferred; +pub use self::duration::format_duration; pub use self::hash::LazyHash; pub use self::pico::PicoStr; +pub use self::round::round_with_precision; pub use self::scalar::Scalar; use std::fmt::{Debug, Formatter}; @@ -298,8 +301,3 @@ pub trait Numeric: /// Whether `self` consists only of finite parts. fn is_finite(self) -> bool; } - -/// Round a float to two decimal places. -pub fn round_2(value: f64) -> f64 { - (value * 100.0).round() / 100.0 -} diff --git a/crates/typst-utils/src/round.rs b/crates/typst-utils/src/round.rs new file mode 100644 index 000000000..e72b45f71 --- /dev/null +++ b/crates/typst-utils/src/round.rs @@ -0,0 +1,105 @@ +/// Returns value with `n` digits after floating point where `n` is `precision`. +/// Standard rounding rules apply (if `n+1`th digit >= 5, round up). +/// +/// If rounding the `value` will have no effect (e.g., it's infinite or NaN), +/// returns `value` unchanged. +/// +/// # Examples +/// +/// ``` +/// # use typst_utils::round_with_precision; +/// let rounded = round_with_precision(-0.56553, 2); +/// assert_eq!(-0.57, rounded); +/// ``` +pub fn round_with_precision(value: f64, precision: u8) -> f64 { + // Don't attempt to round the float if that wouldn't have any effect. + // This includes infinite or NaN values, as well as integer values + // with a filled mantissa (which can't have a fractional part). + // Rounding with a precision larger than the amount of digits that can be + // effectively represented would also be a no-op. Given that, the check + // below ensures we won't proceed if `|value| >= 2^53` or if + // `precision >= 15`, which also ensures the multiplication by `offset` + // won't return `inf`, since `2^53 * 10^15` (larger than any possible + // `value * offset` multiplication) does not. + if value.is_infinite() + || value.is_nan() + || value.abs() >= (1_i64 << f64::MANTISSA_DIGITS) as f64 + || precision as u32 >= f64::DIGITS + { + return value; + } + let offset = 10_f64.powi(precision.into()); + assert!((value * offset).is_finite(), "{value} * {offset} is not finite!"); + (value * offset).round() / offset +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_round_with_precision_0() { + let round = |value| round_with_precision(value, 0); + assert_eq!(0.0, round(0.0)); + assert_eq!(-0.0, round(-0.0)); + assert_eq!(0.0, round(0.4)); + assert_eq!(-0.0, round(-0.4)); + assert_eq!(1.0, round(0.56453)); + assert_eq!(-1.0, round(-0.56453)); + } + + #[test] + fn test_round_with_precision_1() { + let round = |value| round_with_precision(value, 1); + assert_eq!(0.0, round(0.0)); + assert_eq!(-0.0, round(-0.0)); + assert_eq!(0.4, round(0.4)); + assert_eq!(-0.4, round(-0.4)); + assert_eq!(0.4, round(0.44)); + assert_eq!(-0.4, round(-0.44)); + assert_eq!(0.6, round(0.56453)); + assert_eq!(-0.6, round(-0.56453)); + assert_eq!(1.0, round(0.96453)); + assert_eq!(-1.0, round(-0.96453)); + } + + #[test] + fn test_round_with_precision_2() { + let round = |value| round_with_precision(value, 2); + assert_eq!(0.0, round(0.0)); + assert_eq!(-0.0, round(-0.0)); + assert_eq!(0.4, round(0.4)); + assert_eq!(-0.4, round(-0.4)); + assert_eq!(0.44, round(0.44)); + assert_eq!(-0.44, round(-0.44)); + assert_eq!(0.44, round(0.444)); + assert_eq!(-0.44, round(-0.444)); + assert_eq!(0.57, round(0.56553)); + assert_eq!(-0.57, round(-0.56553)); + assert_eq!(1.0, round(0.99553)); + assert_eq!(-1.0, round(-0.99553)); + } + + #[test] + fn test_round_with_precision_fuzzy() { + let round = |value| round_with_precision(value, 0); + assert_eq!(f64::INFINITY, round(f64::INFINITY)); + assert_eq!(f64::NEG_INFINITY, round(f64::NEG_INFINITY)); + assert!(round(f64::NAN).is_nan()); + + let max_int = (1_i64 << f64::MANTISSA_DIGITS) as f64; + let f64_digits = f64::DIGITS as u8; + + // max + assert_eq!(max_int, round(max_int)); + assert_eq!(0.123456, round_with_precision(0.123456, f64_digits)); + assert_eq!(max_int, round_with_precision(max_int, f64_digits)); + + // max - 1 + assert_eq!(max_int - 1f64, round(max_int - 1f64)); + assert_eq!(0.123456, round_with_precision(0.123456, f64_digits - 1)); + assert_eq!(max_int - 1f64, round_with_precision(max_int - 1f64, f64_digits)); + assert_eq!(max_int, round_with_precision(max_int, f64_digits - 1)); + assert_eq!(max_int - 1f64, round_with_precision(max_int - 1f64, f64_digits - 1)); + } +} diff --git a/crates/typst/src/foundations/calc.rs b/crates/typst/src/foundations/calc.rs index e91dd3aee..0e9ef1468 100644 --- a/crates/typst/src/foundations/calc.rs +++ b/crates/typst/src/foundations/calc.rs @@ -10,6 +10,7 @@ use crate::eval::ops; use crate::foundations::{cast, func, Decimal, IntoValue, Module, Scope, Value}; use crate::layout::{Angle, Fr, Length, Ratio}; use crate::syntax::{Span, Spanned}; +use crate::utils::round_with_precision; /// A module with calculation definitions. pub fn module() -> Module { @@ -743,10 +744,9 @@ pub fn round( ) -> DecNum { match value { DecNum::Int(n) => DecNum::Int(n), - DecNum::Float(n) => DecNum::Float(crate::utils::format::round_with_precision( - n, - digits.saturating_as::(), - )), + DecNum::Float(n) => { + DecNum::Float(round_with_precision(n, digits.saturating_as::())) + } DecNum::Decimal(n) => DecNum::Decimal(n.round(digits)), } } diff --git a/crates/typst/src/foundations/repr.rs b/crates/typst/src/foundations/repr.rs index 3b41c611e..551046042 100644 --- a/crates/typst/src/foundations/repr.rs +++ b/crates/typst/src/foundations/repr.rs @@ -3,7 +3,7 @@ use ecow::{eco_format, EcoString}; use crate::foundations::{func, Str, Value}; -use crate::utils::format::round_with_precision; +use crate::utils::round_with_precision; /// The Unicode minus sign. pub const MINUS_SIGN: &str = "\u{2212}";