Temporal.h (12275B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef builtin_temporal_Temporal_h 8 #define builtin_temporal_Temporal_h 9 10 #include "mozilla/Assertions.h" 11 12 #include <stdint.h> 13 14 #include "jstypes.h" 15 16 #include "builtin/temporal/TemporalRoundingMode.h" 17 #include "builtin/temporal/TemporalUnit.h" 18 #include "js/RootingAPI.h" 19 #include "js/TypeDecls.h" 20 #include "vm/Int128.h" 21 #include "vm/NativeObject.h" 22 23 namespace js { 24 struct ClassSpec; 25 } // namespace js 26 27 namespace js::temporal { 28 29 class TemporalObject : public NativeObject { 30 public: 31 static const JSClass class_; 32 33 private: 34 static const ClassSpec classSpec_; 35 }; 36 37 /** 38 * Rounding increment, which is an integer in the range [1, 1'000'000'000]. 39 * 40 * Temporal units are rounded to a multiple of the specified increment value. 41 */ 42 class Increment final { 43 uint32_t value_; 44 45 public: 46 constexpr explicit Increment(uint32_t value) : value_(value) { 47 MOZ_ASSERT(1 <= value && value <= 1'000'000'000); 48 } 49 50 /** 51 * Minimum allowed rounding increment. 52 */ 53 static constexpr auto min() { return Increment{1}; } 54 55 /** 56 * Maximum allowed rounding increment. 57 */ 58 static constexpr auto max() { return Increment{1'000'000'000}; } 59 60 /** 61 * The rounding increment's value. 62 */ 63 uint32_t value() const { return value_; } 64 65 bool operator==(const Increment& other) const { 66 return value_ == other.value_; 67 } 68 69 bool operator<(const Increment& other) const { return value_ < other.value_; } 70 71 // Other operators are implemented in terms of operator== and operator<. 72 bool operator!=(const Increment& other) const { return !(*this == other); } 73 bool operator>(const Increment& other) const { return other < *this; } 74 bool operator<=(const Increment& other) const { return !(other < *this); } 75 bool operator>=(const Increment& other) const { return !(*this < other); } 76 }; 77 78 /** 79 * GetRoundingIncrementOption ( normalizedOptions, dividend, inclusive ) 80 */ 81 bool GetRoundingIncrementOption(JSContext* cx, JS::Handle<JSObject*> options, 82 Increment* increment); 83 84 /** 85 * ValidateTemporalRoundingIncrement ( increment, dividend, inclusive ) 86 */ 87 bool ValidateTemporalRoundingIncrement(JSContext* cx, Increment increment, 88 int64_t dividend, bool inclusive); 89 90 /** 91 * ValidateTemporalRoundingIncrement ( increment, dividend, inclusive ) 92 */ 93 inline bool ValidateTemporalRoundingIncrement(JSContext* cx, 94 Increment increment, 95 Increment dividend, 96 bool inclusive) { 97 return ValidateTemporalRoundingIncrement(cx, increment, dividend.value(), 98 inclusive); 99 } 100 101 /** 102 * MaximumTemporalDurationRoundingIncrement ( unit ) 103 */ 104 constexpr Increment MaximumTemporalDurationRoundingIncrement( 105 TemporalUnit unit) { 106 // Step 1. (Not applicable in our implementation.) 107 MOZ_ASSERT(unit > TemporalUnit::Day); 108 109 // Step 2. 110 if (unit == TemporalUnit::Hour) { 111 return Increment{24}; 112 } 113 114 // Step 3. 115 if (unit <= TemporalUnit::Second) { 116 return Increment{60}; 117 } 118 119 // Steps 4-5. 120 return Increment{1000}; 121 } 122 123 enum class TemporalUnitGroup { 124 // Allow date units: "year", "month", "week", "day". 125 Date, 126 127 // Allow time units: "hour", "minute", "second", "milli-/micro-/nanoseconds". 128 Time, 129 130 // Allow date and time units. 131 DateTime, 132 133 // Allow "day" and time units. 134 DayTime, 135 }; 136 137 enum class TemporalUnitKey { 138 SmallestUnit, 139 LargestUnit, 140 Unit, 141 }; 142 143 /** 144 * GetTemporalUnitValuedOption ( options, key, default ) 145 */ 146 bool GetTemporalUnitValuedOption(JSContext* cx, JS::Handle<JSObject*> options, 147 TemporalUnitKey key, TemporalUnit* unit); 148 149 /** 150 * GetTemporalUnitValuedOption ( normalizedOptions, key, unitGroup, default [ , 151 * extraValues ] ) 152 */ 153 bool GetTemporalUnitValuedOption(JSContext* cx, JS::Handle<JSString*> value, 154 TemporalUnitKey key, TemporalUnit* unit); 155 156 /** 157 * ValidateTemporalUnitValue ( value, unitGroup [ , extraValues ] ) 158 */ 159 bool ValidateTemporalUnitValue(JSContext* cx, TemporalUnitKey key, 160 TemporalUnit unit, TemporalUnitGroup unitGroup); 161 162 /** 163 * GetRoundingModeOption ( normalizedOptions, fallback ) 164 */ 165 bool GetRoundingModeOption(JSContext* cx, JS::Handle<JSObject*> options, 166 TemporalRoundingMode* mode); 167 168 /** 169 * RoundNumberToIncrement ( x, increment, roundingMode ) 170 */ 171 Int128 RoundNumberToIncrement(const Int128& numerator, int64_t denominator, 172 Increment increment, 173 TemporalRoundingMode roundingMode); 174 175 /** 176 * RoundNumberToIncrement ( x, increment, roundingMode ) 177 */ 178 int64_t RoundNumberToIncrement(int64_t x, int64_t increment, 179 TemporalRoundingMode roundingMode); 180 181 /** 182 * RoundNumberToIncrement ( x, increment, roundingMode ) 183 */ 184 inline int64_t RoundNumberToIncrement(int64_t x, Increment increment, 185 TemporalRoundingMode roundingMode) { 186 return RoundNumberToIncrement(x, int64_t(increment.value()), roundingMode); 187 } 188 189 /** 190 * RoundNumberToIncrement ( x, increment, roundingMode ) 191 */ 192 Int128 RoundNumberToIncrement(const Int128& x, const Int128& increment, 193 TemporalRoundingMode roundingMode); 194 195 /** 196 * Return the double value of the fractional number `numerator / denominator`. 197 */ 198 double FractionToDouble(int64_t numerator, int64_t denominator); 199 200 /** 201 * Return the double value of the fractional number `numerator / denominator`. 202 */ 203 double FractionToDouble(const Int128& numerator, const Int128& denominator); 204 205 enum class ShowCalendar { Auto, Always, Never, Critical }; 206 207 /** 208 * GetTemporalShowCalendarNameOption ( normalizedOptions ) 209 */ 210 bool GetTemporalShowCalendarNameOption(JSContext* cx, 211 JS::Handle<JSObject*> options, 212 ShowCalendar* result); 213 214 /** 215 * Precision when displaying fractional seconds. 216 */ 217 class Precision final { 218 int8_t value_; 219 220 enum class Tag {}; 221 constexpr Precision(int8_t value, Tag) : value_(value) {} 222 223 public: 224 constexpr explicit Precision(uint8_t value) : value_(int8_t(value)) { 225 MOZ_ASSERT(value < 10); 226 } 227 228 bool operator==(const Precision& other) const { 229 return value_ == other.value_; 230 } 231 232 bool operator!=(const Precision& other) const { return !(*this == other); } 233 234 /** 235 * Return the number of fractional second digits. 236 */ 237 uint8_t value() const { 238 MOZ_ASSERT(value_ >= 0, "auto and minute precision don't have a value"); 239 return uint8_t(value_); 240 } 241 242 /** 243 * Limit the precision to trim off any trailing zeros. 244 */ 245 static constexpr Precision Auto() { return {-1, Tag{}}; } 246 247 /** 248 * Limit the precision to minutes, i.e. don't display seconds and sub-seconds. 249 */ 250 static constexpr Precision Minute() { return {-2, Tag{}}; } 251 }; 252 253 /** 254 * GetTemporalFractionalSecondDigitsOption ( normalizedOptions ) 255 */ 256 bool GetTemporalFractionalSecondDigitsOption(JSContext* cx, 257 JS::Handle<JSObject*> options, 258 Precision* precision); 259 260 struct SecondsStringPrecision final { 261 Precision precision = Precision{0}; 262 TemporalUnit unit = TemporalUnit::Unset; 263 Increment increment = Increment{1}; 264 }; 265 266 /** 267 * ToSecondsStringPrecisionRecord ( smallestUnit, fractionalDigitCount ) 268 */ 269 SecondsStringPrecision ToSecondsStringPrecision(TemporalUnit smallestUnit, 270 Precision fractionalDigitCount); 271 272 enum class TemporalOverflow { Constrain, Reject }; 273 274 /** 275 * GetTemporalOverflowOption ( normalizedOptions ) 276 */ 277 bool GetTemporalOverflowOption(JSContext* cx, JS::Handle<JSObject*> options, 278 TemporalOverflow* result); 279 280 enum class TemporalDisambiguation { Compatible, Earlier, Later, Reject }; 281 282 /** 283 * GetTemporalDisambiguationOption ( options ) 284 */ 285 bool GetTemporalDisambiguationOption(JSContext* cx, 286 JS::Handle<JSObject*> options, 287 TemporalDisambiguation* disambiguation); 288 289 enum class TemporalOffset { Prefer, Use, Ignore, Reject }; 290 291 /** 292 * GetTemporalOffsetOption ( options, fallback ) 293 */ 294 bool GetTemporalOffsetOption(JSContext* cx, JS::Handle<JSObject*> options, 295 TemporalOffset* offset); 296 297 enum class ShowTimeZoneName { Auto, Never, Critical }; 298 299 bool GetTemporalShowTimeZoneNameOption(JSContext* cx, 300 JS::Handle<JSObject*> options, 301 ShowTimeZoneName* result); 302 303 enum class ShowOffset { Auto, Never }; 304 305 /** 306 * GetTemporalShowOffsetOption ( normalizedOptions ) 307 */ 308 bool GetTemporalShowOffsetOption(JSContext* cx, JS::Handle<JSObject*> options, 309 ShowOffset* result); 310 311 enum class Direction { Next, Previous }; 312 313 /** 314 * GetDirectionOption ( options ) 315 */ 316 bool GetDirectionOption(JSContext* cx, JS::Handle<JSObject*> options, 317 Direction* result); 318 319 /** 320 * GetDirectionOption ( options ) 321 */ 322 bool GetDirectionOption(JSContext* cx, JS::Handle<JSString*> direction, 323 Direction* result); 324 325 /** 326 * IsPartialTemporalObject ( object ) 327 * 328 * Our implementation performs error reporting in this function instead of in 329 * the caller to provide better error messages. 330 */ 331 bool ThrowIfTemporalLikeObject(JSContext* cx, JS::Handle<JSObject*> object); 332 333 /** 334 * ToPositiveIntegerWithTruncation ( argument ) 335 */ 336 bool ToPositiveIntegerWithTruncation(JSContext* cx, JS::Handle<JS::Value> value, 337 const char* name, double* result); 338 339 /** 340 * ToIntegerWithTruncation ( argument ) 341 */ 342 bool ToIntegerWithTruncation(JSContext* cx, JS::Handle<JS::Value> value, 343 const char* name, double* result); 344 345 enum class TemporalDifference { Since, Until }; 346 347 inline const char* ToName(TemporalDifference difference) { 348 return difference == TemporalDifference::Since ? "since" : "until"; 349 } 350 351 enum class TemporalAddDuration { Add, Subtract }; 352 353 inline const char* ToName(TemporalAddDuration addDuration) { 354 return addDuration == TemporalAddDuration::Add ? "add" : "subtract"; 355 } 356 357 struct DifferenceSettings final { 358 TemporalUnit smallestUnit = TemporalUnit::Unset; 359 TemporalUnit largestUnit = TemporalUnit::Unset; 360 TemporalRoundingMode roundingMode = TemporalRoundingMode::Trunc; 361 Increment roundingIncrement = Increment{1}; 362 }; 363 364 /** 365 * GetDifferenceSettings ( operation, options, unitGroup, disallowedUnits, 366 * fallbackSmallestUnit, smallestLargestDefaultUnit ) 367 */ 368 bool GetDifferenceSettings(JSContext* cx, TemporalDifference operation, 369 JS::Handle<JSObject*> options, 370 TemporalUnitGroup unitGroup, 371 TemporalUnit smallestAllowedUnit, 372 TemporalUnit fallbackSmallestUnit, 373 TemporalUnit smallestLargestDefaultUnit, 374 DifferenceSettings* result); 375 376 /** 377 * GetDifferenceSettings ( operation, options, unitGroup, disallowedUnits, 378 * fallbackSmallestUnit, smallestLargestDefaultUnit ) 379 */ 380 inline bool GetDifferenceSettings(JSContext* cx, TemporalDifference operation, 381 JS::Handle<JSObject*> options, 382 TemporalUnitGroup unitGroup, 383 TemporalUnit fallbackSmallestUnit, 384 TemporalUnit smallestLargestDefaultUnit, 385 DifferenceSettings* result) { 386 return GetDifferenceSettings(cx, operation, options, unitGroup, 387 TemporalUnit::Nanosecond, fallbackSmallestUnit, 388 smallestLargestDefaultUnit, result); 389 } 390 391 } /* namespace js::temporal */ 392 393 #endif /* builtin_temporal_Temporal_h */