#include "src/objects/js-temporal-objects.h"
#include <algorithm>
#include <optional>
#include <set>
#include "src/base/numerics/safe_conversions.h"
#include "src/common/globals.h"
#include "src/date/date.h"
#include "src/execution/isolate.h"
#include "src/heap/factory.h"
#include "src/numbers/conversions-inl.h"
#include "src/objects/js-objects-inl.h"
#include "src/objects/js-objects.h"
#include "src/objects/js-temporal-helpers.h"
#include "src/objects/js-temporal-objects-inl.h"
#include "src/objects/js-temporal-zoneinfo64.h"
#include "src/objects/managed-inl.h"
#include "src/objects/objects-inl.h"
#include "src/objects/option-utils.h"
#include "src/objects/property-descriptor.h"
#include "src/objects/string-set.h"
#include "src/strings/string-builder-inl.h"
#include "temporal_rs/I128Nanoseconds.hpp"
#include "temporal_rs/OwnedRelativeTo.hpp"
#include "temporal_rs/Unit.hpp"
#ifdef V8_INTL_SUPPORT
#include "src/objects/intl-objects.h"
#include "src/objects/js-date-time-format.h"
#include "src/objects/js-duration-format.h"
#include "unicode/calendar.h"
#include "unicode/unistr.h"
#endif
namespace v8::internal {
namespace {
using temporal_rs::RoundingMode;
using temporal_rs::Unit;
* This header declare the Abstract Operations defined in the
* Temporal spec with the enum and struct for them.
*/
template <typename T>
using TemporalResult =
temporal_rs::diplomat::result<T, temporal_rs::TemporalError>;
template <typename T>
using TemporalAllocatedResult = TemporalResult<std::unique_ptr<T>>;
using temporal::DurationRecord;
using temporal::TimeDurationRecord;
enum class Disambiguation { kCompatible, kEarlier, kLater, kReject };
enum class ShowCalendar { kAuto, kAlways, kNever };
enum class UnsignedRoundingMode {
kInfinity,
kZero,
kHalfInfinity,
kHalfZero,
kHalfEven
};
enum class UnitGroup {
kDate,
kTime,
kDateTime,
};
enum class DefaultValue {
kUnset,
kRequired,
};
enum Completeness {
kComplete,
kPartial,
};
temporal_rs::Provider& TimeZoneProvider() {
return ZoneInfo64Provider::Singleton().Provider();
}
static constexpr char kInvalidIsoDate[] = "Invalid ISO date.";
static constexpr char kInvalidTime[] = "Invalid time";
static constexpr char kFiniteInteger[] = "Expected finite integer.";
static constexpr char kIntegerOutOfRange[] = "Integer out of range.";
static constexpr char kOptionMustBeObject[] = "Option must be object:";
static constexpr char kCalendarMustBeString[] = "Calendar must be string.";
static constexpr char kRoundToMissing[] = "Must specify a roundTo parameter.";
static constexpr char kRoundToMustBeObject[] = "roundTo must be an object.";
static constexpr char kYearMustBeObject[] = "year argument must be an object.";
static constexpr char kTimeZoneMissing[] = "Must specify time zone.";
static constexpr char kWithNoPartial[] =
"Argument to with() must contain some date/time fields.";
#define ORDINARY_CREATE_FROM_CONSTRUCTOR(obj, target, new_target, T) \
DirectHandle<JSReceiver> new_target_receiver = Cast<JSReceiver>(new_target); \
DirectHandle<Map> map; \
ASSIGN_RETURN_ON_EXCEPTION( \
isolate, map, \
JSFunction::GetDerivedMap(isolate, target, new_target_receiver)); \
DirectHandle<T> object = \
Cast<T>(isolate->factory()->NewFastOrSlowJSObjectFromMap(map));
template <typename RetVal>
RetVal HandleStringEncodings(
Isolate* isolate, DirectHandle<String> string,
std::function<RetVal(std::string_view)> utf8_fn,
std::function<RetVal(std::u16string_view)> utf16_fn) {
string = String::Flatten(isolate, string);
DisallowGarbageCollection no_gc;
auto flat = string->GetFlatContent(no_gc);
if (flat.IsOneByte()) {
auto content = flat.ToOneByteVector();
std::string_view view(reinterpret_cast<const char*>(content.data()),
content.size());
return utf8_fn(view);
} else {
auto content = flat.ToUC16Vector();
std::u16string_view view(reinterpret_cast<const char16_t*>(content.data()),
content.size());
return utf16_fn(view);
}
}
template <typename ContainedValue>
Maybe<ContainedValue> ExtractRustResult(
Isolate* isolate, TemporalResult<ContainedValue>&& rust_result) {
if (rust_result.is_err()) {
auto err = std::move(rust_result).err().value();
Handle<String> msg;
if (err.msg.has_value()) {
bool success =
isolate->factory()->NewStringFromUtf8(err.msg.value()).ToHandle(&msg);
if (!success) {
msg = isolate->factory()->NewStringFromStaticChars("(utf8 error)");
}
} else {
msg = isolate->factory()->NewStringFromStaticChars("Unspecified error.");
}
switch (err.kind) {
case temporal_rs::ErrorKind::Type:
THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kTemporal, msg));
break;
case temporal_rs::ErrorKind::Range:
THROW_NEW_ERROR(isolate,
NewRangeError(MessageTemplate::kTemporal, msg));
break;
case temporal_rs::ErrorKind::Syntax:
THROW_NEW_ERROR(isolate,
NewSyntaxError(MessageTemplate::kTemporal, msg));
case temporal_rs::ErrorKind::Assert:
case temporal_rs::ErrorKind::Generic:
default:
THROW_NEW_ERROR(isolate,
NewError(MessageTemplate::kTemporalWithArg,
isolate->factory()->NewStringFromStaticChars(
"Internal error:"),
msg));
}
return Nothing<ContainedValue>();
}
return Just(std::move(rust_result).ok().value());
}
template <typename JSType>
MaybeDirectHandle<JSType> ConstructRustWrappingType(
Isolate* isolate, DirectHandle<JSFunction> target,
DirectHandle<HeapObject> new_target,
std::unique_ptr<typename JSType::RustType>&& rust_value) {
std::shared_ptr<typename JSType::RustType> rust_shared =
std::move(rust_value);
DirectHandle<Managed<typename JSType::RustType>> managed =
Managed<typename JSType::RustType>::From(isolate, 0, rust_shared);
ORDINARY_CREATE_FROM_CONSTRUCTOR(object, target, new_target, JSType)
object->initialize_with_wrapped_rust_value(*managed);
return object;
}
template <typename JSType>
MaybeDirectHandle<JSType> ConstructRustWrappingType(
Isolate* isolate, DirectHandle<JSFunction> target,
DirectHandle<HeapObject> new_target,
TemporalResult<std::unique_ptr<typename JSType::RustType>>&& rust_result) {
std::unique_ptr<typename JSType::RustType> rust_value = nullptr;
MOVE_RETURN_ON_EXCEPTION(isolate, rust_value,
ExtractRustResult(isolate, std::move(rust_result)));
return ConstructRustWrappingType<JSType>(isolate, target, new_target,
std::move(rust_value));
}
template <typename JSType>
MaybeDirectHandle<JSType> ConstructRustWrappingType(
Isolate* isolate, std::unique_ptr<typename JSType::RustType>&& rust_value) {
auto ctor = JSType::GetConstructorTarget(isolate);
return ConstructRustWrappingType<JSType>(isolate, ctor, ctor,
std::move(rust_value));
}
template <typename JSType>
MaybeDirectHandle<JSType> ConstructRustWrappingType(
Isolate* isolate,
TemporalResult<std::unique_ptr<typename JSType::RustType>>&& rust_result) {
auto ctor = JSType::GetConstructorTarget(isolate);
return ConstructRustWrappingType<JSType>(isolate, ctor, ctor,
std::move(rust_result));
}
}
namespace temporal {
template <typename IntegerType>
IntegerType CastIntegralDouble(double d) {
DCHECK((base::IsValueInRangeForNumericType<IntegerType, double>(d)));
DCHECK_EQ(nearbyint(d), d);
return static_cast<IntegerType>(d);
}
template <typename IntegerType>
IntegerType ClampIntegralDouble(double d, IntegerType min, IntegerType max) {
DCHECK_EQ(nearbyint(d), d);
double clamped =
std::clamp(d, static_cast<double>(min), static_cast<double>(max));
return CastIntegralDouble<IntegerType>(clamped);
}
template <typename IntegerType>
IntegerType ClampIntegralDoubleToRange(double d) {
return ClampIntegralDouble<IntegerType>(
d, std::numeric_limits<IntegerType>::min(),
std::numeric_limits<IntegerType>::max());
}
template <typename IntegerType>
Maybe<IntegerType> CheckDoubleInRange(Isolate* isolate, double d) {
if (!base::IsValueInRangeForNumericType<IntegerType, double>(d)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kIntegerOutOfRange));
}
return Just(CastIntegralDouble<IntegerType>(d));
}
Maybe<double> ToIntegerIfIntegral(Isolate* isolate,
DirectHandle<Object> argument) {
DirectHandle<Number> number;
ASSIGN_RETURN_ON_EXCEPTION(isolate, number,
Object::ToNumber(isolate, argument));
double number_double = Object::NumberValue(*number);
if (!std::isfinite(number_double) ||
nearbyint(number_double) != number_double) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kFiniteInteger));
}
return Just(number_double);
}
template <typename IntegerType>
Maybe<IntegerType> ToIntegerTypeIfIntegral(Isolate* isolate,
DirectHandle<Object> argument) {
double d;
ASSIGN_RETURN_ON_EXCEPTION(isolate, d,
ToIntegerIfIntegral(isolate, argument));
if (!base::IsValueInRangeForNumericType<IntegerType, double>(d)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kIntegerOutOfRange));
}
return Just(static_cast<IntegerType>(d));
}
Maybe<double> ToIntegerWithTruncation(Isolate* isolate,
DirectHandle<Object> argument) {
DirectHandle<Number> number;
ASSIGN_RETURN_ON_EXCEPTION(isolate, number,
Object::ToNumber(isolate, argument));
double number_double = Object::NumberValue(*number);
if (!std::isfinite(number_double)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kFiniteInteger));
}
return Just(std::trunc(number_double));
}
Maybe<double> ToIntegerWithTruncationOrZero(Isolate* isolate,
DirectHandle<Object> argument) {
if (IsUndefined(*argument)) {
return Just(0.0);
}
return ToIntegerWithTruncation(isolate, argument);
}
Maybe<double> ToPositiveIntegerWithTruncation(Isolate* isolate,
DirectHandle<Object> argument) {
double integer;
ASSIGN_RETURN_ON_EXCEPTION(isolate, integer,
ToIntegerWithTruncation(isolate, argument));
if (integer <= 0) {
THROW_NEW_ERROR(isolate,
NEW_TEMPORAL_RANGE_ERROR("Expected positive integer."));
}
return Just(integer);
}
static constexpr uint64_t kU64HighBitMask = uint64_t{1} << 63;
Maybe<temporal_rs::I128Nanoseconds> GetI128FromBigInt(
Isolate* isolate, DirectHandle<BigInt> bigint) {
static constexpr char kNSOutOfRange[] = "Nanoseconds out of range.";
if (bigint->Words64Count() > 2) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kNSOutOfRange));
}
uint64_t words[2] = {0, 0};
uint32_t word_count = 2;
int sign_bit = 0;
bigint->ToWordsArray64(&sign_bit, &word_count, words);
if ((words[1] & kU64HighBitMask) != 0) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kNSOutOfRange));
}
uint64_t high = words[1];
if (sign_bit == 1) {
high |= kU64HighBitMask;
}
temporal_rs::I128Nanoseconds ns;
ns.high = high;
ns.low = words[0];
if (!ns.is_valid()) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kNSOutOfRange));
}
return Just(ns);
#undef NANOSECONDS_RANGE_ERROR
}
MaybeDirectHandle<BigInt> I128ToBigInt(Isolate* isolate,
temporal_rs::I128Nanoseconds ns) {
uint64_t words[2];
bool sign_bit;
if ((ns.high & temporal::kU64HighBitMask) != 0) {
sign_bit = true;
words[1] = ns.high & ~temporal::kU64HighBitMask;
} else {
sign_bit = false;
words[1] = ns.high;
}
words[0] = ns.low;
return BigInt::FromWords64(isolate, sign_bit, 2, words);
}
bool IsValidTime(double hour, double minute, double second, double millisecond,
double microsecond, double nanosecond) {
if (hour < 0 || hour > 23) {
return false;
}
if (minute < 0 || minute > 59) {
return false;
}
if (second < 0 || second > 59) {
return false;
}
if (millisecond < 0 || millisecond > 999) {
return false;
}
if (microsecond < 0 || microsecond > 999) {
return false;
}
if (nanosecond < 0 || nanosecond > 999) {
return false;
}
return true;
}
int8_t ISODaysInMonth(int32_t year, uint8_t month) {
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
return 31;
case 2:
if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) {
return 29;
} else {
return 28;
}
default:
return 30;
}
}
bool IsValidIsoDate(double year, double month, double day) {
if (month < 1 || month > 12) {
return false;
}
if (!base::IsValueInRangeForNumericType<int32_t, double>(year)) {
return false;
}
int32_t year_int = static_cast<int32_t>(year);
uint8_t month_int = static_cast<uint8_t>(month);
if (day < 1 || day > ISODaysInMonth(year_int, month_int)) {
return false;
}
return true;
}
Maybe<std::string> ToMonthCode(Isolate* isolate,
DirectHandle<Object> argument) {
static constexpr char kMonthCodeOutOfRange[] = "Month code out of range.";
DirectHandle<Object> mc_prim;
if (IsJSReceiver(*argument)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, mc_prim,
JSReceiver::ToPrimitive(isolate, Cast<JSReceiver>(argument),
ToPrimitiveHint::kString));
} else {
mc_prim = argument;
}
if (!IsString(*mc_prim)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kMonthCodeOutOfRange));
}
auto month_code = Cast<String>(*mc_prim)->ToStdString();
if (month_code.size() != 3 && month_code.size() != 4) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kMonthCodeOutOfRange));
}
if (month_code[0] != 'M') {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kMonthCodeOutOfRange));
}
if (month_code[1] < '0' || month_code[1] > '9') {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kMonthCodeOutOfRange));
}
if (month_code[2] < '0' || month_code[2] > '9') {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kMonthCodeOutOfRange));
}
if (month_code.size() == 4 && month_code[3] != 'L') {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kMonthCodeOutOfRange));
}
if (month_code[1] == '0' && month_code[2] == '0' && month_code.size() != 4) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kMonthCodeOutOfRange));
}
return Just(month_code);
#undef MONTHCODE_RANGE_ERROR
}
Maybe<temporal_rs::ArithmeticOverflow> ToTemporalOverflowHandleUndefined(
Isolate* isolate, MaybeDirectHandle<Object> maybe_options,
const char* method_name) {
DirectHandle<Object> options;
if (!maybe_options.ToHandle(&options) || IsUndefined(*options))
return Just(temporal_rs::ArithmeticOverflow(
temporal_rs::ArithmeticOverflow::Constrain));
auto overflow_ident = isolate->factory()->overflow_string();
if (!IsJSReceiver(*options)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR_WITH_ARG(
kOptionMustBeObject, overflow_ident));
}
return GetStringOption<temporal_rs::ArithmeticOverflow>(
isolate, Cast<JSReceiver>(options), overflow_ident, method_name,
std::to_array<const std::string_view>({"constrain", "reject"}),
std::to_array<temporal_rs::ArithmeticOverflow>(
{temporal_rs::ArithmeticOverflow::Constrain,
temporal_rs::ArithmeticOverflow::Reject}),
temporal_rs::ArithmeticOverflow::Constrain);
}
Maybe<temporal_rs::TransitionDirection> GetDirectionOption(
Isolate* isolate, DirectHandle<JSReceiver> options,
const char* method_name) {
temporal_rs::TransitionDirection dir;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, dir,
GetStringOption<temporal_rs::TransitionDirection>(
isolate, Cast<JSReceiver>(options),
isolate->factory()->direction_string(), method_name,
std::to_array<const std::string_view>({"next", "previous"}),
std::to_array<temporal_rs::TransitionDirection>(
{temporal_rs::TransitionDirection::Next,
temporal_rs::TransitionDirection::Previous}),
std::nullopt));
return Just(dir);
}
Maybe<temporal_rs::Disambiguation>
GetTemporalDisambiguationOptionHandleUndefined(Isolate* isolate,
DirectHandle<Object> options,
const char* method_name) {
if (IsUndefined(*options)) {
return Just(
temporal_rs::Disambiguation(temporal_rs::Disambiguation::Compatible));
}
auto disambiguation_ident = isolate->factory()->disambiguation_string();
if (!IsJSReceiver(*options)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR_WITH_ARG(
kOptionMustBeObject, disambiguation_ident));
}
return GetStringOption<temporal_rs::Disambiguation>(
isolate, Cast<JSReceiver>(options), disambiguation_ident, method_name,
std::to_array<const std::string_view>(
{"compatible", "earlier", "later", "reject"}),
std::to_array<temporal_rs::Disambiguation>({
temporal_rs::Disambiguation::Compatible,
temporal_rs::Disambiguation::Earlier,
temporal_rs::Disambiguation::Later,
temporal_rs::Disambiguation::Reject,
}),
temporal_rs::Disambiguation::Compatible);
}
Maybe<temporal_rs::OffsetDisambiguation> GetTemporalOffsetOptionHandleUndefined(
Isolate* isolate, DirectHandle<Object> options,
temporal_rs::OffsetDisambiguation fallback, const char* method_name) {
if (IsUndefined(*options)) {
return Just(fallback);
}
auto offset_ident = isolate->factory()->offset_string();
if (!IsJSReceiver(*options)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR_WITH_ARG(
kOptionMustBeObject, offset_ident));
}
return GetStringOption<temporal_rs::OffsetDisambiguation>(
isolate, Cast<JSReceiver>(options), offset_ident, method_name,
std::to_array<const std::string_view>(
{"prefer", "use", "ignore", "reject"}),
std::to_array<temporal_rs::OffsetDisambiguation>({
temporal_rs::OffsetDisambiguation::Prefer,
temporal_rs::OffsetDisambiguation::Use,
temporal_rs::OffsetDisambiguation::Ignore,
temporal_rs::OffsetDisambiguation::Reject,
}),
fallback);
}
Maybe<temporal_rs::Precision> GetTemporalFractionalSecondDigitsOption(
Isolate* isolate, DirectHandle<JSReceiver> normalized_options,
const char* method_name) {
auto auto_val =
temporal_rs::Precision{.is_minute = false, .precision = std::nullopt};
Factory* factory = isolate->factory();
DirectHandle<Object> digits_val;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, digits_val,
JSReceiver::GetProperty(isolate, normalized_options,
factory->fractionalSecondDigits_string()));
if (IsUndefined(*digits_val)) {
return Just(auto_val);
}
if (!IsNumber(*digits_val)) {
DirectHandle<String> string;
ASSIGN_RETURN_ON_EXCEPTION(isolate, string,
Object::ToString(isolate, digits_val));
if (!String::Equals(isolate, string, factory->auto_string())) {
THROW_NEW_ERROR(isolate,
NewRangeError(MessageTemplate::kPropertyValueOutOfRange,
factory->fractionalSecondDigits_string()));
}
return Just(auto_val);
}
auto digits_num = Cast<Number>(*digits_val);
auto digits_float = Object::NumberValue(digits_num);
if (std::isnan(digits_float) || std::isinf(digits_float)) {
THROW_NEW_ERROR(isolate,
NewRangeError(MessageTemplate::kPropertyValueOutOfRange,
factory->fractionalSecondDigits_string()));
}
double digit_count = std::floor(digits_float);
if (digit_count < 0 || digit_count > 9) {
THROW_NEW_ERROR(isolate,
NewRangeError(MessageTemplate::kPropertyValueOutOfRange,
factory->fractionalSecondDigits_string()));
}
uint8_t clamped = CastIntegralDouble<uint8_t>(digit_count);
return Just(
temporal_rs::Precision{.is_minute = false, .precision = clamped});
}
Maybe<std::optional<Unit>> GetTemporalUnitValuedOption(
Isolate* isolate, DirectHandle<JSReceiver> normalized_options,
DirectHandle<String> key, DefaultValue default_value,
const char* method_name) {
constexpr auto strs = std::to_array<const std::string_view>(
{"year", "month", "week", "day", "hour",
"minute", "second", "millisecond", "microsecond", "nanosecond",
"auto", "years", "months", "weeks", "days",
"hours", "minutes", "seconds", "milliseconds", "microseconds",
"nanoseconds"});
constexpr auto enums = std::to_array<const std::optional<Unit::Value>>(
{Unit::Year, Unit::Month, Unit::Week,
Unit::Day, Unit::Hour, Unit::Minute,
Unit::Second, Unit::Millisecond, Unit::Microsecond,
Unit::Nanosecond, Unit::Auto, Unit::Year,
Unit::Month, Unit::Week, Unit::Day,
Unit::Hour, Unit::Minute, Unit::Second,
Unit::Millisecond, Unit::Microsecond, Unit::Nanosecond});
std::optional<std::optional<Unit>> wrapped_default = std::nullopt;
if (default_value == DefaultValue::kUnset) {
wrapped_default = std::make_optional(std::optional<Unit>(std::nullopt));
}
std::optional<Unit::Value> value;
ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
GetStringOption<std::optional<Unit::Value>>(
isolate, normalized_options, key, method_name,
strs, enums, wrapped_default));
if (value.has_value()) {
return Just<std::optional<Unit>>((Unit)value.value());
} else {
return Just<std::optional<Unit>>(std::nullopt);
}
}
Maybe<void> ValidateTemporalUnitValue(
Isolate* isolate, std::optional<Unit> value_or_unset, UnitGroup unit_group,
std::optional<Unit> extra_values = std::nullopt) {
if (!value_or_unset.has_value()) {
return JustVoid();
}
auto value = value_or_unset.value();
if (extra_values == value) {
return JustVoid();
}
switch (value) {
case Unit::Auto:
THROW_NEW_ERROR(isolate,
NEW_TEMPORAL_RANGE_ERROR("Auto unit not allowed here"));
case Unit::Year:
case Unit::Month:
case Unit::Week:
case Unit::Day:
if (unit_group == UnitGroup::kDate ||
unit_group == UnitGroup::kDateTime) {
return JustVoid();
} else {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(
"Found date unit, expect time unit"));
}
default:
if (unit_group == UnitGroup::kTime ||
unit_group == UnitGroup::kDateTime) {
return JustVoid();
}
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(
"Found date unit, expect time unit"));
}
}
Maybe<temporal_rs::AnyCalendarKind> CanonicalizeCalendar(
Isolate* isolate, DirectHandle<String> calendar) {
std::string s = calendar->ToStdString();
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
auto cal = temporal_rs::AnyCalendarKind::get_for_str(s);
if (!cal.has_value()) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR_WITH_ARG(
"Unknown calendar type", calendar));
}
return Just(cal.value());
}
Maybe<uint32_t> GetRoundingIncrementOption(
Isolate* isolate, DirectHandle<JSReceiver> normalized_options) {
DirectHandle<Object> value;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, value,
JSReceiver::GetProperty(isolate, normalized_options,
isolate->factory()->roundingIncrement_string()));
if (IsUndefined(*value)) {
return Just(static_cast<uint32_t>(1));
}
double integer_increment;
ASSIGN_RETURN_ON_EXCEPTION(isolate, integer_increment,
ToIntegerWithTruncation(isolate, value));
if (integer_increment < 1 || integer_increment > 1e9) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kIntegerOutOfRange));
}
return Just(static_cast<uint32_t>(integer_increment));
}
Maybe<RoundingMode> GetRoundingModeOption(Isolate* isolate,
DirectHandle<JSReceiver> options,
RoundingMode fallback,
const char* method_name) {
static const auto values = std::to_array<RoundingMode>(
{RoundingMode::Ceil, RoundingMode::Floor, RoundingMode::Expand,
RoundingMode::Trunc, RoundingMode::HalfCeil, RoundingMode::HalfFloor,
RoundingMode::HalfExpand, RoundingMode::HalfTrunc,
RoundingMode::HalfEven});
return GetStringOption<RoundingMode>(
isolate, options, isolate->factory()->roundingMode_string(), method_name,
std::to_array<const std::string_view>(
{"ceil", "floor", "expand", "trunc", "halfCeil", "halfFloor",
"halfExpand", "halfTrunc", "halfEven"}),
values, fallback);
}
Maybe<temporal_rs::DisplayOffset> GetTemporalShowOffsetOption(
Isolate* isolate, DirectHandle<JSReceiver> options,
const char* method_name) {
static const auto values = std::to_array<temporal_rs::DisplayOffset>(
{temporal_rs::DisplayOffset::Auto, temporal_rs::DisplayOffset::Never});
return GetStringOption<temporal_rs::DisplayOffset>(
isolate, options, isolate->factory()->offset_string(), method_name,
std::to_array<const std::string_view>({"auto", "never"}), values,
temporal_rs::DisplayOffset::Auto);
}
Maybe<temporal_rs::DisplayTimeZone> GetTemporalShowTimeZoneNameOption(
Isolate* isolate, DirectHandle<JSReceiver> options,
const char* method_name) {
static const auto values = std::to_array<temporal_rs::DisplayTimeZone>(
{temporal_rs::DisplayTimeZone::Auto, temporal_rs::DisplayTimeZone::Never,
temporal_rs::DisplayTimeZone::Critical});
return GetStringOption<temporal_rs::DisplayTimeZone>(
isolate, options, isolate->factory()->timeZoneName_string(), method_name,
std::to_array<const std::string_view>({"auto", "never", "critical"}),
values, temporal_rs::DisplayTimeZone::Auto);
}
Maybe<temporal_rs::DifferenceSettings> GetDifferenceSettingsWithoutChecks(
Isolate* isolate, DirectHandle<Object> options_obj, UnitGroup unit_group,
std::optional<Unit> fallback_smallest_unit, const char* method_name) {
DirectHandle<JSReceiver> options;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, options, GetOptionsObject(isolate, options_obj, method_name));
std::optional<Unit> largest_unit;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, largest_unit,
temporal::GetTemporalUnitValuedOption(
isolate, options, isolate->factory()->largestUnit_string(),
DefaultValue::kUnset, method_name));
uint32_t rounding_increment;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, rounding_increment,
temporal::GetRoundingIncrementOption(isolate, options));
RoundingMode rounding_mode;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, rounding_mode,
temporal::GetRoundingModeOption(isolate, options, RoundingMode::Trunc,
method_name));
std::optional<Unit> smallest_unit;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, smallest_unit,
temporal::GetTemporalUnitValuedOption(
isolate, options, isolate->factory()->smallestUnit_string(),
DefaultValue::kUnset, method_name));
return Just(temporal_rs::DifferenceSettings{.largest_unit = largest_unit,
.smallest_unit = smallest_unit,
.rounding_mode = rounding_mode,
.increment = rounding_increment});
}
Maybe<temporal_rs::DisplayCalendar> GetTemporalShowCalendarNameOption(
Isolate* isolate, DirectHandle<JSReceiver> options,
const char* method_name) {
return GetStringOption<temporal_rs::DisplayCalendar>(
isolate, options, isolate->factory()->calendarName_string(), method_name,
std::to_array<const std::string_view>(
{"auto", "always", "never", "critical"}),
std::to_array<temporal_rs::DisplayCalendar>(
{temporal_rs::DisplayCalendar::Auto,
temporal_rs::DisplayCalendar::Always,
temporal_rs::DisplayCalendar::Never,
temporal_rs::DisplayCalendar::Critical}),
temporal_rs::DisplayCalendar::Auto);
}
std::optional<temporal_rs::AnyCalendarKind> ExtractCalendarFrom(
Isolate* isolate, Tagged<HeapObject> calendar_like) {
InstanceType instance_type = calendar_like->map(isolate)->instance_type();
if (InstanceTypeChecker::IsJSTemporalPlainDate(instance_type)) {
return Cast<JSTemporalPlainDate>(*calendar_like)
->wrapped_rust()
.calendar()
.kind();
} else if (InstanceTypeChecker::IsJSTemporalPlainDateTime(instance_type)) {
return Cast<JSTemporalPlainDateTime>(*calendar_like)
->wrapped_rust()
.calendar()
.kind();
} else if (InstanceTypeChecker::IsJSTemporalPlainMonthDay(instance_type)) {
return Cast<JSTemporalPlainMonthDay>(*calendar_like)
->wrapped_rust()
.calendar()
.kind();
} else if (InstanceTypeChecker::IsJSTemporalPlainYearMonth(instance_type)) {
return Cast<JSTemporalPlainYearMonth>(*calendar_like)
->wrapped_rust()
.calendar()
.kind();
} else if (InstanceTypeChecker::IsJSTemporalZonedDateTime(instance_type)) {
return Cast<JSTemporalZonedDateTime>(*calendar_like)
->wrapped_rust()
.calendar()
.kind();
}
return std::nullopt;
}
Maybe<temporal_rs::AnyCalendarKind> ToTemporalCalendarIdentifier(
Isolate* isolate, DirectHandle<Object> calendar_like) {
if (IsHeapObject(*calendar_like)) {
auto cal_field =
ExtractCalendarFrom(isolate, Cast<HeapObject>(*calendar_like));
if (cal_field.has_value()) {
return Just(cal_field.value());
}
}
if (!IsString(*calendar_like)) {
THROW_NEW_ERROR(
isolate, NEW_TEMPORAL_TYPE_ERROR(
"Calendar must be string or calendared Temporal object."));
}
auto stdstr = Cast<String>(calendar_like)->ToStdString();
auto kind =
temporal_rs::AnyCalendarKind::parse_temporal_calendar_string(stdstr);
if (kind.has_value()) {
return Just(kind.value());
} else {
THROW_NEW_ERROR(isolate,
NEW_TEMPORAL_RANGE_ERROR("Invalid calendar string"));
}
}
Maybe<temporal_rs::AnyCalendarKind> GetTemporalCalendarIdentifierWithISODefault(
Isolate* isolate, DirectHandle<JSReceiver> options) {
if (IsHeapObject(*options)) {
auto cal_field = ExtractCalendarFrom(isolate, Cast<HeapObject>(*options));
if (cal_field.has_value()) {
return Just(cal_field.value());
}
}
DirectHandle<Object> calendar;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, calendar,
JSReceiver::GetProperty(isolate, options,
isolate->factory()->calendar_string()));
if (IsUndefined(*calendar)) {
return Just(
temporal_rs::AnyCalendarKind(temporal_rs::AnyCalendarKind::Iso));
}
return ToTemporalCalendarIdentifier(isolate, calendar);
}
constexpr temporal_rs::ToStringRoundingOptions kToStringAuto =
temporal_rs::ToStringRoundingOptions{
.precision = temporal_rs::Precision{.is_minute = false,
.precision = std::nullopt},
.smallest_unit = std::nullopt,
.rounding_mode = std::nullopt,
};
template <typename JSType, typename... Args, typename... Args2>
MaybeDirectHandle<String> GenericTemporalToString(
Isolate* isolate, DirectHandle<JSType> val,
std::string (JSType::RustType::*method)(Args2...) const, Args... args) {
auto output = (val->wrapped_rust().*method)(args...);
IncrementalStringBuilder builder(isolate);
builder.AppendString(output);
return builder.Finish().ToHandleChecked();
}
template <typename JSType, typename... Args, typename... Args2>
MaybeDirectHandle<String> GenericTemporalToString(
Isolate* isolate, DirectHandle<JSType> val,
TemporalResult<std::string> (JSType::RustType::*method)(Args2...) const,
Args... args) {
std::string output;
MOVE_RETURN_ON_EXCEPTION(
isolate, output,
ExtractRustResult(isolate, (val->wrapped_rust().*method)(args...)));
IncrementalStringBuilder builder(isolate);
builder.AppendString(output);
return builder.Finish().ToHandleChecked();
}
constexpr temporal_rs::PartialDate kNullPartialDate = temporal_rs::PartialDate{
.year = std::nullopt,
.month = std::nullopt,
.month_code = "",
.day = std::nullopt,
.era = "",
.era_year = std::nullopt,
.calendar = temporal_rs::AnyCalendarKind::Iso,
};
constexpr temporal_rs::PartialTime kNullPartialTime = temporal_rs::PartialTime{
.hour = std::nullopt,
.minute = std::nullopt,
.second = std::nullopt,
.millisecond = std::nullopt,
.microsecond = std::nullopt,
.nanosecond = std::nullopt,
};
constexpr temporal_rs::PartialZonedDateTime kNullPartialZonedDateTime =
temporal_rs::PartialZonedDateTime{
.date = kNullPartialDate,
.time = kNullPartialTime,
.offset = std::nullopt,
.timezone = std::nullopt,
};
constexpr temporal_rs::PartialDateTime kNullPartialDateTime =
temporal_rs::PartialDateTime{.date = kNullPartialDate,
.time = kNullPartialTime};
struct TimeRecord {
std::optional<double> hour = std::nullopt;
std::optional<double> minute = std::nullopt;
std::optional<double> second = std::nullopt;
std::optional<double> millisecond = std::nullopt;
std::optional<double> microsecond = std::nullopt;
std::optional<double> nanosecond = std::nullopt;
Maybe<temporal_rs::PartialTime> Regulate(
Isolate* isolate, temporal_rs::ArithmeticOverflow overflow);
};
Maybe<temporal_rs::PartialTime> TimeRecord::Regulate(
Isolate* isolate, temporal_rs::ArithmeticOverflow overflow) {
temporal_rs::PartialTime partial = kNullPartialTime;
if (overflow == temporal_rs::ArithmeticOverflow::Constrain) {
if (hour.has_value()) {
partial.hour = ClampIntegralDouble<uint8_t>(hour.value(), 0, 23);
}
if (minute.has_value()) {
partial.minute = ClampIntegralDouble<uint8_t>(minute.value(), 0, 59);
}
if (second.has_value()) {
partial.second = ClampIntegralDouble<uint8_t>(second.value(), 0, 59);
}
if (millisecond.has_value()) {
partial.millisecond =
ClampIntegralDouble<uint16_t>(millisecond.value(), 0, 999);
}
if (microsecond.has_value()) {
partial.microsecond =
ClampIntegralDouble<uint16_t>(microsecond.value(), 0, 999);
}
if (nanosecond.has_value()) {
partial.nanosecond =
ClampIntegralDouble<uint16_t>(nanosecond.value(), 0, 999);
}
} else {
if (!IsValidTime(hour.value_or(0), minute.value_or(0), second.value_or(0),
millisecond.value_or(0), microsecond.value_or(0),
nanosecond.value_or(0))) {
THROW_NEW_ERROR(isolate,
NEW_TEMPORAL_RANGE_ERROR("Invalid time provided"));
}
if (hour.has_value()) {
partial.hour = CastIntegralDouble<uint8_t>(hour.value());
}
if (minute.has_value()) {
partial.minute = CastIntegralDouble<uint8_t>(minute.value());
}
if (second.has_value()) {
partial.second = CastIntegralDouble<uint8_t>(second.value());
}
if (millisecond.has_value()) {
partial.millisecond = CastIntegralDouble<uint16_t>(millisecond.value());
}
if (microsecond.has_value()) {
partial.microsecond = CastIntegralDouble<uint16_t>(microsecond.value());
}
if (nanosecond.has_value()) {
partial.nanosecond = CastIntegralDouble<uint16_t>(nanosecond.value());
}
}
return Just(partial);
}
template <typename RustObject>
temporal_rs::PartialTime GetPartialTimeFromRust(RustObject& rust_object) {
return temporal_rs::PartialTime{
.hour = rust_object->hour(),
.minute = rust_object->minute(),
.second = rust_object->second(),
.millisecond = rust_object->millisecond(),
.microsecond = rust_object->microsecond(),
.nanosecond = rust_object->nanosecond(),
};
}
temporal_rs::PartialTime GetPartialTime(
DirectHandle<JSTemporalPlainTime> plain_time) {
auto rust_object = plain_time->time()->raw();
return GetPartialTimeFromRust(rust_object);
}
temporal_rs::PartialTime GetPartialTime(
DirectHandle<JSTemporalPlainDateTime> date_time) {
auto rust_object = date_time->date_time()->raw();
return GetPartialTimeFromRust(rust_object);
}
temporal_rs::PartialTime GetPartialTime(
DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
auto rust_object = zoned_date_time->zoned_date_time()->raw();
return GetPartialTimeFromRust(rust_object);
}
template <typename RustObject>
temporal_rs::PartialDate GetPartialDateFromRust(RustObject& rust_object) {
return temporal_rs::PartialDate{
.year = rust_object->year(),
.month = rust_object->month(),
.month_code = "",
.day = rust_object->day(),
.era = "",
.era_year = std::nullopt,
.calendar = rust_object->calendar().kind(),
};
}
temporal_rs::PartialDate GetPartialDate(
DirectHandle<JSTemporalPlainDate> plain_date) {
auto rust_object = plain_date->date()->raw();
return GetPartialDateFromRust(rust_object);
}
temporal_rs::PartialDate GetPartialDate(
DirectHandle<JSTemporalPlainDateTime> date_time) {
auto rust_object = date_time->date_time()->raw();
return GetPartialDateFromRust(rust_object);
}
temporal_rs::PartialDate GetPartialDate(
DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
auto rust_object = zoned_date_time->zoned_date_time()->raw();
return GetPartialDateFromRust(rust_object);
}
temporal_rs::PartialDateTime GetPartialDateTime(
DirectHandle<JSTemporalPlainDate> plain_date) {
auto rust_object = plain_date->date()->raw();
return temporal_rs::PartialDateTime{
.date = GetPartialDateFromRust(rust_object),
.time = kNullPartialTime,
};
}
temporal_rs::PartialDateTime GetPartialDateTime(
DirectHandle<JSTemporalPlainDateTime> date_time) {
auto rust_object = date_time->date_time()->raw();
return temporal_rs::PartialDateTime{
.date = GetPartialDateFromRust(rust_object),
.time = GetPartialTimeFromRust(rust_object),
};
}
temporal_rs::PartialDateTime GetPartialDateTime(
DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
auto rust_object = zoned_date_time->zoned_date_time()->raw();
return temporal_rs::PartialDateTime{
.date = GetPartialDateFromRust(rust_object),
.time = GetPartialTimeFromRust(rust_object),
};
}
Maybe<std::optional<double>> GetSingleDurationField(
Isolate* isolate, DirectHandle<JSReceiver> duration_like,
DirectHandle<String> field_name) {
DirectHandle<Object> val;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, val,
JSReceiver::GetProperty(isolate, duration_like, field_name));
if (IsUndefined(*val)) {
return Just((std::optional<double>)std::nullopt);
} else {
double field;
ASSIGN_RETURN_ON_EXCEPTION(isolate, field,
temporal::ToIntegerIfIntegral(isolate, val));
return Just(std::optional(field));
}
}
Maybe<std::optional<int64_t>> GetSingleDurationFieldInteger(
Isolate* isolate, DirectHandle<JSReceiver> duration_like,
DirectHandle<String> field_name) {
std::optional<double> ret_opt;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, ret_opt,
GetSingleDurationField(isolate, duration_like, field_name));
if (ret_opt.has_value()) {
double ret = ret_opt.value();
if (!base::IsValueInRangeForNumericType<int64_t, double>(ret)) {
THROW_NEW_ERROR(isolate,
NEW_TEMPORAL_RANGE_ERROR("Duration field out of range."));
}
return Just(std::optional(static_cast<int64_t>(ret)));
} else {
return Just((std::optional<int64_t>)std::nullopt);
}
}
Maybe<std::string> ToOffsetString(Isolate* isolate,
DirectHandle<Object> argument) {
DirectHandle<Object> offset_prim;
if (IsJSReceiver(*argument)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, offset_prim,
JSReceiver::ToPrimitive(isolate, Cast<JSReceiver>(argument),
ToPrimitiveHint::kString));
} else {
offset_prim = argument;
}
if (!IsString(*offset_prim)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR("Offset must be string."));
}
auto offset_str = Cast<String>(offset_prim);
auto offset = offset_str->ToStdString();
RETURN_ON_EXCEPTION(
isolate,
ExtractRustResult(isolate,
temporal_rs::TimeZone::try_from_offset_str(offset)));
return Just(std::move(offset));
}
Maybe<temporal_rs::TimeZone> ToTemporalTimeZoneIdentifier(
Isolate* isolate, DirectHandle<Object> tz_like) {
if (IsJSTemporalZonedDateTime(*tz_like)) {
return Just(Cast<JSTemporalZonedDateTime>(tz_like)
->zoned_date_time()
->raw()
->timezone());
}
if (!IsString(*tz_like)) {
THROW_NEW_ERROR(isolate,
NEW_TEMPORAL_TYPE_ERROR(
"Time zone must be string or ZonedDateTime object."));
}
DirectHandle<String> str = Cast<String>(tz_like);
auto std_str = str->ToStdString();
return ExtractRustResult(isolate,
temporal_rs::TimeZone::try_from_str_with_provider(
std_str, TimeZoneProvider()));
}
Maybe<temporal_rs::PartialDuration> ToTemporalPartialDurationRecord(
Isolate* isolate, DirectHandle<Object> duration_like_obj) {
Factory* factory = isolate->factory();
if (!IsJSReceiver(*duration_like_obj)) {
THROW_NEW_ERROR(isolate,
NEW_TEMPORAL_TYPE_ERROR("Must provide a duration."));
}
DirectHandle<JSReceiver> duration_like = Cast<JSReceiver>(duration_like_obj);
auto result = temporal_rs::PartialDuration{
.years = std::nullopt,
.months = std::nullopt,
.weeks = std::nullopt,
.days = std::nullopt,
.hours = std::nullopt,
.minutes = std::nullopt,
.seconds = std::nullopt,
.milliseconds = std::nullopt,
.microseconds = std::nullopt,
.nanoseconds = std::nullopt,
};
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result.days,
temporal::GetSingleDurationFieldInteger(isolate, duration_like,
factory->days_string()));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result.hours,
temporal::GetSingleDurationFieldInteger(isolate, duration_like,
factory->hours_string()));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result.microseconds,
temporal::GetSingleDurationField(isolate, duration_like,
factory->microseconds_string()));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result.milliseconds,
temporal::GetSingleDurationFieldInteger(isolate, duration_like,
factory->milliseconds_string()));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result.minutes,
temporal::GetSingleDurationFieldInteger(isolate, duration_like,
factory->minutes_string()));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result.months,
temporal::GetSingleDurationFieldInteger(isolate, duration_like,
factory->months_string()));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result.nanoseconds,
temporal::GetSingleDurationField(isolate, duration_like,
factory->nanoseconds_string()));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result.seconds,
temporal::GetSingleDurationFieldInteger(isolate, duration_like,
factory->seconds_string()));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result.weeks,
temporal::GetSingleDurationFieldInteger(isolate, duration_like,
factory->weeks_string()));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result.years,
temporal::GetSingleDurationFieldInteger(isolate, duration_like,
factory->years_string()));
if (!result.years.has_value() && !result.months.has_value() &&
!result.weeks.has_value() && !result.days.has_value() &&
!result.hours.has_value() && !result.minutes.has_value() &&
!result.seconds.has_value() && !result.milliseconds.has_value() &&
!result.microseconds.has_value() && !result.nanoseconds.has_value()) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(
"Did not provide any valid Duration fields."));
}
return Just(result);
}
Maybe<std::optional<double>> GetSingleTimeRecordField(
Isolate* isolate, DirectHandle<JSReceiver> time_like,
DirectHandle<String> field_name, bool* any) {
DirectHandle<Object> val;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, val, JSReceiver::GetProperty(isolate, time_like, field_name));
if (!IsUndefined(*val)) {
double field;
ASSIGN_RETURN_ON_EXCEPTION(isolate, field,
temporal::ToIntegerWithTruncation(isolate, val));
*any = true;
return Just(std::optional(field));
} else {
return Just((std::optional<double>)std::nullopt);
}
}
Maybe<bool> IsPartialTemporalObject(Isolate* isolate,
DirectHandle<Object> value) {
if (!IsHeapObject(*value)) {
return Just(false);
}
InstanceType instance_type =
Cast<HeapObject>(*value)->map(isolate)->instance_type();
if (!InstanceTypeChecker::IsJSReceiver(instance_type)) {
return Just(false);
}
auto value_recvr = Cast<JSReceiver>(value);
if (InstanceTypeChecker::IsJSTemporalPlainDate(instance_type) ||
InstanceTypeChecker::IsJSTemporalPlainDateTime(instance_type) ||
InstanceTypeChecker::IsJSTemporalPlainMonthDay(instance_type) ||
InstanceTypeChecker::IsJSTemporalPlainTime(instance_type) ||
InstanceTypeChecker::IsJSTemporalPlainYearMonth(instance_type) ||
InstanceTypeChecker::IsJSTemporalZonedDateTime(instance_type)) {
return Just(false);
}
DirectHandle<Object> cal;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, cal,
JSReceiver::GetProperty(isolate, value_recvr,
isolate->factory()->calendar_string()));
if (!IsUndefined(*cal)) {
return Just(false);
}
DirectHandle<Object> tz;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, tz,
JSReceiver::GetProperty(isolate, value_recvr,
isolate->factory()->timeZone_string()));
if (!IsUndefined(*tz)) {
return Just(false);
}
return Just(true);
}
Maybe<TimeRecord> ToTemporalTimeRecord(Isolate* isolate,
DirectHandle<JSReceiver> time_like,
const char* method_name,
Completeness completeness = kComplete) {
Factory* factory = isolate->factory();
auto result = completeness == kPartial ? TimeRecord {
.hour = std::nullopt,
.minute = std::nullopt,
.second = std::nullopt,
.millisecond = std::nullopt,
.microsecond = std::nullopt,
.nanosecond = std::nullopt,
} : TimeRecord {
.hour = 0,
.minute = 0,
.second = 0,
.millisecond = 0,
.microsecond = 0,
.nanosecond = 0,
};
bool any = false;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result.hour,
temporal::GetSingleTimeRecordField(isolate, time_like,
factory->hour_string(), &any));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result.microsecond,
temporal::GetSingleTimeRecordField(isolate, time_like,
factory->microsecond_string(), &any));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result.millisecond,
temporal::GetSingleTimeRecordField(isolate, time_like,
factory->millisecond_string(), &any));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result.minute,
temporal::GetSingleTimeRecordField(isolate, time_like,
factory->minute_string(), &any));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result.nanosecond,
temporal::GetSingleTimeRecordField(isolate, time_like,
factory->nanosecond_string(), &any));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result.second,
temporal::GetSingleTimeRecordField(isolate, time_like,
factory->second_string(), &any));
if (!any) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(
"Must specify at least one time field."));
}
return Just(result);
}
struct DateRecord {
std::optional<double> year;
std::optional<double> month;
std::optional<std::string> month_code;
std::optional<double> day;
std::optional<std::string> era;
std::optional<double> era_year;
temporal_rs::AnyCalendarKind calendar = temporal_rs::AnyCalendarKind::Iso;
Maybe<temporal_rs::PartialDate> Regulate(
Isolate* isolate, temporal_rs::ArithmeticOverflow overflow);
};
Maybe<temporal_rs::PartialDate> DateRecord::Regulate(
Isolate* isolate, temporal_rs::ArithmeticOverflow overflow) {
temporal_rs::PartialDate partial = kNullPartialDate;
if (month_code.has_value()) {
partial.month_code = month_code.value();
}
if (era.has_value()) {
partial.era = era.value();
}
partial.calendar = calendar;
if (overflow == temporal_rs::ArithmeticOverflow::Constrain) {
if (year.has_value()) {
partial.year = ClampIntegralDoubleToRange<int32_t>(year.value());
}
if (month.has_value()) {
partial.month = ClampIntegralDoubleToRange<int8_t>(month.value());
}
if (day.has_value()) {
partial.day = ClampIntegralDoubleToRange<int8_t>(day.value());
}
if (era_year.has_value()) {
partial.era_year = ClampIntegralDoubleToRange<int32_t>(era_year.value());
}
} else {
if (year.has_value()) {
int32_t result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result, CheckDoubleInRange<int32_t>(isolate, year.value()));
partial.year = result;
}
if (month.has_value()) {
uint8_t result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result, CheckDoubleInRange<uint8_t>(isolate, month.value()));
partial.month = result;
}
if (day.has_value()) {
uint8_t result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result, CheckDoubleInRange<uint8_t>(isolate, day.value()));
partial.day = result;
}
if (era_year.has_value()) {
int32_t result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, result,
CheckDoubleInRange<int32_t>(isolate, era_year.value()));
partial.era_year = result;
}
}
return Just(partial);
}
struct CombinedRecord {
DateRecord date;
TimeRecord time;
std::optional<std::string> offset;
std::optional<temporal_rs::TimeZone> time_zone;
template <typename Ret>
Maybe<Ret> Regulate(Isolate* isolate,
temporal_rs::ArithmeticOverflow overflow);
};
template <>
Maybe<temporal_rs::PartialDate> CombinedRecord::Regulate(
Isolate* isolate, temporal_rs::ArithmeticOverflow overflow) {
DCHECK(!offset.has_value() && !time_zone.has_value());
DCHECK(!time.hour.has_value() && !time.minute.has_value() &&
!time.second.has_value() && !time.millisecond.has_value() &&
!time.microsecond.has_value() && !time.nanosecond.has_value());
return date.Regulate(isolate, overflow);
}
template <>
Maybe<temporal_rs::PartialTime> CombinedRecord::Regulate(
Isolate* isolate, temporal_rs::ArithmeticOverflow overflow) {
DCHECK(!offset.has_value() && !time_zone.has_value());
DCHECK(!date.year.has_value() && !date.month.has_value() &&
date.month_code == "" && !date.day.has_value() && date.era == "" &&
!date.era_year.has_value() &&
date.calendar == temporal_rs::AnyCalendarKind::Iso);
return time.Regulate(isolate, overflow);
}
template <>
Maybe<temporal_rs::PartialDateTime> CombinedRecord::Regulate(
Isolate* isolate, temporal_rs::ArithmeticOverflow overflow) {
DCHECK(!offset.has_value() && !time_zone.has_value());
temporal_rs::PartialDate regulated_date = kNullPartialDate;
ASSIGN_RETURN_ON_EXCEPTION(isolate, regulated_date,
date.Regulate(isolate, overflow));
temporal_rs::PartialTime regulated_time = kNullPartialTime;
ASSIGN_RETURN_ON_EXCEPTION(isolate, regulated_time,
time.Regulate(isolate, overflow));
return Just(temporal_rs::PartialDateTime{
.date = regulated_date,
.time = regulated_time,
});
}
template <>
Maybe<temporal_rs::PartialZonedDateTime> CombinedRecord::Regulate(
Isolate* isolate, temporal_rs::ArithmeticOverflow overflow) {
temporal_rs::PartialDate regulated_date = kNullPartialDate;
ASSIGN_RETURN_ON_EXCEPTION(isolate, regulated_date,
date.Regulate(isolate, overflow));
temporal_rs::PartialTime regulated_time = kNullPartialTime;
ASSIGN_RETURN_ON_EXCEPTION(isolate, regulated_time,
time.Regulate(isolate, overflow));
auto record = temporal_rs::PartialZonedDateTime{
.date = regulated_date,
.time = regulated_time,
.offset = std::nullopt,
.timezone = std::nullopt,
};
if (time_zone.has_value()) {
record.timezone = time_zone.value();
}
if (offset.has_value()) {
record.offset = offset.value();
}
return Just(record);
}
enum class CalendarFieldsFlag : uint8_t {
kDay = 1 << 0,
kMonthFields = 1 << 1,
kYearFields = 1 << 2,
kTimeFields = 1 << 3,
kOffset = 1 << 4,
kTimeZone = 1 << 5,
};
using CalendarFieldsFlags = base::Flags<CalendarFieldsFlag>;
DEFINE_OPERATORS_FOR_FLAGS(CalendarFieldsFlags)
constexpr CalendarFieldsFlags kAllDateFlags = CalendarFieldsFlag::kDay |
CalendarFieldsFlag::kMonthFields |
CalendarFieldsFlag::kYearFields;
enum class RequiredFields {
kNone,
kPartial,
kTimeZone,
};
template <typename OutType>
Maybe<bool> GetSingleCalendarField(
Isolate* isolate, DirectHandle<JSReceiver> fields,
DirectHandle<String> field_name, bool& any, OutType& output,
Maybe<OutType> (*conversion_func)(Isolate*, DirectHandle<Object>)) {
DirectHandle<Object> value;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, value, JSReceiver::GetProperty(isolate, fields, field_name));
if (!IsUndefined(*value)) {
any = true;
MOVE_RETURN_ON_EXCEPTION(isolate, output, conversion_func(isolate, value));
return Just(true);
}
return Just(false);
}
template <typename OutType>
Maybe<bool> GetSingleCalendarField(
Isolate* isolate, DirectHandle<JSReceiver> fields,
DirectHandle<String> field_name, bool& any, DirectHandle<OutType>& output,
MaybeDirectHandle<OutType> (*conversion_func)(Isolate*,
DirectHandle<Object>)) {
DirectHandle<Object> value;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, value, JSReceiver::GetProperty(isolate, fields, field_name));
if (!IsUndefined(*value)) {
any = true;
ASSIGN_RETURN_ON_EXCEPTION(isolate, output,
conversion_func(isolate, value));
return Just(true);
}
return Just(false);
}
#define SIMPLE_SETTER(resultField, field) resultField = field;
#define MOVING_SETTER(resultField, field) resultField = std::move(field);
#define STR_CONVERSION_SETTER(resultField, field) \
resultField = field->ToStdString();
#define SIMPLE_CONDITION(cond) cond
#define ERA_CONDITION(cond) calendarUsesEras && (cond)
#define NOOP_REQUIRED_CHECK
#define TIMEZONE_REQUIRED_CHECK \
if (!found && required_fields == RequiredFields::kTimeZone) { \
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(kTimeZoneMissing)); \
}
#define CALENDAR_FIELDS(V) \
V(kDay, day, result.date.day, double, ToPositiveIntegerWithTruncation, \
SIMPLE_CONDITION, SIMPLE_SETTER, NOOP_REQUIRED_CHECK, ASSIGN) \
V(kYearFields, era, result.date.era, DirectHandle<String>, Object::ToString, \
ERA_CONDITION, STR_CONVERSION_SETTER, NOOP_REQUIRED_CHECK, ASSIGN) \
V(kYearFields, eraYear, result.date.era_year, double, \
ToIntegerWithTruncation, ERA_CONDITION, SIMPLE_SETTER, \
NOOP_REQUIRED_CHECK, ASSIGN) \
V(kTimeFields, hour, result.time.hour, double, ToIntegerWithTruncation, \
SIMPLE_CONDITION, SIMPLE_SETTER, NOOP_REQUIRED_CHECK, ASSIGN) \
V(kTimeFields, microsecond, result.time.microsecond, double, \
ToIntegerWithTruncation, SIMPLE_CONDITION, SIMPLE_SETTER, \
NOOP_REQUIRED_CHECK, ASSIGN) \
V(kTimeFields, millisecond, result.time.millisecond, double, \
ToIntegerWithTruncation, SIMPLE_CONDITION, SIMPLE_SETTER, \
NOOP_REQUIRED_CHECK, ASSIGN) \
V(kTimeFields, minute, result.time.minute, double, ToIntegerWithTruncation, \
SIMPLE_CONDITION, SIMPLE_SETTER, NOOP_REQUIRED_CHECK, ASSIGN) \
V(kMonthFields, month, result.date.month, double, \
ToPositiveIntegerWithTruncation, SIMPLE_CONDITION, SIMPLE_SETTER, \
NOOP_REQUIRED_CHECK, ASSIGN) \
V(kMonthFields, monthCode, result.date.month_code, std::string, ToMonthCode, \
SIMPLE_CONDITION, MOVING_SETTER, NOOP_REQUIRED_CHECK, ASSIGN) \
V(kTimeFields, nanosecond, result.time.nanosecond, double, \
ToIntegerWithTruncation, SIMPLE_CONDITION, SIMPLE_SETTER, \
NOOP_REQUIRED_CHECK, ASSIGN) \
V(kOffset, offset, result.offset, std::string, ToOffsetString, \
SIMPLE_CONDITION, MOVING_SETTER, NOOP_REQUIRED_CHECK, ASSIGN) \
V(kTimeFields, second, result.time.second, double, ToIntegerWithTruncation, \
SIMPLE_CONDITION, SIMPLE_SETTER, NOOP_REQUIRED_CHECK, ASSIGN) \
V(kTimeZone, timeZone, result.time_zone, temporal_rs::TimeZone, \
ToTemporalTimeZoneIdentifier, SIMPLE_CONDITION, MOVING_SETTER, \
TIMEZONE_REQUIRED_CHECK, MOVE) \
V(kYearFields, year, result.date.year, double, ToIntegerWithTruncation, \
SIMPLE_CONDITION, SIMPLE_SETTER, NOOP_REQUIRED_CHECK, ASSIGN)
Maybe<CombinedRecord> PrepareCalendarFields(Isolate* isolate,
temporal_rs::AnyCalendarKind kind,
DirectHandle<JSReceiver> fields,
CalendarFieldsFlags which_fields,
RequiredFields required_fields) {
bool calendarUsesEras = kind != temporal_rs::AnyCalendarKind::Iso &&
kind != temporal_rs::AnyCalendarKind::Chinese &&
kind != temporal_rs::AnyCalendarKind::Dangi;
CombinedRecord result;
result.date.calendar = kind;
bool any = false;
#define GET_SINGLE_CALENDAR_FIELD(fieldsFlag, propertyName, resultField, Type, \
Conversion, CONDITION, SETTER, \
REQUIRED_CHECK, AssignOrMove) \
if (CONDITION(which_fields & CalendarFieldsFlag::fieldsFlag)) { \
Type propertyName; \
bool found = 0; \
AssignOrMove##_RETURN_ON_EXCEPTION( \
isolate, found, \
GetSingleCalendarField(isolate, fields, \
isolate->factory()->propertyName##_string(), \
any, propertyName, Conversion)); \
if (found) { \
SETTER(resultField, propertyName); \
} \
REQUIRED_CHECK \
}
CALENDAR_FIELDS(GET_SINGLE_CALENDAR_FIELD);
#undef GET_SINGLE_CALENDAR_FIELD
if (required_fields == RequiredFields::kPartial && !any) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(
"Must specify at least one calendar field."));
}
return Just(std::move(result));
}
#undef SIMPLE_SETTER
#undef MOVING_SETTER
#undef ANCHORED_SETTER_WITH_MOVE
#undef ANCHORED_SETTER_WITH_STR_CONVERSION
#undef SIMPLE_CONDITION
#undef ERA_CONDITION
#undef NOOP_REQUIRED_CHECK
#undef TIMEZONE_REQUIRED_CHECK
#undef CALENDAR_FIELDS
temporal_rs::TimeZone UTCTimeZoneInner() {
auto result = temporal_rs::TimeZone::utc_with_provider(TimeZoneProvider());
if (result.is_ok()) {
return std::move(result).ok().value();
}
return temporal_rs::TimeZone::zero();
}
temporal_rs::TimeZone UTCTimeZone() {
static temporal_rs::TimeZone UTC_TZ = UTCTimeZoneInner();
return UTC_TZ;
}
#ifdef V8_INTL_SUPPORT
temporal_rs::TimeZone SystemTimeZoneIdentifier() {
auto tz_str = Intl::DefaultTimeZone();
auto tz = temporal_rs::TimeZone::try_from_identifier_str_with_provider(
tz_str, TimeZoneProvider())
.ok();
if (tz.has_value()) {
return std::move(tz).value();
}
return UTCTimeZone();
}
#else
temporal_rs::TimeZone SystemTimeZoneIdentifier() { return UTCTimeZone(); }
#endif
int64_t SystemUTCEpochMilliseconds() {
double ms =
V8::GetCurrentPlatform()->CurrentClockTimeMillisecondsHighResolution();
auto min = static_cast<double>(std::numeric_limits<int64_t>::min());
auto max = static_cast<double>(std::numeric_limits<int64_t>::max());
double clamped = std::clamp(ms, min, max);
return static_cast<int64_t>(clamped);
}
Maybe<std::unique_ptr<temporal_rs::ZonedDateTime>> GenericTemporalNowISO(
Isolate* isolate, DirectHandle<Object> temporal_time_zone_like) {
temporal_rs::TimeZone time_zone;
if (IsUndefined(*temporal_time_zone_like)) {
time_zone = SystemTimeZoneIdentifier();
} else {
MOVE_RETURN_ON_EXCEPTION(isolate, time_zone,
temporal::ToTemporalTimeZoneIdentifier(
isolate, temporal_time_zone_like));
}
auto ms = SystemUTCEpochMilliseconds();
std::unique_ptr<temporal_rs::Instant> instant;
MOVE_RETURN_ON_EXCEPTION(
isolate, instant,
ExtractRustResult(isolate,
temporal_rs::Instant::from_epoch_milliseconds(ms)));
std::unique_ptr<temporal_rs::ZonedDateTime> zdt;
MOVE_RETURN_ON_EXCEPTION(
isolate, zdt,
ExtractRustResult(isolate, instant->to_zoned_date_time_iso_with_provider(
time_zone, TimeZoneProvider())));
return Just(std::move(zdt));
}
template <typename DstType, typename SrcType>
MaybeDirectHandle<DstType> GenericToTemporalMethod(
Isolate* isolate, DirectHandle<SrcType> val,
TemporalAllocatedResult<typename DstType::RustType> (
SrcType::RustType::*method)() const) {
return ConstructRustWrappingType<DstType>(isolate,
(val->wrapped_rust().*method)());
}
template <typename DstType, typename SrcType>
MaybeDirectHandle<DstType> GenericToTemporalMethod(
Isolate* isolate, DirectHandle<SrcType> val,
std::unique_ptr<typename DstType::RustType> (SrcType::RustType::*method)()
const) {
return ConstructRustWrappingType<DstType>(isolate,
(val->wrapped_rust().*method)());
}
Maybe<std::unique_ptr<temporal_rs::Duration>> ToTemporalDurationRust(
Isolate* isolate, DirectHandle<Object> item, const char* method_name) {
if (IsJSTemporalDuration(*item)) {
auto duration = Cast<JSTemporalDuration>(item);
return Just(duration->duration()->raw()->clone());
}
if (!IsJSReceiver(*item)) {
if (!IsString(*item)) {
THROW_NEW_ERROR(isolate,
NEW_TEMPORAL_TYPE_ERROR(
"Duration argument must be Duration or string."));
}
DirectHandle<String> str = Cast<String>(item);
DirectHandle<JSTemporalInstant> result;
auto rust_result =
HandleStringEncodings<TemporalAllocatedResult<temporal_rs::Duration>>(
isolate, str,
[](std::string_view view)
-> TemporalAllocatedResult<temporal_rs::Duration> {
return temporal_rs::Duration::from_utf8(view);
},
[](std::u16string_view view)
-> TemporalAllocatedResult<temporal_rs::Duration> {
return temporal_rs::Duration::from_utf16(view);
});
return ExtractRustResult(isolate, std::move(rust_result));
}
temporal_rs::PartialDuration partial;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, partial,
temporal::ToTemporalPartialDurationRecord(isolate, item));
return ExtractRustResult(
isolate, temporal_rs::Duration::from_partial_duration(partial));
}
MaybeDirectHandle<JSTemporalDuration> ToTemporalDuration(
Isolate* isolate, DirectHandle<Object> item, const char* method_name) {
std::unique_ptr<temporal_rs::Duration> duration;
MOVE_RETURN_ON_EXCEPTION(isolate, duration,
ToTemporalDurationRust(isolate, item, method_name));
return ConstructRustWrappingType<JSTemporalDuration>(isolate,
std::move(duration));
}
Maybe<DurationRecord> ToTemporalDurationAsRecord(Isolate* isolate,
DirectHandle<Object> item,
const char* method_name) {
std::unique_ptr<temporal_rs::Duration> duration;
MOVE_RETURN_ON_EXCEPTION(isolate, duration,
ToTemporalDurationRust(isolate, item, method_name));
return Just(temporal::DurationRecord{
.years = static_cast<double>(duration->years()),
.months = static_cast<double>(duration->months()),
.weeks = static_cast<double>(duration->weeks()),
.time_duration = {
.days = static_cast<double>(duration->days()),
.hours = static_cast<double>(duration->hours()),
.minutes = static_cast<double>(duration->minutes()),
.seconds = static_cast<double>(duration->seconds()),
.milliseconds = static_cast<double>(duration->milliseconds()),
.microseconds = static_cast<double>(duration->microseconds()),
.nanoseconds = static_cast<double>(duration->nanoseconds()),
}});
}
MaybeDirectHandle<JSTemporalInstant> ToTemporalInstant(
Isolate* isolate, DirectHandle<Object> item, const char* method_name) {
if (IsJSTemporalInstant(*item)) {
auto instant = Cast<JSTemporalInstant>(item);
return ConstructRustWrappingType<JSTemporalInstant>(
isolate, instant->instant()->raw()->clone());
} else if (IsJSTemporalZonedDateTime(*item)) {
auto zdt = Cast<JSTemporalZonedDateTime>(item);
auto ns = zdt->zoned_date_time()->raw()->epoch_nanoseconds();
return ConstructRustWrappingType<JSTemporalInstant>(
isolate, temporal_rs::Instant::try_new(ns));
}
DirectHandle<Object> item_prim;
if (IsJSReceiver(*item)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, item_prim,
JSReceiver::ToPrimitive(isolate, Cast<JSReceiver>(item),
ToPrimitiveHint::kString));
} else {
item_prim = item;
}
if (!IsString(*item_prim)) {
THROW_NEW_ERROR(
isolate,
NEW_TEMPORAL_TYPE_ERROR("Instant argument must be Instant or string."));
}
DirectHandle<String> item_string = Cast<String>(item_prim);
auto rust_result =
HandleStringEncodings<TemporalAllocatedResult<temporal_rs::Instant>>(
isolate, item_string,
[](std::string_view view)
-> TemporalAllocatedResult<temporal_rs::Instant> {
return temporal_rs::Instant::from_utf8(view);
},
[](std::u16string_view view)
-> TemporalAllocatedResult<temporal_rs::Instant> {
return temporal_rs::Instant::from_utf16(view);
});
return ConstructRustWrappingType<JSTemporalInstant>(isolate,
std::move(rust_result));
}
#define READ_AND_DISCARD_OVERFLOW(options_obj) \
RETURN_ON_EXCEPTION(isolate, temporal::ToTemporalOverflowHandleUndefined( \
isolate, options_obj, method_name))
MaybeDirectHandle<JSTemporalPlainTime> ToTemporalTime(
Isolate* isolate, DirectHandle<Object> item,
MaybeDirectHandle<Object> options_obj, const char* method_name) {
if (!IsHeapObject(*item)) {
THROW_NEW_ERROR(
isolate,
NEW_TEMPORAL_TYPE_ERROR("Time-like argument must be object or string"));
}
InstanceType instance_type =
Cast<HeapObject>(*item)->map(isolate)->instance_type();
if (InstanceTypeChecker::IsJSReceiver(instance_type)) {
auto partial = temporal::kNullPartialTime;
if (InstanceTypeChecker::IsJSTemporalPlainTime(instance_type)) {
auto cast = Cast<JSTemporalPlainTime>(item);
READ_AND_DISCARD_OVERFLOW(options_obj);
return ConstructRustWrappingType<JSTemporalPlainTime>(
isolate, cast->time()->raw()->clone());
} else if (InstanceTypeChecker::IsJSTemporalPlainDateTime(instance_type)) {
partial = GetPartialTime(Cast<JSTemporalPlainDateTime>(item));
} else if (InstanceTypeChecker::IsJSTemporalZonedDateTime(instance_type)) {
partial = GetPartialTime(Cast<JSTemporalZonedDateTime>(item));
} else {
DirectHandle<JSReceiver> item_recvr = Cast<JSReceiver>(item);
temporal::TimeRecord record;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, record,
temporal::ToTemporalTimeRecord(isolate, item_recvr, method_name));
temporal_rs::ArithmeticOverflow overflow;
ASSIGN_RETURN_ON_EXCEPTION(isolate, overflow,
temporal::ToTemporalOverflowHandleUndefined(
isolate, options_obj, method_name));
ASSIGN_RETURN_ON_EXCEPTION(isolate, partial,
record.Regulate(isolate, overflow));
return ConstructRustWrappingType<JSTemporalPlainTime>(
isolate, temporal_rs::PlainTime::from_partial(partial, overflow));
}
temporal_rs::ArithmeticOverflow overflow;
ASSIGN_RETURN_ON_EXCEPTION(isolate, overflow,
temporal::ToTemporalOverflowHandleUndefined(
isolate, options_obj, method_name));
return ConstructRustWrappingType<JSTemporalPlainTime>(
isolate, temporal_rs::PlainTime::from_partial(partial, overflow));
} else {
if (!InstanceTypeChecker::IsString(instance_type)) {
THROW_NEW_ERROR(isolate,
NEW_TEMPORAL_TYPE_ERROR(
"Time-like argument must be object or string"));
}
DirectHandle<String> str = Cast<String>(item);
auto rust_result =
HandleStringEncodings<TemporalAllocatedResult<temporal_rs::PlainTime>>(
isolate, str,
[](std::string_view view)
-> TemporalAllocatedResult<temporal_rs::PlainTime> {
return temporal_rs::PlainTime::from_utf8(view);
},
[](std::u16string_view view)
-> TemporalAllocatedResult<temporal_rs::PlainTime> {
return temporal_rs::PlainTime::from_utf16(view);
});
std::unique_ptr<temporal_rs::PlainTime> time;
MOVE_RETURN_ON_EXCEPTION(
isolate, time, ExtractRustResult(isolate, std::move(rust_result)));
READ_AND_DISCARD_OVERFLOW(options_obj);
return ConstructRustWrappingType<JSTemporalPlainTime>(isolate,
std::move(time));
}
}
Maybe<const temporal_rs::PlainTime*> ToTimeRecordOrMidnight(
Isolate* isolate, DirectHandle<Object> item,
DirectHandle<JSTemporalPlainTime>& output_time, const char* method_name) {
if (IsUndefined(*item)) {
return Just(static_cast<const temporal_rs::PlainTime*>(nullptr));
}
ASSIGN_RETURN_ON_EXCEPTION(isolate, output_time,
ToTemporalTime(isolate, item, {}, method_name));
return Just(
static_cast<const temporal_rs::PlainTime*>(output_time->time()->raw()));
}
MaybeDirectHandle<JSTemporalPlainDate> ToTemporalDate(
Isolate* isolate, DirectHandle<Object> item,
MaybeDirectHandle<Object> options_obj, const char* method_name) {
if (!IsHeapObject(*item)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(
"Date argument must be object or string."));
}
InstanceType instance_type =
Cast<HeapObject>(*item)->map(isolate)->instance_type();
if (InstanceTypeChecker::IsJSReceiver(instance_type)) {
auto partial = temporal::kNullPartialDate;
if (InstanceTypeChecker::IsJSTemporalPlainDate(instance_type)) {
auto cast = Cast<JSTemporalPlainDate>(item);
READ_AND_DISCARD_OVERFLOW(options_obj);
return ConstructRustWrappingType<JSTemporalPlainDate>(
isolate, cast->date()->raw()->clone());
} else if (InstanceTypeChecker::IsJSTemporalZonedDateTime(instance_type)) {
partial = GetPartialDate(Cast<JSTemporalZonedDateTime>(item));
} else if (InstanceTypeChecker::IsJSTemporalPlainDateTime(instance_type)) {
partial = GetPartialDate(Cast<JSTemporalPlainDateTime>(item));
} else {
temporal_rs::AnyCalendarKind kind = temporal_rs::AnyCalendarKind::Iso;
DirectHandle<JSReceiver> item_recvr = Cast<JSReceiver>(item);
ASSIGN_RETURN_ON_EXCEPTION(
isolate, kind,
temporal::GetTemporalCalendarIdentifierWithISODefault(isolate,
item_recvr));
CombinedRecord fields;
MOVE_RETURN_ON_EXCEPTION(
isolate, fields,
PrepareCalendarFields(isolate, kind, item_recvr, kAllDateFlags,
RequiredFields::kNone));
temporal_rs::ArithmeticOverflow overflow;
ASSIGN_RETURN_ON_EXCEPTION(isolate, overflow,
temporal::ToTemporalOverflowHandleUndefined(
isolate, options_obj, method_name));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, partial,
fields.Regulate<temporal_rs::PartialDate>(isolate, overflow));
return ConstructRustWrappingType<JSTemporalPlainDate>(
isolate, temporal_rs::PlainDate::from_partial(partial, overflow));
}
READ_AND_DISCARD_OVERFLOW(options_obj);
return ConstructRustWrappingType<JSTemporalPlainDate>(
isolate, temporal_rs::PlainDate::from_partial(partial, std::nullopt));
} else {
if (!InstanceTypeChecker::IsString(instance_type)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(
"Date argument must be object or string."));
}
DirectHandle<String> str = Cast<String>(item);
std::unique_ptr<temporal_rs::ParsedDate> date;
auto rust_result =
HandleStringEncodings<TemporalAllocatedResult<temporal_rs::ParsedDate>>(
isolate, str,
[](std::string_view view)
-> TemporalAllocatedResult<temporal_rs::ParsedDate> {
return temporal_rs::ParsedDate::from_utf8(view);
},
[](std::u16string_view view)
-> TemporalAllocatedResult<temporal_rs::ParsedDate> {
return temporal_rs::ParsedDate::from_utf16(view);
});
MOVE_RETURN_ON_EXCEPTION(
isolate, date, ExtractRustResult(isolate, std::move(rust_result)));
READ_AND_DISCARD_OVERFLOW(options_obj);
return ConstructRustWrappingType<JSTemporalPlainDate>(
isolate, temporal_rs::PlainDate::from_parsed(*date));
}
}
MaybeDirectHandle<JSTemporalPlainDateTime> ToTemporalDateTime(
Isolate* isolate, DirectHandle<Object> item,
MaybeDirectHandle<Object> options_obj, const char* method_name) {
if (!IsHeapObject(*item)) {
THROW_NEW_ERROR(
isolate,
NEW_TEMPORAL_TYPE_ERROR("DateTime argument must be object or string."));
}
InstanceType instance_type =
Cast<HeapObject>(*item)->map(isolate)->instance_type();
if (InstanceTypeChecker::IsJSReceiver(instance_type)) {
auto partial = temporal::kNullPartialDateTime;
if (InstanceTypeChecker::IsJSTemporalPlainDateTime(instance_type)) {
auto cast = Cast<JSTemporalPlainDateTime>(item);
READ_AND_DISCARD_OVERFLOW(options_obj);
return ConstructRustWrappingType<JSTemporalPlainDateTime>(
isolate, cast->date_time()->raw()->clone());
} else if (InstanceTypeChecker::IsJSTemporalZonedDateTime(instance_type)) {
partial = GetPartialDateTime(Cast<JSTemporalZonedDateTime>(item));
} else if (InstanceTypeChecker::IsJSTemporalPlainDate(instance_type)) {
partial = GetPartialDateTime(Cast<JSTemporalPlainDate>(item));
} else {
temporal_rs::AnyCalendarKind kind = temporal_rs::AnyCalendarKind::Iso;
DirectHandle<JSReceiver> item_recvr = Cast<JSReceiver>(item);
ASSIGN_RETURN_ON_EXCEPTION(
isolate, kind,
temporal::GetTemporalCalendarIdentifierWithISODefault(isolate,
item_recvr));
CombinedRecord fields;
using enum CalendarFieldsFlag;
MOVE_RETURN_ON_EXCEPTION(
isolate, fields,
PrepareCalendarFields(isolate, kind, item_recvr,
kAllDateFlags | kTimeFields,
RequiredFields::kNone));
temporal_rs::ArithmeticOverflow overflow;
ASSIGN_RETURN_ON_EXCEPTION(isolate, overflow,
temporal::ToTemporalOverflowHandleUndefined(
isolate, options_obj, method_name));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, partial,
fields.Regulate<temporal_rs::PartialDateTime>(isolate, overflow));
return ConstructRustWrappingType<JSTemporalPlainDateTime>(
isolate, temporal_rs::PlainDateTime::from_partial(partial, overflow));
}
temporal_rs::ArithmeticOverflow overflow;
ASSIGN_RETURN_ON_EXCEPTION(isolate, overflow,
temporal::ToTemporalOverflowHandleUndefined(
isolate, options_obj, method_name));
return ConstructRustWrappingType<JSTemporalPlainDateTime>(
isolate, temporal_rs::PlainDateTime::from_partial(partial, overflow));
} else {
if (!InstanceTypeChecker::IsString(instance_type)) {
THROW_NEW_ERROR(isolate,
NEW_TEMPORAL_TYPE_ERROR(
"DateTime argument must be object or string."));
}
DirectHandle<String> str = Cast<String>(item);
std::unique_ptr<temporal_rs::ParsedDateTime> date;
auto rust_result = HandleStringEncodings<
TemporalAllocatedResult<temporal_rs::ParsedDateTime>>(
isolate, str,
[](std::string_view view)
-> TemporalAllocatedResult<temporal_rs::ParsedDateTime> {
return temporal_rs::ParsedDateTime::from_utf8(view);
},
[](std::u16string_view view)
-> TemporalAllocatedResult<temporal_rs::ParsedDateTime> {
return temporal_rs::ParsedDateTime::from_utf16(view);
});
MOVE_RETURN_ON_EXCEPTION(
isolate, date, ExtractRustResult(isolate, std::move(rust_result)));
READ_AND_DISCARD_OVERFLOW(options_obj);
return ConstructRustWrappingType<JSTemporalPlainDateTime>(
isolate, temporal_rs::PlainDateTime::from_parsed(*date));
}
}
MaybeDirectHandle<JSTemporalPlainYearMonth> ToTemporalYearMonth(
Isolate* isolate, DirectHandle<Object> item,
MaybeDirectHandle<Object> options_obj, const char* method_name) {
if (!IsHeapObject(*item)) {
THROW_NEW_ERROR(isolate,
NEW_TEMPORAL_TYPE_ERROR(
"YearMonth argument must be object or string."));
}
InstanceType instance_type =
Cast<HeapObject>(*item)->map(isolate)->instance_type();
if (InstanceTypeChecker::IsJSReceiver(instance_type)) {
if (InstanceTypeChecker::IsJSTemporalPlainYearMonth(instance_type)) {
auto cast = Cast<JSTemporalPlainYearMonth>(item);
READ_AND_DISCARD_OVERFLOW(options_obj);
return ConstructRustWrappingType<JSTemporalPlainYearMonth>(
isolate, cast->year_month()->raw()->clone());
} else {
DirectHandle<JSReceiver> item_recvr = Cast<JSReceiver>(item);
temporal_rs::AnyCalendarKind kind;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, kind,
temporal::GetTemporalCalendarIdentifierWithISODefault(isolate,
item_recvr));
CombinedRecord fields;
using enum CalendarFieldsFlag;
MOVE_RETURN_ON_EXCEPTION(isolate, fields,
PrepareCalendarFields(isolate, kind, item_recvr,
kYearFields | kMonthFields,
RequiredFields::kNone));
temporal_rs::ArithmeticOverflow overflow;
ASSIGN_RETURN_ON_EXCEPTION(isolate, overflow,
temporal::ToTemporalOverflowHandleUndefined(
isolate, options_obj, method_name));
temporal_rs::PartialDate partial = temporal::kNullPartialDate;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, partial,
fields.Regulate<temporal_rs::PartialDate>(isolate, overflow));
return ConstructRustWrappingType<JSTemporalPlainYearMonth>(
isolate,
temporal_rs::PlainYearMonth::from_partial(partial, overflow));
}
} else {
if (!InstanceTypeChecker::IsString(instance_type)) {
THROW_NEW_ERROR(isolate,
NEW_TEMPORAL_TYPE_ERROR(
"YearMonth argument must be object or string."));
}
DirectHandle<String> str = Cast<String>(item);
std::unique_ptr<temporal_rs::ParsedDate> date;
auto rust_result =
HandleStringEncodings<TemporalAllocatedResult<temporal_rs::ParsedDate>>(
isolate, str,
[](std::string_view view)
-> TemporalAllocatedResult<temporal_rs::ParsedDate> {
return temporal_rs::ParsedDate::year_month_from_utf8(view);
},
[](std::u16string_view view)
-> TemporalAllocatedResult<temporal_rs::ParsedDate> {
return temporal_rs::ParsedDate::year_month_from_utf16(view);
});
MOVE_RETURN_ON_EXCEPTION(
isolate, date, ExtractRustResult(isolate, std::move(rust_result)));
READ_AND_DISCARD_OVERFLOW(options_obj);
return ConstructRustWrappingType<JSTemporalPlainYearMonth>(
isolate, temporal_rs::PlainYearMonth::from_parsed(*date));
}
}
struct ZDTOptions {
temporal_rs::Disambiguation disambiguation;
temporal_rs::OffsetDisambiguation offset_option;
temporal_rs::ArithmeticOverflow overflow;
};
Maybe<ZDTOptions> GetZDTOptions(Isolate* isolate,
MaybeDirectHandle<Object> maybe_options_obj,
const char* method_name) {
ZDTOptions options =
ZDTOptions{.disambiguation = temporal_rs::Disambiguation::Compatible,
.offset_option = temporal_rs::OffsetDisambiguation::Reject,
.overflow = temporal_rs::ArithmeticOverflow::Constrain};
DirectHandle<Object> options_obj;
if (!maybe_options_obj.ToHandle(&options_obj)) {
return Just(options);
}
ASSIGN_RETURN_ON_EXCEPTION(
isolate, options.disambiguation,
temporal::GetTemporalDisambiguationOptionHandleUndefined(
isolate, options_obj, method_name));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, options.offset_option,
temporal::GetTemporalOffsetOptionHandleUndefined(
isolate, options_obj, temporal_rs::OffsetDisambiguation::Reject,
method_name));
ASSIGN_RETURN_ON_EXCEPTION(isolate, options.overflow,
temporal::ToTemporalOverflowHandleUndefined(
isolate, options_obj, method_name));
return Just(options);
}
MaybeDirectHandle<JSTemporalZonedDateTime> ToTemporalZonedDateTime(
Isolate* isolate, DirectHandle<Object> item,
MaybeDirectHandle<Object> options_obj, const char* method_name) {
if (!IsHeapObject(*item)) {
THROW_NEW_ERROR(isolate,
NEW_TEMPORAL_TYPE_ERROR(
"ZonedDateTime argument must be object or string."));
}
InstanceType instance_type =
Cast<HeapObject>(*item)->map(isolate)->instance_type();
if (InstanceTypeChecker::IsJSReceiver(instance_type)) {
if (InstanceTypeChecker::IsJSTemporalZonedDateTime(instance_type)) {
auto cast = Cast<JSTemporalZonedDateTime>(item);
ZDTOptions options;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, options, GetZDTOptions(isolate, options_obj, method_name));
return ConstructRustWrappingType<JSTemporalZonedDateTime>(
isolate, cast->zoned_date_time()->raw()->clone());
} else {
temporal_rs::AnyCalendarKind kind = temporal_rs::AnyCalendarKind::Iso;
DirectHandle<JSReceiver> item_recvr = Cast<JSReceiver>(item);
ASSIGN_RETURN_ON_EXCEPTION(
isolate, kind,
temporal::GetTemporalCalendarIdentifierWithISODefault(isolate,
item_recvr));
CombinedRecord fields;
using enum CalendarFieldsFlag;
MOVE_RETURN_ON_EXCEPTION(
isolate, fields,
PrepareCalendarFields(
isolate, kind, item_recvr,
kAllDateFlags | kTimeFields | kOffset | kTimeZone,
RequiredFields::kTimeZone));
ZDTOptions options;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, options, GetZDTOptions(isolate, options_obj, method_name));
temporal_rs::PartialZonedDateTime partial = kNullPartialZonedDateTime;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, partial,
fields.Regulate<temporal_rs::PartialZonedDateTime>(isolate,
options.overflow));
return ConstructRustWrappingType<JSTemporalZonedDateTime>(
isolate, temporal_rs::ZonedDateTime::from_partial_with_provider(
partial, options.overflow, options.disambiguation,
options.offset_option, TimeZoneProvider()));
}
} else {
if (!InstanceTypeChecker::IsString(instance_type)) {
THROW_NEW_ERROR(isolate,
NEW_TEMPORAL_TYPE_ERROR(
"ZonedDateTime argument must be object or string."));
}
DirectHandle<String> str = Cast<String>(item);
std::unique_ptr<temporal_rs::ParsedZonedDateTime> parsed;
auto rust_result = HandleStringEncodings<
TemporalAllocatedResult<temporal_rs::ParsedZonedDateTime>>(
isolate, str,
[](std::string_view view)
-> TemporalAllocatedResult<temporal_rs::ParsedZonedDateTime> {
return temporal_rs::ParsedZonedDateTime::from_utf8_with_provider(
view, TimeZoneProvider());
},
[](std::u16string_view view)
-> TemporalAllocatedResult<temporal_rs::ParsedZonedDateTime> {
return temporal_rs::ParsedZonedDateTime::from_utf16_with_provider(
view, TimeZoneProvider());
});
MOVE_RETURN_ON_EXCEPTION(
isolate, parsed, ExtractRustResult(isolate, std::move(rust_result)));
ZDTOptions options;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, options, GetZDTOptions(isolate, options_obj, method_name));
return ConstructRustWrappingType<JSTemporalZonedDateTime>(
isolate, temporal_rs::ZonedDateTime::from_parsed_with_provider(
*parsed, options.disambiguation, options.offset_option,
TimeZoneProvider()));
}
}
MaybeDirectHandle<JSTemporalPlainMonthDay> ToTemporalMonthDay(
Isolate* isolate, DirectHandle<Object> item,
MaybeDirectHandle<Object> options_obj, const char* method_name) {
if (!IsHeapObject(*item)) {
THROW_NEW_ERROR(
isolate,
NEW_TEMPORAL_TYPE_ERROR("MonthDay argument must be object or string."));
}
InstanceType instance_type =
Cast<HeapObject>(*item)->map(isolate)->instance_type();
if (InstanceTypeChecker::IsJSReceiver(instance_type)) {
if (InstanceTypeChecker::IsJSTemporalPlainMonthDay(instance_type)) {
auto cast = Cast<JSTemporalPlainMonthDay>(item);
READ_AND_DISCARD_OVERFLOW(options_obj);
return ConstructRustWrappingType<JSTemporalPlainMonthDay>(
isolate, cast->month_day()->raw()->clone());
} else {
DirectHandle<JSReceiver> item_recvr = Cast<JSReceiver>(item);
temporal_rs::AnyCalendarKind kind;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, kind,
temporal::GetTemporalCalendarIdentifierWithISODefault(isolate,
item_recvr));
CombinedRecord fields;
using enum CalendarFieldsFlag;
MOVE_RETURN_ON_EXCEPTION(
isolate, fields,
PrepareCalendarFields(isolate, kind, item_recvr,
kYearFields | kMonthFields | kDay,
RequiredFields::kNone));
temporal_rs::ArithmeticOverflow overflow;
ASSIGN_RETURN_ON_EXCEPTION(isolate, overflow,
temporal::ToTemporalOverflowHandleUndefined(
isolate, options_obj, method_name));
temporal_rs::PartialDate partial = temporal::kNullPartialDate;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, partial,
fields.Regulate<temporal_rs::PartialDate>(isolate, overflow));
return ConstructRustWrappingType<JSTemporalPlainMonthDay>(
isolate, temporal_rs::PlainMonthDay::from_partial(partial, overflow));
}
} else {
if (!InstanceTypeChecker::IsString(instance_type)) {
THROW_NEW_ERROR(isolate,
NEW_TEMPORAL_TYPE_ERROR(
"MonthDay argument must be object or string."));
}
DirectHandle<String> str = Cast<String>(item);
DirectHandle<JSTemporalPlainDate> result;
std::unique_ptr<temporal_rs::ParsedDate> date;
auto rust_result =
HandleStringEncodings<TemporalAllocatedResult<temporal_rs::ParsedDate>>(
isolate, str,
[](std::string_view view)
-> TemporalAllocatedResult<temporal_rs::ParsedDate> {
return temporal_rs::ParsedDate::month_day_from_utf8(view);
},
[](std::u16string_view view)
-> TemporalAllocatedResult<temporal_rs::ParsedDate> {
return temporal_rs::ParsedDate::month_day_from_utf16(view);
});
MOVE_RETURN_ON_EXCEPTION(
isolate, date, ExtractRustResult(isolate, std::move(rust_result)));
READ_AND_DISCARD_OVERFLOW(options_obj);
return ConstructRustWrappingType<JSTemporalPlainMonthDay>(
isolate, temporal_rs::PlainMonthDay::from_parsed(*date));
}
}
template <typename JSType>
MaybeDirectHandle<JSType> ToTemporalGeneric(
Isolate* isolate, DirectHandle<Object> item,
const char* method_name);
#define DEFINE_TO_TEMPORAL_GENERIC(Type) \
template <> \
MaybeDirectHandle<JSTemporalPlain##Type> \
ToTemporalGeneric<JSTemporalPlain##Type>( \
Isolate * isolate, DirectHandle<Object> item, const char* method_name) { \
return ToTemporal##Type(isolate, item, {}, method_name); \
}
DEFINE_TO_TEMPORAL_GENERIC(Time)
DEFINE_TO_TEMPORAL_GENERIC(Date)
DEFINE_TO_TEMPORAL_GENERIC(DateTime)
DEFINE_TO_TEMPORAL_GENERIC(YearMonth)
DEFINE_TO_TEMPORAL_GENERIC(MonthDay)
#undef DEFINE_TO_TEMPORAL_GENERIC
template <>
MaybeDirectHandle<JSTemporalInstant> ToTemporalGeneric<JSTemporalInstant>(
Isolate* isolate, DirectHandle<Object> item,
const char* method_name) {
return ToTemporalInstant(isolate, item, method_name);
}
template <>
MaybeDirectHandle<JSTemporalZonedDateTime>
ToTemporalGeneric<JSTemporalZonedDateTime>(
Isolate* isolate, DirectHandle<Object> item,
const char* method_name) {
return ToTemporalZonedDateTime(isolate, item, {}, method_name);
}
class RelativeTo {
public:
RelativeTo()
: date_(std::nullopt),
zoned_(std::nullopt),
date_ptr_(nullptr),
zoned_ptr_(nullptr) {}
static RelativeTo Owned(std::unique_ptr<temporal_rs::PlainDate>&& val) {
RelativeTo ret;
ret.date_ = std::move(val);
ret.date_ptr_ = ret.date_.value().get();
return ret;
}
static RelativeTo Owned(std::unique_ptr<temporal_rs::ZonedDateTime>&& val) {
RelativeTo ret;
ret.zoned_ = std::move(val);
ret.zoned_ptr_ = ret.zoned_.value().get();
return ret;
}
static RelativeTo Owned(temporal_rs::OwnedRelativeTo&& owned) {
if (owned.date) {
return Owned(std::move(owned.date));
} else if (owned.zoned) {
return Owned(std::move(owned.zoned));
}
return RelativeTo();
}
static RelativeTo Borrowed(temporal_rs::PlainDate const* val) {
RelativeTo ret;
ret.date_ptr_ = val;
return ret;
}
static RelativeTo Borrowed(temporal_rs::ZonedDateTime const* val) {
RelativeTo ret;
ret.zoned_ptr_ = val;
return ret;
}
temporal_rs::RelativeTo ToRust() const {
return temporal_rs::RelativeTo{
.date = date_ptr_,
.zoned = zoned_ptr_,
};
}
private:
std::optional<std::unique_ptr<temporal_rs::PlainDate>> date_;
std::optional<std::unique_ptr<temporal_rs::ZonedDateTime>> zoned_;
temporal_rs::PlainDate const* date_ptr_;
temporal_rs::ZonedDateTime const* zoned_ptr_;
};
Maybe<RelativeTo> GetTemporalRelativeToOptionHandleUndefined(
Isolate* isolate, DirectHandle<Object> options) {
RelativeTo ret;
if (IsUndefined(*options)) {
return Just(RelativeTo());
}
auto relativeto_ident = isolate->factory()->relativeTo_string();
if (!IsJSReceiver(*options)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR_WITH_ARG(
kOptionMustBeObject, relativeto_ident));
}
DirectHandle<Object> value;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, value,
JSReceiver::GetProperty(isolate, Cast<JSReceiver>(options),
relativeto_ident));
if (IsUndefined(*value)) {
return Just(RelativeTo());
}
if (!IsHeapObject(*value)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(
"relativeTo must be object or string."));
}
InstanceType instance_type =
Cast<HeapObject>(*value)->map(isolate)->instance_type();
if (InstanceTypeChecker::IsJSReceiver(instance_type)) {
if (InstanceTypeChecker::IsJSTemporalZonedDateTime(instance_type)) {
return Just(RelativeTo::Borrowed(
Cast<JSTemporalZonedDateTime>(value)->zoned_date_time()->raw()));
}
if (InstanceTypeChecker::IsJSTemporalPlainDate(instance_type)) {
return Just(RelativeTo::Borrowed(
Cast<JSTemporalPlainDate>(value)->date()->raw()));
}
if (InstanceTypeChecker::IsJSTemporalPlainDateTime(instance_type)) {
auto date_record = GetPartialDate(Cast<JSTemporalPlainDateTime>(value));
std::unique_ptr<temporal_rs::PlainDate> plain_date = nullptr;
MOVE_RETURN_ON_EXCEPTION(
isolate, plain_date,
ExtractRustResult(isolate, temporal_rs::PlainDate::from_partial(
date_record, std::nullopt)));
return Just(RelativeTo::Owned(std::move(plain_date)));
}
temporal_rs::AnyCalendarKind kind = temporal_rs::AnyCalendarKind::Iso;
auto value_recvr = Cast<JSReceiver>(value);
ASSIGN_RETURN_ON_EXCEPTION(
isolate, kind,
temporal::GetTemporalCalendarIdentifierWithISODefault(isolate,
value_recvr));
CombinedRecord fields;
using enum CalendarFieldsFlag;
MOVE_RETURN_ON_EXCEPTION(
isolate, fields,
PrepareCalendarFields(isolate, kind, value_recvr,
kAllDateFlags | kTimeFields | kOffset | kTimeZone,
RequiredFields::kNone));
auto partial = kNullPartialZonedDateTime;
auto overflow = temporal_rs::ArithmeticOverflow::Constrain;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, partial,
fields.Regulate<temporal_rs::PartialZonedDateTime>(isolate, overflow));
if (!partial.timezone) {
std::unique_ptr<temporal_rs::PlainDate> plain_relative_to;
MOVE_RETURN_ON_EXCEPTION(
isolate, plain_relative_to,
ExtractRustResult(isolate, temporal_rs::PlainDate::from_partial(
partial.date, overflow)));
return Just(RelativeTo::Owned(std::move(plain_relative_to)));
}
std::unique_ptr<temporal_rs::ZonedDateTime> zoned_relative_to;
MOVE_RETURN_ON_EXCEPTION(
isolate, zoned_relative_to,
ExtractRustResult(
isolate,
temporal_rs::ZonedDateTime::from_partial_with_provider(
partial, overflow, temporal_rs::Disambiguation::Compatible,
temporal_rs::OffsetDisambiguation::Reject,
TimeZoneProvider())));
return Just(RelativeTo::Owned(std::move(zoned_relative_to)));
} else {
if (!InstanceTypeChecker::IsString(instance_type)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(
"relativeTo must be object or string."));
}
DirectHandle<String> str = Cast<String>(value);
temporal_rs::OwnedRelativeTo relative_to;
auto rust_result =
HandleStringEncodings<TemporalResult<temporal_rs::OwnedRelativeTo>>(
isolate, str,
[](std::string_view view)
-> TemporalResult<temporal_rs::OwnedRelativeTo> {
return temporal_rs::OwnedRelativeTo::from_utf8_with_provider(
view, TimeZoneProvider());
},
[](std::u16string_view view)
-> TemporalResult<temporal_rs::OwnedRelativeTo> {
return temporal_rs::OwnedRelativeTo::from_utf16_with_provider(
view, TimeZoneProvider());
});
MOVE_RETURN_ON_EXCEPTION(
isolate, relative_to,
ExtractRustResult(isolate, std::move(rust_result)));
return Just(RelativeTo::Owned(std::move(relative_to)));
}
}
template <typename RustType, typename... ProviderArg>
using DifferenceOperation = TemporalAllocatedResult<temporal_rs::Duration> (
RustType::*)(const RustType&, temporal_rs::DifferenceSettings,
const ProviderArg&...) const;
template <typename JSType, typename... ProviderArg>
MaybeDirectHandle<JSTemporalDuration> GenericDifferenceTemporal(
Isolate* isolate,
DifferenceOperation<typename JSType::RustType, ProviderArg...> operation,
UnitGroup group, Unit fallback_smallest_unit, DirectHandle<JSType> handle,
DirectHandle<Object> other_obj, DirectHandle<Object> options,
const char* method_name, const ProviderArg&... provider) {
DirectHandle<JSType> other;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, other,
temporal::ToTemporalGeneric<JSType>(isolate, other_obj, method_name));
auto settings = temporal_rs::DifferenceSettings{.largest_unit = std::nullopt,
.smallest_unit = std::nullopt,
.rounding_mode = std::nullopt,
.increment = std::nullopt};
auto& this_rust = handle->wrapped_rust();
auto& other_rust = other->wrapped_rust();
if constexpr (JSType::kTypeContainsCalendar) {
if (this_rust.calendar().kind() != other_rust.calendar().kind()) {
THROW_NEW_ERROR(isolate,
NewRangeError(MessageTemplate::kMismatchedCalendars));
}
}
ASSIGN_RETURN_ON_EXCEPTION(
isolate, settings,
temporal::GetDifferenceSettingsWithoutChecks(
isolate, options, group, fallback_smallest_unit, method_name));
auto diff = (this_rust.*operation)(other_rust, settings, provider...);
return ConstructRustWrappingType<JSTemporalDuration>(isolate,
std::move(diff));
}
template <typename RustType, typename OverflowArgument, typename... ProviderArg>
using BinaryOperation = TemporalAllocatedResult<RustType> (RustType::*)(
const temporal_rs::Duration&, OverflowArgument,
const ProviderArg&...) const;
template <
typename JSType,
typename OverflowArgument = std::optional<temporal_rs::ArithmeticOverflow>,
typename... ProviderArg>
MaybeDirectHandle<JSType> AddDurationToGeneric(
Isolate* isolate,
BinaryOperation<typename JSType::RustType, OverflowArgument, ProviderArg...>
operation,
DirectHandle<JSType> temporal_js_type,
DirectHandle<Object> temporal_duration_like,
DirectHandle<Object> options_obj, const char* method_name,
const ProviderArg&... provider) {
DirectHandle<JSTemporalDuration> other_duration;
ASSIGN_RETURN_ON_EXCEPTION(isolate, other_duration,
temporal::ToTemporalDuration(
isolate, temporal_duration_like, method_name));
temporal_rs::ArithmeticOverflow overflow;
ASSIGN_RETURN_ON_EXCEPTION(isolate, overflow,
temporal::ToTemporalOverflowHandleUndefined(
isolate, options_obj, method_name));
auto added = (temporal_js_type->wrapped_rust().*operation)(
*other_duration->duration()->raw(), overflow, provider...);
return ConstructRustWrappingType<JSType>(isolate, std::move(added));
}
template <typename JSType, typename PartialType>
MaybeDirectHandle<JSType> GenericWithHelper(
Isolate* isolate, const typename JSType::RustType& rust_object,
CombinedRecord& fields, DirectHandle<Object> options_obj,
const char* method_name) {
temporal_rs::ArithmeticOverflow overflow;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, overflow,
ToTemporalOverflowHandleUndefined(isolate, options_obj, method_name));
PartialType partial;
ASSIGN_RETURN_ON_EXCEPTION(isolate, partial,
fields.Regulate<PartialType>(isolate, overflow));
return ConstructRustWrappingType<JSType>(isolate,
rust_object.with(partial, overflow));
}
template <>
MaybeDirectHandle<JSTemporalZonedDateTime>
GenericWithHelper<JSTemporalZonedDateTime, temporal_rs::PartialZonedDateTime>(
Isolate* isolate, const typename temporal_rs::ZonedDateTime& rust_object,
CombinedRecord& fields, DirectHandle<Object> options_obj,
const char* method_name) {
temporal_rs::Disambiguation disambiguation;
temporal_rs::OffsetDisambiguation offset_option;
temporal_rs::ArithmeticOverflow overflow;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, disambiguation,
temporal::GetTemporalDisambiguationOptionHandleUndefined(
isolate, options_obj, method_name));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, offset_option,
temporal::GetTemporalOffsetOptionHandleUndefined(
isolate, options_obj, temporal_rs::OffsetDisambiguation::Prefer,
method_name));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, overflow,
ToTemporalOverflowHandleUndefined(isolate, options_obj, method_name));
temporal_rs::PartialZonedDateTime partial = kNullPartialZonedDateTime;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, partial,
fields.Regulate<temporal_rs::PartialZonedDateTime>(isolate, overflow));
return ConstructRustWrappingType<JSTemporalZonedDateTime>(
isolate,
rust_object.with_with_provider(partial, disambiguation, offset_option,
overflow, TimeZoneProvider()));
}
template <typename JSType, typename PartialType>
MaybeDirectHandle<JSType> GenericWith(Isolate* isolate,
DirectHandle<JSType> this_obj,
DirectHandle<Object> temporal_like_obj,
DirectHandle<Object> options_obj,
CalendarFieldsFlags flags,
const char* method_name) {
bool is_partial = false;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, is_partial, IsPartialTemporalObject(isolate, temporal_like_obj));
if (!is_partial) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(kWithNoPartial));
}
auto options_recvr = Cast<JSReceiver>(temporal_like_obj);
auto& rust_object = this_obj->wrapped_rust();
auto kind = rust_object.calendar().kind();
CombinedRecord fields;
MOVE_RETURN_ON_EXCEPTION(
isolate, fields,
PrepareCalendarFields(isolate, kind, options_recvr, flags,
RequiredFields::kPartial));
return GenericWithHelper<JSType, PartialType>(isolate, rust_object, fields,
options_obj, method_name);
}
V8_WARN_UNUSED_RESULT Maybe<temporal_rs::TimeZone> ToRustTimeZone(
Isolate* isolate, std::string_view tz) {
return ExtractRustResult(isolate,
temporal_rs::TimeZone::try_from_str_with_provider(
tz, TimeZoneProvider()));
}
Maybe<int64_t> GetEpochMillisecondsForDateTime(Isolate* isolate,
temporal_rs::PlainDateTime& date,
std::string_view time_zone) {
temporal_rs::TimeZone tz;
MOVE_RETURN_ON_EXCEPTION(isolate, tz, ToRustTimeZone(isolate, time_zone));
std::unique_ptr<temporal_rs::ZonedDateTime> zdt;
MOVE_RETURN_ON_EXCEPTION(
isolate, zdt,
ExtractRustResult(isolate,
date.to_zoned_date_time_with_provider(
tz, temporal_rs::Disambiguation::Compatible,
TimeZoneProvider())));
return Just(zdt->epoch_milliseconds());
}
Maybe<int64_t> GetEpochMillisecondsForDate(
Isolate* isolate, temporal_rs::PlainDate& date, std::string_view time_zone,
temporal_rs::PlainTime* time = nullptr) {
temporal_rs::TimeZone tz;
MOVE_RETURN_ON_EXCEPTION(isolate, tz, ToRustTimeZone(isolate, time_zone));
std::unique_ptr<temporal_rs::ZonedDateTime> zdt;
MOVE_RETURN_ON_EXCEPTION(
isolate, zdt,
ExtractRustResult(isolate, date.to_zoned_date_time_with_provider(
tz, time, TimeZoneProvider())));
return Just(zdt->epoch_milliseconds());
}
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalDuration::Constructor(
Isolate* isolate, DirectHandle<JSFunction> target,
DirectHandle<HeapObject> new_target, DirectHandle<Object> years,
DirectHandle<Object> months, DirectHandle<Object> weeks,
DirectHandle<Object> days, DirectHandle<Object> hours,
DirectHandle<Object> minutes, DirectHandle<Object> seconds,
DirectHandle<Object> milliseconds, DirectHandle<Object> microseconds,
DirectHandle<Object> nanoseconds) {
if (IsUndefined(*new_target)) {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
isolate->factory()->NewStringFromAsciiChecked(
"Temporal.Duration")));
}
int64_t y = 0;
if (!IsUndefined(*years)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, y, temporal::ToIntegerTypeIfIntegral<int64_t>(isolate, years));
}
int64_t mo = 0;
if (!IsUndefined(*months)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, mo,
temporal::ToIntegerTypeIfIntegral<int64_t>(isolate, months));
}
int64_t w = 0;
if (!IsUndefined(*weeks)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, w, temporal::ToIntegerTypeIfIntegral<int64_t>(isolate, weeks));
}
int64_t d = 0;
if (!IsUndefined(*days)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, d, temporal::ToIntegerTypeIfIntegral<int64_t>(isolate, days));
}
int64_t h = 0;
if (!IsUndefined(*hours)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, h, temporal::ToIntegerTypeIfIntegral<int64_t>(isolate, hours));
}
int64_t m = 0;
if (!IsUndefined(*minutes)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, m,
temporal::ToIntegerTypeIfIntegral<int64_t>(isolate, minutes));
}
int64_t s = 0;
if (!IsUndefined(*seconds)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, s,
temporal::ToIntegerTypeIfIntegral<int64_t>(isolate, seconds));
}
int64_t ms = 0;
if (!IsUndefined(*milliseconds)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, ms,
temporal::ToIntegerTypeIfIntegral<int64_t>(isolate, milliseconds));
}
double mis = 0;
if (!IsUndefined(*microseconds)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, mis, temporal::ToIntegerIfIntegral(isolate, microseconds));
}
double ns = 0;
if (!IsUndefined(*nanoseconds)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, ns, temporal::ToIntegerIfIntegral(isolate, nanoseconds));
}
return ConstructRustWrappingType<JSTemporalDuration>(
isolate, target, new_target,
temporal_rs::Duration::create(y, mo, w, d, h, m, s, ms, mis, ns));
}
MaybeDirectHandle<Smi> JSTemporalDuration::Compare(
Isolate* isolate, DirectHandle<Object> one_obj,
DirectHandle<Object> two_obj, DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.Duration.compare";
DirectHandle<JSTemporalDuration> one;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, one,
temporal::ToTemporalDuration(isolate, one_obj, method_name));
DirectHandle<JSTemporalDuration> two;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, two,
temporal::ToTemporalDuration(isolate, two_obj, method_name));
temporal::RelativeTo relative_to;
MOVE_RETURN_ON_EXCEPTION(isolate, relative_to,
temporal::GetTemporalRelativeToOptionHandleUndefined(
isolate, options_obj));
int8_t comparison = 0;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, comparison,
ExtractRustResult(isolate,
one->duration()->raw()->compare_with_provider(
*two->duration()->raw(), relative_to.ToRust(),
TimeZoneProvider())));
return direct_handle(Smi::FromInt(comparison), isolate);
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalDuration::From(
Isolate* isolate, DirectHandle<Object> item) {
static const char method_name[] = "Temporal.Duration.from";
return temporal::ToTemporalDuration(isolate, item, method_name);
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalDuration::Round(
Isolate* isolate, DirectHandle<JSTemporalDuration> duration,
DirectHandle<Object> round_to_obj) {
static const char method_name[] = "Temporal.Duration.prototype.round";
if (IsUndefined(*round_to_obj)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(kRoundToMissing));
}
DirectHandle<JSReceiver> round_to;
auto factory = isolate->factory();
if (IsString(*round_to_obj)) {
DirectHandle<String> param_string = Cast<String>(round_to_obj);
round_to = factory->NewJSObjectWithNullProto();
CHECK(JSReceiver::CreateDataProperty(isolate, round_to,
factory->smallestUnit_string(),
param_string, Just(kThrowOnError))
.FromJust());
} else {
if (!IsJSReceiver(*round_to_obj)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(kRoundToMustBeObject));
}
round_to = Cast<JSReceiver>(round_to_obj);
}
std::optional<Unit> largest_unit;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, largest_unit,
temporal::GetTemporalUnitValuedOption(
isolate, round_to, isolate->factory()->largestUnit_string(),
DefaultValue::kUnset, method_name));
temporal::RelativeTo relative_to;
MOVE_RETURN_ON_EXCEPTION(
isolate, relative_to,
temporal::GetTemporalRelativeToOptionHandleUndefined(isolate, round_to));
uint32_t rounding_increment;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, rounding_increment,
temporal::GetRoundingIncrementOption(isolate, round_to));
RoundingMode rounding_mode;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, rounding_mode,
temporal::GetRoundingModeOption(isolate, round_to,
RoundingMode::HalfExpand, method_name));
std::optional<Unit> smallest_unit;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, smallest_unit,
temporal::GetTemporalUnitValuedOption(
isolate, round_to, isolate->factory()->smallestUnit_string(),
DefaultValue::kUnset, method_name));
RETURN_ON_EXCEPTION(
isolate, temporal::ValidateTemporalUnitValue(isolate, smallest_unit,
UnitGroup::kDateTime));
auto options = temporal_rs::RoundingOptions{.largest_unit = largest_unit,
.smallest_unit = smallest_unit,
.rounding_mode = rounding_mode,
.increment = rounding_increment};
auto rounded = duration->duration()->raw()->round_with_provider(
options, relative_to.ToRust(), TimeZoneProvider());
return ConstructRustWrappingType<JSTemporalDuration>(isolate,
std::move(rounded));
}
MaybeDirectHandle<Number> JSTemporalDuration::Total(
Isolate* isolate, DirectHandle<JSTemporalDuration> duration,
DirectHandle<Object> total_of_obj) {
static const char method_name[] = "Temporal.Duration.prototype.total";
if (IsUndefined(*total_of_obj)) {
THROW_NEW_ERROR(
isolate, NEW_TEMPORAL_TYPE_ERROR("Must specify a totalOf parameter"));
}
DirectHandle<JSReceiver> total_of;
auto factory = isolate->factory();
if (IsString(*total_of_obj)) {
DirectHandle<String> param_string = Cast<String>(total_of_obj);
total_of = factory->NewJSObjectWithNullProto();
CHECK(JSReceiver::CreateDataProperty(isolate, total_of,
factory->unit_string(), param_string,
Just(kThrowOnError))
.FromJust());
} else {
if (!IsJSReceiver(*total_of_obj)) {
THROW_NEW_ERROR(isolate,
NEW_TEMPORAL_TYPE_ERROR("totalOf must be an object."));
}
total_of = Cast<JSReceiver>(total_of_obj);
}
temporal::RelativeTo relative_to;
MOVE_RETURN_ON_EXCEPTION(
isolate, relative_to,
temporal::GetTemporalRelativeToOptionHandleUndefined(isolate, total_of));
std::optional<Unit> unit;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, unit,
temporal::GetTemporalUnitValuedOption(
isolate, total_of, isolate->factory()->unit_string(),
DefaultValue::kRequired, method_name));
RETURN_ON_EXCEPTION(isolate, temporal::ValidateTemporalUnitValue(
isolate, unit, UnitGroup::kDateTime));
DCHECK(unit.has_value());
double ret;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, ret,
ExtractRustResult(
isolate,
duration->duration()->raw()->total_with_provider(
unit.value(), relative_to.ToRust(), TimeZoneProvider())));
return factory->NewNumber(ret);
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalDuration::With(
Isolate* isolate, DirectHandle<JSTemporalDuration> duration,
DirectHandle<Object> temporal_duration_like) {
temporal_rs::PartialDuration partial;
ASSIGN_RETURN_ON_EXCEPTION(isolate, partial,
temporal::ToTemporalPartialDurationRecord(
isolate, temporal_duration_like));
if (!partial.years.has_value()) {
partial.years = duration->duration()->raw()->years();
}
if (!partial.months.has_value()) {
partial.months = duration->duration()->raw()->months();
}
if (!partial.months.has_value()) {
partial.months = duration->duration()->raw()->months();
}
if (!partial.weeks.has_value()) {
partial.weeks = duration->duration()->raw()->weeks();
}
if (!partial.days.has_value()) {
partial.days = duration->duration()->raw()->days();
}
if (!partial.hours.has_value()) {
partial.hours = duration->duration()->raw()->hours();
}
if (!partial.minutes.has_value()) {
partial.minutes = duration->duration()->raw()->minutes();
}
if (!partial.seconds.has_value()) {
partial.seconds = duration->duration()->raw()->seconds();
}
if (!partial.milliseconds.has_value()) {
partial.milliseconds = duration->duration()->raw()->milliseconds();
}
if (!partial.microseconds.has_value()) {
partial.microseconds = duration->duration()->raw()->microseconds();
}
if (!partial.nanoseconds.has_value()) {
partial.nanoseconds = duration->duration()->raw()->nanoseconds();
}
return ConstructRustWrappingType<JSTemporalDuration>(
isolate, temporal_rs::Duration::from_partial_duration(partial));
}
MaybeDirectHandle<Smi> JSTemporalDuration::Sign(
Isolate* isolate, DirectHandle<JSTemporalDuration> duration) {
auto sign = duration->duration()->raw()->sign();
return direct_handle(Smi::FromInt((temporal_rs::Sign::Value)sign), isolate);
}
MaybeDirectHandle<Oddball> JSTemporalDuration::Blank(
Isolate* isolate, DirectHandle<JSTemporalDuration> duration) {
return isolate->factory()->ToBoolean(duration->duration()->raw()->sign() ==
temporal_rs::Sign::Zero);
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalDuration::Negated(
Isolate* isolate, DirectHandle<JSTemporalDuration> duration) {
return ConstructRustWrappingType<JSTemporalDuration>(
isolate, duration->duration()->raw()->negated());
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalDuration::Abs(
Isolate* isolate, DirectHandle<JSTemporalDuration> duration) {
return ConstructRustWrappingType<JSTemporalDuration>(
isolate, duration->duration()->raw()->abs());
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalDuration::Add(
Isolate* isolate, DirectHandle<JSTemporalDuration> duration,
DirectHandle<Object> other, DirectHandle<Object> options) {
static const char method_name[] = "Temporal.Duration.prototype.add";
DirectHandle<JSTemporalDuration> other_duration;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, other_duration,
temporal::ToTemporalDuration(isolate, other, method_name));
auto result =
duration->duration()->raw()->add(*other_duration->duration()->raw());
return ConstructRustWrappingType<JSTemporalDuration>(isolate,
std::move(result));
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalDuration::Subtract(
Isolate* isolate, DirectHandle<JSTemporalDuration> duration,
DirectHandle<Object> other, DirectHandle<Object> options) {
static const char method_name[] = "Temporal.Duration.prototype.subtract";
DirectHandle<JSTemporalDuration> other_duration;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, other_duration,
temporal::ToTemporalDuration(isolate, other, method_name));
auto result =
duration->duration()->raw()->subtract(*other_duration->duration()->raw());
return ConstructRustWrappingType<JSTemporalDuration>(isolate,
std::move(result));
}
MaybeDirectHandle<String> JSTemporalDuration::ToString(
Isolate* isolate, DirectHandle<JSTemporalDuration> duration,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.Duration.prototype.toString";
DirectHandle<JSReceiver> options;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, options, GetOptionsObject(isolate, options_obj, method_name));
temporal_rs::Precision digits;
ASSIGN_RETURN_ON_EXCEPTION(isolate, digits,
temporal::GetTemporalFractionalSecondDigitsOption(
isolate, options, method_name));
RoundingMode rounding_mode;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, rounding_mode,
temporal::GetRoundingModeOption(isolate, options, RoundingMode::Trunc,
method_name));
std::optional<Unit> smallest_unit;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, smallest_unit,
temporal::GetTemporalUnitValuedOption(
isolate, options, isolate->factory()->smallestUnit_string(),
DefaultValue::kUnset, method_name));
RETURN_ON_EXCEPTION(isolate, temporal::ValidateTemporalUnitValue(
isolate, smallest_unit, UnitGroup::kTime));
auto rust_options = temporal_rs::ToStringRoundingOptions{
.precision = digits,
.smallest_unit = smallest_unit,
.rounding_mode = rounding_mode,
};
return temporal::GenericTemporalToString(isolate, duration,
&temporal_rs::Duration::to_string,
std::move(rust_options));
}
MaybeDirectHandle<String> JSTemporalDuration::ToJSON(
Isolate* isolate, DirectHandle<JSTemporalDuration> duration) {
return temporal::GenericTemporalToString(isolate, duration,
&temporal_rs::Duration::to_string,
std::move(temporal::kToStringAuto));
}
MaybeDirectHandle<String> JSTemporalDuration::ToLocaleString(
Isolate* isolate, DirectHandle<JSTemporalDuration> duration,
DirectHandle<Object> locales, DirectHandle<Object> options) {
#ifdef V8_INTL_SUPPORT
return JSDurationFormat::TemporalToLocaleString(isolate, duration, locales,
options);
#else
return temporal::GenericTemporalToString(isolate, duration,
&temporal_rs::Duration::to_string,
std::move(temporal::kToStringAuto));
#endif
}
MaybeDirectHandle<JSTemporalPlainDate> JSTemporalPlainDate::Constructor(
Isolate* isolate, DirectHandle<JSFunction> target,
DirectHandle<HeapObject> new_target, DirectHandle<Object> iso_year_obj,
DirectHandle<Object> iso_month_obj, DirectHandle<Object> iso_day_obj,
DirectHandle<Object> calendar_like) {
if (IsUndefined(*new_target)) {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
isolate->factory()->NewStringFromAsciiChecked(
"Temporal.PlainDate")));
}
double y = 0;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, y, temporal::ToIntegerWithTruncation(isolate, iso_year_obj));
double m = 0;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, m, temporal::ToIntegerWithTruncation(isolate, iso_month_obj));
double d = 0;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, d, temporal::ToIntegerWithTruncation(isolate, iso_day_obj));
temporal_rs::AnyCalendarKind calendar = temporal_rs::AnyCalendarKind::Iso;
if (!IsUndefined(*calendar_like)) {
if (!IsString(*calendar_like)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(kCalendarMustBeString));
}
ASSIGN_RETURN_ON_EXCEPTION(
isolate, calendar,
temporal::CanonicalizeCalendar(isolate, Cast<String>(calendar_like)));
}
if (!temporal::IsValidIsoDate(y, m, d)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kInvalidIsoDate));
}
auto rust_object = temporal_rs::PlainDate::try_new(
static_cast<int32_t>(y), static_cast<uint8_t>(m), static_cast<uint8_t>(d),
calendar);
return ConstructRustWrappingType<JSTemporalPlainDate>(
isolate, target, new_target, std::move(rust_object));
}
MaybeDirectHandle<Smi> JSTemporalPlainDate::Compare(
Isolate* isolate, DirectHandle<Object> one_obj,
DirectHandle<Object> two_obj) {
static const char method_name[] = "Temporal.PlainDate.compare";
DirectHandle<JSTemporalPlainDate> one;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, one,
temporal::ToTemporalDate(isolate, one_obj, {}, method_name));
DirectHandle<JSTemporalPlainDate> two;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, two,
temporal::ToTemporalDate(isolate, two_obj, {}, method_name));
return direct_handle(Smi::FromInt(temporal_rs::PlainDate::compare(
*one->date()->raw(), *two->date()->raw())),
isolate);
}
MaybeDirectHandle<Oddball> JSTemporalPlainDate::Equals(
Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date,
DirectHandle<Object> other_obj) {
static const char method_name[] = "Temporal.PlainDate.prototype.equals";
DirectHandle<JSTemporalPlainDate> other;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, other,
temporal::ToTemporalDate(isolate, other_obj, {}, method_name));
auto equals = temporal_date->date()->raw()->equals(*other->date()->raw());
return isolate->factory()->ToBoolean(equals);
}
MaybeDirectHandle<JSTemporalPlainYearMonth>
JSTemporalPlainDate::ToPlainYearMonth(
Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date) {
return temporal::GenericToTemporalMethod<JSTemporalPlainYearMonth>(
isolate, temporal_date, &temporal_rs::PlainDate::to_plain_year_month);
}
MaybeDirectHandle<JSTemporalPlainMonthDay> JSTemporalPlainDate::ToPlainMonthDay(
Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date) {
return temporal::GenericToTemporalMethod<JSTemporalPlainMonthDay>(
isolate, temporal_date, &temporal_rs::PlainDate::to_plain_month_day);
}
MaybeDirectHandle<JSTemporalPlainDateTime> JSTemporalPlainDate::ToPlainDateTime(
Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date,
DirectHandle<Object> temporal_time_obj) {
static const char method_name[] = "Temporal.PlainDate.toPlainDateTime";
const temporal_rs::PlainTime* maybe_time;
DirectHandle<JSTemporalPlainTime> time_output;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, maybe_time,
temporal::ToTimeRecordOrMidnight(isolate, temporal_time_obj, time_output,
method_name));
return ConstructRustWrappingType<JSTemporalPlainDateTime>(
isolate, temporal_date->date()->raw()->to_plain_date_time(maybe_time));
}
MaybeDirectHandle<JSTemporalPlainDate> JSTemporalPlainDate::With(
Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date,
DirectHandle<Object> temporal_date_like_obj,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.PlainDate.prototype.with";
return temporal::GenericWith<JSTemporalPlainDate, temporal_rs::PartialDate>(
isolate, temporal_date, temporal_date_like_obj, options_obj,
temporal::kAllDateFlags, method_name);
}
MaybeDirectHandle<JSTemporalPlainDate> JSTemporalPlainDate::WithCalendar(
Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date,
DirectHandle<Object> calendar_id) {
temporal_rs::AnyCalendarKind calendar_kind;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, calendar_kind,
temporal::ToTemporalCalendarIdentifier(isolate, calendar_id));
return ConstructRustWrappingType<JSTemporalPlainDate>(
isolate, temporal_date->date()->raw()->with_calendar(calendar_kind));
}
MaybeDirectHandle<JSTemporalZonedDateTime> JSTemporalPlainDate::ToZonedDateTime(
Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date,
DirectHandle<Object> item_obj) {
static const char method_name[] = "Temporal.PlainDate.toZonedDateTime";
temporal_rs::TimeZone time_zone;
DirectHandle<Object> temporal_time_obj;
if (IsJSReceiver(*item_obj)) {
DirectHandle<JSReceiver> item = Cast<JSReceiver>(item_obj);
DirectHandle<Object> time_zone_like;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, time_zone_like,
JSReceiver::GetProperty(isolate, item,
isolate->factory()->timeZone_string()));
if (IsUndefined(*time_zone_like)) {
MOVE_RETURN_ON_EXCEPTION(
isolate, time_zone,
temporal::ToTemporalTimeZoneIdentifier(isolate, item));
} else {
MOVE_RETURN_ON_EXCEPTION(
isolate, time_zone,
temporal::ToTemporalTimeZoneIdentifier(isolate, time_zone_like));
ASSIGN_RETURN_ON_EXCEPTION(
isolate, temporal_time_obj,
JSReceiver::GetProperty(isolate, item,
isolate->factory()->plainTime_string()));
}
} else {
MOVE_RETURN_ON_EXCEPTION(
isolate, time_zone,
temporal::ToTemporalTimeZoneIdentifier(isolate, item_obj));
}
DirectHandle<JSTemporalPlainTime> temporal_time;
temporal_rs::PlainTime* temporal_time_rust = nullptr;
if (temporal_time_obj.is_null() || IsUndefined(*temporal_time_obj)) {
} else {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, temporal_time,
temporal::ToTemporalTime(isolate, temporal_time_obj, {}, method_name));
temporal_time_rust = temporal_time->time()->raw();
}
return ConstructRustWrappingType<JSTemporalZonedDateTime>(
isolate, temporal_date->date()->raw()->to_zoned_date_time_with_provider(
time_zone, temporal_time_rust, TimeZoneProvider()));
}
MaybeDirectHandle<JSTemporalPlainDate> JSTemporalPlainDate::Add(
Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date,
DirectHandle<Object> temporal_duration_like,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.PlainDate.prototype.add";
return temporal::AddDurationToGeneric(isolate, &temporal_rs::PlainDate::add,
temporal_date, temporal_duration_like,
options_obj, method_name);
}
MaybeDirectHandle<JSTemporalPlainDate> JSTemporalPlainDate::Subtract(
Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date,
DirectHandle<Object> temporal_duration_like,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.PlainDate.prototype.subtract";
return temporal::AddDurationToGeneric<JSTemporalPlainDate>(
isolate, &temporal_rs::PlainDate::subtract, temporal_date,
temporal_duration_like, options_obj, method_name);
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalPlainDate::Until(
Isolate* isolate, DirectHandle<JSTemporalPlainDate> handle,
DirectHandle<Object> other, DirectHandle<Object> options) {
static const char method_name[] = "Temporal.PlainDate.prototype.until";
return temporal::GenericDifferenceTemporal(
isolate, &temporal_rs::PlainDate::until, UnitGroup::kDate, Unit::Day,
handle, other, options, method_name);
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalPlainDate::Since(
Isolate* isolate, DirectHandle<JSTemporalPlainDate> handle,
DirectHandle<Object> other, DirectHandle<Object> options) {
static const char method_name[] = "Temporal.PlainDate.prototype.since";
return temporal::GenericDifferenceTemporal(
isolate, &temporal_rs::PlainDate::since, UnitGroup::kDate, Unit::Day,
handle, other, options, method_name);
}
MaybeDirectHandle<JSTemporalPlainDate> JSTemporalPlainDate::NowISO(
Isolate* isolate, DirectHandle<Object> temporal_time_zone_like) {
std::unique_ptr<temporal_rs::ZonedDateTime> zdt;
MOVE_RETURN_ON_EXCEPTION(
isolate, zdt,
temporal::GenericTemporalNowISO(isolate, temporal_time_zone_like));
return ConstructRustWrappingType<JSTemporalPlainDate>(isolate,
zdt->to_plain_date());
}
MaybeDirectHandle<JSTemporalPlainDate> JSTemporalPlainDate::From(
Isolate* isolate, DirectHandle<Object> item_obj,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.PlainDate.from";
DirectHandle<JSTemporalPlainDate> item;
return temporal::ToTemporalDate(isolate, item_obj, options_obj, method_name);
}
MaybeDirectHandle<String> JSTemporalPlainDate::ToString(
Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.PlainDate.prototype.toString";
DirectHandle<JSReceiver> options;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, options, GetOptionsObject(isolate, options_obj, method_name));
temporal_rs::DisplayCalendar show_calendar;
ASSIGN_RETURN_ON_EXCEPTION(isolate, show_calendar,
temporal::GetTemporalShowCalendarNameOption(
isolate, options, method_name));
return temporal::GenericTemporalToString(
isolate, temporal_date, &temporal_rs::PlainDate::to_ixdtf_string,
show_calendar);
}
MaybeDirectHandle<String> JSTemporalPlainDate::ToJSON(
Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date) {
return temporal::GenericTemporalToString(
isolate, temporal_date, &temporal_rs::PlainDate::to_ixdtf_string,
temporal_rs::DisplayCalendar::Auto);
}
MaybeDirectHandle<String> JSTemporalPlainDate::ToLocaleString(
Isolate* isolate, DirectHandle<JSTemporalPlainDate> temporal_date,
DirectHandle<Object> locales, DirectHandle<Object> options) {
#ifdef V8_INTL_SUPPORT
return JSDateTimeFormat::TemporalToLocaleString(
isolate, temporal_date, locales, options,
JSDateTimeFormat::RequiredOption::kDate,
JSDateTimeFormat::DefaultsOption::kDate,
"Temporal.PlainDate.prototype.toLocaleString");
#else
return temporal::GenericTemporalToString(
isolate, temporal_date, &temporal_rs::PlainDate::to_ixdtf_string,
temporal_rs::DisplayCalendar::Auto);
#endif
}
Maybe<int64_t> JSTemporalPlainDate::GetEpochMillisecondsFor(
Isolate* isolate, std::string_view time_zone) {
return temporal::GetEpochMillisecondsForDate(isolate, *this->date()->raw(),
time_zone);
}
MaybeDirectHandle<JSTemporalPlainDateTime> JSTemporalPlainDateTime::Constructor(
Isolate* isolate, DirectHandle<JSFunction> target,
DirectHandle<HeapObject> new_target, DirectHandle<Object> iso_year_obj,
DirectHandle<Object> iso_month_obj, DirectHandle<Object> iso_day_obj,
DirectHandle<Object> hour_obj, DirectHandle<Object> minute_obj,
DirectHandle<Object> second_obj, DirectHandle<Object> millisecond_obj,
DirectHandle<Object> microsecond_obj, DirectHandle<Object> nanosecond_obj,
DirectHandle<Object> calendar_like) {
if (IsUndefined(*new_target)) {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
isolate->factory()->NewStringFromAsciiChecked(
"Temporal.PlainDateTime")));
}
double y = 0;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, y, temporal::ToIntegerWithTruncation(isolate, iso_year_obj));
double m = 0;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, m, temporal::ToIntegerWithTruncation(isolate, iso_month_obj));
double d = 0;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, d, temporal::ToIntegerWithTruncation(isolate, iso_day_obj));
double hour = 0;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, hour,
temporal::ToIntegerWithTruncationOrZero(isolate, hour_obj));
double minute = 0;
if (!IsUndefined(*minute_obj)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, minute,
temporal::ToIntegerWithTruncationOrZero(isolate, minute_obj));
}
double second = 0;
if (!IsUndefined(*second_obj)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, second,
temporal::ToIntegerWithTruncationOrZero(isolate, second_obj));
}
double millisecond = 0;
if (!IsUndefined(*millisecond_obj)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, millisecond,
temporal::ToIntegerWithTruncationOrZero(isolate, millisecond_obj));
}
double microsecond = 0;
if (!IsUndefined(*microsecond_obj)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, microsecond,
temporal::ToIntegerWithTruncationOrZero(isolate, microsecond_obj));
}
double nanosecond = 0;
if (!IsUndefined(*nanosecond_obj)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, nanosecond,
temporal::ToIntegerWithTruncationOrZero(isolate, nanosecond_obj));
}
temporal_rs::AnyCalendarKind calendar = temporal_rs::AnyCalendarKind::Iso;
if (!IsUndefined(*calendar_like)) {
if (!IsString(*calendar_like)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(kCalendarMustBeString));
}
ASSIGN_RETURN_ON_EXCEPTION(
isolate, calendar,
temporal::CanonicalizeCalendar(isolate, Cast<String>(calendar_like)));
}
if (!temporal::IsValidIsoDate(y, m, d)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kInvalidIsoDate));
}
if (!temporal::IsValidTime(hour, minute, second, millisecond, microsecond,
nanosecond)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kInvalidTime));
}
auto rust_object = temporal_rs::PlainDateTime::try_new(
static_cast<int32_t>(y), static_cast<uint8_t>(m), static_cast<uint8_t>(d),
static_cast<uint8_t>(hour), static_cast<uint8_t>(minute),
static_cast<uint8_t>(second), static_cast<uint16_t>(millisecond),
static_cast<uint16_t>(microsecond), static_cast<uint16_t>(nanosecond),
calendar);
return ConstructRustWrappingType<JSTemporalPlainDateTime>(
isolate, target, new_target, std::move(rust_object));
}
MaybeDirectHandle<JSTemporalPlainDateTime> JSTemporalPlainDateTime::From(
Isolate* isolate, DirectHandle<Object> item_obj,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.PlainDateTime.from";
DirectHandle<JSTemporalPlainDateTime> item;
return temporal::ToTemporalDateTime(isolate, item_obj, options_obj,
method_name);
}
MaybeDirectHandle<Smi> JSTemporalPlainDateTime::Compare(
Isolate* isolate, DirectHandle<Object> one_obj,
DirectHandle<Object> two_obj) {
static const char method_name[] = "Temporal.PlainDateTime.compare";
DirectHandle<JSTemporalPlainDateTime> one;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, one,
temporal::ToTemporalDateTime(isolate, one_obj, {}, method_name));
DirectHandle<JSTemporalPlainDateTime> two;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, two,
temporal::ToTemporalDateTime(isolate, two_obj, {}, method_name));
return direct_handle(Smi::FromInt(temporal_rs::PlainDateTime::compare(
*one->date_time()->raw(), *two->date_time()->raw())),
isolate);
}
MaybeDirectHandle<Oddball> JSTemporalPlainDateTime::Equals(
Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> date_time,
DirectHandle<Object> other_obj) {
static const char method_name[] = "Temporal.PlainDateTime.prototype.equals";
DirectHandle<JSTemporalPlainDateTime> other;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, other,
temporal::ToTemporalDateTime(isolate, other_obj, {}, method_name));
auto equals =
date_time->date_time()->raw()->equals(*other->date_time()->raw());
return isolate->factory()->ToBoolean(equals);
}
MaybeDirectHandle<JSTemporalPlainDateTime> JSTemporalPlainDateTime::With(
Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> date_time,
DirectHandle<Object> temporal_date_time_like_obj,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.PlainDateTime.prototype.with";
using enum temporal::CalendarFieldsFlag;
return temporal::GenericWith<JSTemporalPlainDateTime,
temporal_rs::PartialDateTime>(
isolate, date_time, temporal_date_time_like_obj, options_obj,
temporal::kAllDateFlags | kTimeFields, method_name);
}
MaybeDirectHandle<JSTemporalPlainDateTime>
JSTemporalPlainDateTime::WithCalendar(
Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> temporal_date,
DirectHandle<Object> calendar_id) {
temporal_rs::AnyCalendarKind calendar_kind;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, calendar_kind,
temporal::ToTemporalCalendarIdentifier(isolate, calendar_id));
return ConstructRustWrappingType<JSTemporalPlainDateTime>(
isolate, temporal_date->date_time()->raw()->with_calendar(calendar_kind));
}
MaybeDirectHandle<JSTemporalPlainDateTime>
JSTemporalPlainDateTime::WithPlainTime(
Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> date_time,
DirectHandle<Object> plain_time_like) {
static const char method_name[] =
"Temporal.PlainDateTime.prototype.withPlainTime";
const temporal_rs::PlainTime* maybe_time;
DirectHandle<JSTemporalPlainTime> time_output;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, maybe_time,
temporal::ToTimeRecordOrMidnight(isolate, plain_time_like, time_output,
method_name));
return ConstructRustWrappingType<JSTemporalPlainDateTime>(
isolate, date_time->date_time()->raw()->with_time(maybe_time));
}
MaybeDirectHandle<JSTemporalZonedDateTime>
JSTemporalPlainDateTime::ToZonedDateTime(
Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> date_time,
DirectHandle<Object> temporal_time_zone_like,
DirectHandle<Object> options_obj) {
static const char method_name[] =
"Temporal.PlainDateTime.prototype.toZonedDateTime";
temporal_rs::TimeZone time_zone;
MOVE_RETURN_ON_EXCEPTION(
isolate, time_zone,
temporal::ToTemporalTimeZoneIdentifier(isolate, temporal_time_zone_like));
temporal_rs::Disambiguation disambiguation;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, disambiguation,
temporal::GetTemporalDisambiguationOptionHandleUndefined(
isolate, options_obj, method_name));
return ConstructRustWrappingType<JSTemporalZonedDateTime>(
isolate, date_time->date_time()->raw()->to_zoned_date_time_with_provider(
time_zone, disambiguation, TimeZoneProvider()));
}
MaybeDirectHandle<String> JSTemporalPlainDateTime::ToString(
Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> date_time,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.DateTime.prototype.toString";
DirectHandle<JSReceiver> options;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, options, GetOptionsObject(isolate, options_obj, method_name));
temporal_rs::DisplayCalendar show_calendar;
ASSIGN_RETURN_ON_EXCEPTION(isolate, show_calendar,
temporal::GetTemporalShowCalendarNameOption(
isolate, options, method_name));
temporal_rs::Precision digits;
ASSIGN_RETURN_ON_EXCEPTION(isolate, digits,
temporal::GetTemporalFractionalSecondDigitsOption(
isolate, options, method_name));
RoundingMode rounding_mode;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, rounding_mode,
temporal::GetRoundingModeOption(isolate, options, RoundingMode::Trunc,
method_name));
std::optional<Unit> smallest_unit;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, smallest_unit,
temporal::GetTemporalUnitValuedOption(
isolate, options, isolate->factory()->smallestUnit_string(),
DefaultValue::kUnset, method_name));
RETURN_ON_EXCEPTION(isolate, temporal::ValidateTemporalUnitValue(
isolate, smallest_unit, UnitGroup::kTime));
auto rust_options = temporal_rs::ToStringRoundingOptions{
.precision = digits,
.smallest_unit = smallest_unit,
.rounding_mode = rounding_mode,
};
return temporal::GenericTemporalToString(
isolate, date_time, &temporal_rs::PlainDateTime::to_ixdtf_string,
std::move(rust_options), show_calendar);
}
MaybeDirectHandle<String> JSTemporalPlainDateTime::ToJSON(
Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> date_time) {
return temporal::GenericTemporalToString(
isolate, date_time, &temporal_rs::PlainDateTime::to_ixdtf_string,
std::move(temporal::kToStringAuto), temporal_rs::DisplayCalendar::Auto);
}
MaybeDirectHandle<String> JSTemporalPlainDateTime::ToLocaleString(
Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> date_time,
DirectHandle<Object> locales, DirectHandle<Object> options) {
#ifdef V8_INTL_SUPPORT
return JSDateTimeFormat::TemporalToLocaleString(
isolate, date_time, locales, options,
JSDateTimeFormat::RequiredOption::kAny,
JSDateTimeFormat::DefaultsOption::kAll,
"Temporal.PlainDateTime.prototype.toLocaleString");
#else
return temporal::GenericTemporalToString(
isolate, date_time, &temporal_rs::PlainDateTime::to_ixdtf_string,
std::move(temporal::kToStringAuto), temporal_rs::DisplayCalendar::Auto);
#endif
}
MaybeDirectHandle<JSTemporalPlainDateTime> JSTemporalPlainDateTime::NowISO(
Isolate* isolate, DirectHandle<Object> temporal_time_zone_like) {
std::unique_ptr<temporal_rs::ZonedDateTime> zdt;
MOVE_RETURN_ON_EXCEPTION(
isolate, zdt,
temporal::GenericTemporalNowISO(isolate, temporal_time_zone_like));
return ConstructRustWrappingType<JSTemporalPlainDateTime>(
isolate, zdt->to_plain_datetime());
}
MaybeDirectHandle<JSTemporalPlainDateTime> JSTemporalPlainDateTime::Round(
Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> date_time,
DirectHandle<Object> round_to_obj) {
static const char method_name[] = "Temporal.PlainDateTime.prototype.round";
if (IsUndefined(*round_to_obj)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(kRoundToMissing));
}
DirectHandle<JSReceiver> round_to;
auto factory = isolate->factory();
if (IsString(*round_to_obj)) {
DirectHandle<String> param_string = Cast<String>(round_to_obj);
round_to = factory->NewJSObjectWithNullProto();
CHECK(JSReceiver::CreateDataProperty(isolate, round_to,
factory->smallestUnit_string(),
param_string, Just(kThrowOnError))
.FromJust());
} else {
if (!IsJSReceiver(*round_to_obj)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(kRoundToMustBeObject));
}
round_to = Cast<JSReceiver>(round_to_obj);
}
uint32_t rounding_increment;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, rounding_increment,
temporal::GetRoundingIncrementOption(isolate, round_to));
RoundingMode rounding_mode;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, rounding_mode,
temporal::GetRoundingModeOption(isolate, round_to,
RoundingMode::HalfExpand, method_name));
std::optional<Unit> smallest_unit;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, smallest_unit,
temporal::GetTemporalUnitValuedOption(
isolate, round_to, isolate->factory()->smallestUnit_string(),
DefaultValue::kRequired, method_name));
RETURN_ON_EXCEPTION(isolate,
temporal::ValidateTemporalUnitValue(
isolate, smallest_unit, UnitGroup::kTime, Unit::Day));
auto options = temporal_rs::RoundingOptions{.largest_unit = std::nullopt,
.smallest_unit = smallest_unit,
.rounding_mode = rounding_mode,
.increment = rounding_increment};
auto rounded = date_time->date_time()->raw()->round(options);
return ConstructRustWrappingType<JSTemporalPlainDateTime>(isolate,
std::move(rounded));
}
MaybeDirectHandle<JSTemporalPlainDateTime> JSTemporalPlainDateTime::Add(
Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> date_time,
DirectHandle<Object> temporal_duration_like, DirectHandle<Object> options) {
static const char method_name[] = "Temporal.PlainDateTime.prototype.add";
return temporal::AddDurationToGeneric(
isolate, &temporal_rs::PlainDateTime::add, date_time,
temporal_duration_like, options, method_name);
}
MaybeDirectHandle<JSTemporalPlainDateTime> JSTemporalPlainDateTime::Subtract(
Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> date_time,
DirectHandle<Object> temporal_duration_like, DirectHandle<Object> options) {
static const char method_name[] = "Temporal.PlainDateTime.prototype.subtract";
return temporal::AddDurationToGeneric(
isolate, &temporal_rs::PlainDateTime::subtract, date_time,
temporal_duration_like, options, method_name);
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalPlainDateTime::Until(
Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> handle,
DirectHandle<Object> other, DirectHandle<Object> options) {
static const char method_name[] = "Temporal.PlainDateTime.prototype.until";
return temporal::GenericDifferenceTemporal(
isolate, &temporal_rs::PlainDateTime::until, UnitGroup::kDateTime,
Unit::Nanosecond, handle, other, options, method_name);
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalPlainDateTime::Since(
Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> handle,
DirectHandle<Object> other, DirectHandle<Object> options) {
static const char method_name[] = "Temporal.PlainDateTime.prototype.since";
return temporal::GenericDifferenceTemporal(
isolate, &temporal_rs::PlainDateTime::since, UnitGroup::kDateTime,
Unit::Nanosecond, handle, other, options, method_name);
}
MaybeDirectHandle<JSTemporalPlainDate> JSTemporalPlainDateTime::ToPlainDate(
Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> date_time) {
return temporal::GenericToTemporalMethod<JSTemporalPlainDate>(
isolate, date_time, &temporal_rs::PlainDateTime::to_plain_date);
}
MaybeDirectHandle<JSTemporalPlainTime> JSTemporalPlainDateTime::ToPlainTime(
Isolate* isolate, DirectHandle<JSTemporalPlainDateTime> date_time) {
return temporal::GenericToTemporalMethod<JSTemporalPlainTime>(
isolate, date_time, &temporal_rs::PlainDateTime::to_plain_time);
}
V8_WARN_UNUSED_RESULT Maybe<int64_t>
JSTemporalPlainDateTime::GetEpochMillisecondsFor(Isolate* isolate,
std::string_view time_zone) {
return temporal::GetEpochMillisecondsForDateTime(isolate, *date_time()->raw(),
time_zone);
}
MaybeDirectHandle<JSTemporalPlainMonthDay> JSTemporalPlainMonthDay::Constructor(
Isolate* isolate, DirectHandle<JSFunction> target,
DirectHandle<HeapObject> new_target, DirectHandle<Object> iso_month_obj,
DirectHandle<Object> iso_day_obj, DirectHandle<Object> calendar_like,
DirectHandle<Object> reference_iso_year_obj) {
if (IsUndefined(*new_target)) {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
isolate->factory()->NewStringFromAsciiChecked(
"Temporal.PlainYearMonth")));
}
double reference_iso_year = 1972.0;
double m = 0;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, m, temporal::ToIntegerWithTruncation(isolate, iso_month_obj));
double d = 0;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, d, temporal::ToIntegerWithTruncation(isolate, iso_day_obj));
temporal_rs::AnyCalendarKind calendar = temporal_rs::AnyCalendarKind::Iso;
if (!IsUndefined(*calendar_like)) {
if (!IsString(*calendar_like)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(kCalendarMustBeString));
}
ASSIGN_RETURN_ON_EXCEPTION(
isolate, calendar,
temporal::CanonicalizeCalendar(isolate, Cast<String>(calendar_like)));
}
if (!IsUndefined(*reference_iso_year_obj)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, reference_iso_year,
temporal::ToIntegerWithTruncation(isolate, reference_iso_year_obj));
}
if (!temporal::IsValidIsoDate(reference_iso_year, m, d)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kInvalidIsoDate));
}
auto rust_object = temporal_rs::PlainMonthDay::try_new_with_overflow(
static_cast<uint8_t>(m), static_cast<uint8_t>(d), calendar,
temporal_rs::ArithmeticOverflow::Reject,
static_cast<int32_t>(reference_iso_year));
return ConstructRustWrappingType<JSTemporalPlainMonthDay>(
isolate, target, new_target, std::move(rust_object));
}
MaybeDirectHandle<JSTemporalPlainMonthDay> JSTemporalPlainMonthDay::From(
Isolate* isolate, DirectHandle<Object> item_obj,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.PlainMonthDay.from";
DirectHandle<JSTemporalPlainMonthDay> item;
return temporal::ToTemporalMonthDay(isolate, item_obj, options_obj,
method_name);
}
MaybeDirectHandle<Oddball> JSTemporalPlainMonthDay::Equals(
Isolate* isolate, DirectHandle<JSTemporalPlainMonthDay> month_day,
DirectHandle<Object> other_obj) {
static const char method_name[] = "Temporal.PlainMonthDay.prototype.equals";
DirectHandle<JSTemporalPlainMonthDay> other;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, other,
temporal::ToTemporalMonthDay(isolate, other_obj, {}, method_name));
auto equals =
month_day->month_day()->raw()->equals(*other->month_day()->raw());
return isolate->factory()->ToBoolean(equals);
}
MaybeDirectHandle<JSTemporalPlainMonthDay> JSTemporalPlainMonthDay::With(
Isolate* isolate, DirectHandle<JSTemporalPlainMonthDay> temporal_month_day,
DirectHandle<Object> temporal_month_day_like_obj,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.PlainYearMonth.prototype.with";
using enum temporal::CalendarFieldsFlag;
return temporal::GenericWith<JSTemporalPlainMonthDay,
temporal_rs::PartialDate>(
isolate, temporal_month_day, temporal_month_day_like_obj, options_obj,
kYearFields | kMonthFields | kDay, method_name);
}
MaybeDirectHandle<JSTemporalPlainDate> JSTemporalPlainMonthDay::ToPlainDate(
Isolate* isolate, DirectHandle<JSTemporalPlainMonthDay> month_day,
DirectHandle<Object> item_obj) {
if (!IsJSReceiver(*item_obj)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(kYearMustBeObject));
}
DirectHandle<JSReceiver> item = Cast<JSReceiver>(item_obj);
auto calendar = month_day->month_day()->raw()->calendar().kind();
using enum temporal::CalendarFieldsFlag;
temporal::CombinedRecord fields;
MOVE_RETURN_ON_EXCEPTION(
isolate, fields,
temporal::PrepareCalendarFields(isolate, calendar, item, kYearFields,
temporal::RequiredFields::kNone));
temporal_rs::PartialDate partial_date = temporal::kNullPartialDate;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, partial_date,
fields.Regulate<temporal_rs::PartialDate>(
isolate, temporal_rs::ArithmeticOverflow::Constrain));
return ConstructRustWrappingType<JSTemporalPlainDate>(
isolate, month_day->month_day()->raw()->to_plain_date(partial_date));
}
MaybeDirectHandle<String> JSTemporalPlainMonthDay::ToString(
Isolate* isolate, DirectHandle<JSTemporalPlainMonthDay> month_day,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.PlainMonthDay.prototype.toString";
DirectHandle<JSReceiver> options;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, options, GetOptionsObject(isolate, options_obj, method_name));
temporal_rs::DisplayCalendar show_calendar;
ASSIGN_RETURN_ON_EXCEPTION(isolate, show_calendar,
temporal::GetTemporalShowCalendarNameOption(
isolate, options, method_name));
return temporal::GenericTemporalToString(
isolate, month_day, &temporal_rs::PlainMonthDay::to_ixdtf_string,
show_calendar);
}
MaybeDirectHandle<String> JSTemporalPlainMonthDay::ToJSON(
Isolate* isolate, DirectHandle<JSTemporalPlainMonthDay> month_day) {
return temporal::GenericTemporalToString(
isolate, month_day, &temporal_rs::PlainMonthDay::to_ixdtf_string,
temporal_rs::DisplayCalendar::Auto);
}
MaybeDirectHandle<String> JSTemporalPlainMonthDay::ToLocaleString(
Isolate* isolate, DirectHandle<JSTemporalPlainMonthDay> month_day,
DirectHandle<Object> locales, DirectHandle<Object> options) {
#ifdef V8_INTL_SUPPORT
return JSDateTimeFormat::TemporalToLocaleString(
isolate, month_day, locales, options,
JSDateTimeFormat::RequiredOption::kDate,
JSDateTimeFormat::DefaultsOption::kDate,
"Temporal.PlainMonthDay.prototype.toLocaleString");
#else
return temporal::GenericTemporalToString(
isolate, month_day, &temporal_rs::PlainMonthDay::to_ixdtf_string,
temporal_rs::DisplayCalendar::Auto);
#endif
}
Maybe<int64_t> JSTemporalPlainMonthDay::GetEpochMillisecondsFor(
Isolate* isolate, std::string_view time_zone) {
temporal_rs::TimeZone tz;
MOVE_RETURN_ON_EXCEPTION(isolate, tz,
temporal::ToRustTimeZone(isolate, time_zone));
return ExtractRustResult(isolate,
this->month_day()->raw()->epoch_ms_for_with_provider(
tz, TimeZoneProvider()));
}
MaybeDirectHandle<JSTemporalPlainYearMonth>
JSTemporalPlainYearMonth::Constructor(
Isolate* isolate, DirectHandle<JSFunction> target,
DirectHandle<HeapObject> new_target, DirectHandle<Object> iso_year_obj,
DirectHandle<Object> iso_month_obj, DirectHandle<Object> calendar_like,
DirectHandle<Object> reference_iso_day_obj) {
if (IsUndefined(*new_target)) {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
isolate->factory()->NewStringFromAsciiChecked(
"Temporal.PlainYearMonth")));
}
double reference_iso_day = 1.0;
double y = 0;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, y, temporal::ToIntegerWithTruncation(isolate, iso_year_obj));
double m = 0;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, m, temporal::ToIntegerWithTruncation(isolate, iso_month_obj));
temporal_rs::AnyCalendarKind calendar = temporal_rs::AnyCalendarKind::Iso;
if (!IsUndefined(*calendar_like)) {
if (!IsString(*calendar_like)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(kCalendarMustBeString));
}
ASSIGN_RETURN_ON_EXCEPTION(
isolate, calendar,
temporal::CanonicalizeCalendar(isolate, Cast<String>(calendar_like)));
}
if (!IsUndefined(*reference_iso_day_obj)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, reference_iso_day,
temporal::ToIntegerWithTruncation(isolate, reference_iso_day_obj));
}
if (!temporal::IsValidIsoDate(y, m, reference_iso_day)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kInvalidIsoDate));
}
auto rust_object = temporal_rs::PlainYearMonth::try_new_with_overflow(
static_cast<int32_t>(y), static_cast<uint8_t>(m),
static_cast<uint8_t>(reference_iso_day), calendar,
temporal_rs::ArithmeticOverflow::Reject);
return ConstructRustWrappingType<JSTemporalPlainYearMonth>(
isolate, target, new_target, std::move(rust_object));
}
MaybeDirectHandle<JSTemporalPlainYearMonth> JSTemporalPlainYearMonth::From(
Isolate* isolate, DirectHandle<Object> item_obj,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.PlainYearMonth.from";
DirectHandle<JSTemporalPlainYearMonth> item;
return temporal::ToTemporalYearMonth(isolate, item_obj, options_obj,
method_name);
}
MaybeDirectHandle<Smi> JSTemporalPlainYearMonth::Compare(
Isolate* isolate, DirectHandle<Object> one_obj,
DirectHandle<Object> two_obj) {
static const char method_name[] = "Temporal.PlainYearMonth.compare";
DirectHandle<JSTemporalPlainYearMonth> one;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, one,
temporal::ToTemporalYearMonth(isolate, one_obj, {}, method_name));
DirectHandle<JSTemporalPlainYearMonth> two;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, two,
temporal::ToTemporalYearMonth(isolate, two_obj, {}, method_name));
return direct_handle(
Smi::FromInt(temporal_rs::PlainYearMonth::compare(
*one->year_month()->raw(), *two->year_month()->raw())),
isolate);
}
MaybeDirectHandle<Oddball> JSTemporalPlainYearMonth::Equals(
Isolate* isolate, DirectHandle<JSTemporalPlainYearMonth> year_month,
DirectHandle<Object> other_obj) {
static const char method_name[] = "Temporal.PlainYearMonth.prototype.equals";
DirectHandle<JSTemporalPlainYearMonth> other;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, other,
temporal::ToTemporalYearMonth(isolate, other_obj, {}, method_name));
auto equals =
year_month->year_month()->raw()->equals(*other->year_month()->raw());
return isolate->factory()->ToBoolean(equals);
}
MaybeDirectHandle<JSTemporalPlainYearMonth> JSTemporalPlainYearMonth::Add(
Isolate* isolate, DirectHandle<JSTemporalPlainYearMonth> year_month,
DirectHandle<Object> temporal_duration_like, DirectHandle<Object> options) {
static const char method_name[] = "Temporal.PlainYearMonth.prototype.add";
return temporal::AddDurationToGeneric(
isolate, &temporal_rs::PlainYearMonth::add, year_month,
temporal_duration_like, options, method_name);
}
MaybeDirectHandle<JSTemporalPlainYearMonth> JSTemporalPlainYearMonth::Subtract(
Isolate* isolate, DirectHandle<JSTemporalPlainYearMonth> year_month,
DirectHandle<Object> temporal_duration_like, DirectHandle<Object> options) {
static const char method_name[] =
"Temporal.PlainYearMonth.prototype.subtract";
return temporal::AddDurationToGeneric(
isolate, &temporal_rs::PlainYearMonth::subtract, year_month,
temporal_duration_like, options, method_name);
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalPlainYearMonth::Until(
Isolate* isolate, DirectHandle<JSTemporalPlainYearMonth> handle,
DirectHandle<Object> other, DirectHandle<Object> options) {
static const char method_name[] = "Temporal.PlainYearMonth.prototype.until";
return temporal::GenericDifferenceTemporal(
isolate, &temporal_rs::PlainYearMonth::until, UnitGroup::kDate,
Unit::Month, handle, other, options, method_name);
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalPlainYearMonth::Since(
Isolate* isolate, DirectHandle<JSTemporalPlainYearMonth> handle,
DirectHandle<Object> other, DirectHandle<Object> options) {
static const char method_name[] = "Temporal.PlainYearMonth.prototype.since";
return temporal::GenericDifferenceTemporal(
isolate, &temporal_rs::PlainYearMonth::since, UnitGroup::kDate,
Unit::Month, handle, other, options, method_name);
}
MaybeDirectHandle<JSTemporalPlainYearMonth> JSTemporalPlainYearMonth::With(
Isolate* isolate,
DirectHandle<JSTemporalPlainYearMonth> temporal_year_month,
DirectHandle<Object> temporal_year_month_like_obj,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.PlainYearMonth.prototype.with";
using enum temporal::CalendarFieldsFlag;
return temporal::GenericWith<JSTemporalPlainYearMonth,
temporal_rs::PartialDate>(
isolate, temporal_year_month, temporal_year_month_like_obj, options_obj,
kYearFields | kMonthFields, method_name);
}
MaybeDirectHandle<JSTemporalPlainDate> JSTemporalPlainYearMonth::ToPlainDate(
Isolate* isolate, DirectHandle<JSTemporalPlainYearMonth> year_month,
DirectHandle<Object> item_obj) {
if (!IsJSReceiver(*item_obj)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(kYearMustBeObject));
}
DirectHandle<JSReceiver> item = Cast<JSReceiver>(item_obj);
auto calendar = year_month->year_month()->raw()->calendar().kind();
using enum temporal::CalendarFieldsFlag;
temporal::CombinedRecord fields;
MOVE_RETURN_ON_EXCEPTION(
isolate, fields,
temporal::PrepareCalendarFields(isolate, calendar, item, kDay,
temporal::RequiredFields::kNone));
temporal_rs::PartialDate partial_date = temporal::kNullPartialDate;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, partial_date,
fields.Regulate<temporal_rs::PartialDate>(
isolate, temporal_rs::ArithmeticOverflow::Constrain));
return ConstructRustWrappingType<JSTemporalPlainDate>(
isolate, year_month->year_month()->raw()->to_plain_date(partial_date));
}
MaybeDirectHandle<String> JSTemporalPlainYearMonth::ToString(
Isolate* isolate, DirectHandle<JSTemporalPlainYearMonth> year_month,
DirectHandle<Object> options_obj) {
static const char method_name[] =
"Temporal.PlainYearMonth.prototype.toString";
DirectHandle<JSReceiver> options;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, options, GetOptionsObject(isolate, options_obj, method_name));
temporal_rs::DisplayCalendar show_calendar;
ASSIGN_RETURN_ON_EXCEPTION(isolate, show_calendar,
temporal::GetTemporalShowCalendarNameOption(
isolate, options, method_name));
return temporal::GenericTemporalToString(
isolate, year_month, &temporal_rs::PlainYearMonth::to_ixdtf_string,
show_calendar);
}
MaybeDirectHandle<String> JSTemporalPlainYearMonth::ToLocaleString(
Isolate* isolate, DirectHandle<JSTemporalPlainYearMonth> year_month,
DirectHandle<Object> locales, DirectHandle<Object> options) {
#ifdef V8_INTL_SUPPORT
return JSDateTimeFormat::TemporalToLocaleString(
isolate, year_month, locales, options,
JSDateTimeFormat::RequiredOption::kDate,
JSDateTimeFormat::DefaultsOption::kDate,
"Temporal.PlainYearMonth.prototype.toLocaleString");
#else
return temporal::GenericTemporalToString(
isolate, year_month, &temporal_rs::PlainYearMonth::to_ixdtf_string,
temporal_rs::DisplayCalendar::Auto);
#endif
}
Maybe<int64_t> JSTemporalPlainYearMonth::GetEpochMillisecondsFor(
Isolate* isolate, std::string_view time_zone) {
temporal_rs::TimeZone tz;
MOVE_RETURN_ON_EXCEPTION(isolate, tz,
temporal::ToRustTimeZone(isolate, time_zone));
return ExtractRustResult(
isolate, this->year_month()->raw()->epoch_ms_for_with_provider(
tz, TimeZoneProvider()));
}
MaybeDirectHandle<String> JSTemporalPlainYearMonth::ToJSON(
Isolate* isolate, DirectHandle<JSTemporalPlainYearMonth> year_month) {
return temporal::GenericTemporalToString(
isolate, year_month, &temporal_rs::PlainYearMonth::to_ixdtf_string,
temporal_rs::DisplayCalendar::Auto);
}
MaybeDirectHandle<JSTemporalPlainTime> JSTemporalPlainTime::Constructor(
Isolate* isolate, DirectHandle<JSFunction> target,
DirectHandle<HeapObject> new_target, DirectHandle<Object> hour_obj,
DirectHandle<Object> minute_obj, DirectHandle<Object> second_obj,
DirectHandle<Object> millisecond_obj, DirectHandle<Object> microsecond_obj,
DirectHandle<Object> nanosecond_obj) {
if (IsUndefined(*new_target)) {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
isolate->factory()->NewStringFromAsciiChecked(
"Temporal.PlainTime")));
}
double hour = 0;
if (!IsUndefined(*hour_obj)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, hour,
temporal::ToIntegerWithTruncationOrZero(isolate, hour_obj));
}
double minute = 0;
if (!IsUndefined(*minute_obj)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, minute,
temporal::ToIntegerWithTruncationOrZero(isolate, minute_obj));
}
double second = 0;
if (!IsUndefined(*second_obj)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, second,
temporal::ToIntegerWithTruncationOrZero(isolate, second_obj));
}
double millisecond = 0;
if (!IsUndefined(*millisecond_obj)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, millisecond,
temporal::ToIntegerWithTruncationOrZero(isolate, millisecond_obj));
}
double microsecond = 0;
if (!IsUndefined(*microsecond_obj)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, microsecond,
temporal::ToIntegerWithTruncationOrZero(isolate, microsecond_obj));
}
double nanosecond = 0;
if (!IsUndefined(*nanosecond_obj)) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, nanosecond,
temporal::ToIntegerWithTruncationOrZero(isolate, nanosecond_obj));
}
if (!temporal::IsValidTime(hour, minute, second, millisecond, microsecond,
nanosecond)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_RANGE_ERROR(kInvalidTime));
}
auto rust_object = temporal_rs::PlainTime::try_new(
static_cast<uint8_t>(hour), static_cast<uint8_t>(minute),
static_cast<uint8_t>(second), static_cast<uint16_t>(millisecond),
static_cast<uint16_t>(microsecond), static_cast<uint16_t>(nanosecond));
return ConstructRustWrappingType<JSTemporalPlainTime>(
isolate, target, new_target, std::move(rust_object));
}
MaybeDirectHandle<Smi> JSTemporalPlainTime::Compare(
Isolate* isolate, DirectHandle<Object> one_obj,
DirectHandle<Object> two_obj) {
static const char method_name[] = "Temporal.PlainTime.compare";
DirectHandle<JSTemporalPlainTime> one;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, one,
temporal::ToTemporalTime(isolate, one_obj, {}, method_name));
DirectHandle<JSTemporalPlainTime> two;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, two,
temporal::ToTemporalTime(isolate, two_obj, {}, method_name));
return direct_handle(Smi::FromInt(temporal_rs::PlainTime::compare(
*one->time()->raw(), *two->time()->raw())),
isolate);
}
MaybeDirectHandle<Oddball> JSTemporalPlainTime::Equals(
Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time,
DirectHandle<Object> other_obj) {
static const char method_name[] = "Temporal.PlainTime.prototype.equals";
DirectHandle<JSTemporalPlainTime> other;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, other,
temporal::ToTemporalTime(isolate, other_obj, {}, method_name));
auto equals = temporal_time->time()->raw()->equals(*other->time()->raw());
return isolate->factory()->ToBoolean(equals);
}
MaybeDirectHandle<JSTemporalPlainTime> JSTemporalPlainTime::Round(
Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time,
DirectHandle<Object> round_to_obj) {
static const char method_name[] = "Temporal.PlainDateTime.prototype.round";
if (IsUndefined(*round_to_obj)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(kRoundToMissing));
}
DirectHandle<JSReceiver> round_to;
auto factory = isolate->factory();
if (IsString(*round_to_obj)) {
DirectHandle<String> param_string = Cast<String>(round_to_obj);
round_to = factory->NewJSObjectWithNullProto();
CHECK(JSReceiver::CreateDataProperty(isolate, round_to,
factory->smallestUnit_string(),
param_string, Just(kThrowOnError))
.FromJust());
} else {
if (!IsJSReceiver(*round_to_obj)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(kRoundToMustBeObject));
}
round_to = Cast<JSReceiver>(round_to_obj);
}
uint32_t rounding_increment;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, rounding_increment,
temporal::GetRoundingIncrementOption(isolate, round_to));
RoundingMode rounding_mode;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, rounding_mode,
temporal::GetRoundingModeOption(isolate, round_to,
RoundingMode::HalfExpand, method_name));
std::optional<Unit> smallest_unit;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, smallest_unit,
temporal::GetTemporalUnitValuedOption(
isolate, round_to, factory->smallestUnit_string(),
DefaultValue::kRequired, method_name));
RETURN_ON_EXCEPTION(isolate, temporal::ValidateTemporalUnitValue(
isolate, smallest_unit, UnitGroup::kTime));
auto options = temporal_rs::RoundingOptions{.largest_unit = std::nullopt,
.smallest_unit = smallest_unit,
.rounding_mode = rounding_mode,
.increment = rounding_increment};
auto rounded = temporal_time->time()->raw()->round(options);
return ConstructRustWrappingType<JSTemporalPlainTime>(isolate,
std::move(rounded));
}
MaybeDirectHandle<JSTemporalPlainTime> JSTemporalPlainTime::With(
Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time,
DirectHandle<Object> temporal_time_like_obj,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.PlainTime.prototype.with";
bool is_partial = false;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, is_partial,
temporal::IsPartialTemporalObject(isolate, temporal_time_like_obj));
if (!is_partial) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(kWithNoPartial));
}
temporal::TimeRecord partial_time;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, partial_time,
temporal::ToTemporalTimeRecord(isolate,
Cast<JSReceiver>(temporal_time_like_obj),
method_name, kPartial));
temporal_rs::ArithmeticOverflow overflow;
ASSIGN_RETURN_ON_EXCEPTION(isolate, overflow,
temporal::ToTemporalOverflowHandleUndefined(
isolate, options_obj, method_name));
temporal_rs::PartialTime result;
ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
partial_time.Regulate(isolate, overflow));
return ConstructRustWrappingType<JSTemporalPlainTime>(
isolate, temporal_time->time()->raw()->with(result, overflow));
}
MaybeDirectHandle<JSTemporalPlainTime> JSTemporalPlainTime::NowISO(
Isolate* isolate, DirectHandle<Object> temporal_time_zone_like) {
std::unique_ptr<temporal_rs::ZonedDateTime> zdt;
MOVE_RETURN_ON_EXCEPTION(
isolate, zdt,
temporal::GenericTemporalNowISO(isolate, temporal_time_zone_like));
return ConstructRustWrappingType<JSTemporalPlainTime>(isolate,
zdt->to_plain_time());
}
MaybeDirectHandle<JSTemporalPlainTime> JSTemporalPlainTime::From(
Isolate* isolate, DirectHandle<Object> item_obj,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.PlainTime.from";
DirectHandle<JSTemporalPlainTime> item;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, item,
temporal::ToTemporalTime(isolate, item_obj, options_obj, method_name));
return item;
}
MaybeDirectHandle<JSTemporalPlainTime> JSTemporalPlainTime::Add(
Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time,
DirectHandle<Object> temporal_duration_like) {
static const char method_name[] = "Temporal.PlainTime.prototype.add";
DirectHandle<JSTemporalDuration> other_duration;
ASSIGN_RETURN_ON_EXCEPTION(isolate, other_duration,
temporal::ToTemporalDuration(
isolate, temporal_duration_like, method_name));
auto added =
temporal_time->time()->raw()->add(*other_duration->duration()->raw());
return ConstructRustWrappingType<JSTemporalPlainTime>(isolate,
std::move(added));
}
MaybeDirectHandle<JSTemporalPlainTime> JSTemporalPlainTime::Subtract(
Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time,
DirectHandle<Object> temporal_duration_like) {
static const char method_name[] = "Temporal.PlainTime.prototype.subtract";
DirectHandle<JSTemporalDuration> other_duration;
ASSIGN_RETURN_ON_EXCEPTION(isolate, other_duration,
temporal::ToTemporalDuration(
isolate, temporal_duration_like, method_name));
auto subtracted = temporal_time->time()->raw()->subtract(
*other_duration->duration()->raw());
return ConstructRustWrappingType<JSTemporalPlainTime>(isolate,
std::move(subtracted));
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalPlainTime::Until(
Isolate* isolate, DirectHandle<JSTemporalPlainTime> handle,
DirectHandle<Object> other, DirectHandle<Object> options) {
static const char method_name[] = "Temporal.PlainTime.prototype.until";
return temporal::GenericDifferenceTemporal(
isolate, &temporal_rs::PlainTime::until, UnitGroup::kTime,
Unit::Nanosecond, handle, other, options, method_name);
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalPlainTime::Since(
Isolate* isolate, DirectHandle<JSTemporalPlainTime> handle,
DirectHandle<Object> other, DirectHandle<Object> options) {
static const char method_name[] = "Temporal.PlainTime.prototype.since";
return temporal::GenericDifferenceTemporal(
isolate, &temporal_rs::PlainTime::since, UnitGroup::kTime,
Unit::Nanosecond, handle, other, options, method_name);
}
MaybeDirectHandle<String> JSTemporalPlainTime::ToString(
Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.PlainTime.prototype.toString";
DirectHandle<JSReceiver> options;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, options, GetOptionsObject(isolate, options_obj, method_name));
temporal_rs::Precision digits;
ASSIGN_RETURN_ON_EXCEPTION(isolate, digits,
temporal::GetTemporalFractionalSecondDigitsOption(
isolate, options, method_name));
RoundingMode rounding_mode;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, rounding_mode,
temporal::GetRoundingModeOption(isolate, options, RoundingMode::Trunc,
method_name));
std::optional<Unit> smallest_unit;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, smallest_unit,
temporal::GetTemporalUnitValuedOption(
isolate, options, isolate->factory()->smallestUnit_string(),
DefaultValue::kUnset, method_name));
RETURN_ON_EXCEPTION(isolate, temporal::ValidateTemporalUnitValue(
isolate, smallest_unit, UnitGroup::kTime));
auto rust_options = temporal_rs::ToStringRoundingOptions{
.precision = digits,
.smallest_unit = smallest_unit,
.rounding_mode = rounding_mode,
};
return temporal::GenericTemporalToString(
isolate, temporal_time, &temporal_rs::PlainTime::to_ixdtf_string,
std::move(rust_options));
}
MaybeDirectHandle<String> JSTemporalPlainTime::ToJSON(
Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time) {
return temporal::GenericTemporalToString(
isolate, temporal_time, &temporal_rs::PlainTime::to_ixdtf_string,
std::move(temporal::kToStringAuto));
}
MaybeDirectHandle<String> JSTemporalPlainTime::ToLocaleString(
Isolate* isolate, DirectHandle<JSTemporalPlainTime> temporal_time,
DirectHandle<Object> locales, DirectHandle<Object> options) {
#ifdef V8_INTL_SUPPORT
return JSDateTimeFormat::TemporalToLocaleString(
isolate, temporal_time, locales, options,
JSDateTimeFormat::RequiredOption::kTime,
JSDateTimeFormat::DefaultsOption::kTime,
"Temporal.PlainTime.prototype.toLocaleString");
#else
return temporal::GenericTemporalToString(
isolate, temporal_time, &temporal_rs::PlainTime::to_ixdtf_string,
std::move(temporal::kToStringAuto));
#endif
}
Maybe<int64_t> JSTemporalPlainTime::GetEpochMillisecondsFor(
Isolate* isolate, std::string_view time_zone) {
std::unique_ptr<temporal_rs::PlainDate> pd;
MOVE_RETURN_ON_EXCEPTION(
isolate, pd,
ExtractRustResult(isolate,
temporal_rs::PlainDate::try_new(
1970, 1, 1, temporal_rs::AnyCalendarKind::Iso)));
return temporal::GetEpochMillisecondsForDate(isolate, *pd, time_zone,
time()->raw());
}
MaybeDirectHandle<JSTemporalZonedDateTime> JSTemporalZonedDateTime::Constructor(
Isolate* isolate, DirectHandle<JSFunction> target,
DirectHandle<HeapObject> new_target,
DirectHandle<Object> epoch_nanoseconds_obj,
DirectHandle<Object> time_zone_like, DirectHandle<Object> calendar_like) {
if (IsUndefined(*new_target)) {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
isolate->factory()->NewStringFromAsciiChecked(
"Temporal.ZonedDateTime")));
}
DirectHandle<BigInt> epoch_nanoseconds;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, epoch_nanoseconds,
BigInt::FromObject(isolate, epoch_nanoseconds_obj));
temporal_rs::I128Nanoseconds ns;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, ns, temporal::GetI128FromBigInt(isolate, epoch_nanoseconds));
if (!IsString(*time_zone_like)) {
THROW_NEW_ERROR(isolate,
NEW_TEMPORAL_TYPE_ERROR("Time zone must be string"));
}
auto tz_str = Cast<String>(time_zone_like);
auto tz_stdstr = tz_str->ToStdString();
temporal_rs::TimeZone time_zone;
MOVE_RETURN_ON_EXCEPTION(
isolate, time_zone,
ExtractRustResult(
isolate, temporal_rs::TimeZone::try_from_identifier_str_with_provider(
tz_stdstr, TimeZoneProvider())));
temporal_rs::AnyCalendarKind calendar = temporal_rs::AnyCalendarKind::Iso;
if (!IsUndefined(*calendar_like)) {
if (!IsString(*calendar_like)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(kCalendarMustBeString));
}
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, calendar,
temporal::CanonicalizeCalendar(isolate, Cast<String>(calendar_like)),
kNullMaybeHandle);
}
return ConstructRustWrappingType<JSTemporalZonedDateTime>(
isolate, target, new_target,
temporal_rs::ZonedDateTime::try_new_with_provider(ns, calendar, time_zone,
TimeZoneProvider()));
}
MaybeDirectHandle<Number> JSTemporalZonedDateTime::HoursInDay(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
double hours;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, hours,
ExtractRustResult(
isolate,
zoned_date_time->zoned_date_time()->raw()->hours_in_day_with_provider(
TimeZoneProvider())));
return isolate->factory()->NewNumber(hours);
}
MaybeDirectHandle<JSTemporalZonedDateTime> JSTemporalZonedDateTime::From(
Isolate* isolate, DirectHandle<Object> item_obj,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.ZonedDateTime.from";
DirectHandle<JSTemporalPlainDateTime> item;
return temporal::ToTemporalZonedDateTime(isolate, item_obj, options_obj,
method_name);
}
MaybeDirectHandle<Smi> JSTemporalZonedDateTime::Compare(
Isolate* isolate, DirectHandle<Object> one_obj,
DirectHandle<Object> two_obj) {
static const char method_name[] = "Temporal.ZonedDateTime.compare";
DirectHandle<JSTemporalZonedDateTime> one;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, one,
temporal::ToTemporalZonedDateTime(isolate, one_obj, {}, method_name));
DirectHandle<JSTemporalZonedDateTime> two;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, two,
temporal::ToTemporalZonedDateTime(isolate, two_obj, {}, method_name));
return direct_handle(
Smi::FromInt(one->zoned_date_time()->raw()->compare_instant(
*two->zoned_date_time()->raw())),
isolate);
}
MaybeDirectHandle<Oddball> JSTemporalZonedDateTime::Equals(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
DirectHandle<Object> other_obj) {
static const char method_name[] = "Temporal.ZonedDateTime.prototype.equals";
DirectHandle<JSTemporalZonedDateTime> other;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, other,
temporal::ToTemporalZonedDateTime(isolate, other_obj, {}, method_name));
auto result = zoned_date_time->zoned_date_time()->raw()->equals_with_provider(
*other->zoned_date_time()->raw(), TimeZoneProvider());
bool equals;
ASSIGN_RETURN_ON_EXCEPTION(isolate, equals,
ExtractRustResult(isolate, std::move(result)));
return isolate->factory()->ToBoolean(equals);
}
MaybeDirectHandle<JSTemporalZonedDateTime> JSTemporalZonedDateTime::With(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
DirectHandle<Object> temporal_zoned_date_time_like_obj,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.ZonedDateTime.prototype.with";
using enum temporal::CalendarFieldsFlag;
return temporal::GenericWith<JSTemporalZonedDateTime,
temporal_rs::PartialZonedDateTime>(
isolate, zoned_date_time, temporal_zoned_date_time_like_obj, options_obj,
temporal::kAllDateFlags | kTimeFields | kOffset, method_name);
}
MaybeDirectHandle<JSTemporalZonedDateTime>
JSTemporalZonedDateTime::WithCalendar(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> temporal_date,
DirectHandle<Object> calendar_id) {
temporal_rs::AnyCalendarKind calendar_kind;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, calendar_kind,
temporal::ToTemporalCalendarIdentifier(isolate, calendar_id));
return ConstructRustWrappingType<JSTemporalZonedDateTime>(
isolate,
temporal_date->zoned_date_time()->raw()->with_calendar(calendar_kind));
}
MaybeDirectHandle<JSTemporalZonedDateTime>
JSTemporalZonedDateTime::WithPlainTime(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
DirectHandle<Object> plain_time_like) {
static const char method_name[] =
"Temporal.ZonedDateTime.prototype.withPlainTime";
DirectHandle<JSTemporalPlainTime> plain_time_obj;
temporal_rs::PlainTime* plain_time = nullptr;
if (IsUndefined(*plain_time_like)) {
} else {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, plain_time_obj,
temporal::ToTemporalTime(isolate, plain_time_like, {}, method_name));
plain_time = plain_time_obj->time()->raw();
}
return ConstructRustWrappingType<JSTemporalZonedDateTime>(
isolate,
zoned_date_time->zoned_date_time()->raw()->with_plain_time_and_provider(
plain_time, TimeZoneProvider()));
}
MaybeDirectHandle<JSTemporalZonedDateTime>
JSTemporalZonedDateTime::WithTimeZone(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
DirectHandle<Object> time_zone_like) {
temporal_rs::TimeZone time_zone;
MOVE_RETURN_ON_EXCEPTION(
isolate, time_zone,
temporal::ToTemporalTimeZoneIdentifier(isolate, time_zone_like));
return ConstructRustWrappingType<JSTemporalZonedDateTime>(
isolate,
zoned_date_time->zoned_date_time()->raw()->with_timezone_with_provider(
time_zone, TimeZoneProvider()));
}
MaybeDirectHandle<String> JSTemporalZonedDateTime::ToString(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.ZonedDateTime.prototype.toString";
DirectHandle<JSReceiver> options;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, options, GetOptionsObject(isolate, options_obj, method_name));
temporal_rs::DisplayCalendar show_calendar;
ASSIGN_RETURN_ON_EXCEPTION(isolate, show_calendar,
temporal::GetTemporalShowCalendarNameOption(
isolate, options, method_name));
temporal_rs::Precision digits;
ASSIGN_RETURN_ON_EXCEPTION(isolate, digits,
temporal::GetTemporalFractionalSecondDigitsOption(
isolate, options, method_name));
temporal_rs::DisplayOffset show_offset;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, show_offset,
temporal::GetTemporalShowOffsetOption(isolate, options, method_name));
RoundingMode rounding_mode;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, rounding_mode,
temporal::GetRoundingModeOption(isolate, options, RoundingMode::Trunc,
method_name));
std::optional<Unit> smallest_unit;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, smallest_unit,
temporal::GetTemporalUnitValuedOption(
isolate, options, isolate->factory()->smallestUnit_string(),
DefaultValue::kUnset, method_name));
temporal_rs::DisplayTimeZone show_tz;
ASSIGN_RETURN_ON_EXCEPTION(isolate, show_tz,
temporal::GetTemporalShowTimeZoneNameOption(
isolate, options, method_name));
RETURN_ON_EXCEPTION(isolate, temporal::ValidateTemporalUnitValue(
isolate, smallest_unit, UnitGroup::kTime));
if (smallest_unit == Unit::Hour) {
THROW_NEW_ERROR(isolate,
NEW_TEMPORAL_RANGE_ERROR("smallestUnit cannot be Hour."));
}
auto rust_options = temporal_rs::ToStringRoundingOptions{
.precision = digits,
.smallest_unit = smallest_unit,
.rounding_mode = rounding_mode,
};
return temporal::GenericTemporalToString(
isolate, zoned_date_time,
&temporal_rs::ZonedDateTime::to_ixdtf_string_with_provider, show_offset,
show_tz, show_calendar, std::move(rust_options),
std::ref(TimeZoneProvider()));
}
MaybeDirectHandle<String> JSTemporalZonedDateTime::ToJSON(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
return temporal::GenericTemporalToString(
isolate, zoned_date_time,
&temporal_rs::ZonedDateTime::to_ixdtf_string_with_provider,
temporal_rs::DisplayOffset::Auto, temporal_rs::DisplayTimeZone::Auto,
temporal_rs::DisplayCalendar::Auto, std::move(temporal::kToStringAuto),
std::ref(TimeZoneProvider()));
}
MaybeDirectHandle<String> JSTemporalZonedDateTime::ToLocaleString(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
DirectHandle<Object> locales, DirectHandle<Object> options) {
#ifdef V8_INTL_SUPPORT
return JSDateTimeFormat::TemporalZonedDateTimeToLocaleString(
isolate, zoned_date_time, locales, options,
"Temporal.ZonedDateTime.prototype.toLocaleString");
#else
return temporal::GenericTemporalToString(
isolate, zoned_date_time,
&temporal_rs::ZonedDateTime::to_ixdtf_string_with_provider,
temporal_rs::DisplayOffset::Auto, temporal_rs::DisplayTimeZone::Auto,
temporal_rs::DisplayCalendar::Auto, std::move(temporal::kToStringAuto),
std::ref(TimeZoneProvider()));
#endif
}
MaybeDirectHandle<JSTemporalZonedDateTime> JSTemporalZonedDateTime::NowISO(
Isolate* isolate, DirectHandle<Object> temporal_time_zone_like) {
std::unique_ptr<temporal_rs::ZonedDateTime> zdt;
MOVE_RETURN_ON_EXCEPTION(
isolate, zdt,
temporal::GenericTemporalNowISO(isolate, temporal_time_zone_like));
return ConstructRustWrappingType<JSTemporalZonedDateTime>(isolate,
std::move(zdt));
}
MaybeDirectHandle<JSTemporalZonedDateTime> JSTemporalZonedDateTime::Round(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
DirectHandle<Object> round_to_obj) {
static const char method_name[] = "Temporal.PlainDateTime.prototype.round";
if (IsUndefined(*round_to_obj)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(kRoundToMissing));
}
DirectHandle<JSReceiver> round_to;
auto factory = isolate->factory();
if (IsString(*round_to_obj)) {
DirectHandle<String> param_string = Cast<String>(round_to_obj);
round_to = factory->NewJSObjectWithNullProto();
CHECK(JSReceiver::CreateDataProperty(isolate, round_to,
factory->smallestUnit_string(),
param_string, Just(kThrowOnError))
.FromJust());
} else {
if (!IsJSReceiver(*round_to_obj)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(kRoundToMustBeObject));
}
round_to = Cast<JSReceiver>(round_to_obj);
}
uint32_t rounding_increment;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, rounding_increment,
temporal::GetRoundingIncrementOption(isolate, round_to));
RoundingMode rounding_mode;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, rounding_mode,
temporal::GetRoundingModeOption(isolate, round_to,
RoundingMode::HalfExpand, method_name));
std::optional<Unit> smallest_unit;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, smallest_unit,
temporal::GetTemporalUnitValuedOption(
isolate, round_to, isolate->factory()->smallestUnit_string(),
DefaultValue::kRequired, method_name));
RETURN_ON_EXCEPTION(isolate,
temporal::ValidateTemporalUnitValue(
isolate, smallest_unit, UnitGroup::kTime, Unit::Day));
auto options = temporal_rs::RoundingOptions{.largest_unit = std::nullopt,
.smallest_unit = smallest_unit,
.rounding_mode = rounding_mode,
.increment = rounding_increment};
auto rounded = zoned_date_time->zoned_date_time()->raw()->round_with_provider(
options, TimeZoneProvider());
return ConstructRustWrappingType<JSTemporalZonedDateTime>(isolate,
std::move(rounded));
}
MaybeDirectHandle<JSTemporalZonedDateTime> JSTemporalZonedDateTime::Add(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
DirectHandle<Object> temporal_duration_like, DirectHandle<Object> options) {
static const char method_name[] = "Temporal.ZonedDateTime.prototype.add";
return temporal::AddDurationToGeneric(
isolate, &temporal_rs::ZonedDateTime::add_with_provider, zoned_date_time,
temporal_duration_like, options, method_name, TimeZoneProvider());
}
MaybeDirectHandle<JSTemporalZonedDateTime> JSTemporalZonedDateTime::Subtract(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
DirectHandle<Object> temporal_duration_like, DirectHandle<Object> options) {
static const char method_name[] = "Temporal.ZonedDateTime.prototype.subtract";
return temporal::AddDurationToGeneric(
isolate, &temporal_rs::ZonedDateTime::subtract_with_provider,
zoned_date_time, temporal_duration_like, options, method_name,
TimeZoneProvider());
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalZonedDateTime::Until(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> handle,
DirectHandle<Object> other, DirectHandle<Object> options) {
static const char method_name[] = "Temporal.ZonedDateTime.prototype.since";
return temporal::GenericDifferenceTemporal(
isolate, &temporal_rs::ZonedDateTime::until_with_provider,
UnitGroup::kDateTime, Unit::Nanosecond, handle, other, options,
method_name, TimeZoneProvider());
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalZonedDateTime::Since(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> handle,
DirectHandle<Object> other, DirectHandle<Object> options) {
static const char method_name[] = "Temporal.ZonedDateTime.prototype.since";
return temporal::GenericDifferenceTemporal(
isolate, &temporal_rs::ZonedDateTime::since_with_provider,
UnitGroup::kDateTime, Unit::Nanosecond, handle, other, options,
method_name, TimeZoneProvider());
}
MaybeDirectHandle<JSTemporalInstant> JSTemporalInstant::Now(Isolate* isolate) {
auto ms = temporal::SystemUTCEpochMilliseconds();
return ConstructRustWrappingType<JSTemporalInstant>(
isolate, temporal_rs::Instant::from_epoch_milliseconds(ms));
}
MaybeDirectHandle<Object> JSTemporalZonedDateTime::OffsetNanoseconds(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
int64_t offset_ns =
zoned_date_time->zoned_date_time()->raw()->offset_nanoseconds();
return isolate->factory()->NewNumberFromInt64(offset_ns);
}
MaybeDirectHandle<BigInt> JSTemporalZonedDateTime::EpochNanoseconds(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
return temporal::I128ToBigInt(
isolate, zoned_date_time->zoned_date_time()->raw()->epoch_nanoseconds());
}
MaybeDirectHandle<String> JSTemporalZonedDateTime::TimeZoneId(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
std::string id;
MOVE_RETURN_ON_EXCEPTION(
isolate, id,
ExtractRustResult(isolate,
zoned_date_time->zoned_date_time()
->raw()
->timezone()
.identifier_with_provider(TimeZoneProvider())));
IncrementalStringBuilder builder(isolate);
builder.AppendString(id);
return builder.Finish().ToHandleChecked();
}
MaybeDirectHandle<String> JSTemporalZonedDateTime::Offset(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
std::string offset;
MOVE_RETURN_ON_EXCEPTION(
isolate, offset,
ExtractRustResult(isolate,
zoned_date_time->zoned_date_time()->raw()->offset()));
IncrementalStringBuilder builder(isolate);
builder.AppendString(offset);
return builder.Finish().ToHandleChecked();
}
MaybeDirectHandle<JSTemporalZonedDateTime> JSTemporalZonedDateTime::StartOfDay(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
return ConstructRustWrappingType<JSTemporalZonedDateTime>(
isolate,
zoned_date_time->zoned_date_time()->raw()->start_of_day_with_provider(
TimeZoneProvider()));
}
MaybeDirectHandle<UnionOf<JSTemporalZonedDateTime, Null>>
JSTemporalZonedDateTime::GetTimeZoneTransition(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time,
DirectHandle<Object> direction_param_obj) {
static const char method_name[] =
"Temporal.ZonedDateTime.prototype.getTimeZoneTransition";
if (IsUndefined(*direction_param_obj)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(
"Must specify a direction parameter."));
}
DirectHandle<JSReceiver> direction_param;
auto factory = isolate->factory();
if (IsString(*direction_param_obj)) {
DirectHandle<String> param_string = Cast<String>(direction_param_obj);
direction_param = factory->NewJSObjectWithNullProto();
CHECK(JSReceiver::CreateDataProperty(isolate, direction_param,
factory->direction_string(),
param_string, Just(kThrowOnError))
.FromJust());
} else {
if (!IsJSReceiver(*direction_param_obj)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(
"directionParam must be object or string."));
}
direction_param = Cast<JSReceiver>(direction_param_obj);
}
temporal_rs::TransitionDirection dir;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, dir,
temporal::GetDirectionOption(isolate, direction_param, method_name));
std::unique_ptr<temporal_rs::ZonedDateTime> zdt;
MOVE_RETURN_ON_EXCEPTION(
isolate, zdt,
ExtractRustResult(isolate, zoned_date_time->zoned_date_time()
->raw()
->get_time_zone_transition_with_provider(
dir, TimeZoneProvider())));
if (!zdt) {
return isolate->factory()->null_value();
}
return ConstructRustWrappingType<JSTemporalZonedDateTime>(isolate,
std::move(zdt));
}
MaybeDirectHandle<JSTemporalInstant> JSTemporalZonedDateTime::ToInstant(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
return temporal::GenericToTemporalMethod<JSTemporalInstant>(
isolate, zoned_date_time, &temporal_rs::ZonedDateTime::to_instant);
}
MaybeDirectHandle<JSTemporalPlainDate> JSTemporalZonedDateTime::ToPlainDate(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
return temporal::GenericToTemporalMethod<JSTemporalPlainDate>(
isolate, zoned_date_time, &temporal_rs::ZonedDateTime::to_plain_date);
}
MaybeDirectHandle<JSTemporalPlainTime> JSTemporalZonedDateTime::ToPlainTime(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
return temporal::GenericToTemporalMethod<JSTemporalPlainTime>(
isolate, zoned_date_time, &temporal_rs::ZonedDateTime::to_plain_time);
}
MaybeDirectHandle<JSTemporalPlainDateTime>
JSTemporalZonedDateTime::ToPlainDateTime(
Isolate* isolate, DirectHandle<JSTemporalZonedDateTime> zoned_date_time) {
return temporal::GenericToTemporalMethod<JSTemporalPlainDateTime>(
isolate, zoned_date_time, &temporal_rs::ZonedDateTime::to_plain_datetime);
}
namespace temporal {
MaybeDirectHandle<JSTemporalInstant> CreateTemporalInstantWithValidityCheck(
Isolate* isolate, DirectHandle<JSFunction> target,
DirectHandle<HeapObject> new_target,
DirectHandle<BigInt> epoch_nanoseconds) {
temporal_rs::I128Nanoseconds ns;
ASSIGN_RETURN_ON_EXCEPTION(isolate, ns,
GetI128FromBigInt(isolate, epoch_nanoseconds));
return ConstructRustWrappingType<JSTemporalInstant>(
isolate, target, new_target, temporal_rs::Instant::try_new(ns));
}
MaybeDirectHandle<JSTemporalInstant> CreateTemporalInstantWithValidityCheck(
Isolate* isolate, DirectHandle<BigInt> epoch_nanoseconds) {
auto ctor = JSTemporalInstant::GetConstructorTarget(isolate);
return CreateTemporalInstantWithValidityCheck(isolate, ctor, ctor,
epoch_nanoseconds);
}
}
MaybeDirectHandle<JSTemporalInstant> JSTemporalInstant::Constructor(
Isolate* isolate, DirectHandle<JSFunction> target,
DirectHandle<HeapObject> new_target,
DirectHandle<Object> epoch_nanoseconds_obj) {
if (IsUndefined(*new_target)) {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kMethodInvokedOnWrongType,
isolate->factory()->NewStringFromAsciiChecked(
"Temporal.Instant")));
}
DirectHandle<BigInt> epoch_nanoseconds;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, epoch_nanoseconds,
BigInt::FromObject(isolate, epoch_nanoseconds_obj));
return temporal::CreateTemporalInstantWithValidityCheck(
isolate, target, new_target, epoch_nanoseconds);
}
MaybeDirectHandle<JSTemporalInstant> JSTemporalInstant::From(
Isolate* isolate, DirectHandle<Object> item) {
static const char method_name[] = "Temporal.Instant.from";
DirectHandle<JSTemporalInstant> item_instant;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, item_instant,
temporal::ToTemporalInstant(isolate, item, method_name));
return item_instant;
}
MaybeDirectHandle<JSTemporalInstant> JSTemporalInstant::FromEpochMilliseconds(
Isolate* isolate, DirectHandle<Object> epoch_milliseconds) {
DirectHandle<Number> number;
ASSIGN_RETURN_ON_EXCEPTION(isolate, number,
Object::ToNumber(isolate, epoch_milliseconds));
double ms = Object::NumberValue(*number);
if (!std::isfinite(ms) ||
!base::IsValueInRangeForNumericType<int64_t, double>(ms) ||
nearbyint(ms) != ms) {
THROW_NEW_ERROR(isolate,
NEW_TEMPORAL_RANGE_ERROR("Expected finite integer."));
}
auto ms_int = static_cast<int64_t>(ms);
return ConstructRustWrappingType<JSTemporalInstant>(
isolate, temporal_rs::Instant::from_epoch_milliseconds(ms_int));
}
MaybeDirectHandle<JSTemporalInstant> JSTemporalInstant::FromEpochNanoseconds(
Isolate* isolate, DirectHandle<Object> epoch_nanoseconds_obj) {
DirectHandle<BigInt> epoch_nanoseconds;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, epoch_nanoseconds,
BigInt::FromObject(isolate, epoch_nanoseconds_obj));
return temporal::CreateTemporalInstantWithValidityCheck(isolate,
epoch_nanoseconds);
}
MaybeDirectHandle<Smi> JSTemporalInstant::Compare(
Isolate* isolate, DirectHandle<Object> one_obj,
DirectHandle<Object> two_obj) {
static const char method_name[] = "Temporal.Instant.compare";
DirectHandle<JSTemporalInstant> one;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, one, temporal::ToTemporalInstant(isolate, one_obj, method_name));
DirectHandle<JSTemporalInstant> two;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, two, temporal::ToTemporalInstant(isolate, two_obj, method_name));
return direct_handle(
Smi::FromInt(one->instant()->raw()->compare(*two->instant()->raw())),
isolate);
}
MaybeDirectHandle<Oddball> JSTemporalInstant::Equals(
Isolate* isolate, DirectHandle<JSTemporalInstant> handle,
DirectHandle<Object> other_obj) {
static const char method_name[] = "Temporal.Instant.prototype.equals";
DirectHandle<JSTemporalInstant> other;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, other,
temporal::ToTemporalInstant(isolate, other_obj, method_name));
auto this_ns = handle->instant()->raw()->epoch_nanoseconds();
auto other_ns = other->instant()->raw()->epoch_nanoseconds();
return isolate->factory()->ToBoolean(this_ns.high == other_ns.high &&
this_ns.low == other_ns.low);
}
MaybeDirectHandle<JSTemporalInstant> JSTemporalInstant::Round(
Isolate* isolate, DirectHandle<JSTemporalInstant> handle,
DirectHandle<Object> round_to_obj) {
static const char method_name[] = "Temporal.Instant.prototype.round";
Factory* factory = isolate->factory();
if (IsUndefined(*round_to_obj)) {
THROW_NEW_ERROR(isolate, NEW_TEMPORAL_TYPE_ERROR(kRoundToMissing));
}
DirectHandle<JSReceiver> round_to;
if (IsString(*round_to_obj)) {
DirectHandle<String> param_string = Cast<String>(round_to_obj);
round_to = factory->NewJSObjectWithNullProto();
CHECK(JSReceiver::CreateDataProperty(isolate, round_to,
factory->smallestUnit_string(),
param_string, Just(kThrowOnError))
.FromJust());
} else {
ASSIGN_RETURN_ON_EXCEPTION(
isolate, round_to,
GetOptionsObject(isolate, round_to_obj, method_name));
}
uint32_t rounding_increment;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, rounding_increment,
temporal::GetRoundingIncrementOption(isolate, round_to));
RoundingMode rounding_mode;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, rounding_mode,
temporal::GetRoundingModeOption(isolate, round_to,
RoundingMode::HalfExpand, method_name));
std::optional<Unit> smallest_unit;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, smallest_unit,
temporal::GetTemporalUnitValuedOption(
isolate, round_to, isolate->factory()->smallestUnit_string(),
DefaultValue::kRequired, method_name));
RETURN_ON_EXCEPTION(isolate, temporal::ValidateTemporalUnitValue(
isolate, smallest_unit, UnitGroup::kTime));
auto options = temporal_rs::RoundingOptions{.largest_unit = std::nullopt,
.smallest_unit = smallest_unit,
.rounding_mode = rounding_mode,
.increment = rounding_increment};
auto rounded = handle->instant()->raw()->round(options);
return ConstructRustWrappingType<JSTemporalInstant>(isolate,
std::move(rounded));
}
MaybeDirectHandle<Number> JSTemporalInstant::EpochMilliseconds(
Isolate* isolate, DirectHandle<JSTemporalInstant> handle) {
int64_t ms = handle->instant()->raw()->epoch_milliseconds();
return isolate->factory()->NewNumberFromInt64(ms);
}
MaybeDirectHandle<BigInt> JSTemporalInstant::EpochNanoseconds(
Isolate* isolate, DirectHandle<JSTemporalInstant> handle) {
return temporal::I128ToBigInt(isolate,
handle->instant()->raw()->epoch_nanoseconds());
}
MaybeDirectHandle<JSTemporalZonedDateTime>
JSTemporalInstant::ToZonedDateTimeISO(Isolate* isolate,
DirectHandle<JSTemporalInstant> instant,
DirectHandle<Object> time_zone_obj) {
temporal_rs::TimeZone time_zone;
MOVE_RETURN_ON_EXCEPTION(
isolate, time_zone,
temporal::ToTemporalTimeZoneIdentifier(isolate, time_zone_obj));
return ConstructRustWrappingType<JSTemporalZonedDateTime>(
isolate, instant->instant()->raw()->to_zoned_date_time_iso_with_provider(
time_zone, TimeZoneProvider()));
}
MaybeDirectHandle<String> JSTemporalInstant::ToString(
Isolate* isolate, DirectHandle<JSTemporalInstant> instant,
DirectHandle<Object> options_obj) {
static const char method_name[] = "Temporal.Instant.prototype.toString";
DirectHandle<JSReceiver> options;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, options, GetOptionsObject(isolate, options_obj, method_name));
temporal_rs::Precision digits;
ASSIGN_RETURN_ON_EXCEPTION(isolate, digits,
temporal::GetTemporalFractionalSecondDigitsOption(
isolate, options, method_name));
RoundingMode rounding_mode;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, rounding_mode,
temporal::GetRoundingModeOption(isolate, options, RoundingMode::Trunc,
method_name));
std::optional<Unit> smallest_unit;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, smallest_unit,
temporal::GetTemporalUnitValuedOption(
isolate, options, isolate->factory()->smallestUnit_string(),
DefaultValue::kUnset, method_name));
DirectHandle<Object> time_zone;
ASSIGN_RETURN_ON_EXCEPTION(
isolate, time_zone,
JSReceiver::GetProperty(isolate, options,
isolate->factory()->timeZone_string()));
RETURN_ON_EXCEPTION(isolate, temporal::ValidateTemporalUnitValue(
isolate, smallest_unit, UnitGroup::kTime));
if (smallest_unit == Unit::Hour) {
THROW_NEW_ERROR(isolate,
NewRangeError(MessageTemplate::kPropertyValueOutOfRange,
isolate->factory()->smallestUnit_string()));
}
std::optional<temporal_rs::TimeZone> tz_for_passing;
if (!IsUndefined(*time_zone)) {
temporal_rs::TimeZone rust_time_zone;
MOVE_RETURN_ON_EXCEPTION(
isolate, rust_time_zone,
temporal::ToTemporalTimeZoneIdentifier(isolate, time_zone));
tz_for_passing = rust_time_zone;
}
auto rust_options = temporal_rs::ToStringRoundingOptions{
.precision = digits,
.smallest_unit = smallest_unit,
.rounding_mode = rounding_mode,
};
return temporal::GenericTemporalToString(
isolate, instant, &temporal_rs::Instant::to_ixdtf_string_with_provider,
tz_for_passing, std::move(rust_options), std::ref(TimeZoneProvider()));
}
MaybeDirectHandle<String> JSTemporalInstant::ToJSON(
Isolate* isolate, DirectHandle<JSTemporalInstant> instant) {
return temporal::GenericTemporalToString(
isolate, instant, &temporal_rs::Instant::to_ixdtf_string_with_provider,
std::nullopt, std::move(temporal::kToStringAuto),
std::ref(TimeZoneProvider()));
}
MaybeDirectHandle<String> JSTemporalInstant::ToLocaleString(
Isolate* isolate, DirectHandle<JSTemporalInstant> instant,
DirectHandle<Object> locales, DirectHandle<Object> options) {
#ifdef V8_INTL_SUPPORT
return JSDateTimeFormat::TemporalToLocaleString(
isolate, instant, locales, options,
JSDateTimeFormat::RequiredOption::kAny,
JSDateTimeFormat::DefaultsOption::kAll,
"Temporal.Instant.prototype.toLocaleString");
#else
return temporal::GenericTemporalToString(
isolate, instant, &temporal_rs::Instant::to_ixdtf_string_with_provider,
std::nullopt, std::move(temporal::kToStringAuto),
std::ref(TimeZoneProvider()));
#endif
}
MaybeDirectHandle<JSTemporalInstant> JSTemporalInstant::Add(
Isolate* isolate, DirectHandle<JSTemporalInstant> handle,
DirectHandle<Object> temporal_duration_like) {
static const char method_name[] = "Temporal.Duration.prototype.add";
DirectHandle<JSTemporalDuration> other_duration;
ASSIGN_RETURN_ON_EXCEPTION(isolate, other_duration,
temporal::ToTemporalDuration(
isolate, temporal_duration_like, method_name));
auto added =
handle->instant()->raw()->add(*other_duration->duration()->raw());
return ConstructRustWrappingType<JSTemporalInstant>(isolate,
std::move(added));
}
MaybeDirectHandle<JSTemporalInstant> JSTemporalInstant::Subtract(
Isolate* isolate, DirectHandle<JSTemporalInstant> handle,
DirectHandle<Object> temporal_duration_like) {
static const char method_name[] = "Temporal.Duration.prototype.subtract";
DirectHandle<JSTemporalDuration> other_duration;
ASSIGN_RETURN_ON_EXCEPTION(isolate, other_duration,
temporal::ToTemporalDuration(
isolate, temporal_duration_like, method_name));
auto subtracted =
handle->instant()->raw()->subtract(*other_duration->duration()->raw());
return ConstructRustWrappingType<JSTemporalInstant>(isolate,
std::move(subtracted));
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalInstant::Until(
Isolate* isolate, DirectHandle<JSTemporalInstant> handle,
DirectHandle<Object> other, DirectHandle<Object> options) {
static const char method_name[] = "Temporal.Instant.prototype.until";
return temporal::GenericDifferenceTemporal(
isolate, &temporal_rs::Instant::until, UnitGroup::kTime, Unit::Nanosecond,
handle, other, options, method_name);
}
MaybeDirectHandle<JSTemporalDuration> JSTemporalInstant::Since(
Isolate* isolate, DirectHandle<JSTemporalInstant> handle,
DirectHandle<Object> other, DirectHandle<Object> options) {
static const char method_name[] = "Temporal.Instant.prototype.since";
return temporal::GenericDifferenceTemporal(
isolate, &temporal_rs::Instant::since, UnitGroup::kTime, Unit::Nanosecond,
handle, other, options, method_name);
}
V8_WARN_UNUSED_RESULT MaybeDirectHandle<String> JSTemporalNowTimeZoneId(
Isolate* isolate) {
#ifdef V8_INTL_SUPPORT
auto tz_str = Intl::DefaultTimeZone();
IncrementalStringBuilder builder(isolate);
builder.AppendString(tz_str);
return builder.Finish().ToHandleChecked();
#else
return isolate->factory()->UTC_string();
#endif
}
}