Skip to content

Commit

Permalink
Bump the temporal_rs version and related changes (#4098)
Browse files Browse the repository at this point in the history
  • Loading branch information
nekevss authored Dec 27, 2024
1 parent 1af4494 commit fdd8acc
Show file tree
Hide file tree
Showing 12 changed files with 209 additions and 196 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ intrusive-collections = "0.9.7"
cfg-if = "1.0.0"
either = "1.13.0"
sys-locale = "0.3.2"
temporal_rs = { git = "https://github.com/boa-dev/temporal.git", rev = "4498edf4efa52f0cdec0bbed8bf49cae7e543e74", features = ["tzdb", "now"] }
temporal_rs = { git = "https://github.com/boa-dev/temporal.git", rev = "8b796edec18a2652af282735aab4a2d0512b9a1d", features = ["tzdb", "now"] }
web-time = "1.1.0"
criterion = "0.5.1"
float-cmp = "0.10.0"
Expand Down
17 changes: 7 additions & 10 deletions core/engine/src/builtins/temporal/duration/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Boa's implementation of the `Temporal.Duration` Builtin Object.

use super::{
get_relative_to_option,
options::{get_temporal_unit, TemporalUnitGroup},
DateTimeValues,
};
Expand All @@ -22,7 +23,7 @@ use crate::{
use boa_gc::{Finalize, Trace};
use boa_profiler::Profiler;
use temporal_rs::{
options::{RelativeTo, RoundingIncrement, RoundingOptions, TemporalRoundingMode, TemporalUnit},
options::{RoundingIncrement, RoundingOptions, TemporalRoundingMode, TemporalUnit},
partial::PartialDuration,
Duration as InnerDuration,
};
Expand Down Expand Up @@ -712,8 +713,7 @@ 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) =
super::to_relative_temporal_object(&round_to, context)?;
let relative_to = get_relative_to_option(&round_to, context)?;

// 13. Let roundingIncrement be ? ToTemporalRoundingIncrement(roundTo).
options.increment =
Expand All @@ -735,13 +735,10 @@ impl Duration {
// NOTE: execute step 21 earlier before initial values are shadowed.
// 21. If smallestUnitPresent is false and largestUnitPresent is false, then

let rounded_duration = duration.inner.round(
options,
&RelativeTo {
date: plain_relative_to.as_ref(),
zdt: zoned_relative_to.as_ref(),
},
)?;
let rounded_duration =
duration
.inner
.round_with_provider(options, relative_to, context.tz_provider())?;
create_temporal_duration(rounded_duration, None, context).map(Into::into)
}

Expand Down
4 changes: 2 additions & 2 deletions core/engine/src/builtins/temporal/instant/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ impl Instant {
let settings =
get_difference_settings(&get_options_object(args.get_or_undefined(1))?, context)?;
let result = instant.inner.until(&other, settings)?;
create_temporal_duration(result.into(), None, context).map(Into::into)
create_temporal_duration(result, None, context).map(Into::into)
}

/// 8.3.10 `Temporal.Instant.prototype.since ( other [ , options ] )`
Expand All @@ -334,7 +334,7 @@ impl Instant {
let settings =
get_difference_settings(&get_options_object(args.get_or_undefined(1))?, context)?;
let result = instant.inner.since(&other, settings)?;
create_temporal_duration(result.into(), None, context).map(Into::into)
create_temporal_duration(result, None, context).map(Into::into)
}

/// 8.3.11 `Temporal.Instant.prototype.round ( roundTo )`
Expand Down
124 changes: 73 additions & 51 deletions core/engine/src/builtins/temporal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,16 @@ pub use self::{

use crate::value::JsVariant;
use crate::{
builtins::{iterable::IteratorRecord, BuiltInBuilder, BuiltInObject, IntrinsicObject},
builtins::{BuiltInBuilder, BuiltInObject, IntrinsicObject},
context::intrinsics::Intrinsics,
js_string,
property::Attribute,
realm::Realm,
string::StaticJsStrings,
value::Type,
Context, JsBigInt, JsNativeError, JsObject, JsResult, JsString, JsSymbol, JsValue,
};
use boa_profiler::Profiler;
use temporal_rs::options::RelativeTo;
use temporal_rs::{
primitive::FiniteF64, PlainDate as TemporalDate, ZonedDateTime as TemporalZonedDateTime,
NS_PER_DAY,
Expand All @@ -57,7 +57,6 @@ pub(crate) fn ns_min_instant() -> JsBigInt {
}

// An enum representing common fields across `Temporal` objects.
#[allow(unused)]
pub(crate) enum DateTimeValues {
Year,
Month,
Expand Down Expand Up @@ -95,27 +94,22 @@ impl IntrinsicObject for Temporal {
.static_property(
js_string!("Now"),
realm.intrinsics().objects().now(),
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
js_string!("Calendar"),
realm.intrinsics().constructors().calendar().constructor(),
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
js_string!("Duration"),
realm.intrinsics().constructors().duration().constructor(),
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
js_string!("Instant"),
realm.intrinsics().constructors().instant().constructor(),
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
js_string!("PlainDate"),
realm.intrinsics().constructors().plain_date().constructor(),
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
js_string!("PlainDateTime"),
Expand All @@ -124,7 +118,7 @@ impl IntrinsicObject for Temporal {
.constructors()
.plain_date_time()
.constructor(),
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
js_string!("PlainMonthDay"),
Expand All @@ -133,12 +127,12 @@ impl IntrinsicObject for Temporal {
.constructors()
.plain_month_day()
.constructor(),
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
js_string!("PlainTime"),
realm.intrinsics().constructors().plain_time().constructor(),
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
js_string!("PlainYearMonth"),
Expand All @@ -147,12 +141,7 @@ impl IntrinsicObject for Temporal {
.constructors()
.plain_year_month()
.constructor(),
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
js_string!("TimeZone"),
realm.intrinsics().constructors().time_zone().constructor(),
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.static_property(
js_string!("ZonedDateTime"),
Expand All @@ -161,7 +150,7 @@ impl IntrinsicObject for Temporal {
.constructors()
.zoned_date_time()
.constructor(),
Attribute::READONLY | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE,
)
.build();
}
Expand All @@ -181,38 +170,71 @@ fn to_zero_padded_decimal_string(n: u64, min_length: usize) -> String {
format!("{n:0min_length$}")
}

/// Abstract Operation 13.1 [`IteratorToListOfType`][proposal]
///
/// [proposal]: https://tc39.es/proposal-temporal/#sec-iteratortolistoftype
pub(crate) fn _iterator_to_list_of_types(
iterator: &mut IteratorRecord,
element_types: &[Type],
pub(crate) fn get_relative_to_option(
options: &JsObject,
context: &mut Context,
) -> JsResult<Vec<JsValue>> {
// 1. Let values be a new empty List.
let mut values = Vec::new();

// 2. Repeat,
// a. Let next be ? IteratorStepValue(iteratorRecord).
while let Some(next) = iterator.step_value(context)? {
// c. If Type(next) is not an element of elementTypes, then

if element_types.contains(&next.get_type()) {
// i. Let completion be ThrowCompletion(a newly created TypeError object).
let completion = JsNativeError::typ()
.with_message("IteratorNext is not within allowed type values.");

// ii. Return ? IteratorClose(iteratorRecord, completion).
let _never = iterator.close(Err(completion.into()), context)?;
) -> JsResult<Option<RelativeTo>> {
// Let value be ? Get(options, "relativeTo").
let value = options.get(js_string!("relativeTo"), context)?;
// 2. If value is undefined, return the Record { [[PlainRelativeTo]]: undefined, [[ZonedRelativeTo]]: undefined }.
if value.is_undefined() {
return Ok(None);
}
// 3. Let offsetBehaviour be option.
// 4. Let matchBehaviour be match-exactly.
// 5. If value is an Object, then
if let Some(object) = value.as_object() {
// a. If value has an [[InitializedTemporalZonedDateTime]] internal slot, then
if let Some(zdt) = object.downcast_ref::<ZonedDateTime>() {
// i. Return the Record { [[PlainRelativeTo]]: undefined, [[ZonedRelativeTo]]: value }.
return Ok(Some(RelativeTo::ZonedDateTime(zdt.inner.clone())));
// b. If value has an [[InitializedTemporalDate]] internal slot, then
} else if let Some(date) = object.downcast_ref::<PlainDate>() {
// i. Return the Record { [[PlainRelativeTo]]: value, [[ZonedRelativeTo]]: undefined }.
return Ok(Some(RelativeTo::PlainDate(date.inner.clone())));
// c. If value has an [[InitializedTemporalDateTime]] internal slot, then
} else if let Some(dt) = object.downcast_ref::<PlainDateTime>() {
// i. Let plainDate be ! CreateTemporalDate(value.[[ISODateTime]].[[ISODate]], value.[[Calendar]]).
// ii. Return the Record { [[PlainRelativeTo]]: plainDate, [[ZonedRelativeTo]]: undefined }.
return Ok(Some(RelativeTo::PlainDate(dt.inner.clone().into())));
}

// d. Append next to the end of the List values.
values.push(next);
// d. Let calendar be ? GetTemporalCalendarIdentifierWithISODefault(value).
// e. Let fields be ? PrepareCalendarFields(calendar, value, « year, month, month-code, day », « hour, minute, second, millisecond, microsecond, nanosecond, offset, time-zone », «»).
let partial = to_partial_zoneddatetime(object, context)?;
// f. Let result be ? InterpretTemporalDateTimeFields(calendar, fields, constrain).
// g. Let timeZone be fields.[[TimeZone]].
// h. Let offsetString be fields.[[OffsetString]].
// i. If offsetString is unset, then
// i. Set offsetBehaviour to wall.
// j. Let isoDate be result.[[ISODate]].
if partial.timezone.is_none() {
return Ok(Some(RelativeTo::PlainDate(TemporalDate::from_partial(
partial.date,
None,
)?)));
}
// k. Let time be result.[[Time]].
let zdt = TemporalZonedDateTime::from_partial_with_provider(
partial,
None,
None,
None,
context.tz_provider(),
)?;
return Ok(Some(RelativeTo::ZonedDateTime(zdt)));
}

// b. If next is done, then
// i. Return values.
Ok(values)
// 6. Else,
// a. If value is not a String, throw a TypeError exception.
let Some(relative_to_str) = value.as_string() else {
return Err(JsNativeError::typ()
.with_message("relativeTo must be an object or string.")
.into());
};
// Steps 7-12 are handled by temporal_rs
Ok(Some(RelativeTo::try_from_str_with_provider(
&relative_to_str.to_std_string_escaped(),
context.tz_provider(),
)?))
}

type RelativeTemporalObjectResult = JsResult<(Option<TemporalDate>, Option<TemporalZonedDateTime>)>;
Expand Down
41 changes: 29 additions & 12 deletions core/engine/src/builtins/temporal/now.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ use boa_profiler::Profiler;
use temporal_rs::{Now as NowInner, TimeZone};

use super::{
create_temporal_datetime, create_temporal_instant, ns_max_instant, ns_min_instant,
time_zone::default_time_zone, to_temporal_timezone_identifier,
create_temporal_date, create_temporal_datetime, create_temporal_instant, create_temporal_time,
create_temporal_zoneddatetime, ns_max_instant, ns_min_instant, time_zone::default_time_zone,
to_temporal_timezone_identifier,
};

/// JavaScript `Temporal.Now` object.
Expand All @@ -41,8 +42,9 @@ impl IntrinsicObject for Now {
.static_method(Self::time_zone_id, js_string!("timeZoneId"), 0)
.static_method(Self::instant, js_string!("instant"), 0)
.static_method(Self::plain_datetime, js_string!("plainDateTimeISO"), 0)
.static_method(Self::zoned_date_time, js_string!("zonedDateTimeISO"), 0)
.static_method(Self::zoneddatetime, js_string!("zonedDateTimeISO"), 0)
.static_method(Self::plain_date, js_string!("plainDateISO"), 0)
.static_method(Self::plain_time, js_string!("plainTimeISO"), 0)
.build();
}

Expand Down Expand Up @@ -83,25 +85,40 @@ impl Now {
.map(|v| to_temporal_timezone_identifier(v, context))
.transpose()?;
create_temporal_datetime(
NowInner::plain_date_time_with_provider(tz, context.tz_provider())?,
NowInner::plain_datetime_iso_with_provider(tz, context.tz_provider())?,
None,
context,
)
.map(Into::into)
}

/// `Temporal.Now.zonedDateTime`
fn zoned_date_time(_: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
fn zoneddatetime(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let timezone = args
.first()
.map(|v| to_temporal_timezone_identifier(v, context))
.transpose()?;
let zdt = NowInner::zoneddatetime_iso(timezone)?;
create_temporal_zoneddatetime(zdt, None, context).map(Into::into)
}

/// `Temporal.Now.plainDateISO`
fn plain_date(_: &JsValue, _: &[JsValue], _: &mut Context) -> JsResult<JsValue> {
Err(JsNativeError::error()
.with_message("not yet implemented.")
.into())
fn plain_date(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let tz = args
.first()
.map(|v| to_temporal_timezone_identifier(v, context))
.transpose()?;
let pd = NowInner::plain_date_iso_with_provider(tz, context.tz_provider())?;
create_temporal_date(pd, None, context).map(Into::into)
}

fn plain_time(_: &JsValue, args: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let tz = args
.first()
.map(|v| to_temporal_timezone_identifier(v, context))
.transpose()?;
let pt = NowInner::plain_time_iso_with_provider(tz, context.tz_provider())?;
create_temporal_time(pt, None, context).map(Into::into)
}
}

Expand Down
Loading

0 comments on commit fdd8acc

Please sign in to comment.