From 48750f361a2049d32fdca4e3c533bb966970e7c8 Mon Sep 17 00:00:00 2001 From: Matthew Stone Date: Sun, 24 Mar 2024 21:04:34 -0700 Subject: [PATCH] Swap to Duration::round from temporal_rs (#3731) * Swap to Duration::round from temporal_rs * Clean up round method and impl From for RoundingMode enum * Fix build failure * Fix clippy error * Respond to comments * Remove commented line --- .../src/builtins/temporal/duration/mod.rs | 35 ++++++++++++------- core/engine/src/builtins/temporal/mod.rs | 35 ++++++++++++++----- core/engine/src/builtins/temporal/options.rs | 13 ++++--- 3 files changed, 54 insertions(+), 29 deletions(-) diff --git a/core/engine/src/builtins/temporal/duration/mod.rs b/core/engine/src/builtins/temporal/duration/mod.rs index c8d71d3797..4f0c3dc822 100644 --- a/core/engine/src/builtins/temporal/duration/mod.rs +++ b/core/engine/src/builtins/temporal/duration/mod.rs @@ -2,7 +2,7 @@ use crate::{ builtins::{ - options::{get_option, get_options_object, RoundingMode}, + options::{get_option, get_options_object}, BuiltInBuilder, BuiltInConstructor, BuiltInObject, IntrinsicObject, }, context::intrinsics::{Intrinsics, StandardConstructor, StandardConstructors}, @@ -15,7 +15,10 @@ use crate::{ }; use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; -use temporal_rs::{components::Duration as InnerDuration, options::TemporalUnit}; +use temporal_rs::{ + components::Duration as InnerDuration, + options::{RelativeTo, TemporalRoundingMode, TemporalUnit}, +}; use super::{ options::{get_temporal_rounding_increment, get_temporal_unit, TemporalUnitGroup}, @@ -590,7 +593,6 @@ impl Duration { .into()) } - // TODO: Migrate to `temporal_rs's Duration::round` /// 7.3.20 `Temporal.Duration.prototype.round ( roundTo )` pub(crate) fn round( this: &JsValue, @@ -599,7 +601,7 @@ impl Duration { ) -> JsResult { // 1. Let duration be the this value. // 2. Perform ? RequireInternalSlot(duration, [[InitializedTemporalDuration]]). - let _duration = this + let duration = this .as_object() .and_then(JsObject::downcast_ref::) .ok_or_else(|| { @@ -651,15 +653,15 @@ impl Duration { // 10. Let relativeToRecord be ? ToRelativeTemporalObject(roundTo). // 11. Let zonedRelativeTo be relativeToRecord.[[ZonedRelativeTo]]. // 12. Let plainRelativeTo be relativeToRecord.[[PlainRelativeTo]]. - let (_plain_relative_to, _zoned_relative_to) = + let (plain_relative_to, zoned_relative_to) = super::to_relative_temporal_object(&round_to, context)?; // 13. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo). - let _rounding_increment = get_temporal_rounding_increment(&round_to, context)?; + let rounding_increment = get_temporal_rounding_increment(&round_to, context)?; // 14. Let roundingMode be ? ToTemporalRoundingMode(roundTo, "halfExpand"). - let _rounding_mode = get_option(&round_to, utf16!("roundingMode"), context)? - .unwrap_or(RoundingMode::HalfExpand); + let rounding_mode = + get_option::(&round_to, utf16!("roundingMode"), context)?; // 15. Let smallestUnit be ? GetTemporalUnit(roundTo, "smallestUnit", datetime, undefined). let smallest_unit = get_temporal_unit( @@ -678,11 +680,18 @@ impl Duration { .with_message("smallestUnit or largestUnit must be present.") .into()); } - - // NOTE: - Err(JsNativeError::range() - .with_message("not yet implemented.") - .into()) + let rounded_duration = duration.inner.round( + rounding_increment, + smallest_unit, + largest_unit, + rounding_mode, + &RelativeTo { + date: plain_relative_to.as_ref(), + zdt: zoned_relative_to.as_ref(), + }, + context, + )?; + create_temporal_duration(rounded_duration, None, context).map(Into::into) } /// 7.3.21 `Temporal.Duration.prototype.total ( totalOf )` diff --git a/core/engine/src/builtins/temporal/mod.rs b/core/engine/src/builtins/temporal/mod.rs index f7b88efd4c..be27d83323 100644 --- a/core/engine/src/builtins/temporal/mod.rs +++ b/core/engine/src/builtins/temporal/mod.rs @@ -31,14 +31,18 @@ use crate::{ builtins::{iterable::IteratorRecord, BuiltInBuilder, BuiltInObject, IntrinsicObject}, context::intrinsics::Intrinsics, js_string, - property::Attribute, + property::{Attribute, PropertyKey}, realm::Realm, string::common::StaticJsStrings, value::Type, - Context, JsBigInt, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, + Context, JsBigInt, JsError, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; +use boa_macros::utf16; use boa_profiler::Profiler; -use temporal_rs::NS_PER_DAY; +use temporal_rs::{ + components::{Date as TemporalDate, ZonedDateTime as TemporalZonedDateTime}, + NS_PER_DAY, +}; // TODO: Remove in favor of `temporal_rs` pub(crate) fn ns_max_instant() -> JsBigInt { @@ -238,14 +242,27 @@ pub(crate) fn _iterator_to_list_of_types( // 13.17 `ValidateTemporalRoundingIncrement ( increment, dividend, inclusive )` // Moved to temporal_rs +type RelativeTemporalObjectResult = JsResult<( + Option>, + Option>, +)>; + /// 13.21 `ToRelativeTemporalObject ( options )` pub(crate) fn to_relative_temporal_object( - _options: &JsObject, - _context: &mut Context, -) -> JsResult<(Option, Option)> { - Err(JsNativeError::range() - .with_message("not yet implemented.") - .into()) + options: &JsObject, + context: &mut Context, +) -> RelativeTemporalObjectResult { + let relative_to = options.get(PropertyKey::from(utf16!("relativeTo")), context)?; + let plain_date = match relative_to { + JsValue::String(relative_to_str) => Some(relative_to_str.into()), + JsValue::Object(relative_to_obj) => Some(relative_to_obj.into()), + _ => None, + } + .map(|plane_date| Ok::<_, JsError>(to_temporal_date(&plane_date, None, context)?.inner)) + .transpose()?; + + // TODO: Implement TemporalZonedDateTime conversion when ZonedDateTime is implemented + Ok((plain_date, None)) } // 13.22 `LargerOfTwoTemporalUnits ( u1, u2 )` diff --git a/core/engine/src/builtins/temporal/options.rs b/core/engine/src/builtins/temporal/options.rs index 9059ed793b..bbdd360178 100644 --- a/core/engine/src/builtins/temporal/options.rs +++ b/core/engine/src/builtins/temporal/options.rs @@ -24,15 +24,14 @@ use temporal_rs::options::{ pub(crate) fn get_temporal_rounding_increment( options: &JsObject, context: &mut Context, -) -> JsResult { +) -> JsResult> { // 1. Let increment be ? GetOption(normalizedOptions, "roundingIncrement", "number", undefined, 1𝔽). let value = options.get(js_string!("roundingIncrement"), context)?; - let increment = if value.is_undefined() { - 1.0 - } else { - value.to_number(context)? - }; + if value.is_undefined() { + return Ok(None); + } + let increment = value.to_number(context)?; // 2. If increment is not finite, throw a RangeError exception. if !increment.is_finite() { @@ -52,7 +51,7 @@ pub(crate) fn get_temporal_rounding_increment( } // 5. Return integerIncrement. - Ok(integer_increment as u32) + Ok(Some(integer_increment)) } /// Gets the `TemporalUnit` from an options object.