DurationFormat.h (5510B)
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_intl_DurationFormat_h 8 #define builtin_intl_DurationFormat_h 9 10 #include <stdint.h> 11 12 #include "builtin/SelfHostingDefines.h" 13 #include "builtin/temporal/TemporalUnit.h" 14 #include "js/Class.h" 15 #include "vm/NativeObject.h" 16 17 namespace mozilla::intl { 18 class ListFormat; 19 class NumberFormat; 20 } // namespace mozilla::intl 21 22 namespace js { 23 24 namespace intl { 25 enum class DurationDisplay : uint8_t { Auto, Always }; 26 enum class DurationStyle : uint8_t { Long, Short, Narrow, Numeric, TwoDigit }; 27 28 struct DurationFormatOptions { 29 // Packed representation to keep the unit options as small as possible. 30 // 31 // Use |uint8_t| instead of the actual enum type to avoid GCC warnings: 32 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414 33 #define DECLARE_DURATION_UNIT(name) \ 34 /* DurationDisplay */ uint8_t name##Display : 1; \ 35 /* DurationStyle */ uint8_t name##Style : 3; 36 37 DECLARE_DURATION_UNIT(years); 38 DECLARE_DURATION_UNIT(months); 39 DECLARE_DURATION_UNIT(weeks); 40 DECLARE_DURATION_UNIT(days); 41 DECLARE_DURATION_UNIT(hours); 42 DECLARE_DURATION_UNIT(minutes); 43 DECLARE_DURATION_UNIT(seconds); 44 DECLARE_DURATION_UNIT(milliseconds); 45 DECLARE_DURATION_UNIT(microseconds); 46 DECLARE_DURATION_UNIT(nanoseconds); 47 48 #undef DECLARE_DURATION_UNIT 49 50 int8_t fractionalDigits; 51 }; 52 53 struct DurationUnitOptions { 54 // Use the same bit-widths for fast extraction from DurationFormatOptions. 55 /* DurationDisplay */ uint8_t display_ : 1; 56 /* DurationStyle */ uint8_t style_ : 3; 57 58 auto display() const { return static_cast<DurationDisplay>(display_); } 59 60 auto style() const { return static_cast<DurationStyle>(style_); } 61 }; 62 63 } // namespace intl 64 65 class DurationFormatObject : public NativeObject { 66 public: 67 static const JSClass class_; 68 static const JSClass& protoClass_; 69 70 static constexpr uint32_t INTERNALS_SLOT = 0; 71 static constexpr uint32_t LIST_FORMAT_SLOT = 1; 72 static constexpr uint32_t NUMBER_FORMAT_YEARS_SLOT = 2; 73 static constexpr uint32_t NUMBER_FORMAT_MONTHS_SLOT = 3; 74 static constexpr uint32_t NUMBER_FORMAT_WEEKS_SLOT = 4; 75 static constexpr uint32_t NUMBER_FORMAT_DAYS_SLOT = 5; 76 static constexpr uint32_t NUMBER_FORMAT_HOURS_SLOT = 6; 77 static constexpr uint32_t NUMBER_FORMAT_MINUTES_SLOT = 7; 78 static constexpr uint32_t NUMBER_FORMAT_SECONDS_SLOT = 8; 79 static constexpr uint32_t NUMBER_FORMAT_MILLISECONDS_SLOT = 9; 80 static constexpr uint32_t NUMBER_FORMAT_MICROSECONDS_SLOT = 10; 81 static constexpr uint32_t NUMBER_FORMAT_NANOSECONDS_SLOT = 11; 82 static constexpr uint32_t OPTIONS_SLOT = 12; 83 static constexpr uint32_t TIME_SEPARATOR_SLOT = 13; 84 static constexpr uint32_t SLOT_COUNT = 14; 85 86 static_assert(INTERNALS_SLOT == INTL_INTERNALS_OBJECT_SLOT, 87 "INTERNALS_SLOT must match self-hosting define for internals " 88 "object slot"); 89 90 private: 91 static constexpr uint32_t numberFormatSlot(temporal::TemporalUnit unit) { 92 MOZ_ASSERT(temporal::TemporalUnit::Year <= unit && 93 unit <= temporal::TemporalUnit::Nanosecond); 94 95 static_assert(uint32_t(temporal::TemporalUnit::Year) == 96 NUMBER_FORMAT_YEARS_SLOT); 97 static_assert(uint32_t(temporal::TemporalUnit::Nanosecond) == 98 NUMBER_FORMAT_NANOSECONDS_SLOT); 99 100 return uint32_t(unit); 101 } 102 103 public: 104 mozilla::intl::NumberFormat* getNumberFormat( 105 temporal::TemporalUnit unit) const { 106 const auto& slot = getFixedSlot(numberFormatSlot(unit)); 107 if (slot.isUndefined()) { 108 return nullptr; 109 } 110 return static_cast<mozilla::intl::NumberFormat*>(slot.toPrivate()); 111 } 112 113 void setNumberFormat(temporal::TemporalUnit unit, 114 mozilla::intl::NumberFormat* numberFormat) { 115 setFixedSlot(numberFormatSlot(unit), PrivateValue(numberFormat)); 116 } 117 118 mozilla::intl::ListFormat* getListFormat() const { 119 const auto& slot = getFixedSlot(LIST_FORMAT_SLOT); 120 if (slot.isUndefined()) { 121 return nullptr; 122 } 123 return static_cast<mozilla::intl::ListFormat*>(slot.toPrivate()); 124 } 125 126 void setListFormat(mozilla::intl::ListFormat* listFormat) { 127 setFixedSlot(LIST_FORMAT_SLOT, PrivateValue(listFormat)); 128 } 129 130 intl::DurationFormatOptions* getOptions() const { 131 const auto& slot = getFixedSlot(OPTIONS_SLOT); 132 if (slot.isUndefined()) { 133 return nullptr; 134 } 135 return static_cast<intl::DurationFormatOptions*>(slot.toPrivate()); 136 } 137 138 void setOptions(intl::DurationFormatOptions* options) { 139 setFixedSlot(OPTIONS_SLOT, PrivateValue(options)); 140 } 141 142 JSString* getTimeSeparator() const { 143 const auto& slot = getFixedSlot(TIME_SEPARATOR_SLOT); 144 if (slot.isUndefined()) { 145 return nullptr; 146 } 147 return slot.toString(); 148 } 149 150 void setTimeSeparator(JSString* timeSeparator) { 151 setFixedSlot(TIME_SEPARATOR_SLOT, StringValue(timeSeparator)); 152 } 153 154 private: 155 static const JSClassOps classOps_; 156 static const ClassSpec classSpec_; 157 158 static void finalize(JS::GCContext* gcx, JSObject* obj); 159 }; 160 161 /** 162 * `toLocaleString` implementation for Temporal.Duration objects. 163 */ 164 [[nodiscard]] extern bool TemporalDurationToLocaleString( 165 JSContext* cx, const JS::CallArgs& args); 166 167 } // namespace js 168 169 #endif /* builtin_intl_DurationFormat_h */