Skip to content

Commit 811cfb0

Browse files
Merge branch 'difference_temporal_instant' into temporal_intrinsic
2 parents 0f3b4a6 + fc8e1ac commit 811cfb0

File tree

5 files changed

+154
-14
lines changed

5 files changed

+154
-14
lines changed

nova_vm/src/builtin_strings

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ isSealed
259259
isWellFormed
260260
#[cfg(feature = "annex-b-string")]italics
261261
#[cfg(feature = "temporal")]Instant
262+
#[cfg(feature = "temporal")]largestUnit
262263
Iterator
263264
iterator
264265
join

nova_vm/src/ecmascript/builtins/temporal.rs

Lines changed: 98 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,22 @@ pub mod instant;
88
pub mod options;
99
pub mod plain_time;
1010

11+
use temporal_rs::options::{DifferenceSettings, RoundingMode, Unit, UnitGroup};
12+
1113
use crate::{
1214
ecmascript::{
1315
builders::ordinary_object_builder::OrdinaryObjectBuilder,
14-
execution::{Agent, Realm},
15-
types::{BUILTIN_STRING_MEMORY, IntoValue},
16+
builtins::temporal::{
17+
instant::instant_prototype::{DefaultOption, get_temporal_unit_valued_option},
18+
options::{get_rounding_increment_option, get_rounding_mode_option},
19+
},
20+
execution::{Agent, JsResult, Realm},
21+
types::{BUILTIN_STRING_MEMORY, IntoValue, Object},
22+
},
23+
engine::{
24+
context::{Bindable, GcScope, NoGcScope, trivially_bindable},
25+
rootable::Scopable,
1626
},
17-
engine::context::NoGcScope,
1827
heap::WellKnownSymbolIndexes,
1928
};
2029

@@ -68,3 +77,89 @@ impl Temporal {
6877
.build();
6978
}
7079
}
80+
81+
trivially_bindable!(DifferenceSettings);
82+
trivially_bindable!(UnitGroup);
83+
trivially_bindable!(Unit);
84+
85+
/// [13.42 GetDifferenceSettings ( operation, options, unitGroup, disallowedUnits, fallbackSmallestUnit, smallestLargestDefaultUnit )](https://tc39.es/proposal-temporal/#sec-temporal-getdifferencesettings)
86+
/// The abstract operation GetDifferenceSettings takes arguments operation (since or until),
87+
/// options (an Object), unitGroup (date, time, or datetime), disallowedUnits (a List of Temporal units),
88+
/// fallbackSmallestUnit (a Temporal unit), and smallestLargestDefaultUnit (a Temporal unit) and returns either
89+
/// a normal completion containing a Record with fields [[SmallestUnit]] (a Temporal unit),
90+
/// [[LargestUnit]] (a Temporal unit), [[RoundingMode]] (a rounding mode),
91+
/// and [[RoundingIncrement]] (an integer in the inclusive interval from 1 to 10**9),
92+
/// or a throw completion. It reads unit and rounding options needed by difference operations.
93+
pub(crate) fn get_difference_settings<'gc, const IS_UNTIL: bool>(
94+
agent: &mut Agent,
95+
options: Object<'gc>, // options (an Object)
96+
_unit_group: UnitGroup, // unitGroup (date, time, or datetime)
97+
_disallowed_units: Vec<Unit>, // disallowedUnits (todo:a List of Temporal units)
98+
_fallback_smallest_unit: Unit, // fallbackSmallestUnit (a Temporal unit)
99+
_smallest_largest_default_unit: Unit, // smallestLargestDefaultUnit (a Temporal unit)
100+
mut gc: GcScope<'gc, '_>,
101+
) -> JsResult<'gc, DifferenceSettings> {
102+
let _unit_group = _unit_group.bind(gc.nogc());
103+
let _disallowed_units = _disallowed_units.bind(gc.nogc());
104+
let _fallback_smallest_unit = _fallback_smallest_unit.bind(gc.nogc());
105+
let _smallest_largest_default_unit = _smallest_largest_default_unit.bind(gc.nogc());
106+
107+
let options = options.scope(agent, gc.nogc());
108+
// 1. NOTE: The following steps read options and perform independent validation in alphabetical order.
109+
// 2. Let largestUnit be ? GetTemporalUnitValuedOption(options, "largestUnit", unset).
110+
let largest_unit = get_temporal_unit_valued_option(
111+
agent,
112+
options.get(agent),
113+
BUILTIN_STRING_MEMORY.largestUnit.to_property_key(),
114+
DefaultOption::Unset,
115+
gc.reborrow(),
116+
)
117+
.unbind()?
118+
.bind(gc.nogc());
119+
// 3. Let roundingIncrement be ? GetRoundingIncrementOption(options).
120+
let rounding_increment =
121+
get_rounding_increment_option(agent, options.get(agent), gc.reborrow())
122+
.unbind()?
123+
.bind(gc.nogc());
124+
// 4. Let roundingMode be ? GetRoundingModeOption(options, trunc).
125+
let rounding_mode = get_rounding_mode_option(
126+
agent,
127+
options.get(agent),
128+
RoundingMode::Trunc,
129+
gc.reborrow(),
130+
)
131+
.unbind()?
132+
.bind(gc.nogc());
133+
// 5. Let smallestUnit be ? GetTemporalUnitValuedOption(options, "smallestUnit", unset).
134+
let smallest_unit = get_temporal_unit_valued_option(
135+
agent,
136+
options.get(agent),
137+
BUILTIN_STRING_MEMORY.smallestUnit.to_property_key(),
138+
DefaultOption::Unset,
139+
gc.reborrow(),
140+
)
141+
.unbind()?
142+
.bind(gc.nogc());
143+
// 6. Perform ? ValidateTemporalUnitValue(largestUnit, unitGroup, « auto »).
144+
// 7. If largestUnit is unset, then
145+
// a. Set largestUnit to auto.
146+
// 8. If disallowedUnits contains largestUnit, throw a RangeError exception.
147+
// 9. If operation is since, then
148+
// a. Set roundingMode to NegateRoundingMode(roundingMode).
149+
// 10. Perform ? ValidateTemporalUnitValue(smallestUnit, unitGroup).
150+
// 11. If smallestUnit is unset, then
151+
// a. Set smallestUnit to fallbackSmallestUnit.
152+
// 12. If disallowedUnits contains smallestUnit, throw a RangeError exception.
153+
// 13. Let defaultLargestUnit be LargerOfTwoTemporalUnits(smallestLargestDefaultUnit, smallestUnit).
154+
// 14. If largestUnit is auto, set largestUnit to defaultLargestUnit.
155+
// 15. If LargerOfTwoTemporalUnits(largestUnit, smallestUnit) is not largestUnit, throw a RangeError exception.
156+
// 16. Let maximum be MaximumTemporalDurationRoundingIncrement(smallestUnit).
157+
// 17. If maximum is not unset, perform ? ValidateTemporalRoundingIncrement(roundingIncrement, maximum, false).
158+
// 18. Return the Record { [[SmallestUnit]]: smallestUnit, [[LargestUnit]]: largestUnit, [[RoundingMode]]: roundingMode, [[RoundingIncrement]]: roundingIncrement, }.
159+
let mut diff_settings = temporal_rs::options::DifferenceSettings::default();
160+
diff_settings.largest_unit = Some(largest_unit);
161+
diff_settings.smallest_unit = Some(smallest_unit);
162+
diff_settings.rounding_mode = Some(rounding_mode);
163+
diff_settings.increment = Some(rounding_increment);
164+
Ok(diff_settings)
165+
}

nova_vm/src/ecmascript/builtins/temporal/duration.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ impl IndexMut<TemporalDuration<'_>> for Vec<DurationHeapData<'static>> {
104104
/// It creates a Temporal.Duration instance and fills
105105
/// the internal slots with valid values.
106106
/// It performs the following steps when called:
107-
fn create_temporal_duration<'gc>(// years,
107+
pub(crate) fn create_temporal_duration<'gc>(// years,
108108
// months,
109109
// weeks,
110110
// days,

nova_vm/src/ecmascript/builtins/temporal/instant.rs

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,19 @@ pub(crate) mod data;
88
pub mod instant_constructor;
99
pub mod instant_prototype;
1010

11+
use temporal_rs::options::{Unit, UnitGroup};
12+
1113
use crate::{
1214
ecmascript::{
1315
abstract_operations::type_conversion::{PreferredType, to_primitive_object},
1416
builtins::{
1517
ordinary::ordinary_create_from_constructor,
16-
temporal::{duration::to_temporal_duration, error::temporal_err_to_js_err},
18+
temporal::{
19+
duration::{TemporalDuration, create_temporal_duration, to_temporal_duration},
20+
error::temporal_err_to_js_err,
21+
get_difference_settings,
22+
options::get_options_object,
23+
},
1724
},
1825
execution::{
1926
JsResult, ProtoIntrinsics,
@@ -327,23 +334,60 @@ fn add_duration_to_instant<'gc, const IS_ADD: bool>(
327334
/// rounds it, and returns it as a Temporal.Duration object.
328335
fn difference_temporal_instant<'gc, const IS_UNTIL: bool>(
329336
agent: &mut Agent,
330-
instant: Value,
337+
instant: TemporalInstant,
331338
other: Value,
332339
options: Value,
333340
mut gc: GcScope<'gc, '_>,
334-
) -> JsResult<'gc, Value<'gc>> {
335-
let instant = instant.bind(gc.nogc());
341+
) -> JsResult<'gc, TemporalDuration<'gc>> {
342+
let instant = instant.scope(agent, gc.nogc());
336343
let other = other.bind(gc.nogc());
337-
let options = options.bind(gc.nogc());
344+
let options = options.scope(agent, gc.nogc());
338345
// 1. Set other to ? ToTemporalInstant(other).
339-
let other = to_temporal_instant(agent, other.unbind(), gc.reborrow());
346+
let other = to_temporal_instant(agent, other.unbind(), gc.reborrow())
347+
.unbind()?
348+
.bind(gc.nogc());
340349
// 2. Let resolvedOptions be ? GetOptionsObject(options).
350+
let resolved_options = get_options_object(agent, options.get(agent), gc.nogc())
351+
.unbind()?
352+
.bind(gc.nogc());
341353
// 3. Let settings be ? GetDifferenceSettings(operation, resolvedOptions, time, « », nanosecond, second).
354+
let _result;
355+
if IS_UNTIL {
356+
const UNTIL: bool = true;
357+
let settings = get_difference_settings::<UNTIL>(
358+
agent,
359+
resolved_options.unbind(),
360+
UnitGroup::Time,
361+
vec![],
362+
Unit::Nanosecond,
363+
Unit::Second,
364+
gc.reborrow(),
365+
)
366+
.unbind()?
367+
.bind(gc.nogc());
368+
_result =
369+
temporal_rs::Instant::until(&instant.get(agent).inner_instant(agent), &other, settings);
370+
} else {
371+
const SINCE: bool = false;
372+
let settings = get_difference_settings::<SINCE>(
373+
agent,
374+
resolved_options.unbind(),
375+
UnitGroup::Time,
376+
vec![],
377+
Unit::Nanosecond,
378+
Unit::Second,
379+
gc.reborrow(),
380+
)
381+
.unbind()?
382+
.bind(gc.nogc());
383+
_result =
384+
temporal_rs::Instant::since(&instant.get(agent).inner_instant(agent), &other, settings);
385+
}
342386
// 4. Let internalDuration be DifferenceInstant(instant.[[EpochNanoseconds]], other.[[EpochNanoseconds]], settings.[[RoundingIncrement]], settings.[[SmallestUnit]], settings.[[RoundingMode]]).
343387
// 5. Let result be ! TemporalDurationFromInternal(internalDuration, settings.[[LargestUnit]]).
344-
// 6. If operation is since, set result to CreateNegatedTemporalDuration(result).
388+
// 6. If operation is since, set result to CreateNegatedTemporsalDuration(result).
345389
// 7. Return result.
346-
unimplemented!()
390+
create_temporal_duration() // skip CreateNegatedTemporsalDuration and just CreateTemporsalDuration() with result
347391
}
348392

349393
#[inline(always)]

nova_vm/src/ecmascript/builtins/temporal/instant/instant_prototype.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ impl TemporalInstantPrototype {
232232
const UNTIL: bool = true;
233233
let result = difference_temporal_instant::<UNTIL>(
234234
agent,
235-
instant.into_value().unbind(),
235+
instant.unbind(),
236236
other.unbind(),
237237
options.unbind(),
238238
gc,
@@ -260,7 +260,7 @@ impl TemporalInstantPrototype {
260260
const SINCE: bool = false;
261261
let result = difference_temporal_instant::<SINCE>(
262262
agent,
263-
instant.into_value().unbind(),
263+
instant.unbind(),
264264
other.unbind(),
265265
options.unbind(),
266266
gc,

0 commit comments

Comments
 (0)