From df6eeb83a883c1c83e309bb357ff0726c112e06c Mon Sep 17 00:00:00 2001 From: Kevin Ness <46825870+nekevss@users.noreply.github.com> Date: Sun, 15 Dec 2024 21:32:13 -0600 Subject: [PATCH] Update PR to temporal_rs FiniteF64 changes --- .../src/builtins/temporal/duration/mod.rs | 225 ++++++++++++------ .../src/builtins/temporal/instant/mod.rs | 2 +- core/engine/src/builtins/temporal/mod.rs | 128 +--------- .../src/builtins/temporal/plain_date/mod.rs | 87 +++---- .../builtins/temporal/plain_date_time/mod.rs | 64 +++-- .../builtins/temporal/plain_month_day/mod.rs | 71 +++--- .../src/builtins/temporal/plain_time/mod.rs | 84 ++++--- .../builtins/temporal/plain_year_month/mod.rs | 55 +++-- 8 files changed, 367 insertions(+), 349 deletions(-) diff --git a/core/engine/src/builtins/temporal/duration/mod.rs b/core/engine/src/builtins/temporal/duration/mod.rs index 31f8957ea9b..f8d2a539a14 100644 --- a/core/engine/src/builtins/temporal/duration/mod.rs +++ b/core/engine/src/builtins/temporal/duration/mod.rs @@ -11,7 +11,8 @@ use crate::{ property::Attribute, realm::Realm, string::StaticJsStrings, - Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, + Context, JsArgs, JsData, JsError, JsNativeError, JsObject, JsResult, JsString, JsSymbol, + JsValue, }; use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; @@ -23,7 +24,7 @@ use temporal_rs::{ use super::{ options::{get_temporal_unit, TemporalUnitGroup}, - to_integer_if_integral, DateTimeValues, + DateTimeValues, }; #[cfg(test)] @@ -222,66 +223,96 @@ impl BuiltInConstructor for Duration { // TOOD: Support conversion to i64 // 2. If years is undefined, let y be 0; else let y be ? ToIntegerIfIntegral(years). - let years = args - .get_or_undefined(0) - .map_or(Ok(0), |y| to_integer_if_integral(y, context))?; + let years = args.get_or_undefined(0).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; // 3. If months is undefined, let mo be 0; else let mo be ? ToIntegerIfIntegral(months). - let months = args - .get_or_undefined(1) - .map_or(Ok(0), |mo| to_integer_if_integral(mo, context))?; + let months = args.get_or_undefined(1).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; // 4. If weeks is undefined, let w be 0; else let w be ? ToIntegerIfIntegral(weeks). - let weeks = args - .get_or_undefined(2) - .map_or(Ok(0), |wk| to_integer_if_integral(wk, context))?; + let weeks = args.get_or_undefined(2).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; // 5. If days is undefined, let d be 0; else let d be ? ToIntegerIfIntegral(days). - let days = args - .get_or_undefined(3) - .map_or(Ok(0), |d| to_integer_if_integral(d, context))?; + let days = args.get_or_undefined(3).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; // 6. If hours is undefined, let h be 0; else let h be ? ToIntegerIfIntegral(hours). - let hours = args - .get_or_undefined(4) - .map_or(Ok(0), |h| to_integer_if_integral(h, context))?; + let hours = args.get_or_undefined(4).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; // 7. If minutes is undefined, let m be 0; else let m be ? ToIntegerIfIntegral(minutes). - let minutes = args - .get_or_undefined(5) - .map_or(Ok(0), |m| to_integer_if_integral(m, context))?; + let minutes = args.get_or_undefined(5).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; // 8. If seconds is undefined, let s be 0; else let s be ? ToIntegerIfIntegral(seconds). - let seconds = args - .get_or_undefined(6) - .map_or(Ok(0), |s| to_integer_if_integral(s, context))?; + let seconds = args.get_or_undefined(6).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; // 9. If milliseconds is undefined, let ms be 0; else let ms be ? ToIntegerIfIntegral(milliseconds). - let milliseconds = args - .get_or_undefined(7) - .map_or(Ok(0), |ms| to_integer_if_integral(ms, context))?; + let milliseconds = args.get_or_undefined(7).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; // 10. If microseconds is undefined, let mis be 0; else let mis be ? ToIntegerIfIntegral(microseconds). - let microseconds = args - .get_or_undefined(8) - .map_or(Ok(0), |mis| to_integer_if_integral(mis, context))?; + let microseconds = args.get_or_undefined(8).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; // 11. If nanoseconds is undefined, let ns be 0; else let ns be ? ToIntegerIfIntegral(nanoseconds). - let nanoseconds = args - .get_or_undefined(9) - .map_or(Ok(0), |ns| to_integer_if_integral(ns, context))?; + let nanoseconds = args.get_or_undefined(9).map_or(Ok(0), |v| { + let finite = v.to_finitef64(context)?; + finite + .as_integer_if_integral::() + .map_err(JsError::from) + })?; let record = InnerDuration::new( - years.into(), - months.into(), - weeks.into(), - days.into(), - hours.into(), - minutes.into(), - seconds.into(), - milliseconds.into(), - microseconds.into(), - nanoseconds.into(), + years.try_into()?, + months.try_into()?, + weeks.try_into()?, + days.try_into()?, + hours.try_into()?, + minutes.try_into()?, + seconds.try_into()?, + milliseconds.try_into()?, + microseconds.try_into()?, + nanoseconds.try_into()?, )?; // 12. Return ? CreateTemporalDuration(y, mo, w, d, h, m, s, ms, mis, ns, NewTarget). @@ -934,81 +965,131 @@ pub(crate) fn to_temporal_partial_duration( // TODO: Increase to i64 let days = unknown_object .get(js_string!("days"), context)? - .map_or(None, |v| Some(to_integer_if_integral::(v, context))) - .transpose()? - .map(Into::into); + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; // 6. Let hours be ? Get(temporalDurationLike, "hours"). // 7. If hours is not undefined, set result.[[Hours]] to ? ToIntegerIfIntegral(hours). let hours = unknown_object .get(js_string!("hours"), context)? - .map_or(None, |v| Some(to_integer_if_integral::(v, context))) - .transpose()? - .map(Into::into); + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; // 8. Let microseconds be ? Get(temporalDurationLike, "microseconds"). // 9. If microseconds is not undefined, set result.[[Microseconds]] to ? ToIntegerIfIntegral(microseconds). let microseconds = unknown_object .get(js_string!("microseconds"), context)? - .map_or(None, |v| Some(to_integer_if_integral::(v, context))) - .transpose()? - .map(Into::into); + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; // 10. Let milliseconds be ? Get(temporalDurationLike, "milliseconds"). // 11. If milliseconds is not undefined, set result.[[Milliseconds]] to ? ToIntegerIfIntegral(milliseconds). let milliseconds = unknown_object .get(js_string!("milliseconds"), context)? - .map_or(None, |v| Some(to_integer_if_integral::(v, context))) - .transpose()? - .map(Into::into); + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; // 12. Let minutes be ? Get(temporalDurationLike, "minutes"). // 13. If minutes is not undefined, set result.[[Minutes]] to ? ToIntegerIfIntegral(minutes). let minutes = unknown_object .get(js_string!("minutes"), context)? - .map_or(None, |v| Some(to_integer_if_integral::(v, context))) - .transpose()? - .map(Into::into); + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; // 14. Let months be ? Get(temporalDurationLike, "months"). // 15. If months is not undefined, set result.[[Months]] to ? ToIntegerIfIntegral(months). let months = unknown_object .get(js_string!("months"), context)? - .map_or(None, |v| Some(to_integer_if_integral::(v, context))) - .transpose()? - .map(Into::into); + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; // 16. Let nanoseconds be ? Get(temporalDurationLike, "nanoseconds"). // 17. If nanoseconds is not undefined, set result.[[Nanoseconds]] to ? ToIntegerIfIntegral(nanoseconds). let nanoseconds = unknown_object .get(js_string!("nanoseconds"), context)? - .map_or(None, |v| Some(to_integer_if_integral::(v, context))) - .transpose()? - .map(Into::into); + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; // 18. Let seconds be ? Get(temporalDurationLike, "seconds"). // 19. If seconds is not undefined, set result.[[Seconds]] to ? ToIntegerIfIntegral(seconds). let seconds = unknown_object .get(js_string!("seconds"), context)? - .map_or(None, |v| Some(to_integer_if_integral::(v, context))) - .transpose()? - .map(Into::into); + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; // 20. Let weeks be ? Get(temporalDurationLike, "weeks"). // 21. If weeks is not undefined, set result.[[Weeks]] to ? ToIntegerIfIntegral(weeks). let weeks = unknown_object .get(js_string!("weeks"), context)? - .map_or(None, |v| Some(to_integer_if_integral::(v, context))) - .transpose()? - .map(Into::into); + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; // 22. Let years be ? Get(temporalDurationLike, "years"). // 23. If years is not undefined, set result.[[Years]] to ? ToIntegerIfIntegral(years). let years = unknown_object .get(js_string!("years"), context)? - .map_or(None, |v| Some(to_integer_if_integral::(v, context))) - .transpose()? - .map(Into::into); + .map(|v| { + let finite = v.to_finitef64(context)?; + let integral_int = finite + .as_integer_if_integral::() + .map_err(JsError::from)?; + integral_int.try_into().map_err(JsError::from) + }) + .transpose()?; let partial = PartialDuration { years, diff --git a/core/engine/src/builtins/temporal/instant/mod.rs b/core/engine/src/builtins/temporal/instant/mod.rs index 4014c5d7882..186f6204d9d 100644 --- a/core/engine/src/builtins/temporal/instant/mod.rs +++ b/core/engine/src/builtins/temporal/instant/mod.rs @@ -529,7 +529,7 @@ fn to_temporal_instant(item: &JsValue, context: &mut Context) -> JsResult() { - return Ok(instant.inner.clone()); + return Ok(instant.inner); } else if let Some(_zdt) = obj.downcast_ref::() { return Err(JsNativeError::error() .with_message("Not yet implemented.") diff --git a/core/engine/src/builtins/temporal/mod.rs b/core/engine/src/builtins/temporal/mod.rs index 93be8c5c43a..69c40bbb23b 100644 --- a/core/engine/src/builtins/temporal/mod.rs +++ b/core/engine/src/builtins/temporal/mod.rs @@ -1,5 +1,8 @@ //! The ECMAScript `Temporal` stage 3 built-in implementation. //! +//! Boa's Temporal implementation uses the `temporal_rs` crate +//! for the core functionality of the implementation. +//! //! More information: //! //! [spec]: https://tc39.es/proposal-temporal/ @@ -37,7 +40,6 @@ use crate::{ Context, JsBigInt, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, }; use boa_profiler::Profiler; -use num_traits::{AsPrimitive, PrimInt}; use temporal_rs::{ primitive::FiniteF64, PlainDate as TemporalDate, ZonedDateTime as TemporalZonedDateTime, NS_PER_DAY, @@ -212,33 +214,6 @@ pub(crate) fn _iterator_to_list_of_types( Ok(values) } -// Abstract Operation 13.3 `EpochDaysToEpochMs` -// Migrated to `temporal_rs` - -// 13.4 Date Equations -// implemented in temporal/date_equations.rs - -// Abstract Operation 13.5 `GetOptionsObject ( options )` -// Implemented in builtin/options.rs - -// 13.6 `GetOption ( options, property, type, values, default )` -// Implemented in builtin/options.rs - -// 13.7 `ToTemporalOverflow (options)` -// Now implemented in temporal/options.rs - -// 13.10 `ToTemporalRoundingMode ( normalizedOptions, fallback )` -// Now implemented in builtin/options.rs - -// 13.11 `NegateTemporalRoundingMode ( roundingMode )` -// Now implemented in builtin/options.rs - -// 13.16 `ToTemporalRoundingIncrement ( normalizedOptions )` -// Now implemented in temporal/options.rs - -// 13.17 `ValidateTemporalRoundingIncrement ( increment, dividend, inclusive )` -// Moved to temporal_rs - type RelativeTemporalObjectResult = JsResult<(Option, Option)>; /// 13.21 `ToRelativeTemporalObject ( options )` @@ -263,15 +238,6 @@ pub(crate) fn to_relative_temporal_object( Ok((Some(plain_date), None)) } -// 13.22 `LargerOfTwoTemporalUnits ( u1, u2 )` -// use core::cmp::max - -// 13.23 `MaximumTemporalDurationRoundingIncrement ( unit )` -// Implemented on TemporalUnit in temporal/options.rs - -// 13.26 `GetUnsignedRoundingMode ( roundingMode, isNegative )` -// Implemented on RoundingMode in builtins/options.rs - // 13.26 IsPartialTemporalObject ( object ) pub(crate) fn is_partial_temporal_object<'value>( value: &'value JsValue, @@ -312,92 +278,14 @@ pub(crate) fn is_partial_temporal_object<'value>( Ok(Some(obj)) } -// 13.27 `ApplyUnsignedRoundingMode ( x, r1, r2, unsignedRoundingMode )` -// Migrated to `temporal_rs` - -// 13.28 `RoundNumberToIncrement ( x, increment, roundingMode )` -// Migrated to `temporal_rs` - -// 13.29 `RoundNumberToIncrementAsIfPositive ( x, increment, roundingMode )` -// Migrated to `temporal_rs` - -/// 13.43 `ToPositiveIntegerWithTruncation ( argument )` -#[inline] -pub(crate) fn truncate_as_positive>(value: FiniteF64) -> JsResult -where - f64: AsPrimitive, - i8: AsPrimitive, -{ - let truncated = truncate::(value); - if truncated <= 0i8.as_() { - return Err(JsNativeError::range() - .with_message("integer must be positive.") - .into()); - } - Ok(truncated) -} - -// TODO: move to `temporal_rs` -#[inline] -pub(crate) fn truncate>(value: FiniteF64) -> T -where - f64: AsPrimitive, -{ - let clamped = num_traits::clamp(value.as_inner(), T::min_value().as_(), T::max_value().as_()); - clamped.as_() -} - -/// 13.44 `ToIntegerWithTruncation ( argument )` -#[inline] -pub(crate) fn to_finite_number(value: &JsValue, context: &mut Context) -> JsResult { - // 1. Let number be ? ToNumber(argument). - let number = value.to_number(context)?; - // 2. If number is NaN, +∞𝔽 or -∞𝔽, throw a RangeError exception. - // 3. Return truncate(ℝ(number)). - FiniteF64::try_from(number).map_err(Into::into) -} - -#[allow(clippy::float_cmp)] -pub(crate) fn as_integer_strict>(value: FiniteF64) -> JsResult -where - f64: AsPrimitive, -{ - if value.as_inner().trunc() != value.as_inner() { - return Err(JsNativeError::range() - .with_message("value was not integral.") - .into()); +impl JsValue { + pub(crate) fn to_finitef64(&self, context: &mut Context) -> JsResult { + let number = self.to_number(context)?; + let result = FiniteF64::try_from(number)?; + Ok(result) } - Ok(value.as_inner().as_()) } -#[inline] -pub(crate) fn to_integer_if_integral>( - value: &JsValue, - context: &mut Context, -) -> JsResult -where - f64: AsPrimitive, -{ - let number = value.to_number(context)?; - let finite = FiniteF64::try_from(number)?; - as_integer_strict::(finite) -} - -// 13.46 `PrepareTemporalFields ( fields, fieldNames, requiredFields [ , duplicateBehaviour ] )` -// See fields.rs - -// NOTE: op -> true == until | false == since -// 13.47 `GetDifferenceSettings ( operation, options, unitGroup, disallowedUnits, fallbackSmallestUnit, smallestLargestDefaultUnit )` -// Migrated to `temporal_rs` - -// NOTE: used for MergeFields methods. Potentially can be omitted in favor of `TemporalFields`. -// 14.6 `CopyDataProperties ( target, source, excludedKeys [ , excludedValues ] )` -// Migrated or repurposed to `temporal_rs`/`fields.rs` - -// Note: Deviates from Proposal spec -> proto appears to be always null across the specification. -// 14.7 `SnapshotOwnProperties ( source, proto [ , excludedKeys [ , excludedValues ] ] )` -// Migrated or repurposed to `temporal_rs`/`fields.rs` - fn extract_from_temporal_type( object: &JsObject, date_f: DF, diff --git a/core/engine/src/builtins/temporal/plain_date/mod.rs b/core/engine/src/builtins/temporal/plain_date/mod.rs index 66faf79fba5..9c87449468a 100644 --- a/core/engine/src/builtins/temporal/plain_date/mod.rs +++ b/core/engine/src/builtins/temporal/plain_date/mod.rs @@ -28,8 +28,7 @@ use super::{ calendar::{get_temporal_calendar_slot_value_with_default, to_temporal_calendar_slot_value}, create_temporal_datetime, create_temporal_duration, options::get_difference_settings, - to_finite_number, to_temporal_duration_record, to_temporal_time, truncate, - truncate_as_positive, PlainDateTime, ZonedDateTime, + to_temporal_duration_record, to_temporal_time, PlainDateTime, ZonedDateTime, }; #[cfg(feature = "temporal")] @@ -244,9 +243,18 @@ impl BuiltInConstructor for PlainDate { .into()); }; - let year = truncate::(to_finite_number(args.get_or_undefined(0), context)?); - let month = truncate::(to_finite_number(args.get_or_undefined(1), context)?); - let day = truncate::(to_finite_number(args.get_or_undefined(2), context)?); + let year = args + .get_or_undefined(0) + .to_finitef64(context)? + .as_integer_with_truncation::(); + let month = args + .get_or_undefined(1) + .to_finitef64(context)? + .as_integer_with_truncation::(); + let day = args + .get_or_undefined(2) + .to_finitef64(context)? + .as_integer_with_truncation::(); let calendar_slot = to_temporal_calendar_slot_value(args.get_or_undefined(3))?; let inner = InnerDate::try_new(year, month.into(), day.into(), calendar_slot)?; @@ -893,63 +901,62 @@ pub(crate) fn to_partial_date_record( // TODO: Most likely need to use an iterator to handle. let day = partial_object .get(js_string!("day"), context)? - .map_or(None, |v| Some(to_finite_number(v, context))) - .transpose()? - .map(truncate_as_positive) + .map(|v| { + let finite = v.to_finitef64(context)?; + finite + .as_positive_integer_with_truncation() + .map_err(JsError::from) + }) .transpose()?; let month = partial_object .get(js_string!("month"), context)? - .map_or(None, |v| Some(to_finite_number(v, context))) - .transpose()? - .map(truncate_as_positive) + .map(|v| { + let finite = v.to_finitef64(context)?; + finite + .as_positive_integer_with_truncation() + .map_err(JsError::from) + }) .transpose()?; let month_code = partial_object .get(js_string!("monthCode"), context)? - .map_or(None, |v| { - let v = match v.to_primitive(context, crate::value::PreferredType::String) { - Ok(val) => val, - Err(e) => return Some(Err(e)), - }; - + .map(|v| { + let v = v.to_primitive(context, crate::value::PreferredType::String)?; let JsValue::String(month_code) = v else { - return Some(Err(JsNativeError::typ() + return Err(JsNativeError::typ() .with_message("The monthCode field value must be a string.") - .into())); + .into()); }; - Some( - TinyAsciiStr::<4>::try_from_str(&month_code.to_std_string_escaped()) - .map_err(|e| JsError::from(JsNativeError::typ().with_message(e.to_string()))), - ) + TinyAsciiStr::<4>::try_from_str(&month_code.to_std_string_escaped()) + .map_err(|e| JsError::from(JsNativeError::typ().with_message(e.to_string()))) }) .transpose()?; let year = partial_object .get(js_string!("year"), context)? - .map_or(None, |v| Some(to_finite_number(v, context))) - .transpose()? - .map(truncate); + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) + .transpose()?; let era_year = partial_object .get(js_string!("eraYear"), context)? - .map_or(None, |v| Some(to_finite_number(v, context))) - .transpose()? - .map(truncate); + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) + .transpose()?; let era = partial_object .get(js_string!("era"), context)? - .map_or(None, |v| { - let v = match v.to_primitive(context, crate::value::PreferredType::String) { - Ok(val) => val, - Err(e) => return Some(Err(e)), - }; + .map(|v| { + let v = v.to_primitive(context, crate::value::PreferredType::String)?; let JsValue::String(era) = v else { - return Some(Err(JsError::from( + return Err(JsError::from( JsNativeError::typ() .with_message("The monthCode field value must be a string."), - ))); + )); }; // TODO: double check if an invalid monthCode is a range or type error. - Some( - TinyAsciiStr::<19>::try_from_str(&era.to_std_string_escaped()) - .map_err(|e| JsError::from(JsNativeError::range().with_message(e.to_string()))), - ) + TinyAsciiStr::<19>::try_from_str(&era.to_std_string_escaped()) + .map_err(|e| JsError::from(JsNativeError::range().with_message(e.to_string()))) }) .transpose()?; diff --git a/core/engine/src/builtins/temporal/plain_date_time/mod.rs b/core/engine/src/builtins/temporal/plain_date_time/mod.rs index 91a45fdcc7a..5942a710f13 100644 --- a/core/engine/src/builtins/temporal/plain_date_time/mod.rs +++ b/core/engine/src/builtins/temporal/plain_date_time/mod.rs @@ -14,7 +14,8 @@ use crate::{ realm::Realm, string::StaticJsStrings, value::IntoOrUndefined, - Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, + Context, JsArgs, JsData, JsError, JsNativeError, JsObject, JsResult, JsString, JsSymbol, + JsValue, }; use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; @@ -25,7 +26,6 @@ mod tests; use temporal_rs::{ options::{ArithmeticOverflow, RoundingIncrement, RoundingOptions, TemporalRoundingMode}, partial::PartialDateTime, - primitive::FiniteF64, PlainDateTime as InnerDateTime, PlainTime, }; @@ -33,8 +33,7 @@ use super::{ calendar::{get_temporal_calendar_slot_value_with_default, to_temporal_calendar_slot_value}, create_temporal_duration, options::{get_difference_settings, get_temporal_unit, TemporalUnitGroup}, - to_finite_number, to_temporal_duration_record, to_temporal_time, truncate, PlainDate, - ZonedDateTime, + to_temporal_duration_record, to_temporal_time, PlainDate, ZonedDateTime, }; /// The `Temporal.PlainDateTime` object. @@ -310,45 +309,60 @@ impl BuiltInConstructor for PlainDateTime { }; // 2. Set isoYear to ? ToIntegerWithTruncation(isoYear). - let iso_year = truncate::(to_finite_number(args.get_or_undefined(0), context)?); + let iso_year = args + .get_or_undefined(0) + .to_finitef64(context)? + .as_integer_with_truncation::(); // 3. Set isoMonth to ? ToIntegerWithTruncation(isoMonth). - let iso_month = truncate::(to_finite_number(args.get_or_undefined(1), context)?); + let iso_month = args + .get_or_undefined(1) + .to_finitef64(context)? + .as_integer_with_truncation::(); // 4. Set isoDay to ? ToIntegerWithTruncation(isoDay). - let iso_day = truncate::(to_finite_number(args.get_or_undefined(2), context)?); + let iso_day = args + .get_or_undefined(2) + .to_finitef64(context)? + .as_integer_with_truncation::(); // 5. If hour is undefined, set hour to 0; else set hour to ? ToIntegerWithTruncation(hour). - let hour = args - .get_or_undefined(3) - .map_or(Ok(FiniteF64::from(0)), |v| to_finite_number(v, context)) - .map(truncate::)?; + let hour = args.get_or_undefined(3).map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; // 6. If minute is undefined, set minute to 0; else set minute to ? ToIntegerWithTruncation(minute). - let minute = args - .get_or_undefined(4) - .map_or(Ok(FiniteF64::from(0)), |v| to_finite_number(v, context)) - .map(truncate::)?; + let minute = args.get_or_undefined(4).map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; // 7. If second is undefined, set second to 0; else set second to ? ToIntegerWithTruncation(second). - let second = args - .get_or_undefined(5) - .map_or(Ok(FiniteF64::from(0)), |v| to_finite_number(v, context)) - .map(truncate::)?; + let second = args.get_or_undefined(5).map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; // 8. If millisecond is undefined, set millisecond to 0; else set millisecond to ? ToIntegerWithTruncation(millisecond). let millisecond = args .get_or_undefined(6) - .map_or(Ok(FiniteF64::from(0)), |v| to_finite_number(v, context)) - .map(truncate::)?; + .map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; // 9. If microsecond is undefined, set microsecond to 0; else set microsecond to ? ToIntegerWithTruncation(microsecond). let microsecond = args .get_or_undefined(7) - .map_or(Ok(FiniteF64::from(0)), |v| to_finite_number(v, context)) - .map(truncate::)?; + .map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; // 10. If nanosecond is undefined, set nanosecond to 0; else set nanosecond to ? ToIntegerWithTruncation(nanosecond). let nanosecond = args .get_or_undefined(8) - .map_or(Ok(FiniteF64::from(0)), |v| to_finite_number(v, context)) - .map(truncate::)?; + .map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; let calendar_slot = to_temporal_calendar_slot_value(args.get_or_undefined(9))?; diff --git a/core/engine/src/builtins/temporal/plain_month_day/mod.rs b/core/engine/src/builtins/temporal/plain_month_day/mod.rs index 858decf23be..b211f269d98 100644 --- a/core/engine/src/builtins/temporal/plain_month_day/mod.rs +++ b/core/engine/src/builtins/temporal/plain_month_day/mod.rs @@ -22,14 +22,10 @@ use boa_profiler::Profiler; use temporal_rs::{ options::{ArithmeticOverflow, CalendarName}, partial::PartialDate, - primitive::FiniteF64, PlainDateTime, PlainMonthDay as InnerMonthDay, TinyAsciiStr, }; -use super::{ - calendar::to_temporal_calendar_slot_value, to_finite_number, truncate, truncate_as_positive, - DateTimeValues, -}; +use super::{calendar::to_temporal_calendar_slot_value, DateTimeValues}; /// The `Temporal.PlainMonthDay` object. #[derive(Debug, Clone, Trace, Finalize, JsData)] @@ -204,20 +200,22 @@ impl BuiltInConstructor for PlainMonthDay { let ref_year = args .get_or_undefined(3) - .map(|v| to_finite_number(v, context)) - .transpose()? - .map(truncate::); + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) + .transpose()?; // We can ignore 2 as the underlying temporal library handles the reference year let m = args .get_or_undefined(0) - .map_or(Ok(FiniteF64::from(0)), |v| to_finite_number(v, context)) - .map(truncate::)?; + .to_finitef64(context)? + .as_integer_with_truncation::(); let d = args .get_or_undefined(1) - .map_or(Ok(FiniteF64::from(0)), |v| to_finite_number(v, context)) - .map(truncate::)?; + .to_finitef64(context)? + .as_integer_with_truncation::(); let calendar = to_temporal_calendar_slot_value(args.get_or_undefined(2))?; let inner = InnerMonthDay::new_with_overflow( @@ -334,43 +332,46 @@ fn to_temporal_month_day( } else if item.is_object() { let day = item .get_v(js_string!("day"), context)? - .map_or(None, |v| Some(to_finite_number(v, context))) - .transpose()? - .map(truncate_as_positive) + .map(|v| { + let finite = v.to_finitef64(context)?; + // TODO: Update to the below to u8 after temporal_rs change + finite + .as_positive_integer_with_truncation::() + .map_err(JsError::from) + }) .transpose()?; let month = item .get_v(js_string!("month"), context)? - .map_or(None, |v| Some(to_finite_number(v, context))) - .transpose()? - .map(truncate_as_positive) + .map(|v| { + let finite = v.to_finitef64(context)?; + // TODO: Update to the below to u8 after temporal_rs change + finite + .as_positive_integer_with_truncation::() + .map_err(JsError::from) + }) .transpose()?; let month_code = item .get_v(js_string!("monthCode"), context)? - .map_or(None, |v| { - let v = match v.to_primitive(context, crate::value::PreferredType::String) { - Ok(v) => v, - Err(e) => return Some(Err(e)), - }; + .map(|v| { + let v = v.to_primitive(context, crate::value::PreferredType::String)?; let JsValue::String(month_code) = v else { - return Some(Err(JsNativeError::typ() + return Err(JsNativeError::typ() .with_message("The monthCode field value must be a string.") - .into())); + .into()); }; - Some( - TinyAsciiStr::<4>::from_str(&month_code.to_std_string_escaped()).map_err(|e| { - JsError::from(JsNativeError::typ().with_message(e.to_string())) - }), - ) + TinyAsciiStr::<4>::from_str(&month_code.to_std_string_escaped()) + .map_err(|e| JsError::from(JsNativeError::typ().with_message(e.to_string()))) }) .transpose()?; - let year = item - .get_v(js_string!("year"), context)? - .map_or(None, |v| Some(to_finite_number(v, context))) - .transpose()? - .map_or(1972, truncate); + let year = + item.get_v(js_string!("year"), context)? + .map_or(Ok::(1972), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; let partial_date = &PartialDate { month, diff --git a/core/engine/src/builtins/temporal/plain_time/mod.rs b/core/engine/src/builtins/temporal/plain_time/mod.rs index ee2cb4e3a13..139252c169e 100644 --- a/core/engine/src/builtins/temporal/plain_time/mod.rs +++ b/core/engine/src/builtins/temporal/plain_time/mod.rs @@ -11,21 +11,21 @@ use crate::{ property::Attribute, realm::Realm, string::StaticJsStrings, - Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, + Context, JsArgs, JsData, JsError, JsNativeError, JsObject, JsResult, JsString, JsSymbol, + JsValue, }; use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; use temporal_rs::{ options::{ArithmeticOverflow, TemporalRoundingMode}, partial::PartialTime, - primitive::FiniteF64, PlainTime as PlainTimeInner, }; use super::{ create_temporal_duration, options::{get_difference_settings, get_temporal_unit, TemporalUnitGroup}, - to_finite_number, to_temporal_duration_record, truncate, PlainDateTime, ZonedDateTime, + to_temporal_duration_record, PlainDateTime, ZonedDateTime, }; /// The `Temporal.PlainTime` object. @@ -150,38 +150,44 @@ impl BuiltInConstructor for PlainTime { } // 2. If hour is undefined, set hour to 0; else set hour to ? ToIntegerWithTruncation(hour). - let hour = args - .get_or_undefined(0) - .map_or(Ok(FiniteF64::from(0)), |v| to_finite_number(v, context)) - .map(truncate::)?; + let hour = args.get_or_undefined(0).map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; // 3. If minute is undefined, set minute to 0; else set minute to ? ToIntegerWithTruncation(minute). - let minute = args - .get_or_undefined(1) - .map_or(Ok(FiniteF64::from(0)), |v| to_finite_number(v, context)) - .map(truncate::)?; + let minute = args.get_or_undefined(1).map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; // 4. If second is undefined, set second to 0; else set second to ? ToIntegerWithTruncation(second). - let second = args - .get_or_undefined(2) - .map_or(Ok(FiniteF64::from(0)), |v| to_finite_number(v, context)) - .map(truncate::)?; + let second = args.get_or_undefined(2).map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; // 5. If millisecond is undefined, set millisecond to 0; else set millisecond to ? ToIntegerWithTruncation(millisecond). let millisecond = args .get_or_undefined(3) - .map_or(Ok(FiniteF64::from(0)), |v| to_finite_number(v, context)) - .map(truncate::)?; + .map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; // 6. If microsecond is undefined, set microsecond to 0; else set microsecond to ? ToIntegerWithTruncation(microsecond). let microsecond = args .get_or_undefined(4) - .map_or(Ok(FiniteF64::from(0)), |v| to_finite_number(v, context)) - .map(truncate::)?; + .map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; // 7. If nanosecond is undefined, set nanosecond to 0; else set nanosecond to ? ToIntegerWithTruncation(nanosecond). let nanosecond = args .get_or_undefined(5) - .map_or(Ok(FiniteF64::from(0)), |v| to_finite_number(v, context)) - .map(truncate::)?; + .map_or(Ok::(0), |v| { + let finite = v.to_finitef64(context)?; + Ok(finite.as_integer_with_truncation::()) + })?; let inner = PlainTimeInner::new( hour.into(), @@ -716,44 +722,56 @@ pub(crate) fn to_partial_time_record( ) -> JsResult { let hour = partial_object .get(js_string!("hour"), context)? - .map_or(None, |v| Some(to_finite_number(v, context))) + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) .transpose()? - .map(truncate::) .map(Into::into); let minute = partial_object .get(js_string!("minute"), context)? - .map_or(None, |v| Some(to_finite_number(v, context))) + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) .transpose()? - .map(truncate::) .map(Into::into); let second = partial_object .get(js_string!("second"), context)? - .map_or(None, |v| Some(to_finite_number(v, context))) + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) .transpose()? - .map(truncate::) .map(Into::into); let millisecond = partial_object .get(js_string!("millisecond"), context)? - .map_or(None, |v| Some(to_finite_number(v, context))) + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) .transpose()? - .map(truncate::) .map(Into::into); let microsecond = partial_object .get(js_string!("microsecond"), context)? - .map_or(None, |v| Some(to_finite_number(v, context))) + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) .transpose()? - .map(truncate::) .map(Into::into); let nanosecond = partial_object .get(js_string!("nanosecond"), context)? - .map_or(None, |v| Some(to_finite_number(v, context))) + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) .transpose()? - .map(truncate::) .map(Into::into); Ok(PartialTime { diff --git a/core/engine/src/builtins/temporal/plain_year_month/mod.rs b/core/engine/src/builtins/temporal/plain_year_month/mod.rs index 964bc738651..4a075a21c5a 100644 --- a/core/engine/src/builtins/temporal/plain_year_month/mod.rs +++ b/core/engine/src/builtins/temporal/plain_year_month/mod.rs @@ -13,21 +13,18 @@ use crate::{ property::Attribute, realm::Realm, string::StaticJsStrings, - Context, JsArgs, JsData, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue, + Context, JsArgs, JsData, JsError, JsNativeError, JsObject, JsResult, JsString, JsSymbol, + JsValue, }; use boa_gc::{Finalize, Trace}; use boa_profiler::Profiler; use temporal_rs::{ options::{ArithmeticOverflow, CalendarName}, - primitive::FiniteF64, Duration, PlainYearMonth as InnerYearMonth, }; -use super::{ - calendar::to_temporal_calendar_slot_value, to_finite_number, to_temporal_duration, truncate, - DateTimeValues, -}; +use super::{calendar::to_temporal_calendar_slot_value, to_temporal_duration, DateTimeValues}; /// The `Temporal.PlainYearMonth` object. #[derive(Debug, Clone, Trace, Finalize, JsData)] @@ -179,14 +176,14 @@ impl BuiltInConstructor for PlainYearMonth { // 3. Let y be ? ToIntegerWithTruncation(isoYear). let y = args .get_or_undefined(0) - .map_or(Ok(FiniteF64::from(0)), |v| to_finite_number(v, context)) - .map(truncate::)?; + .to_finitef64(context)? + .as_integer_with_truncation::(); // 4. Let m be ? ToIntegerWithTruncation(isoMonth). let m = args .get_or_undefined(1) - .map_or(Ok(FiniteF64::from(0)), |v| to_finite_number(v, context)) - .map(truncate::)?; + .to_finitef64(context)? + .as_integer_with_truncation::(); // 5. Let calendar be ? ToTemporalCalendarSlotValue(calendarLike, "iso8601"). let calendar = to_temporal_calendar_slot_value(args.get_or_undefined(2))?; @@ -194,14 +191,16 @@ impl BuiltInConstructor for PlainYearMonth { // 6. Let ref be ? ToIntegerWithTruncation(referenceISODay). let ref_day = args .get_or_undefined(3) - .map(|v| to_finite_number(v, context)) - .transpose()? - .map(truncate::); + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) + .transpose()?; // 7. Return ? CreateTemporalYearMonth(y, m, calendar, ref, NewTarget). let inner = InnerYearMonth::new_with_overflow( - y.into(), - m.into(), + y, + m, ref_day.map(Into::into), calendar, ArithmeticOverflow::Reject, @@ -237,25 +236,35 @@ impl PlainYearMonth { let year = item .get_v(js_string!("year"), context)? - .map_or(Ok(FiniteF64::from(0)), |v| to_finite_number(v, context)) - .map(truncate::)?; + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) + .transpose()? + .unwrap_or_default(); let month = item .get_v(js_string!("month"), context)? - .map_or(Ok(FiniteF64::from(0)), |v| to_finite_number(v, context)) - .map(truncate::)?; + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) + .transpose()? + .unwrap_or_default(); let ref_day = item .get_v(js_string!("day"), context)? - .map(|v| to_finite_number(v, context)) - .transpose()? - .map(truncate::); + .map(|v| { + let finite = v.to_finitef64(context)?; + Ok::(finite.as_integer_with_truncation::()) + }) + .transpose()?; // a. Let calendar be ? ToTemporalCalendar(item). let calendar = to_temporal_calendar_slot_value(args.get_or_undefined(1))?; InnerYearMonth::new_with_overflow( year, - month.into(), + month, ref_day.map(Into::into), calendar, overflow,