Browse Source

Temporal: Refactor Calendar protocol for `JsObject`s (#3651)

* Progress on refactor

* fix ToTemporalCalendarSlot on to differentiate builtins

* Fix rebase regression in custom calendar

* Revert to old ToTemporalCalendarSlot
pull/3655/head
Kevin 9 months ago committed by GitHub
parent
commit
d423bba8ef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 69
      core/engine/src/builtins/temporal/calendar/mod.rs
  2. 143
      core/engine/src/builtins/temporal/calendar/object.rs
  3. 228
      core/engine/src/builtins/temporal/plain_date/mod.rs
  4. 229
      core/engine/src/builtins/temporal/plain_date_time/mod.rs
  5. 10
      core/engine/src/builtins/temporal/plain_date_time/tests.rs
  6. 30
      core/engine/src/builtins/temporal/plain_month_day/mod.rs
  7. 32
      core/engine/src/builtins/temporal/plain_year_month/mod.rs
  8. 4
      core/engine/src/builtins/temporal/zoned_date_time/mod.rs
  9. 99
      core/temporal/src/components/calendar.rs
  10. 278
      core/temporal/src/components/date.rs
  11. 286
      core/temporal/src/components/datetime.rs
  12. 8
      core/temporal/src/components/month_day.rs
  13. 11
      core/temporal/src/components/year_month.rs

69
core/engine/src/builtins/temporal/calendar/mod.rs

@ -33,15 +33,12 @@ use boa_temporal::{
mod object;
#[doc(inline)]
pub(crate) use object::JsCustomCalendar;
#[cfg(test)]
mod tests;
/// The `Temporal.Calendar` object.
#[derive(Debug, Finalize, JsData)]
pub struct Calendar {
slot: CalendarSlot<JsCustomCalendar>,
slot: CalendarSlot<JsObject>,
}
unsafe impl Trace for Calendar {
@ -55,7 +52,7 @@ unsafe impl Trace for Calendar {
}
impl Calendar {
pub(crate) fn new(slot: CalendarSlot<JsCustomCalendar>) -> Self {
pub(crate) fn new(slot: CalendarSlot<JsObject>) -> Self {
Self { slot }
}
}
@ -155,7 +152,7 @@ impl BuiltInConstructor for Calendar {
// 4. Return ? CreateTemporalCalendar(id, NewTarget).
create_temporal_calendar(
CalendarSlot::<JsCustomCalendar>::from_str(&id.to_std_string_escaped())?,
CalendarSlot::<JsObject>::from_str(&id.to_std_string_escaped())?,
Some(new_target.clone()),
context,
)
@ -956,7 +953,7 @@ impl Calendar {
/// 12.2.1 `CreateTemporalCalendar ( identifier [ , newTarget ] )`
pub(crate) fn create_temporal_calendar(
identifier: CalendarSlot<JsCustomCalendar>,
identifier: CalendarSlot<JsObject>,
new_target: Option<JsValue>,
context: &mut Context,
) -> JsResult<JsValue> {
@ -992,23 +989,21 @@ fn extract_from_temporal_type<DF, DTF, YMF, MDF, ZDTF, Ret>(
zoned_datetime_f: ZDTF,
) -> JsResult<Option<Ret>>
where
DF: FnOnce(&PlainDate) -> JsResult<Option<Ret>>,
DTF: FnOnce(&PlainDateTime) -> JsResult<Option<Ret>>,
YMF: FnOnce(&PlainYearMonth) -> JsResult<Option<Ret>>,
MDF: FnOnce(&PlainMonthDay) -> JsResult<Option<Ret>>,
ZDTF: FnOnce(&ZonedDateTime) -> JsResult<Option<Ret>>,
DF: FnOnce(JsObject<PlainDate>) -> JsResult<Option<Ret>>,
DTF: FnOnce(JsObject<PlainDateTime>) -> JsResult<Option<Ret>>,
YMF: FnOnce(JsObject<PlainYearMonth>) -> JsResult<Option<Ret>>,
MDF: FnOnce(JsObject<PlainMonthDay>) -> JsResult<Option<Ret>>,
ZDTF: FnOnce(JsObject<ZonedDateTime>) -> JsResult<Option<Ret>>,
{
let o = object.borrow();
if let Some(date) = o.downcast_ref::<PlainDate>() {
if let Ok(date) = object.clone().downcast::<PlainDate>() {
return date_f(date);
} else if let Some(dt) = o.downcast_ref::<PlainDateTime>() {
} else if let Ok(dt) = object.clone().downcast::<PlainDateTime>() {
return datetime_f(dt);
} else if let Some(ym) = o.downcast_ref::<PlainYearMonth>() {
} else if let Ok(ym) = object.clone().downcast::<PlainYearMonth>() {
return year_month_f(ym);
} else if let Some(md) = o.downcast_ref::<PlainMonthDay>() {
} else if let Ok(md) = object.clone().downcast::<PlainMonthDay>() {
return month_day_f(md);
} else if let Some(dt) = o.downcast_ref::<ZonedDateTime>() {
} else if let Ok(dt) = object.clone().downcast::<ZonedDateTime>() {
return zoned_datetime_f(dt);
}
@ -1020,15 +1015,15 @@ where
pub(crate) fn get_temporal_calendar_slot_value_with_default(
item: &JsObject,
context: &mut Context,
) -> JsResult<CalendarSlot<JsCustomCalendar>> {
) -> JsResult<CalendarSlot<JsObject>> {
// 1. If item has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
// a. Return item.[[Calendar]].
if let Some(calendar) = extract_from_temporal_type(
item,
|d| Ok(Some(d.inner.calendar().clone())),
|dt| Ok(Some(dt.inner.calendar().clone())),
|ym| Ok(Some(ym.inner.calendar().clone())),
|md| Ok(Some(md.inner.calendar().clone())),
|d| Ok(Some(d.borrow().data().inner.calendar().clone())),
|dt| Ok(Some(dt.borrow().data().inner.calendar().clone())),
|ym| Ok(Some(ym.borrow().data().inner.calendar().clone())),
|md| Ok(Some(md.borrow().data().inner.calendar().clone())),
|zdt| {
Err(JsNativeError::range()
.with_message("Not yet implemented.")
@ -1049,7 +1044,7 @@ pub(crate) fn get_temporal_calendar_slot_value_with_default(
pub(crate) fn to_temporal_calendar_slot_value(
calendar_like: &JsValue,
context: &mut Context,
) -> JsResult<CalendarSlot<JsCustomCalendar>> {
) -> JsResult<CalendarSlot<JsObject>> {
// 1. If temporalCalendarLike is undefined and default is present, then
// a. Assert: IsBuiltinCalendar(default) is true.
// b. Return default.
@ -1061,11 +1056,11 @@ pub(crate) fn to_temporal_calendar_slot_value(
// i. Return temporalCalendarLike.[[Calendar]].
if let Some(calendar) = extract_from_temporal_type(
calendar_like,
|d| Ok(Some(d.inner.calendar().clone())),
|dt| Ok(Some(dt.inner.calendar().clone())),
|ym| Ok(Some(ym.inner.calendar().clone())),
|md| Ok(Some(md.inner.calendar().clone())),
|zdt| Ok(Some(zdt.inner.calendar().clone())),
|d| Ok(Some(d.borrow().data().inner.calendar().clone())),
|dt| Ok(Some(dt.borrow().data().inner.calendar().clone())),
|ym| Ok(Some(ym.borrow().data().inner.calendar().clone())),
|md| Ok(Some(md.borrow().data().inner.calendar().clone())),
|zdt| Ok(Some(zdt.borrow().data().inner.calendar().clone())),
)? {
return Ok(calendar);
}
@ -1078,10 +1073,8 @@ pub(crate) fn to_temporal_calendar_slot_value(
.into());
}
// Types: Box<dyn CalendarProtocol> <- UserCalendar
let custom = JsCustomCalendar::new(calendar_like);
// c. Return temporalCalendarLike.
return Ok(CalendarSlot::Protocol(custom));
return Ok(CalendarSlot::Protocol(calendar_like.clone()));
}
// 3. If temporalCalendarLike is not a String, throw a TypeError exception.
@ -1094,7 +1087,7 @@ pub(crate) fn to_temporal_calendar_slot_value(
// 4. Let identifier be ? ParseTemporalCalendarString(temporalCalendarLike).
// 5. If IsBuiltinCalendar(identifier) is false, throw a RangeError exception.
// 6. Return the ASCII-lowercase of identifier.
Ok(CalendarSlot::<JsCustomCalendar>::from_str(
Ok(CalendarSlot::<JsObject>::from_str(
&calendar_id.to_std_string_escaped(),
)?)
}
@ -1111,7 +1104,7 @@ fn object_implements_calendar_protocol(calendar_like: &JsObject, context: &mut C
fn to_calendar_date_like(
date_like: &JsValue,
context: &mut Context,
) -> JsResult<CalendarDateLike<JsCustomCalendar>> {
) -> JsResult<CalendarDateLike<JsObject>> {
let Some(obj) = date_like.as_object() else {
let date = temporal::plain_date::to_temporal_date(date_like, None, context)?;
@ -1120,9 +1113,9 @@ fn to_calendar_date_like(
let Some(date_like) = extract_from_temporal_type(
obj,
|d| Ok(Some(CalendarDateLike::Date(d.inner.clone()))),
|dt| Ok(Some(CalendarDateLike::DateTime(dt.inner.clone()))),
|ym| Ok(Some(CalendarDateLike::YearMonth(ym.inner.clone()))),
|d| Ok(Some(CalendarDateLike::CustomDate(d))),
|dt| Ok(Some(CalendarDateLike::CustomDateTime(dt))),
|ym| Ok(Some(CalendarDateLike::CustomYearMonth(ym))),
|_| Ok(None),
|_| Ok(None),
)?

143
core/engine/src/builtins/temporal/calendar/object.rs

@ -14,11 +14,10 @@ use crate::{
};
use std::any::Any;
use boa_gc::{Finalize, Trace};
use boa_macros::utf16;
use boa_temporal::{
components::{
calendar::{CalendarDateLike, CalendarProtocol},
calendar::{CalendarDateLike, CalendarProtocol, DateTypes},
Date, Duration, MonthDay, YearMonth,
},
options::ArithmeticOverflow,
@ -26,28 +25,23 @@ use boa_temporal::{
};
use num_traits::ToPrimitive;
use plain_date::PlainDate;
use plain_date_time::PlainDateTime;
use plain_month_day::PlainMonthDay;
use plain_year_month::PlainYearMonth;
/// A user-defined, custom calendar that is only known at runtime
/// and executed at runtime.
///
/// A user-defined calendar implements all of the `CalendarProtocolMethods`
/// and therefore satisfies the requirements to be used as a calendar.
#[derive(Debug, Clone, Trace, Finalize)]
pub(crate) struct JsCustomCalendar {
calendar: JsObject,
}
/// The custom data types for a Custom `JsObject` Calendar.
#[derive(Debug, Clone, Copy)]
pub struct CustomDateLikes;
impl JsCustomCalendar {
pub(crate) fn new(calendar: &JsObject) -> Self {
Self {
calendar: calendar.clone(),
}
}
impl DateTypes<JsObject> for CustomDateLikes {
type Date = JsObject<PlainDate>;
type DateTime = JsObject<PlainDateTime>;
type YearMonth = JsObject<PlainYearMonth>;
type MonthDay = JsObject<PlainMonthDay>;
}
impl CalendarProtocol for JsCustomCalendar {
impl CalendarProtocol for JsObject {
type DateLikes = CustomDateLikes;
fn date_from_fields(
&self,
fields: &mut TemporalFields,
@ -59,7 +53,6 @@ impl CalendarProtocol for JsCustomCalendar {
.expect("Context was not provided for a CustomCalendar.");
let method = self
.calendar
.get(utf16!("dateFromFields"), context)
.expect("method must exist on a object that implements the CalendarProtocol.");
@ -82,7 +75,7 @@ impl CalendarProtocol for JsCustomCalendar {
TemporalError::general("dateFromFields must be implemented as a callable method.")
})?
.call(
&self.calendar.clone().into(),
&self.clone().into(),
&[fields.into(), overflow_obj.into()],
context,
)
@ -105,13 +98,12 @@ impl CalendarProtocol for JsCustomCalendar {
fields: &mut TemporalFields,
overflow: ArithmeticOverflow,
context: &mut dyn Any,
) -> TemporalResult<YearMonth<JsCustomCalendar>> {
) -> TemporalResult<YearMonth<JsObject>> {
let context = context
.downcast_mut::<Context>()
.expect("Context was not provided for a CustomCalendar.");
let method = self
.calendar
.get(utf16!("yearMonthFromFields"), context)
.expect("method must exist on a object that implements the CalendarProtocol.");
@ -136,7 +128,7 @@ impl CalendarProtocol for JsCustomCalendar {
)
})?
.call(
&self.calendar.clone().into(),
&self.clone().into(),
&[fields.into(), overflow_obj.into()],
context,
)
@ -159,13 +151,12 @@ impl CalendarProtocol for JsCustomCalendar {
fields: &mut TemporalFields,
overflow: ArithmeticOverflow,
context: &mut dyn Any,
) -> TemporalResult<MonthDay<JsCustomCalendar>> {
) -> TemporalResult<MonthDay<JsObject>> {
let context = context
.downcast_mut::<Context>()
.expect("Context was not provided for a CustomCalendar.");
let method = self
.calendar
.get(utf16!("yearMonthFromFields"), context)
.expect("method must exist on a object that implements the CalendarProtocol.");
@ -190,7 +181,7 @@ impl CalendarProtocol for JsCustomCalendar {
)
})?
.call(
&self.calendar.clone().into(),
&self.clone().into(),
&[fields.into(), overflow_obj.into()],
context,
)
@ -210,19 +201,19 @@ impl CalendarProtocol for JsCustomCalendar {
fn date_add(
&self,
_date: &Date<JsCustomCalendar>,
_date: &Date<JsObject>,
_duration: &Duration,
_overflow: ArithmeticOverflow,
_context: &mut dyn Any,
) -> TemporalResult<Date<JsCustomCalendar>> {
) -> TemporalResult<Date<JsObject>> {
// TODO
Err(TemporalError::general("Not yet implemented."))
}
fn date_until(
&self,
_one: &Date<JsCustomCalendar>,
_two: &Date<JsCustomCalendar>,
_one: &Date<JsObject>,
_two: &Date<JsObject>,
_largest_unit: boa_temporal::options::TemporalUnit,
_context: &mut dyn Any,
) -> TemporalResult<Duration> {
@ -232,7 +223,7 @@ impl CalendarProtocol for JsCustomCalendar {
fn era(
&self,
_: &CalendarDateLike<JsCustomCalendar>,
_: &CalendarDateLike<JsObject>,
_: &mut dyn Any,
) -> TemporalResult<Option<TinyAsciiStr<16>>> {
// Return undefined as custom calendars do not implement -> Currently.
@ -241,7 +232,7 @@ impl CalendarProtocol for JsCustomCalendar {
fn era_year(
&self,
_: &CalendarDateLike<JsCustomCalendar>,
_: &CalendarDateLike<JsObject>,
_: &mut dyn Any,
) -> TemporalResult<Option<i32>> {
// Return undefined as custom calendars do not implement -> Currently.
@ -250,7 +241,7 @@ impl CalendarProtocol for JsCustomCalendar {
fn year(
&self,
date_like: &CalendarDateLike<JsCustomCalendar>,
date_like: &CalendarDateLike<JsObject>,
context: &mut dyn Any,
) -> TemporalResult<i32> {
let context = context
@ -260,14 +251,13 @@ impl CalendarProtocol for JsCustomCalendar {
let date_like = date_like_to_object(date_like, context)?;
let method = self
.calendar
.get(PropertyKey::from(utf16!("year")), context)
.expect("method must exist on a object that implements the CalendarProtocol.");
let val = method
.as_callable()
.expect("is method")
.call(&self.calendar.clone().into(), &[date_like], context)
.call(&self.clone().into(), &[date_like], context)
.map_err(|err| TemporalError::general(err.to_string()))?;
// Validate the return value.
@ -297,7 +287,7 @@ impl CalendarProtocol for JsCustomCalendar {
fn month(
&self,
date_like: &CalendarDateLike<JsCustomCalendar>,
date_like: &CalendarDateLike<JsObject>,
context: &mut dyn Any,
) -> TemporalResult<u8> {
let context = context
@ -307,14 +297,13 @@ impl CalendarProtocol for JsCustomCalendar {
let date_like = date_like_to_object(date_like, context)?;
let method = self
.calendar
.get(PropertyKey::from(utf16!("month")), context)
.expect("method must exist on a object that implements the CalendarProtocol.");
let val = method
.as_callable()
.expect("is method")
.call(&self.calendar.clone().into(), &[date_like], context)
.call(&self.clone().into(), &[date_like], context)
.map_err(|err| TemporalError::general(err.to_string()))?;
// Validate the return value.
@ -344,7 +333,7 @@ impl CalendarProtocol for JsCustomCalendar {
fn month_code(
&self,
date_like: &CalendarDateLike<JsCustomCalendar>,
date_like: &CalendarDateLike<JsObject>,
context: &mut dyn Any,
) -> TemporalResult<TinyAsciiStr<4>> {
let context = context
@ -354,14 +343,13 @@ impl CalendarProtocol for JsCustomCalendar {
let date_like = date_like_to_object(date_like, context)?;
let method = self
.calendar
.get(PropertyKey::from(utf16!("monthCode")), context)
.expect("method must exist on a object that implements the CalendarProtocol.");
let val = method
.as_callable()
.expect("is method")
.call(&self.calendar.clone().into(), &[date_like], context)
.call(&self.clone().into(), &[date_like], context)
.map_err(|err| TemporalError::general(err.to_string()))?;
let JsValue::String(result) = val else {
@ -376,7 +364,7 @@ impl CalendarProtocol for JsCustomCalendar {
fn day(
&self,
date_like: &CalendarDateLike<JsCustomCalendar>,
date_like: &CalendarDateLike<JsObject>,
context: &mut dyn Any,
) -> TemporalResult<u8> {
let context = context
@ -386,14 +374,13 @@ impl CalendarProtocol for JsCustomCalendar {
let date_like = date_like_to_object(date_like, context)?;
let method = self
.calendar
.get(PropertyKey::from(utf16!("day")), context)
.expect("method must exist on a object that implements the CalendarProtocol.");
let val = method
.as_callable()
.expect("is method")
.call(&self.calendar.clone().into(), &[date_like], context)
.call(&self.clone().into(), &[date_like], context)
.map_err(|err| TemporalError::general(err.to_string()))?;
// Validate the return value.
@ -423,7 +410,7 @@ impl CalendarProtocol for JsCustomCalendar {
fn day_of_week(
&self,
date_like: &CalendarDateLike<JsCustomCalendar>,
date_like: &CalendarDateLike<JsObject>,
context: &mut dyn Any,
) -> TemporalResult<u16> {
let context = context
@ -433,14 +420,13 @@ impl CalendarProtocol for JsCustomCalendar {
let date_like = date_like_to_object(date_like, context)?;
let method = self
.calendar
.get(PropertyKey::from(utf16!("dayOfWeek")), context)
.expect("method must exist on a object that implements the CalendarProtocol.");
let val = method
.as_callable()
.expect("is method")
.call(&self.calendar.clone().into(), &[date_like], context)
.call(&self.clone().into(), &[date_like], context)
.map_err(|err| TemporalError::general(err.to_string()))?;
// Validate the return value.
@ -472,7 +458,7 @@ impl CalendarProtocol for JsCustomCalendar {
fn day_of_year(
&self,
date_like: &CalendarDateLike<JsCustomCalendar>,
date_like: &CalendarDateLike<JsObject>,
context: &mut dyn Any,
) -> TemporalResult<u16> {
let context = context
@ -482,14 +468,13 @@ impl CalendarProtocol for JsCustomCalendar {
let date_like = date_like_to_object(date_like, context)?;
let method = self
.calendar
.get(PropertyKey::from(utf16!("dayOfYear")), context)
.expect("method must exist on a object that implements the CalendarProtocol.");
let val = method
.as_callable()
.expect("is method")
.call(&self.calendar.clone().into(), &[date_like], context)
.call(&self.clone().into(), &[date_like], context)
.map_err(|err| TemporalError::general(err.to_string()))?;
// Validate the return value.
@ -521,7 +506,7 @@ impl CalendarProtocol for JsCustomCalendar {
fn week_of_year(
&self,
date_like: &CalendarDateLike<JsCustomCalendar>,
date_like: &CalendarDateLike<JsObject>,
context: &mut dyn Any,
) -> TemporalResult<u16> {
let context = context
@ -531,14 +516,13 @@ impl CalendarProtocol for JsCustomCalendar {
let date_like = date_like_to_object(date_like, context)?;
let method = self
.calendar
.get(PropertyKey::from(utf16!("weekOfYear")), context)
.expect("method must exist on a object that implements the CalendarProtocol.");
let val = method
.as_callable()
.expect("is method")
.call(&self.calendar.clone().into(), &[date_like], context)
.call(&self.clone().into(), &[date_like], context)
.map_err(|err| TemporalError::general(err.to_string()))?;
// Validate the return value.
@ -570,7 +554,7 @@ impl CalendarProtocol for JsCustomCalendar {
fn year_of_week(
&self,
date_like: &CalendarDateLike<JsCustomCalendar>,
date_like: &CalendarDateLike<JsObject>,
context: &mut dyn Any,
) -> TemporalResult<i32> {
let context = context
@ -580,14 +564,13 @@ impl CalendarProtocol for JsCustomCalendar {
let date_like = date_like_to_object(date_like, context)?;
let method = self
.calendar
.get(PropertyKey::from(utf16!("yearOfWeek")), context)
.expect("method must exist on a object that implements the CalendarProtocol.");
let val = method
.as_callable()
.expect("is method")
.call(&self.calendar.clone().into(), &[date_like], context)
.call(&self.clone().into(), &[date_like], context)
.map_err(|err| TemporalError::general(err.to_string()))?;
// Validate the return value.
@ -612,7 +595,7 @@ impl CalendarProtocol for JsCustomCalendar {
fn days_in_week(
&self,
date_like: &CalendarDateLike<JsCustomCalendar>,
date_like: &CalendarDateLike<JsObject>,
context: &mut dyn Any,
) -> TemporalResult<u16> {
let context = context
@ -622,14 +605,13 @@ impl CalendarProtocol for JsCustomCalendar {
let date_like = date_like_to_object(date_like, context)?;
let method = self
.calendar
.get(PropertyKey::from(utf16!("daysInWeek")), context)
.expect("method must exist on a object that implements the CalendarProtocol.");
let val = method
.as_callable()
.expect("is method")
.call(&self.calendar.clone().into(), &[date_like], context)
.call(&self.clone().into(), &[date_like], context)
.map_err(|err| TemporalError::general(err.to_string()))?;
// Validate the return value.
@ -661,7 +643,7 @@ impl CalendarProtocol for JsCustomCalendar {
fn days_in_month(
&self,
date_like: &CalendarDateLike<JsCustomCalendar>,
date_like: &CalendarDateLike<JsObject>,
context: &mut dyn Any,
) -> TemporalResult<u16> {
let context = context
@ -671,13 +653,12 @@ impl CalendarProtocol for JsCustomCalendar {
let date_like = date_like_to_object(date_like, context)?;
let method = self
.calendar
.get(PropertyKey::from(utf16!("daysInMonth")), context)
.expect("method must exist on a object that implements the CalendarProtocol.");
let val = method
.as_callable()
.expect("is method")
.call(&self.calendar.clone().into(), &[date_like], context)
.call(&self.clone().into(), &[date_like], context)
.map_err(|err| TemporalError::general(err.to_string()))?;
// Validate the return value.
@ -711,7 +692,7 @@ impl CalendarProtocol for JsCustomCalendar {
fn days_in_year(
&self,
date_like: &CalendarDateLike<JsCustomCalendar>,
date_like: &CalendarDateLike<JsObject>,
context: &mut dyn Any,
) -> TemporalResult<u16> {
let context = context
@ -721,14 +702,13 @@ impl CalendarProtocol for JsCustomCalendar {
let date_like = date_like_to_object(date_like, context)?;
let method = self
.calendar
.get(PropertyKey::from(utf16!("daysInYear")), context)
.expect("method must exist on a object that implements the CalendarProtocol.");
let val = method
.as_callable()
.expect("is method")
.call(&self.calendar.clone().into(), &[date_like], context)
.call(&self.clone().into(), &[date_like], context)
.map_err(|err| TemporalError::general(err.to_string()))?;
// Validate the return value.
@ -760,7 +740,7 @@ impl CalendarProtocol for JsCustomCalendar {
fn months_in_year(
&self,
date_like: &CalendarDateLike<JsCustomCalendar>,
date_like: &CalendarDateLike<JsObject>,
context: &mut dyn Any,
) -> TemporalResult<u16> {
let context = context
@ -770,14 +750,13 @@ impl CalendarProtocol for JsCustomCalendar {
let date_like = date_like_to_object(date_like, context)?;
let method = self
.calendar
.get(PropertyKey::from(utf16!("monthsInYear")), context)
.expect("method must exist on a object that implements the CalendarProtocol.");
let val = method
.as_callable()
.expect("is method")
.call(&self.calendar.clone().into(), &[date_like], context)
.call(&self.clone().into(), &[date_like], context)
.map_err(|err| TemporalError::general(err.to_string()))?;
// Validate the return value.
@ -811,7 +790,7 @@ impl CalendarProtocol for JsCustomCalendar {
fn in_leap_year(
&self,
date_like: &CalendarDateLike<JsCustomCalendar>,
date_like: &CalendarDateLike<JsObject>,
context: &mut dyn Any,
) -> TemporalResult<bool> {
let context = context
@ -821,14 +800,13 @@ impl CalendarProtocol for JsCustomCalendar {
let date_like = date_like_to_object(date_like, context)?;
let method = self
.calendar
.get(PropertyKey::from(utf16!("inLeapYear")), context)
.expect("method must exist on a object that implements the CalendarProtocol.");
let val = method
.as_callable()
.expect("is method")
.call(&self.calendar.clone().into(), &[date_like], context)
.call(&self.clone().into(), &[date_like], context)
.map_err(|err| TemporalError::general(err.to_string()))?;
let JsValue::Boolean(result) = val else {
@ -851,14 +829,13 @@ impl CalendarProtocol for JsCustomCalendar {
);
let method = self
.calendar
.get(PropertyKey::from(utf16!("fields")), context)
.expect("method must exist on an object that implements the CalendarProtocol.");
let result = method
.as_callable()
.expect("is method")
.call(&self.calendar.clone().into(), &[fields_js.into()], context)
.call(&self.clone().into(), &[fields_js.into()], context)
.map_err(|e| TemporalError::general(e.to_string()))?;
// validate result and map to a `Vec<String>`
@ -902,7 +879,6 @@ impl CalendarProtocol for JsCustomCalendar {
.map_err(|e| TemporalError::general(e.to_string()))?;
let method = self
.calendar
.get(PropertyKey::from(utf16!("mergeFields")), context)
.expect("method must exist on an object that implements the CalendarProtocol.");
@ -910,7 +886,7 @@ impl CalendarProtocol for JsCustomCalendar {
.as_callable()
.expect("is method")
.call(
&self.calendar.clone().into(),
&self.clone().into(),
&[fields.into(), add_fields.into()],
context,
)
@ -931,10 +907,9 @@ impl CalendarProtocol for JsCustomCalendar {
.expect("Context was not provided for a CustomCalendar.");
let identifier = self
.calendar
.__get__(
&PropertyKey::from(utf16!("id")),
self.calendar.clone().into(),
self.clone().into(),
&mut context.into(),
)
.expect("method must exist on a object that implements the CalendarProtocol.");
@ -949,7 +924,7 @@ impl CalendarProtocol for JsCustomCalendar {
/// Utility function for converting `Temporal`'s `CalendarDateLike` to it's `Boa` specific `JsObject`.
pub(crate) fn date_like_to_object(
date_like: &CalendarDateLike<JsCustomCalendar>,
date_like: &CalendarDateLike<JsObject>,
context: &mut Context,
) -> TemporalResult<JsValue> {
match date_like {
@ -961,13 +936,9 @@ pub(crate) fn date_like_to_object(
.map_err(|e| TemporalError::general(e.to_string()))
.map(Into::into)
}
CalendarDateLike::MonthDay(md) => {
plain_month_day::create_temporal_month_day(md.clone(), None, context)
.map_err(|e| TemporalError::general(e.to_string()))
}
CalendarDateLike::YearMonth(ym) => {
plain_year_month::create_temporal_year_month(ym.clone(), None, context)
.map_err(|e| TemporalError::general(e.to_string()))
}
CalendarDateLike::CustomMonthDay(md) => Ok(md.clone().upcast().into()),
CalendarDateLike::CustomYearMonth(ym) => Ok(ym.clone().upcast().into()),
CalendarDateLike::CustomDate(pd) => Ok(pd.clone().upcast().into()),
CalendarDateLike::CustomDateTime(pdt) => Ok(pdt.clone().upcast().into()),
}
}

228
core/engine/src/builtins/temporal/plain_date/mod.rs

@ -19,25 +19,41 @@ use crate::{
use boa_gc::{Finalize, Trace};
use boa_profiler::Profiler;
use boa_temporal::{
components::{Date as InnerDate, DateTime},
components::{
calendar::{CalendarSlot, GetCalendarSlot},
Date as InnerDate, DateTime,
},
iso::IsoDateSlots,
options::ArithmeticOverflow,
};
use super::{calendar, create_temporal_calendar, JsCustomCalendar, PlainDateTime, ZonedDateTime};
use super::{calendar, create_temporal_calendar, PlainDateTime, ZonedDateTime};
/// The `Temporal.PlainDate` object.
#[derive(Debug, Clone, Trace, Finalize, JsData)]
#[boa_gc(unsafe_empty_trace)] // TODO: Remove this!!! `InnerDate` could contain `Trace` types.
pub struct PlainDate {
pub(crate) inner: InnerDate<JsCustomCalendar>,
pub(crate) inner: InnerDate<JsObject>,
}
impl PlainDate {
pub(crate) fn new(inner: InnerDate<JsCustomCalendar>) -> Self {
pub(crate) fn new(inner: InnerDate<JsObject>) -> Self {
Self { inner }
}
}
impl IsoDateSlots for JsObject<PlainDate> {
fn iso_date(&self) -> boa_temporal::iso::IsoDate {
self.borrow().data().inner.iso()
}
}
impl GetCalendarSlot<JsObject> for JsObject<PlainDate> {
fn get_calendar(&self) -> CalendarSlot<JsObject> {
self.borrow().data().inner.get_calendar()
}
}
impl BuiltInObject for PlainDate {
const NAME: JsString = StaticJsStrings::PLAIN_DATE;
}
@ -258,110 +274,140 @@ impl PlainDate {
/// 3.3.4 get `Temporal.PlainDate.prototype.year`
fn get_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDate object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDate object.")
.into());
};
Ok(date.inner.contextual_year(context)?.into())
Ok(InnerDate::<JsObject>::contextualized_year(&date, context)?.into())
}
/// 3.3.5 get `Temporal.PlainDate.prototype.month`
fn get_month(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDate object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDate object.")
.into());
};
Ok(date.inner.contextual_month(context)?.into())
Ok(InnerDate::<JsObject>::contextualized_month(&date, context)?.into())
}
/// 3.3.6 get Temporal.PlainDate.prototype.monthCode
fn get_month_code(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDate object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
Ok(JsString::from(date.inner.contextual_month_code(context)?.as_str()).into())
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDate object.")
.into());
};
Ok(JsString::from(
InnerDate::<JsObject>::contextualized_month_code(&date, context)?.as_str(),
)
.into())
}
/// 3.3.7 get `Temporal.PlainDate.prototype.day`
fn get_day(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDate object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDate object.")
.into());
};
Ok(date.inner.contextual_day(context)?.into())
Ok(InnerDate::<JsObject>::contextualized_day(&date, context)?.into())
}
/// 3.3.8 get `Temporal.PlainDate.prototype.dayOfWeek`
fn get_day_of_week(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDate object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDate object.")
.into());
};
Ok(date.inner.contextual_day_of_week(context)?.into())
Ok(InnerDate::<JsObject>::contextualized_day_of_week(&date, context)?.into())
}
/// 3.3.9 get `Temporal.PlainDate.prototype.dayOfYear`
fn get_day_of_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDate object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDate object.")
.into());
};
Ok(date.inner.contextual_day_of_year(context)?.into())
Ok(InnerDate::<JsObject>::contextualized_day_of_year(&date, context)?.into())
}
/// 3.3.10 get `Temporal.PlainDate.prototype.weekOfYear`
fn get_week_of_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDate object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDate object.")
.into());
};
Ok(date.inner.contextual_week_of_year(context)?.into())
Ok(InnerDate::<JsObject>::contextualized_week_of_year(&date, context)?.into())
}
/// 3.3.11 get `Temporal.PlainDate.prototype.yearOfWeek`
fn get_year_of_week(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDate object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDate object.")
.into());
};
Ok(date.inner.contextual_year_of_week(context)?.into())
Ok(InnerDate::<JsObject>::contextualized_year_of_week(&date, context)?.into())
}
/// 3.3.12 get `Temporal.PlainDate.prototype.daysInWeek`
fn get_days_in_week(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDate object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDate object.")
.into());
};
Ok(date.inner.contextual_days_in_week(context)?.into())
Ok(InnerDate::<JsObject>::contextualized_days_in_week(&date, context)?.into())
}
/// 3.3.13 get `Temporal.PlainDate.prototype.daysInMonth`
@ -370,26 +416,32 @@ impl PlainDate {
_: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDate object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
Ok(date.inner.contextual_days_in_month(context)?.into())
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDate object.")
.into());
};
Ok(InnerDate::<JsObject>::contextualized_days_in_month(&date, context)?.into())
}
/// 3.3.14 get `Temporal.PlainDate.prototype.daysInYear`
fn get_days_in_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDate object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDate object.")
.into());
};
Ok(date.inner.contextual_days_in_year(context)?.into())
Ok(InnerDate::<JsObject>::contextualized_days_in_year(&date, context)?.into())
}
/// 3.3.15 get `Temporal.PlainDate.prototype.monthsInYear`
@ -398,26 +450,32 @@ impl PlainDate {
_: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDate object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDate object.")
.into());
};
Ok(date.inner.contextual_months_in_year(context)?.into())
Ok(InnerDate::<JsObject>::contextualized_months_in_year(&date, context)?.into())
}
/// 3.3.16 get `Temporal.PlainDate.prototype.inLeapYear`
fn get_in_leap_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDate object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDate object.")
.into());
};
Ok(date.inner.contextual_in_leap_year(context)?.into())
Ok(InnerDate::<JsObject>::contextualized_in_leap_year(&date, context)?.into())
}
}
@ -511,7 +569,7 @@ impl PlainDate {
/// 3.5.3 `CreateTemporalDate ( isoYear, isoMonth, isoDay, calendar [ , newTarget ] )`
pub(crate) fn create_temporal_date(
inner: InnerDate<JsCustomCalendar>,
inner: InnerDate<JsObject>,
new_target: Option<&JsValue>,
context: &mut Context,
) -> JsResult<JsObject> {
@ -519,7 +577,7 @@ pub(crate) fn create_temporal_date(
// 1. If IsValidISODate(isoYear, isoMonth, isoDay) is false, throw a RangeError exception.
// 2. If ISODateTimeWithinLimits(isoYear, isoMonth, isoDay, 12, 0, 0, 0, 0, 0) is false, throw a RangeError exception.
if !DateTime::<JsCustomCalendar>::validate(&inner) {
if !DateTime::<JsObject>::validate(&inner) {
return Err(JsNativeError::range()
.with_message("Date is not within ISO date time limits.")
.into());
@ -620,7 +678,7 @@ pub(crate) fn to_temporal_date(
// 13. Return ? CreateTemporalDate(result.[[Year]], result.[[Month]], result.[[Day]], calendar).
let result = date_like_string
.to_std_string_escaped()
.parse::<InnerDate<JsCustomCalendar>>()
.parse::<InnerDate<JsObject>>()
.map_err(|err| JsNativeError::range().with_message(err.to_string()))?;
Ok(PlainDate::new(result))

229
core/engine/src/builtins/temporal/plain_date_time/mod.rs

@ -17,27 +17,46 @@ use crate::{
use boa_gc::{Finalize, Trace};
use boa_profiler::Profiler;
use boa_temporal::components::DateTime as InnerDateTime;
#[cfg(test)]
mod tests;
use super::JsCustomCalendar;
use boa_temporal::{
components::{
calendar::{CalendarSlot, GetCalendarSlot},
DateTime as InnerDateTime,
},
iso::{IsoDate, IsoDateSlots},
};
/// The `Temporal.PlainDateTime` object.
#[derive(Debug, Clone, Trace, Finalize, JsData)]
#[boa_gc(unsafe_empty_trace)] // TODO: Remove this!!! `InnerDateTime` could contain `Trace` types.
pub struct PlainDateTime {
pub(crate) inner: InnerDateTime<JsCustomCalendar>,
pub(crate) inner: InnerDateTime<JsObject>,
}
impl PlainDateTime {
fn new(inner: InnerDateTime<JsCustomCalendar>) -> Self {
fn new(inner: InnerDateTime<JsObject>) -> Self {
Self { inner }
}
pub(crate) fn inner(&self) -> &InnerDateTime<JsCustomCalendar> {
pub(crate) fn inner(&self) -> &InnerDateTime<JsObject> {
&self.inner
}
}
impl IsoDateSlots for JsObject<PlainDateTime> {
fn iso_date(&self) -> IsoDate {
self.borrow().data().inner.iso_date()
}
}
impl GetCalendarSlot<JsObject> for JsObject<PlainDateTime> {
fn get_calendar(&self) -> CalendarSlot<JsObject> {
self.borrow().data().inner.get_calendar()
}
}
impl BuiltInObject for PlainDateTime {
const NAME: JsString = StaticJsStrings::PLAIN_DATETIME;
}
@ -343,50 +362,65 @@ impl PlainDateTime {
/// 5.3.4 get `Temporal.PlainDateTime.prototype.year`
fn get_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDateTime object.")
.into());
};
Ok(date.inner.contextual_year(context)?.into())
Ok(InnerDateTime::<JsObject>::contextualized_year(&date, context)?.into())
}
/// 5.3.5 get `Temporal.PlainDateTime.prototype.month`
fn get_month(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDateTime object.")
.into());
};
Ok(date.inner.contextual_month(context)?.into())
Ok(InnerDateTime::<JsObject>::contextualized_month(&date, context)?.into())
}
/// 5.3.6 get Temporal.PlainDateTime.prototype.monthCode
fn get_month_code(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
Ok(JsString::from(date.inner.contextual_month_code(context)?.as_str()).into())
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDateTime object.")
.into());
};
Ok(JsString::from(
InnerDateTime::<JsObject>::contextualized_month_code(&date, context)?.as_str(),
)
.into())
}
/// 5.3.7 get `Temporal.PlainDateTime.prototype.day`
fn get_day(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDateTime object.")
.into());
};
Ok(date.inner.contextual_day(context)?.into())
Ok(InnerDateTime::<JsObject>::contextualized_day(&date, context)?.into())
}
/// 5.3.8 get `Temporal.PlainDateTime.prototype.hour`
@ -481,62 +515,77 @@ impl PlainDateTime {
/// 5.3.14 get `Temporal.PlainDateTime.prototype.dayOfWeek`
fn get_day_of_week(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDateTime object.")
.into());
};
Ok(date.inner.contextual_day_of_week(context)?.into())
Ok(InnerDateTime::<JsObject>::contextualized_day_of_week(&date, context)?.into())
}
/// 5.3.15 get `Temporal.PlainDateTime.prototype.dayOfYear`
fn get_day_of_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDateTime object.")
.into());
};
Ok(date.inner.contextual_day_of_year(context)?.into())
Ok(InnerDateTime::<JsObject>::contextualized_day_of_year(&date, context)?.into())
}
/// 5.3.16 get `Temporal.PlainDateTime.prototype.weekOfYear`
fn get_week_of_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDateTime object.")
.into());
};
Ok(date.inner.contextual_week_of_year(context)?.into())
Ok(InnerDateTime::<JsObject>::contextualized_week_of_year(&date, context)?.into())
}
/// 5.3.17 get `Temporal.PlainDateTime.prototype.yearOfWeek`
fn get_year_of_week(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDateTime object.")
.into());
};
Ok(date.inner.contextual_year_of_week(context)?.into())
Ok(InnerDateTime::<JsObject>::contextualized_year_of_week(&date, context)?.into())
}
/// 5.3.18 get `Temporal.PlainDateTime.prototype.daysInWeek`
fn get_days_in_week(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDateTime object.")
.into());
};
Ok(date.inner.contextual_days_in_week(context)?.into())
Ok(InnerDateTime::<JsObject>::contextualized_days_in_week(&date, context)?.into())
}
/// 5.3.19 get `Temporal.PlainDateTime.prototype.daysInMonth`
@ -545,26 +594,32 @@ impl PlainDateTime {
_: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
Ok(date.inner.contextual_days_in_month(context)?.into())
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDateTime object.")
.into());
};
Ok(InnerDateTime::<JsObject>::contextualized_days_in_month(&date, context)?.into())
}
/// 5.3.20 get `Temporal.PlainDateTime.prototype.daysInYear`
fn get_days_in_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDateTime object.")
.into());
};
Ok(date.inner.contextual_days_in_year(context)?.into())
Ok(InnerDateTime::<JsObject>::contextualized_days_in_year(&date, context)?.into())
}
/// 5.3.21 get `Temporal.PlainDateTime.prototype.monthsInYear`
@ -573,33 +628,39 @@ impl PlainDateTime {
_: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDateTime object.")
.into());
};
Ok(date.inner.contextual_months_in_year(context)?.into())
Ok(InnerDateTime::<JsObject>::contextualized_months_in_year(&date, context)?.into())
}
/// 5.3.22 get `Temporal.PlainDateTime.prototype.inLeapYear`
fn get_in_leap_year(this: &JsValue, _: &[JsValue], context: &mut Context) -> JsResult<JsValue> {
let date = this
let obj = this
.as_object()
.and_then(JsObject::downcast_ref::<Self>)
.ok_or_else(|| {
JsNativeError::typ().with_message("the this object must be a PlainDateTime object.")
})?;
.ok_or_else(|| JsNativeError::typ().with_message("this must be an object."))?;
let Ok(date) = obj.clone().downcast::<Self>() else {
return Err(JsNativeError::typ()
.with_message("the this object must be a PlainDateTime object.")
.into());
};
Ok(date.inner.contextual_in_leap_year(context)?.into())
Ok(InnerDateTime::<JsObject>::contextualized_in_leap_year(&date, context)?.into())
}
}
// ==== `PlainDateTime` Abstract Operations` ====
pub(crate) fn create_temporal_datetime(
inner: InnerDateTime<JsCustomCalendar>,
inner: InnerDateTime<JsObject>,
new_target: Option<&JsValue>,
context: &mut Context,
) -> JsResult<JsObject> {

10
core/engine/src/builtins/temporal/plain_date_time/tests.rs

@ -0,0 +1,10 @@
use crate::{run_test_actions, TestAction};
#[test]
fn pdt_year_of_week_basic() {
run_test_actions([
TestAction::run("let calendar = Temporal.Calendar.from('iso8601')"),
TestAction::run("let pdt = new Temporal.PlainDateTime(1976, 11, 18, 15, 23, 30, 123, 456, 789, calendar)"),
TestAction::assert_eq("pdt.yearOfWeek", 1976),
]);
}

30
core/engine/src/builtins/temporal/plain_month_day/mod.rs

@ -12,23 +12,39 @@ use crate::{
use boa_gc::{Finalize, Trace};
use boa_profiler::Profiler;
use boa_temporal::components::{DateTime, MonthDay as InnerMonthDay};
use super::JsCustomCalendar;
use boa_temporal::{
components::{
calendar::{CalendarSlot, GetCalendarSlot},
DateTime, MonthDay as InnerMonthDay,
},
iso::IsoDateSlots,
};
/// The `Temporal.PlainMonthDay` object.
#[derive(Debug, Clone, Trace, Finalize, JsData)]
#[boa_gc(unsafe_empty_trace)] // TODO: Remove this!!! `InnerMonthDay` could contain `Trace` types.
pub struct PlainMonthDay {
pub(crate) inner: InnerMonthDay<JsCustomCalendar>,
pub(crate) inner: InnerMonthDay<JsObject>,
}
impl PlainMonthDay {
fn new(inner: InnerMonthDay<JsCustomCalendar>) -> Self {
fn new(inner: InnerMonthDay<JsObject>) -> Self {
Self { inner }
}
}
impl IsoDateSlots for JsObject<PlainMonthDay> {
fn iso_date(&self) -> boa_temporal::iso::IsoDate {
self.borrow().data().inner.iso_date()
}
}
impl GetCalendarSlot<JsObject> for JsObject<PlainMonthDay> {
fn get_calendar(&self) -> CalendarSlot<JsObject> {
self.borrow().data().inner.get_calendar()
}
}
impl BuiltInObject for PlainMonthDay {
const NAME: JsString = StaticJsStrings::PLAIN_MD;
}
@ -71,13 +87,13 @@ impl BuiltInConstructor for PlainMonthDay {
// ==== `PlainMonthDay` Abstract Operations ====
pub(crate) fn create_temporal_month_day(
inner: InnerMonthDay<JsCustomCalendar>,
inner: InnerMonthDay<JsObject>,
new_target: Option<&JsValue>,
context: &mut Context,
) -> JsResult<JsValue> {
// 1. If IsValidISODate(referenceISOYear, isoMonth, isoDay) is false, throw a RangeError exception.
// 2. If ISODateTimeWithinLimits(referenceISOYear, isoMonth, isoDay, 12, 0, 0, 0, 0, 0) is false, throw a RangeError exception.
if DateTime::<JsCustomCalendar>::validate(&inner) {
if DateTime::<JsObject>::validate(&inner) {
return Err(JsNativeError::range()
.with_message("PlainMonthDay is not a valid ISO date time.")
.into());

32
core/engine/src/builtins/temporal/plain_year_month/mod.rs

@ -13,22 +13,44 @@ use crate::{
use boa_gc::{Finalize, Trace};
use boa_profiler::Profiler;
use super::{calendar::to_temporal_calendar_slot_value, JsCustomCalendar};
use boa_temporal::{components::YearMonth as InnerYearMonth, options::ArithmeticOverflow};
use super::calendar::to_temporal_calendar_slot_value;
use boa_temporal::{
iso::IsoDateSlots,
{
components::{
calendar::{CalendarSlot, GetCalendarSlot},
YearMonth as InnerYearMonth,
},
options::ArithmeticOverflow,
},
};
/// The `Temporal.PlainYearMonth` object.
#[derive(Debug, Clone, Trace, Finalize, JsData)]
#[boa_gc(unsafe_empty_trace)] // TODO: Remove this!!! `InnerYearMonth` could contain `Trace` types.
pub struct PlainYearMonth {
pub(crate) inner: InnerYearMonth<JsCustomCalendar>,
pub(crate) inner: InnerYearMonth<JsObject>,
}
impl PlainYearMonth {
pub(crate) fn new(inner: InnerYearMonth<JsCustomCalendar>) -> Self {
pub(crate) fn new(inner: InnerYearMonth<JsObject>) -> Self {
Self { inner }
}
}
impl IsoDateSlots for JsObject<PlainYearMonth> {
fn iso_date(&self) -> boa_temporal::iso::IsoDate {
self.borrow().data().inner.iso_date()
}
}
impl GetCalendarSlot<JsObject> for JsObject<PlainYearMonth> {
fn get_calendar(&self) -> CalendarSlot<JsObject> {
self.borrow().data().inner.get_calendar()
}
}
impl BuiltInObject for PlainYearMonth {
const NAME: JsString = StaticJsStrings::PLAIN_YM;
}
@ -279,7 +301,7 @@ impl PlainYearMonth {
// 9.5.5 `CreateTemporalYearMonth ( isoYear, isoMonth, calendar, referenceISODay [ , newTarget ] )`
pub(crate) fn create_temporal_year_month(
ym: InnerYearMonth<JsCustomCalendar>,
ym: InnerYearMonth<JsObject>,
new_target: Option<&JsValue>,
context: &mut Context,
) -> JsResult<JsValue> {

4
core/engine/src/builtins/temporal/zoned_date_time/mod.rs

@ -14,12 +14,12 @@ use boa_temporal::components::{
ZonedDateTime as InnerZdt,
};
use super::{JsCustomCalendar, JsCustomTimeZone};
use super::JsCustomTimeZone;
/// The `Temporal.ZonedDateTime` object.
#[derive(Debug, Clone, Finalize, JsData)]
pub struct ZonedDateTime {
pub(crate) inner: InnerZdt<JsCustomCalendar, JsCustomTimeZone>,
pub(crate) inner: InnerZdt<JsObject, JsCustomTimeZone>,
}
unsafe impl Trace for ZonedDateTime {

99
core/temporal/src/components/calendar.rs

@ -76,17 +76,29 @@ impl From<&[String]> for CalendarFieldsType {
}
}
// NOTE (nekevss): May be worth switching the below to "Custom" `DateLikes`, and
// allow the non-custom to be engine specific types.
//
// enum CalendarDateLike<C: CalendarProtocol, D: DateTypes<C>> {
// Date(Date<C>),
// CustomDate(D::Date),
// ...
// }
/// The `DateLike` objects that can be provided to the `CalendarProtocol`.
#[derive(Debug)]
pub enum CalendarDateLike<C: CalendarProtocol> {
/// Represents a `Date` datelike
Date(Date<C>),
/// Represents a `DateTime` datelike
/// Represents a user-defined `Date` datelike
CustomDate(<<C as CalendarProtocol>::DateLikes as DateTypes<C>>::Date),
/// Represents a user-defined `DateTime` datelike
CustomDateTime(<<C as CalendarProtocol>::DateLikes as DateTypes<C>>::DateTime),
/// Represents a user-defined `YearMonth` datelike
CustomYearMonth(<<C as CalendarProtocol>::DateLikes as DateTypes<C>>::YearMonth),
/// Represents a user-defined `MonthDay` datelike
CustomMonthDay(<<C as CalendarProtocol>::DateLikes as DateTypes<C>>::MonthDay),
/// Represents a `DateTime<C>`.
DateTime(DateTime<C>),
/// Represents a `YearMonth` datelike
YearMonth(YearMonth<C>),
/// Represents a `MonthDay` datelike
MonthDay(MonthDay<C>),
/// Represents a `Date<C>`.
Date(Date<C>),
}
impl<C: CalendarProtocol> CalendarDateLike<C> {
@ -95,18 +107,35 @@ impl<C: CalendarProtocol> CalendarDateLike<C> {
#[must_use]
pub fn as_iso_date(&self) -> IsoDate {
match self {
CalendarDateLike::CustomDate(d) => d.iso_date(),
CalendarDateLike::CustomMonthDay(md) => md.iso_date(),
CalendarDateLike::CustomYearMonth(ym) => ym.iso_date(),
CalendarDateLike::CustomDateTime(dt) => dt.iso_date(),
CalendarDateLike::DateTime(dt) => dt.iso_date(),
CalendarDateLike::Date(d) => d.iso_date(),
CalendarDateLike::DateTime(dt) => *dt.iso_date(),
CalendarDateLike::MonthDay(md) => md.iso_date(),
CalendarDateLike::YearMonth(ym) => ym.iso_date(),
}
}
}
// TODO: DateTypes should implement a trait -> `ToTemporalDate`: `GetCalendarSlot`
/// A trait for implementing `DateLike` types
pub trait DateTypes<C: CalendarProtocol> {
/// A Custom `Date` Type for an associated `CalendarProtocol`. Default `Date<C>`
type Date: IsoDateSlots + GetCalendarSlot<C> + Clone + core::fmt::Debug;
/// A Custom `DateTime` Type for an associated `CalendarProtocol`. Default `DateTime<C>`
type DateTime: IsoDateSlots + GetCalendarSlot<C> + Clone + core::fmt::Debug;
/// A Custom `YearMonth` Type for an associated `CalendarProtocol`. Default `YearMonth<C>`
type YearMonth: IsoDateSlots + GetCalendarSlot<C> + Clone + core::fmt::Debug;
/// A Custom `MonthDay` Type for an associated `CalendarProtocol`. Default `MonthDay<C>`
type MonthDay: IsoDateSlots + GetCalendarSlot<C> + Clone + core::fmt::Debug;
}
// ==== CalendarProtocol trait ====
/// A trait for implementing a Builtin Calendar's Calendar Protocol in Rust.
pub trait CalendarProtocol: Clone {
/// Registers a valid set of custom `CalendarDateLike` values.
type DateLikes: DateTypes<Self>;
/// Creates a `Temporal.PlainDate` object from provided fields.
fn date_from_fields(
&self,
@ -244,6 +273,12 @@ pub trait CalendarProtocol: Clone {
fn identifier(&self, context: &mut dyn Any) -> TemporalResult<String>;
}
/// A trait for retrieving an internal calendar slice.
pub trait GetCalendarSlot<C: CalendarProtocol> {
/// Returns the `CalendarSlot<C>` value of the implementor.
fn get_calendar(&self) -> CalendarSlot<C>;
}
// NOTE(nekevss): Builtin could be `Rc<AnyCalendar>`, but doing so may
// have an effect on the pattern matching for `CalendarSlot`'s methods.
/// The `[[Calendar]]` field slot of a Temporal Object.
@ -816,12 +851,26 @@ impl<C: CalendarProtocol> CalendarSlot<C> {
}
}
impl IsoDateSlots for () {
fn iso_date(&self) -> IsoDate {
unreachable!()
}
}
impl DateTypes<()> for () {
type Date = Date<()>;
type DateTime = DateTime<()>;
type YearMonth = YearMonth<()>;
type MonthDay = MonthDay<()>;
}
/// An empty `CalendarProtocol` implementation on `()`.
///
/// # Panics
///
/// Attempting to use this empty calendar implementation as a valid calendar is an error and will cause a panic.
impl CalendarProtocol for () {
type DateLikes = ();
fn date_from_fields(
&self,
_: &mut TemporalFields,
@ -871,69 +920,69 @@ impl CalendarProtocol for () {
fn era(
&self,
_: &CalendarDateLike<()>,
_: &CalendarDateLike<Self>,
_: &mut dyn Any,
) -> TemporalResult<Option<TinyAsciiStr<16>>> {
unreachable!();
}
fn era_year(&self, _: &CalendarDateLike<()>, _: &mut dyn Any) -> TemporalResult<Option<i32>> {
fn era_year(&self, _: &CalendarDateLike<Self>, _: &mut dyn Any) -> TemporalResult<Option<i32>> {
unreachable!();
}
fn year(&self, _: &CalendarDateLike<()>, _: &mut dyn Any) -> TemporalResult<i32> {
fn year(&self, _: &CalendarDateLike<Self>, _: &mut dyn Any) -> TemporalResult<i32> {
unreachable!();
}
fn month(&self, _: &CalendarDateLike<()>, _: &mut dyn Any) -> TemporalResult<u8> {
fn month(&self, _: &CalendarDateLike<Self>, _: &mut dyn Any) -> TemporalResult<u8> {
unreachable!();
}
fn month_code(
&self,
_: &CalendarDateLike<()>,
_: &CalendarDateLike<Self>,
_: &mut dyn Any,
) -> TemporalResult<TinyAsciiStr<4>> {
unreachable!();
}
fn day(&self, _: &CalendarDateLike<()>, _: &mut dyn Any) -> TemporalResult<u8> {
fn day(&self, _: &CalendarDateLike<Self>, _: &mut dyn Any) -> TemporalResult<u8> {
unreachable!();
}
fn day_of_week(&self, _: &CalendarDateLike<()>, _: &mut dyn Any) -> TemporalResult<u16> {
fn day_of_week(&self, _: &CalendarDateLike<Self>, _: &mut dyn Any) -> TemporalResult<u16> {
unreachable!();
}
fn day_of_year(&self, _: &CalendarDateLike<()>, _: &mut dyn Any) -> TemporalResult<u16> {
fn day_of_year(&self, _: &CalendarDateLike<Self>, _: &mut dyn Any) -> TemporalResult<u16> {
unreachable!();
}
fn week_of_year(&self, _: &CalendarDateLike<()>, _: &mut dyn Any) -> TemporalResult<u16> {
fn week_of_year(&self, _: &CalendarDateLike<Self>, _: &mut dyn Any) -> TemporalResult<u16> {
unreachable!();
}
fn year_of_week(&self, _: &CalendarDateLike<()>, _: &mut dyn Any) -> TemporalResult<i32> {
fn year_of_week(&self, _: &CalendarDateLike<Self>, _: &mut dyn Any) -> TemporalResult<i32> {
unreachable!();
}
fn days_in_week(&self, _: &CalendarDateLike<()>, _: &mut dyn Any) -> TemporalResult<u16> {
fn days_in_week(&self, _: &CalendarDateLike<Self>, _: &mut dyn Any) -> TemporalResult<u16> {
unreachable!();
}
fn days_in_month(&self, _: &CalendarDateLike<()>, _: &mut dyn Any) -> TemporalResult<u16> {
fn days_in_month(&self, _: &CalendarDateLike<Self>, _: &mut dyn Any) -> TemporalResult<u16> {
unreachable!();
}
fn days_in_year(&self, _: &CalendarDateLike<()>, _: &mut dyn Any) -> TemporalResult<u16> {
fn days_in_year(&self, _: &CalendarDateLike<Self>, _: &mut dyn Any) -> TemporalResult<u16> {
unreachable!();
}
fn months_in_year(&self, _: &CalendarDateLike<()>, _: &mut dyn Any) -> TemporalResult<u16> {
fn months_in_year(&self, _: &CalendarDateLike<Self>, _: &mut dyn Any) -> TemporalResult<u16> {
unreachable!();
}
fn in_leap_year(&self, _: &CalendarDateLike<()>, _: &mut dyn Any) -> TemporalResult<bool> {
fn in_leap_year(&self, _: &CalendarDateLike<Self>, _: &mut dyn Any) -> TemporalResult<bool> {
unreachable!();
}

278
core/temporal/src/components/date.rs

@ -15,7 +15,10 @@ use crate::{
};
use std::{any::Any, str::FromStr};
use super::duration::TimeDuration;
use super::{
calendar::{CalendarDateLike, DateTypes, GetCalendarSlot},
duration::TimeDuration,
};
/// The native Rust implementation of `Temporal.PlainDate`.
#[derive(Debug, Default, Clone)]
@ -67,7 +70,7 @@ impl<C: CalendarProtocol> Date<C> {
/// Creates a `Date` from a `DateTime`.
pub fn from_datetime(dt: &DateTime<C>) -> Self {
Self {
iso: *dt.iso_date(),
iso: dt.iso_date(),
calendar: dt.calendar().clone(),
}
}
@ -127,174 +130,211 @@ impl<C: CalendarProtocol> Date<C> {
// ==== Calendar-derived Public API ====
impl<C: CalendarProtocol> Date<C> {
/// Returns the calendar year value with provided context.
pub fn contextual_year(&self, context: &mut dyn Any) -> TemporalResult<i32> {
self.calendar.year(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
}
impl Date<()> {
/// Returns the calendar year value.
pub fn year(&self) -> TemporalResult<i32> {
self.contextual_year(&mut ())
}
/// Returns the calendar month value with provided context.
pub fn contextual_month(&self, context: &mut dyn Any) -> TemporalResult<u8> {
self.calendar.month(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
self.calendar
.year(&CalendarDateLike::Date(self.clone()), &mut ())
}
/// Returns the calendar month value.
pub fn month(&self) -> TemporalResult<u8> {
self.contextual_month(&mut ())
}
/// Returns the calendar month code value with provided context.
pub fn contextual_month_code(&self, context: &mut dyn Any) -> TemporalResult<TinyAsciiStr<4>> {
self.calendar.month_code(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
self.calendar
.month(&CalendarDateLike::Date(self.clone()), &mut ())
}
/// Returns the calendar month code value.
pub fn month_code(&self) -> TemporalResult<TinyAsciiStr<4>> {
self.contextual_month_code(&mut ())
}
/// Returns the calendar day value with provided context.
pub fn contextual_day(&self, context: &mut dyn Any) -> TemporalResult<u8> {
self.calendar.day(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
self.calendar
.month_code(&CalendarDateLike::Date(self.clone()), &mut ())
}
/// Returns the calendar day value.
pub fn day(&self) -> TemporalResult<u8> {
self.contextual_day(&mut ())
}
/// Returns the calendar day of week value with provided context.
pub fn contextual_day_of_week(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.day_of_week(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
self.calendar
.day(&CalendarDateLike::Date(self.clone()), &mut ())
}
/// Returns the calendar day of week value.
pub fn day_of_week(&self) -> TemporalResult<u16> {
self.contextual_day_of_week(&mut ())
}
/// Returns the calendar day of year value with provided context.
pub fn contextual_day_of_year(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.day_of_year(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
self.calendar
.day_of_week(&CalendarDateLike::Date(self.clone()), &mut ())
}
/// Returns the calendar day of year value.
pub fn day_of_year(&self) -> TemporalResult<u16> {
self.contextual_day_of_year(&mut ())
}
/// Returns the calendar week of year value with provided context.
pub fn contextual_week_of_year(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.week_of_year(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
self.calendar
.day_of_year(&CalendarDateLike::Date(self.clone()), &mut ())
}
/// Returns the calendar week of year value.
pub fn week_of_year(&self) -> TemporalResult<u16> {
self.contextual_week_of_year(&mut ())
}
/// Returns the calendar year of week value with provided context.
pub fn contextual_year_of_week(&self, context: &mut dyn Any) -> TemporalResult<i32> {
self.calendar.year_of_week(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
self.calendar
.week_of_year(&CalendarDateLike::Date(self.clone()), &mut ())
}
/// Returns the calendar year of week value.
pub fn year_of_week(&self) -> TemporalResult<i32> {
self.contextual_year_of_week(&mut ())
}
/// Returns the calendar days in week value with provided context.
pub fn contextual_days_in_week(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.days_in_week(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
self.calendar
.year_of_week(&CalendarDateLike::Date(self.clone()), &mut ())
}
/// Returns the calendar days in week value.
pub fn days_in_week(&self) -> TemporalResult<u16> {
self.contextual_days_in_week(&mut ())
}
/// Returns the calendar days in month value with provided context.
pub fn contextual_days_in_month(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.days_in_month(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
self.calendar
.days_in_week(&CalendarDateLike::Date(self.clone()), &mut ())
}
/// Returns the calendar days in month value.
pub fn days_in_month(&self) -> TemporalResult<u16> {
self.contextual_days_in_month(&mut ())
}
/// Returns the calendar days in year value with provided context.
pub fn contextual_days_in_year(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.days_in_year(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
self.calendar
.days_in_month(&CalendarDateLike::Date(self.clone()), &mut ())
}
/// Returns the calendar days in year value.
pub fn days_in_year(&self) -> TemporalResult<u16> {
self.contextual_days_in_year(&mut ())
}
/// Returns the calendar months in year value with provided context.
pub fn contextual_months_in_year(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.months_in_year(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
self.calendar
.days_in_year(&CalendarDateLike::Date(self.clone()), &mut ())
}
/// Returns the calendar months in year value.
pub fn months_in_year(&self) -> TemporalResult<u16> {
self.contextual_months_in_year(&mut ())
self.calendar
.months_in_year(&CalendarDateLike::Date(self.clone()), &mut ())
}
/// Returns returns whether the date in a leap year for the given calendar.
pub fn in_leap_year(&self) -> TemporalResult<bool> {
self.calendar
.in_leap_year(&CalendarDateLike::Date(self.clone()), &mut ())
}
}
// NOTE(nekevss): The clone below should ideally not change the memory address, but that may
// not be true across all cases. I.e., it should be fine as long as the clone is simply a
// reference count increment. Need to test.
impl<C: CalendarProtocol> Date<C> {
/// Returns the calendar year value with provided context.
pub fn contextualized_year(
this: &<C::DateLikes as DateTypes<C>>::Date,
context: &mut dyn Any,
) -> TemporalResult<i32> {
this.get_calendar()
.year(&CalendarDateLike::CustomDate(this.clone()), context)
}
/// Returns the calendar month value with provided context.
pub fn contextualized_month(
this: &<C::DateLikes as DateTypes<C>>::Date,
context: &mut dyn Any,
) -> TemporalResult<u8> {
this.get_calendar()
.month(&CalendarDateLike::CustomDate(this.clone()), context)
}
/// Returns the calendar month code value with provided context.
pub fn contextualized_month_code(
this: &<C::DateLikes as DateTypes<C>>::Date,
context: &mut dyn Any,
) -> TemporalResult<TinyAsciiStr<4>> {
this.get_calendar()
.month_code(&CalendarDateLike::CustomDate(this.clone()), context)
}
/// Returns the calendar day value with provided context.
pub fn contextualized_day(
this: &<C::DateLikes as DateTypes<C>>::Date,
context: &mut dyn Any,
) -> TemporalResult<u8> {
this.get_calendar()
.day(&CalendarDateLike::CustomDate(this.clone()), context)
}
/// Returns the calendar day of week value with provided context.
pub fn contextualized_day_of_week(
this: &<C::DateLikes as DateTypes<C>>::Date,
context: &mut dyn Any,
) -> TemporalResult<u16> {
this.get_calendar()
.day_of_week(&CalendarDateLike::CustomDate(this.clone()), context)
}
/// Returns the calendar day of year value with provided context.
pub fn contextualized_day_of_year(
this: &<C::DateLikes as DateTypes<C>>::Date,
context: &mut dyn Any,
) -> TemporalResult<u16> {
this.get_calendar()
.day_of_year(&CalendarDateLike::CustomDate(this.clone()), context)
}
/// Returns the calendar week of year value with provided context.
pub fn contextualized_week_of_year(
this: &<C::DateLikes as DateTypes<C>>::Date,
context: &mut dyn Any,
) -> TemporalResult<u16> {
this.get_calendar()
.week_of_year(&CalendarDateLike::CustomDate(this.clone()), context)
}
/// Returns the calendar year of week value with provided context.
pub fn contextualized_year_of_week(
this: &<C::DateLikes as DateTypes<C>>::Date,
context: &mut dyn Any,
) -> TemporalResult<i32> {
this.get_calendar()
.year_of_week(&CalendarDateLike::CustomDate(this.clone()), context)
}
/// Returns the calendar days in week value with provided context.
pub fn contextualized_days_in_week(
this: &<C::DateLikes as DateTypes<C>>::Date,
context: &mut dyn Any,
) -> TemporalResult<u16> {
this.get_calendar()
.days_in_week(&CalendarDateLike::CustomDate(this.clone()), context)
}
/// Returns the calendar days in month value with provided context.
pub fn contextualized_days_in_month(
this: &<C::DateLikes as DateTypes<C>>::Date,
context: &mut dyn Any,
) -> TemporalResult<u16> {
this.get_calendar()
.days_in_month(&CalendarDateLike::CustomDate(this.clone()), context)
}
/// Returns the calendar days in year value with provided context.
pub fn contextualized_days_in_year(
this: &<C::DateLikes as DateTypes<C>>::Date,
context: &mut dyn Any,
) -> TemporalResult<u16> {
this.get_calendar()
.days_in_year(&CalendarDateLike::CustomDate(this.clone()), context)
}
/// Returns the calendar months in year value with provided context.
pub fn contextualized_months_in_year(
this: &<C::DateLikes as DateTypes<C>>::Date,
context: &mut dyn Any,
) -> TemporalResult<u16> {
this.get_calendar()
.months_in_year(&CalendarDateLike::CustomDate(this.clone()), context)
}
/// Returns whether the date is in a leap year for the given calendar with provided context.
pub fn contextual_in_leap_year(&self, context: &mut dyn Any) -> TemporalResult<bool> {
self.calendar.in_leap_year(
&super::calendar::CalendarDateLike::Date(self.clone()),
context,
)
pub fn contextualized_in_leap_year(
this: &<C::DateLikes as DateTypes<C>>::Date,
context: &mut dyn Any,
) -> TemporalResult<bool> {
this.get_calendar()
.in_leap_year(&CalendarDateLike::CustomDate(this.clone()), context)
}
}
/// Returns returns whether the date in a leap year for the given calendar.
pub fn in_leap_year(&self) -> TemporalResult<bool> {
self.contextual_in_leap_year(&mut ())
impl<C: CalendarProtocol> GetCalendarSlot<C> for Date<C> {
fn get_calendar(&self) -> CalendarSlot<C> {
self.calendar.clone()
}
}

286
core/temporal/src/components/datetime.rs

@ -14,6 +14,8 @@ use crate::{
use std::{any::Any, str::FromStr};
use tinystr::TinyAsciiStr;
use super::calendar::{CalendarDateLike, DateTypes, GetCalendarSlot};
/// The native Rust implementation of `Temporal.PlainDateTime`
#[derive(Debug, Default, Clone)]
pub struct DateTime<C: CalendarProtocol> {
@ -48,13 +50,6 @@ impl<C: CalendarProtocol> DateTime<C> {
let iso = IsoDateTime::from_epoch_nanos(&instant.nanos, offset)?;
Ok(Self { iso, calendar })
}
/// Returns the inner `IsoDate` value.
#[inline]
#[must_use]
pub(crate) fn iso_date(&self) -> &IsoDate {
self.iso.date()
}
}
// ==== Public DateTime API ====
@ -170,179 +165,220 @@ impl<C: CalendarProtocol> DateTime<C> {
// ==== Calendar-derived public API ====
impl<C: CalendarProtocol> DateTime<C> {
/// Returns the calendar year value with provided context.
pub fn contextual_year(&self, context: &mut dyn Any) -> TemporalResult<i32> {
self.calendar.year(
&super::calendar::CalendarDateLike::DateTime(self.clone()),
context,
)
}
// TODO: Revert to `DateTime<C>`.
impl DateTime<()> {
/// Returns the calendar year value.
pub fn year(&self) -> TemporalResult<i32> {
self.contextual_year(&mut ())
}
/// Returns the calendar month value with provided context.
pub fn contextual_month(&self, context: &mut dyn Any) -> TemporalResult<u8> {
self.calendar.month(
&super::calendar::CalendarDateLike::DateTime(self.clone()),
context,
)
self.calendar
.year(&CalendarDateLike::DateTime(self.clone()), &mut ())
}
/// Returns the calendar month value.
pub fn month(&self) -> TemporalResult<u8> {
self.contextual_month(&mut ())
}
/// Returns the calendar month code value with provided context.
pub fn contextual_month_code(&self, context: &mut dyn Any) -> TemporalResult<TinyAsciiStr<4>> {
self.calendar.month_code(
&super::calendar::CalendarDateLike::DateTime(self.clone()),
context,
)
self.calendar
.month(&CalendarDateLike::DateTime(self.clone()), &mut ())
}
/// Returns the calendar month code value.
pub fn month_code(&self) -> TemporalResult<TinyAsciiStr<4>> {
self.contextual_month_code(&mut ())
}
/// Returns the calendar day value with provided context.
pub fn contextual_day(&self, context: &mut dyn Any) -> TemporalResult<u8> {
self.calendar.day(
&super::calendar::CalendarDateLike::DateTime(self.clone()),
context,
)
self.calendar
.month_code(&CalendarDateLike::DateTime(self.clone()), &mut ())
}
/// Returns the calendar day value.
pub fn day(&self) -> TemporalResult<u8> {
self.contextual_day(&mut ())
}
/// Returns the calendar day of week value with provided context.
pub fn contextual_day_of_week(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.day_of_week(
&super::calendar::CalendarDateLike::DateTime(self.clone()),
context,
)
self.calendar
.day(&CalendarDateLike::DateTime(self.clone()), &mut ())
}
/// Returns the calendar day of week value.
pub fn day_of_week(&self) -> TemporalResult<u16> {
self.contextual_day_of_week(&mut ())
}
/// Returns the calendar day of year value with provided context.
pub fn contextual_day_of_year(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.day_of_year(
&super::calendar::CalendarDateLike::DateTime(self.clone()),
context,
)
self.calendar
.day_of_week(&CalendarDateLike::DateTime(self.clone()), &mut ())
}
/// Returns the calendar day of year value.
pub fn day_of_year(&self) -> TemporalResult<u16> {
self.contextual_day_of_year(&mut ())
}
/// Returns the calendar week of year value with provided context.
pub fn contextual_week_of_year(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.week_of_year(
&super::calendar::CalendarDateLike::DateTime(self.clone()),
context,
)
self.calendar
.day_of_year(&CalendarDateLike::DateTime(self.clone()), &mut ())
}
/// Returns the calendar week of year value.
pub fn week_of_year(&self) -> TemporalResult<u16> {
self.contextual_week_of_year(&mut ())
}
/// Returns the calendar year of week value with provided context.
pub fn contextual_year_of_week(&self, context: &mut dyn Any) -> TemporalResult<i32> {
self.calendar.year_of_week(
&super::calendar::CalendarDateLike::DateTime(self.clone()),
context,
)
self.calendar
.week_of_year(&CalendarDateLike::DateTime(self.clone()), &mut ())
}
/// Returns the calendar year of week value.
pub fn year_of_week(&self) -> TemporalResult<i32> {
self.contextual_year_of_week(&mut ())
}
/// Returns the calendar days in week value with provided context.
pub fn contextual_days_in_week(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.days_in_week(
&super::calendar::CalendarDateLike::DateTime(self.clone()),
context,
)
self.calendar
.year_of_week(&CalendarDateLike::DateTime(self.clone()), &mut ())
}
/// Returns the calendar days in week value.
pub fn days_in_week(&self) -> TemporalResult<u16> {
self.contextual_days_in_week(&mut ())
}
/// Returns the calendar days in month value with provided context.
pub fn contextual_days_in_month(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.days_in_month(
&super::calendar::CalendarDateLike::DateTime(self.clone()),
context,
)
self.calendar
.days_in_week(&CalendarDateLike::DateTime(self.clone()), &mut ())
}
/// Returns the calendar days in month value.
pub fn days_in_month(&self) -> TemporalResult<u16> {
self.contextual_days_in_month(&mut ())
}
/// Returns the calendar days in year value with provided context.
pub fn contextual_days_in_year(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.days_in_year(
&super::calendar::CalendarDateLike::DateTime(self.clone()),
context,
)
self.calendar
.days_in_month(&CalendarDateLike::DateTime(self.clone()), &mut ())
}
/// Returns the calendar days in year value.
pub fn days_in_year(&self) -> TemporalResult<u16> {
self.contextual_days_in_year(&mut ())
}
/// Returns the calendar months in year value with provided context.
pub fn contextual_months_in_year(&self, context: &mut dyn Any) -> TemporalResult<u16> {
self.calendar.months_in_year(
&super::calendar::CalendarDateLike::DateTime(self.clone()),
context,
)
self.calendar
.days_in_year(&CalendarDateLike::DateTime(self.clone()), &mut ())
}
/// Returns the calendar months in year value.
pub fn months_in_year(&self) -> TemporalResult<u16> {
self.contextual_months_in_year(&mut ())
}
/// Returns whether the date is in a leap year for the given calendar with provided context.
pub fn contextual_in_leap_year(&self, context: &mut dyn Any) -> TemporalResult<bool> {
self.calendar.in_leap_year(
&super::calendar::CalendarDateLike::DateTime(self.clone()),
context,
)
self.calendar
.months_in_year(&CalendarDateLike::DateTime(self.clone()), &mut ())
}
/// Returns returns whether the date in a leap year for the given calendar.
pub fn in_leap_year(&self) -> TemporalResult<bool> {
self.contextual_in_leap_year(&mut ())
self.calendar
.in_leap_year(&CalendarDateLike::DateTime(self.clone()), &mut ())
}
}
impl<C: CalendarProtocol> DateTime<C> {
/// Returns the calendar year value with provided context.
pub fn contextualized_year(
this: &<C::DateLikes as DateTypes<C>>::DateTime,
context: &mut dyn Any,
) -> TemporalResult<i32> {
this.get_calendar()
.year(&CalendarDateLike::CustomDateTime(this.clone()), context)
}
/// Returns the calendar month value with provided context.
pub fn contextualized_month(
this: &<C::DateLikes as DateTypes<C>>::DateTime,
context: &mut dyn Any,
) -> TemporalResult<u8> {
this.get_calendar()
.month(&CalendarDateLike::CustomDateTime(this.clone()), context)
}
/// Returns the calendar month code value with provided context.
pub fn contextualized_month_code(
this: &<C::DateLikes as DateTypes<C>>::DateTime,
context: &mut dyn Any,
) -> TemporalResult<TinyAsciiStr<4>> {
this.get_calendar()
.month_code(&CalendarDateLike::CustomDateTime(this.clone()), context)
}
/// Returns the calendar day value with provided context.
pub fn contextualized_day(
this: &<C::DateLikes as DateTypes<C>>::DateTime,
context: &mut dyn Any,
) -> TemporalResult<u8> {
this.get_calendar()
.day(&CalendarDateLike::CustomDateTime(this.clone()), context)
}
/// Returns the calendar day of week value with provided context.
pub fn contextualized_day_of_week(
this: &<C::DateLikes as DateTypes<C>>::DateTime,
context: &mut dyn Any,
) -> TemporalResult<u16> {
this.get_calendar()
.day_of_week(&CalendarDateLike::CustomDateTime(this.clone()), context)
}
/// Returns the calendar day of year value with provided context.
pub fn contextualized_day_of_year(
this: &<C::DateLikes as DateTypes<C>>::DateTime,
context: &mut dyn Any,
) -> TemporalResult<u16> {
this.get_calendar()
.day_of_year(&CalendarDateLike::CustomDateTime(this.clone()), context)
}
/// Returns the calendar week of year value with provided context.
pub fn contextualized_week_of_year(
this: &<C::DateLikes as DateTypes<C>>::DateTime,
context: &mut dyn Any,
) -> TemporalResult<u16> {
this.get_calendar()
.week_of_year(&CalendarDateLike::CustomDateTime(this.clone()), context)
}
/// Returns the calendar year of week value with provided context.
pub fn contextualized_year_of_week(
this: &<C::DateLikes as DateTypes<C>>::DateTime,
context: &mut dyn Any,
) -> TemporalResult<i32> {
this.get_calendar()
.year_of_week(&CalendarDateLike::CustomDateTime(this.clone()), context)
}
/// Returns the calendar days in week value with provided context.
pub fn contextualized_days_in_week(
this: &<C::DateLikes as DateTypes<C>>::DateTime,
context: &mut dyn Any,
) -> TemporalResult<u16> {
this.get_calendar()
.days_in_week(&CalendarDateLike::CustomDateTime(this.clone()), context)
}
/// Returns the calendar days in month value with provided context.
pub fn contextualized_days_in_month(
this: &<C::DateLikes as DateTypes<C>>::DateTime,
context: &mut dyn Any,
) -> TemporalResult<u16> {
this.get_calendar()
.days_in_month(&CalendarDateLike::CustomDateTime(this.clone()), context)
}
/// Returns the calendar days in year value with provided context.
pub fn contextualized_days_in_year(
this: &<C::DateLikes as DateTypes<C>>::DateTime,
context: &mut dyn Any,
) -> TemporalResult<u16> {
this.get_calendar()
.days_in_year(&CalendarDateLike::CustomDateTime(this.clone()), context)
}
/// Returns the calendar months in year value with provided context.
pub fn contextualized_months_in_year(
this: &<C::DateLikes as DateTypes<C>>::DateTime,
context: &mut dyn Any,
) -> TemporalResult<u16> {
this.get_calendar()
.months_in_year(&CalendarDateLike::CustomDateTime(this.clone()), context)
}
/// Returns whether the date is in a leap year for the given calendar with provided context.
pub fn contextualized_in_leap_year(
this: &<C::DateLikes as DateTypes<C>>::DateTime,
context: &mut dyn Any,
) -> TemporalResult<bool> {
this.get_calendar()
.in_leap_year(&CalendarDateLike::CustomDateTime(this.clone()), context)
}
}
// ==== Trait impls ====
impl<C: CalendarProtocol> GetCalendarSlot<C> for DateTime<C> {
fn get_calendar(&self) -> CalendarSlot<C> {
self.calendar.clone()
}
}
impl<C: CalendarProtocol> IsoDateSlots for DateTime<C> {
fn iso_date(&self) -> IsoDate {
*self.iso.date()
}
}
impl<C: CalendarProtocol> FromStr for DateTime<C> {
type Err = TemporalError;

8
core/temporal/src/components/month_day.rs

@ -9,7 +9,7 @@ use crate::{
TemporalError, TemporalResult,
};
use super::calendar::CalendarProtocol;
use super::calendar::{CalendarProtocol, GetCalendarSlot};
/// The native Rust implementation of `Temporal.PlainMonthDay`
#[derive(Debug, Default, Clone)]
@ -60,6 +60,12 @@ impl<C: CalendarProtocol> MonthDay<C> {
}
}
impl<C: CalendarProtocol> GetCalendarSlot<C> for MonthDay<C> {
fn get_calendar(&self) -> CalendarSlot<C> {
self.calendar.clone()
}
}
impl<C: CalendarProtocol> IsoDateSlots for MonthDay<C> {
#[inline]
/// Returns this structs `IsoDate`.

11
core/temporal/src/components/year_month.rs

@ -9,7 +9,7 @@ use crate::{
TemporalError, TemporalResult,
};
use super::calendar::CalendarProtocol;
use super::calendar::{CalendarProtocol, GetCalendarSlot};
/// The native Rust implementation of `Temporal.YearMonth`.
#[derive(Debug, Default, Clone)]
@ -54,14 +54,21 @@ impl<C: CalendarProtocol> YearMonth<C> {
self.iso.month
}
/// Returns the Calendar value.
#[inline]
#[must_use]
/// Returns a reference to `YearMonth`'s `CalendarSlot`
pub fn calendar(&self) -> &CalendarSlot<C> {
&self.calendar
}
}
impl<C: CalendarProtocol> GetCalendarSlot<C> for YearMonth<C> {
/// Returns a reference to `YearMonth`'s `CalendarSlot`
fn get_calendar(&self) -> CalendarSlot<C> {
self.calendar.clone()
}
}
impl<C: CalendarProtocol> IsoDateSlots for YearMonth<C> {
#[inline]
/// Returns this `YearMonth`'s `IsoDate`

Loading…
Cancel
Save