use crate::{
ecmascript::{
Agent, ArgumentsList, BUILTIN_STRING_MEMORY, Behaviour, Builtin,
BuiltinIntrinsicConstructor, ExceptionType, Function, JsResult, Object, Realm, String,
Value, builders::BuiltinFunctionBuilder, create_temporal_duration, temporal_err_to_js_err,
to_integer_if_integral,
},
engine::{Bindable, GcScope, NoGcScope, Scopable},
heap::IntrinsicConstructorIndexes,
};
pub(crate) struct TemporalDurationConstructor;
impl Builtin for TemporalDurationConstructor {
const NAME: String<'static> = BUILTIN_STRING_MEMORY.Duration;
const LENGTH: u8 = 1;
const BEHAVIOUR: Behaviour = Behaviour::Constructor(TemporalDurationConstructor::constructor);
}
impl BuiltinIntrinsicConstructor for TemporalDurationConstructor {
const INDEX: IntrinsicConstructorIndexes = IntrinsicConstructorIndexes::TemporalDuration;
}
impl TemporalDurationConstructor {
fn constructor<'gc>(
agent: &mut Agent,
_: Value,
args: ArgumentsList,
new_target: Option<Object>,
mut gc: GcScope<'gc, '_>,
) -> JsResult<'gc, Value<'gc>> {
let years = args.get(1).scope(agent, gc.nogc());
let months = args.get(2).scope(agent, gc.nogc());
let weeks = args.get(3).scope(agent, gc.nogc());
let days = args.get(4).scope(agent, gc.nogc());
let hours = args.get(5).scope(agent, gc.nogc());
let minutes = args.get(6).scope(agent, gc.nogc());
let seconds = args.get(7).scope(agent, gc.nogc());
let milliseconds = args.get(8).scope(agent, gc.nogc());
let microseconds = args.get(9).scope(agent, gc.nogc());
let nanoseconds = args.get(10).scope(agent, gc.nogc());
let new_target = new_target.bind(gc.nogc());
let Some(new_target) = new_target else {
return Err(agent.throw_exception_with_static_message(
ExceptionType::TypeError,
"calling a builtin Temporal.Duration constructor without new is forbidden",
gc.into_nogc(),
));
};
let Ok(new_target) = Function::try_from(new_target) else {
unreachable!()
};
let new_target = new_target.scope(agent, gc.nogc());
let y = if years.get(agent).is_undefined() {
0
} else {
to_integer_if_integral(agent, years.get(agent), gc.reborrow()).unbind()? as i64
};
let mo = if months.get(agent).is_undefined() {
0
} else {
to_integer_if_integral(agent, months.get(agent), gc.reborrow()).unbind()? as i64
};
let w = if weeks.get(agent).is_undefined() {
0
} else {
to_integer_if_integral(agent, weeks.get(agent), gc.reborrow()).unbind()? as i64
};
let d = if days.get(agent).is_undefined() {
0
} else {
to_integer_if_integral(agent, days.get(agent), gc.reborrow()).unbind()? as i64
};
let h = if hours.get(agent).is_undefined() {
0
} else {
to_integer_if_integral(agent, hours.get(agent), gc.reborrow()).unbind()? as i64
};
let m = if minutes.get(agent).is_undefined() {
0
} else {
to_integer_if_integral(agent, minutes.get(agent), gc.reborrow()).unbind()? as i64
};
let s = if seconds.get(agent).is_undefined() {
0
} else {
to_integer_if_integral(agent, seconds.get(agent), gc.reborrow()).unbind()? as i64
};
let ms = if milliseconds.get(agent).is_undefined() {
0
} else {
to_integer_if_integral(agent, milliseconds.get(agent), gc.reborrow()).unbind()? as i64
};
let mis = if microseconds.get(agent).is_undefined() {
0
} else {
to_integer_if_integral(agent, microseconds.get(agent), gc.reborrow()).unbind()?
};
let ns = if nanoseconds.get(agent).is_undefined() {
0
} else {
to_integer_if_integral(agent, nanoseconds.get(agent), gc.reborrow()).unbind()?
};
let duration = temporal_rs::Duration::new(y, mo, w, d, h, m, s, ms, mis, ns)
.map_err(|e| temporal_err_to_js_err(agent, e, gc.nogc()))
.unbind()?;
create_temporal_duration(agent, duration, Some(new_target.get(agent)), gc).map(Value::from)
}
pub(crate) fn create_intrinsic(agent: &mut Agent, realm: Realm<'static>, _gc: NoGcScope) {
let intrinsics = agent.get_realm_record_by_id(realm).intrinsics();
let duration_prototype = intrinsics.temporal_duration_prototype();
BuiltinFunctionBuilder::new_intrinsic_constructor::<TemporalDurationConstructor>(
agent, realm,
)
.with_property_capacity(1)
.with_prototype_property(duration_prototype.into())
.build();
}
}