/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- * vim: set ts=8 sts=2 et sw=2 tw=80: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef builtin_temporal_Temporal_h #define builtin_temporal_Temporal_h #include "mozilla/Assertions.h" #include #include "jstypes.h" #include "builtin/temporal/Int128.h" #include "builtin/temporal/TemporalRoundingMode.h" #include "builtin/temporal/TemporalUnit.h" #include "js/RootingAPI.h" #include "js/TypeDecls.h" #include "vm/NativeObject.h" namespace js { struct ClassSpec; class PlainObject; class PropertyName; } // namespace js namespace js::temporal { class TemporalObject : public NativeObject { public: static const JSClass class_; private: static const ClassSpec classSpec_; }; /** * Rounding increment, which is an integer in the range [1, 1'000'000'000]. * * Temporal units are rounded to a multiple of the specified increment value. */ class Increment final { uint32_t value_; public: constexpr explicit Increment(uint32_t value) : value_(value) { MOZ_ASSERT(1 <= value && value <= 1'000'000'000); } /** * Minimum allowed rounding increment. */ static constexpr auto min() { return Increment{1}; } /** * Maximum allowed rounding increment. */ static constexpr auto max() { return Increment{1'000'000'000}; } /** * The rounding increment's value. */ uint32_t value() const { return value_; } bool operator==(const Increment& other) const { return value_ == other.value_; } bool operator<(const Increment& other) const { return value_ < other.value_; } // Other operators are implemented in terms of operator== and operator<. bool operator!=(const Increment& other) const { return !(*this == other); } bool operator>(const Increment& other) const { return other < *this; } bool operator<=(const Increment& other) const { return !(other < *this); } bool operator>=(const Increment& other) const { return !(*this < other); } }; /** * ToTemporalRoundingIncrement ( normalizedOptions, dividend, inclusive ) */ bool ToTemporalRoundingIncrement(JSContext* cx, JS::Handle options, Increment* increment); /** * ValidateTemporalRoundingIncrement ( increment, dividend, inclusive ) */ bool ValidateTemporalRoundingIncrement(JSContext* cx, Increment increment, int64_t dividend, bool inclusive); /** * ValidateTemporalRoundingIncrement ( increment, dividend, inclusive ) */ inline bool ValidateTemporalRoundingIncrement(JSContext* cx, Increment increment, Increment dividend, bool inclusive) { return ValidateTemporalRoundingIncrement(cx, increment, dividend.value(), inclusive); } /** * MaximumTemporalDurationRoundingIncrement ( unit ) */ constexpr Increment MaximumTemporalDurationRoundingIncrement( TemporalUnit unit) { // Step 1. (Not applicable in our implementation.) MOZ_ASSERT(unit > TemporalUnit::Day); // Step 2. if (unit == TemporalUnit::Hour) { return Increment{24}; } // Step 3. if (unit <= TemporalUnit::Second) { return Increment{60}; } // Steps 4-5. return Increment{1000}; } PropertyName* TemporalUnitToString(JSContext* cx, TemporalUnit unit); enum class TemporalUnitGroup { // Allow date units: "year", "month", "week", "day". Date, // Allow time units: "hour", "minute", "second", "milli-/micro-/nanoseconds". Time, // Allow date and time units. DateTime, // Allow "day" and time units. DayTime, }; enum class TemporalUnitKey { SmallestUnit, LargestUnit, Unit, }; /** * GetTemporalUnit ( normalizedOptions, key, unitGroup, default [ , extraValues * ] ) */ bool GetTemporalUnit(JSContext* cx, JS::Handle options, TemporalUnitKey key, TemporalUnitGroup unitGroup, TemporalUnit* unit); /** * GetTemporalUnit ( normalizedOptions, key, unitGroup, default [ , extraValues * ] ) */ bool GetTemporalUnit(JSContext* cx, JS::Handle value, TemporalUnitKey key, TemporalUnitGroup unitGroup, TemporalUnit* unit); /** * ToTemporalRoundingMode ( normalizedOptions, fallback ) */ bool ToTemporalRoundingMode(JSContext* cx, JS::Handle options, TemporalRoundingMode* mode); /** * RoundNumberToIncrement ( x, increment, roundingMode ) */ Int128 RoundNumberToIncrement(int64_t numerator, int64_t denominator, Increment increment, TemporalRoundingMode roundingMode); /** * RoundNumberToIncrement ( x, increment, roundingMode ) */ Int128 RoundNumberToIncrement(const Int128& numerator, const Int128& denominator, Increment increment, TemporalRoundingMode roundingMode); /** * RoundNumberToIncrement ( x, increment, roundingMode ) */ Int128 RoundNumberToIncrement(const Int128& x, const Int128& increment, TemporalRoundingMode roundingMode); /** * Return the double value of the fractional number `numerator / denominator`. */ double FractionToDouble(int64_t numerator, int64_t denominator); /** * Return the double value of the fractional number `numerator / denominator`. */ double FractionToDouble(const Int128& numerator, const Int128& denominator); enum class CalendarOption { Auto, Always, Never, Critical }; /** * ToCalendarNameOption ( normalizedOptions ) */ bool ToCalendarNameOption(JSContext* cx, JS::Handle options, CalendarOption* result); /** * Precision when displaying fractional seconds. */ class Precision final { int8_t value_; enum class Tag {}; constexpr Precision(int8_t value, Tag) : value_(value) {} public: constexpr explicit Precision(uint8_t value) : value_(int8_t(value)) { MOZ_ASSERT(value < 10); } bool operator==(const Precision& other) const { return value_ == other.value_; } bool operator!=(const Precision& other) const { return !(*this == other); } /** * Return the number of fractional second digits. */ uint8_t value() const { MOZ_ASSERT(value_ >= 0, "auto and minute precision don't have a value"); return uint8_t(value_); } /** * Limit the precision to trim off any trailing zeros. */ static constexpr Precision Auto() { return {-1, Tag{}}; } /** * Limit the precision to minutes, i.e. don't display seconds and sub-seconds. */ static constexpr Precision Minute() { return {-2, Tag{}}; } }; /** * ToFractionalSecondDigits ( normalizedOptions ) */ bool ToFractionalSecondDigits(JSContext* cx, JS::Handle options, Precision* precision); struct SecondsStringPrecision final { Precision precision = Precision{0}; TemporalUnit unit = TemporalUnit::Auto; Increment increment = Increment{1}; }; /** * ToSecondsStringPrecisionRecord ( smallestUnit, fractionalDigitCount ) */ SecondsStringPrecision ToSecondsStringPrecision(TemporalUnit smallestUnit, Precision fractionalDigitCount); enum class TemporalOverflow { Constrain, Reject }; /** * ToTemporalOverflow ( normalizedOptions ) */ bool ToTemporalOverflow(JSContext* cx, JS::Handle options, TemporalOverflow* result); enum class TemporalDisambiguation { Compatible, Earlier, Later, Reject }; /** * ToTemporalDisambiguation ( options ) */ bool ToTemporalDisambiguation(JSContext* cx, JS::Handle options, TemporalDisambiguation* disambiguation); enum class TemporalOffset { Prefer, Use, Ignore, Reject }; /** * ToTemporalOffset ( options, fallback ) */ bool ToTemporalOffset(JSContext* cx, JS::Handle options, TemporalOffset* offset); enum class TimeZoneNameOption { Auto, Never, Critical }; bool ToTimeZoneNameOption(JSContext* cx, JS::Handle options, TimeZoneNameOption* result); enum class ShowOffsetOption { Auto, Never }; /** * ToShowOffsetOption ( normalizedOptions ) */ bool ToShowOffsetOption(JSContext* cx, JS::Handle options, ShowOffsetOption* result); /** * IsPartialTemporalObject ( object ) * * Our implementation performs error reporting in this function instead of in * the caller to provide better error messages. */ bool ThrowIfTemporalLikeObject(JSContext* cx, JS::Handle object); /** * ToPositiveIntegerWithTruncation ( argument ) */ bool ToPositiveIntegerWithTruncation(JSContext* cx, JS::Handle value, const char* name, double* result); /** * ToIntegerWithTruncation ( argument ) */ bool ToIntegerWithTruncation(JSContext* cx, JS::Handle value, const char* name, double* result); /** * GetMethod ( V, P ) */ JSObject* GetMethod(JSContext* cx, JS::Handle object, JS::Handle name); /** * SnapshotOwnProperties ( source, proto [ , excludedKeys [ , excludedValues ] ] * ) */ PlainObject* SnapshotOwnProperties(JSContext* cx, JS::Handle source); /** * SnapshotOwnProperties ( source, proto [ , excludedKeys [ , excludedValues ] ] * ) */ PlainObject* SnapshotOwnPropertiesIgnoreUndefined(JSContext* cx, JS::Handle source); /** * CopyDataProperties ( target, source, excludedKeys [ , excludedValues ] ) */ bool CopyDataProperties(JSContext* cx, JS::Handle target, JS::Handle source); enum class TemporalDifference { Since, Until }; inline const char* ToName(TemporalDifference difference) { return difference == TemporalDifference::Since ? "since" : "until"; } struct DifferenceSettings final { TemporalUnit smallestUnit = TemporalUnit::Auto; TemporalUnit largestUnit = TemporalUnit::Auto; TemporalRoundingMode roundingMode = TemporalRoundingMode::Trunc; Increment roundingIncrement = Increment{1}; }; /** * GetDifferenceSettings ( operation, options, unitGroup, disallowedUnits, * fallbackSmallestUnit, smallestLargestDefaultUnit ) */ bool GetDifferenceSettings(JSContext* cx, TemporalDifference operation, JS::Handle options, TemporalUnitGroup unitGroup, TemporalUnit smallestAllowedUnit, TemporalUnit fallbackSmallestUnit, TemporalUnit smallestLargestDefaultUnit, DifferenceSettings* result); /** * GetDifferenceSettings ( operation, options, unitGroup, disallowedUnits, * fallbackSmallestUnit, smallestLargestDefaultUnit ) */ inline bool GetDifferenceSettings(JSContext* cx, TemporalDifference operation, JS::Handle options, TemporalUnitGroup unitGroup, TemporalUnit fallbackSmallestUnit, TemporalUnit smallestLargestDefaultUnit, DifferenceSettings* result) { return GetDifferenceSettings(cx, operation, options, unitGroup, TemporalUnit::Nanosecond, fallbackSmallestUnit, smallestLargestDefaultUnit, result); } /** * Sets |result| to `true` when array iteration is still in its initial state. */ bool IsArrayIterationSane(JSContext* cx, bool* result); } /* namespace js::temporal */ #endif /* builtin_temporal_Temporal_h */