Skip to content

Commit e7e240f

Browse files
committed
feat(ecmascript): PlainTime.prototype.round
1 parent 285a37e commit e7e240f

1 file changed

Lines changed: 104 additions & 3 deletions

File tree

nova_vm/src/ecmascript/builtins/temporal/plain_time/plain_time_prototype.rs

Lines changed: 104 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,20 @@
22
// License, v. 2.0. If a copy of the MPL was not distributed with this
33
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44

5+
use temporal_rs::options::{RoundingMode, RoundingOptions, Unit};
6+
57
use crate::{
68
ecmascript::{
7-
Agent, ArgumentsList, BUILTIN_STRING_MEMORY, Behaviour, Builtin, BuiltinGetter, JsResult,
8-
PropertyKey, Realm, String, Value,
9+
Agent, ArgumentsList, BUILTIN_STRING_MEMORY, Behaviour, Builtin, BuiltinGetter,
10+
ExceptionType, JsResult, PropertyKey, Realm, String, StringOptionType, Value,
911
builders::OrdinaryObjectBuilder,
1012
builtins::temporal::plain_time::{
1113
add_duration_to_time, require_internal_slot_temporal_plain_time,
1214
},
15+
create_temporal_plain_time, get_options_object, get_rounding_increment_option,
16+
get_rounding_mode_option, get_temporal_unit_valued_option, temporal_err_to_js_err,
1317
},
14-
engine::{Bindable, GcScope, NoGcScope},
18+
engine::{Bindable, GcScope, NoGcScope, Scopable},
1519
heap::WellKnownSymbols,
1620
};
1721

@@ -90,6 +94,12 @@ impl Builtin for TemporalPlainTimePrototypeSubtract {
9094
const BEHAVIOUR: Behaviour = Behaviour::Regular(TemporalPlainTimePrototype::subtract);
9195
}
9296

97+
struct TemporalPlainTimePrototypeRound;
98+
impl Builtin for TemporalPlainTimePrototypeRound {
99+
const NAME: String<'static> = BUILTIN_STRING_MEMORY.round;
100+
const LENGTH: u8 = 1;
101+
const BEHAVIOUR: Behaviour = Behaviour::Regular(TemporalPlainTimePrototype::round);
102+
}
93103
impl TemporalPlainTimePrototype {
94104
/// ### [4.3.4 get Temporal.PlainTime.prototype.minute](https://tc39.es/proposal-temporal/#sec-get-temporal.plaintime.prototype.minute)
95105
pub(crate) fn get_minute<'gc>(
@@ -228,6 +238,96 @@ impl TemporalPlainTimePrototype {
228238
.map(Value::from)
229239
}
230240

241+
/// ### [5.3.14 Temporal.PlainTime.prototype.round ( roundTo )](https://tc39.es/proposal-temporal/#sec-temporal.plaintime.prototype.round)
242+
fn round<'gc>(
243+
agent: &mut Agent,
244+
this_value: Value,
245+
args: ArgumentsList,
246+
mut gc: GcScope<'gc, '_>,
247+
) -> JsResult<'gc, Value<'gc>> {
248+
let this_value = this_value.bind(gc.nogc());
249+
let round_to = args.get(0).bind(gc.nogc());
250+
// 1. Let plainTime be the this value.
251+
// 2. Perform ? RequireInternalSlot(plainTime, [[InitializedTemporalTime]]).
252+
let plain_time = require_internal_slot_temporal_plain_time(agent, this_value, gc.nogc())
253+
.unbind()?;
254+
let inner_time = plain_time.inner_plain_time(agent);
255+
// 3. If roundTo is undefined, throw a TypeError exception.
256+
if round_to.is_undefined() {
257+
return Err(agent.throw_exception_with_static_message(
258+
ExceptionType::TypeError,
259+
"rountTo cannot be undefined",
260+
gc.into_nogc(),
261+
));
262+
}
263+
264+
// 4. If roundTo is a String, then
265+
let options = if let Ok(round_to) = String::try_from(round_to) {
266+
// a. Let paramString be roundTo.
267+
// b. Set roundTo to OrdinaryObjectCreate(null).
268+
// c. Perform ! CreateDataPropertyOrThrow(roundTo, "smallestUnit", paramString).
269+
let mut options = RoundingOptions::default();
270+
options.smallest_unit =
271+
Some(Unit::from_string(agent, round_to.unbind(), gc.nogc()).unbind()?);
272+
options
273+
} else {
274+
// 5. Else,
275+
// a. Set roundTo to ? GetOptionsObject(roundTo).
276+
let round_to = get_options_object(agent, round_to, gc.nogc())
277+
.unbind()?
278+
.map(|r| r.scope(agent, gc.nogc()));
279+
// 6. NOTE: The following steps read options and perform independent validation in alphabetical
280+
// order (GetRoundingIncrementOption reads "roundingIncrement" and GetRoundingModeOption reads "roundingMode").
281+
let mut options = RoundingOptions::default();
282+
283+
let (rounding_increment, rounding_mode, smallest_unit) =
284+
if let Some(round_to) = round_to {
285+
// 7. Let roundingIncrement be ? GetRoundingIncrementOption(roundTo).
286+
let rounding_increment =
287+
get_rounding_increment_option(agent, round_to.get(agent), gc.reborrow())
288+
.unbind()?;
289+
// 8. Let roundingMode be ? GetRoundingModeOption(roundTo, half-expand).
290+
let rounding_mode = get_rounding_mode_option(
291+
agent,
292+
round_to.get(agent),
293+
RoundingMode::default(),
294+
gc.reborrow(),
295+
)
296+
.unbind()?;
297+
// 9. Let smallestUnit be ? GetTemporalUnitValuedOption(roundTo, "smallestUnit", required).
298+
let smallest_unit = get_temporal_unit_valued_option(
299+
agent,
300+
round_to.get(agent),
301+
BUILTIN_STRING_MEMORY.smallestUnit.into(),
302+
gc.reborrow(),
303+
)
304+
.unbind()?;
305+
(rounding_increment, rounding_mode, smallest_unit)
306+
} else {
307+
Default::default()
308+
};
309+
310+
options.increment = Some(rounding_increment);
311+
options.rounding_mode = Some(rounding_mode);
312+
options.smallest_unit = smallest_unit;
313+
options
314+
};
315+
316+
// 10. Perform ? ValidateTemporalUnitValue(smallestUnit, time).
317+
// 11. Let maximum be MaximumTemporalDurationRoundingIncrement(smallestUnit).
318+
// 12. Assert: maximum is not unset.
319+
// 13. Perform ? ValidateTemporalRoundingIncrement(roundingIncrement, maximum, false).
320+
// 14. Let result be RoundTime(plainTime.[[Time]], roundingIncrement, smallestUnit, roundingMode).
321+
let result = inner_time
322+
.round(options)
323+
.map_err(|e| temporal_err_to_js_err(agent, e, gc.nogc()))
324+
.unbind()?;
325+
// 15. Return ! CreateTemporalTime(result).
326+
Ok(create_temporal_plain_time(agent, result, None, gc)
327+
.unwrap()
328+
.into())
329+
}
330+
231331
pub(crate) fn create_intrinsic(agent: &mut Agent, realm: Realm<'static>, _: NoGcScope) {
232332
let intrinsics = agent.get_realm_record_by_id(realm).intrinsics();
233333
let this = intrinsics.temporal_plain_time_prototype();
@@ -246,6 +346,7 @@ impl TemporalPlainTimePrototype {
246346
.with_builtin_function_getter_property::<TemporalPlainTimePrototypeGetMillisecond>()
247347
.with_builtin_function_property::<TemporalPlainTimePrototypeAdd>()
248348
.with_builtin_function_property::<TemporalPlainTimePrototypeSubtract>()
349+
.with_builtin_function_property::<TemporalPlainTimePrototypeRound>()
249350
.with_property(|builder| {
250351
builder
251352
.with_key(WellKnownSymbols::ToStringTag.into())

0 commit comments

Comments
 (0)