From f7adcd8359928e6322ec0835305223863aee7aa0 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Mon, 22 Jun 2026 00:47:25 -0700 Subject: [PATCH 001/131] stream: respect iter consumer abort signals Delegate broadcast.push() and share.pull() calls with per-consumer AbortSignals through pull(), so pending next() calls reject when the signal aborts. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.5 PR-URL: https://github.com/nodejs/node/pull/63997 Fixes: https://github.com/nodejs/node/issues/63302 Reviewed-By: James M Snell Reviewed-By: Filip Skokan --- lib/internal/streams/iter/broadcast.js | 2 +- lib/internal/streams/iter/share.js | 2 +- .../test-stream-iter-broadcast-basic.js | 14 +++++++++++++ test/parallel/test-stream-iter-share-async.js | 20 +++++++++++++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/lib/internal/streams/iter/broadcast.js b/lib/internal/streams/iter/broadcast.js index d9bb1d86b6f646..b667857c478885 100644 --- a/lib/internal/streams/iter/broadcast.js +++ b/lib/internal/streams/iter/broadcast.js @@ -128,7 +128,7 @@ class BroadcastImpl { // own internal AbortController that follows the external signal. // When no transforms, return rawConsumer directly (controller elided // per PULL-02 optimization -- no transforms means no signal recipient). - if (transforms.length > 0) { + if (transforms.length > 0 || options?.signal) { const pullArgs = [...transforms]; if (options?.signal) { ArrayPrototypePush(pullArgs, diff --git a/lib/internal/streams/iter/share.js b/lib/internal/streams/iter/share.js index f755550712efa7..e65a5eb648b620 100644 --- a/lib/internal/streams/iter/share.js +++ b/lib/internal/streams/iter/share.js @@ -97,7 +97,7 @@ class ShareImpl { const { transforms, options } = parsePullArgs(args); const rawConsumer = this.#createRawConsumer(); - if (transforms.length > 0) { + if (transforms.length > 0 || options?.signal) { if (options) { return pullWithTransforms(rawConsumer, ...transforms, options); } diff --git a/test/parallel/test-stream-iter-broadcast-basic.js b/test/parallel/test-stream-iter-broadcast-basic.js index 39a2e2348ecb2e..bdecd7d5beb9b1 100644 --- a/test/parallel/test-stream-iter-broadcast-basic.js +++ b/test/parallel/test-stream-iter-broadcast-basic.js @@ -174,6 +174,19 @@ async function testPendingNextSettlesAfterReturn() { assert.strictEqual(result.value, undefined); } +async function testPushAbortSignalRejectsPendingNext() { + const ac = new AbortController(); + const reason = new Error('push aborted'); + const { broadcast: bc } = broadcast(); + const iter = bc.push({ signal: ac.signal })[Symbol.asyncIterator](); + + const pendingNext = iter.next(); + const rejected = assert.rejects(pendingNext, (error) => error === reason); + ac.abort(reason); + + await rejected; +} + // ============================================================================= // Writer fail detaches consumers // ============================================================================= @@ -300,6 +313,7 @@ Promise.all([ testCancelWithReason(), testCancelWithFalsyReason(), testPendingNextSettlesAfterReturn(), + testPushAbortSignalRejectsPendingNext(), testFailDetachesConsumers(), testWriterFailIdempotent(), testLateJoinerSeesBufferedData(), diff --git a/test/parallel/test-stream-iter-share-async.js b/test/parallel/test-stream-iter-share-async.js index 7e1c06b6328f19..ad382c97e03cf7 100644 --- a/test/parallel/test-stream-iter-share-async.js +++ b/test/parallel/test-stream-iter-share-async.js @@ -196,6 +196,25 @@ async function testShareAbortSignalWhileSourcePullPending() { await Promise.all([rejected1, rejected2]); } +async function testSharePullAbortSignalRejectsPendingNext() { + const ac = new AbortController(); + const reason = new Error('pull aborted'); + const shared = share( + // eslint-disable-next-line require-yield + (async function* never() { + await new Promise(() => {}); + })(), + ); + const iter = shared.pull({ signal: ac.signal })[Symbol.asyncIterator](); + + const pendingNext = iter.next(); + const rejected = assert.rejects(pendingNext, (error) => error === reason); + ac.abort(reason); + + await rejected; + shared.cancel(); +} + async function testShareAlreadyAborted() { const shared = share(from('data'), { signal: AbortSignal.abort() }); const consumer = shared.pull(); @@ -340,6 +359,7 @@ Promise.all([ testShareCancelWithReason(), testShareAbortSignal(), testShareAbortSignalWhileSourcePullPending(), + testSharePullAbortSignalRejectsPendingNext(), testShareAlreadyAborted(), testShareSourceError(), testShareLateJoiningConsumer(), From d0b830b382d4c1e6c54565ec9db3ac08ca0b8a43 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Mon, 22 Jun 2026 00:47:40 -0700 Subject: [PATCH 002/131] stream: observe abort while awaiting pipeTo source Use the abort-aware iterator wrapper in the no-transform pipeTo() path so a pending source read does not block AbortSignal handling. Fixes: https://github.com/nodejs/node/issues/64014 Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.5 PR-URL: https://github.com/nodejs/node/pull/64015 Fixes: https://github.com/nodejs/node/issues/64014 Reviewed-By: Matteo Collina Reviewed-By: Filip Skokan --- lib/internal/streams/iter/pull.js | 2 +- .../test-stream-iter-pipeto-signal.js | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/internal/streams/iter/pull.js b/lib/internal/streams/iter/pull.js index 8cca6b31a50e3f..f2ac4033dc051a 100644 --- a/lib/internal/streams/iter/pull.js +++ b/lib/internal/streams/iter/pull.js @@ -1090,7 +1090,7 @@ async function pipeTo(source, ...args) { } else if (transforms.length === 0) { // Fast path: no transforms - iterate normalized source directly if (signal) { - for await (const batch of normalized) { + for await (const batch of yieldAbortable(normalized, signal)) { signal.throwIfAborted(); const p = writeBatch(batch); if (p) await p; diff --git a/test/parallel/test-stream-iter-pipeto-signal.js b/test/parallel/test-stream-iter-pipeto-signal.js index 153ee1a80e6176..ec1324a4e04bdc 100644 --- a/test/parallel/test-stream-iter-pipeto-signal.js +++ b/test/parallel/test-stream-iter-pipeto-signal.js @@ -6,6 +6,7 @@ const common = require('../common'); const assert = require('assert'); +const { setTimeout } = require('timers/promises'); const { pipeTo, from } = require('stream/iter'); // pipeTo with live signal, no transforms — abort mid-stream @@ -30,6 +31,38 @@ async function testPipeToLiveSignalNoTransforms() { assert.ok(written.length >= 1); } +// pipeTo with live signal, no transforms — abort while waiting for next chunk +async function testPipeToLiveSignalNoTransformsPendingNext() { + const ac = new AbortController(); + const reason = new Error('abort reason'); + const writer = { + write: common.mustNotCall(), + }; + const source = { + [Symbol.asyncIterator]() { + return { + next() { + return new Promise(() => {}); + }, + }; + }, + }; + + setTimeout(10) + .then(() => ac.abort(reason)) + .then(common.mustCall()); + + const result = await Promise.race([ + assert.rejects( + () => pipeTo(source, writer, { signal: ac.signal }), + reason, + ).then(() => 'aborted'), + setTimeout(1000, 'timed out'), + ]); + + assert.strictEqual(result, 'aborted'); +} + // pipeTo with live signal + transforms — abort mid-stream async function testPipeToLiveSignalWithTransforms() { const ac = new AbortController(); @@ -84,6 +117,7 @@ async function testPipeToLiveSignalWithTransformsCompletes() { Promise.all([ testPipeToLiveSignalNoTransforms(), + testPipeToLiveSignalNoTransformsPendingNext(), testPipeToLiveSignalWithTransforms(), testPipeToLiveSignalCompletes(), testPipeToLiveSignalWithTransformsCompletes(), From e470c74a6c3968cad6bef482a1bd1a847b612607 Mon Sep 17 00:00:00 2001 From: Jahanzaib iqbal <78400134+jahanzaib-iqbal-dev@users.noreply.github.com> Date: Mon, 22 Jun 2026 14:48:46 +0500 Subject: [PATCH 003/131] doc: fix keepAliveTimeout default in http.createServer options PR #62782 updated the keepAliveTimeout default from 5s to 65s and correctly updated server.keepAliveTimeout (line 2006), but the http.createServer() options table at line 3775 was not updated. Fix the remaining reference to reflect the current default of 65000ms. Signed-off-by: Jahanzaib iqbal PR-URL: https://github.com/nodejs/node/pull/63974 Reviewed-By: Tim Perry Reviewed-By: Luigi Pinca --- doc/api/http.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/http.md b/doc/api/http.md index 6993cd315c97f0..43fa46e7d6ed09 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -3754,7 +3754,7 @@ changes: needs to wait for additional incoming data, after it has finished writing the last response, before a socket will be destroyed. See [`server.keepAliveTimeout`][] for more information. - **Default:** `5000`. + **Default:** `65000`. * `maxHeaderSize` {number} Optionally overrides the value of [`--max-http-header-size`][] for requests received by this server, i.e. the maximum length of request headers in bytes. From 0342744c34b1b3cf4eb8676d938b562c20a61f75 Mon Sep 17 00:00:00 2001 From: sangwook Date: Tue, 23 Jun 2026 00:42:03 +0900 Subject: [PATCH 004/131] test_runner: add timestamp to JUnit reporter testsuites Emit the standard JUnit timestamp (ISO 8601) on elements, which the reporter was omitting. The suite start time is reconstructed as end-minus-duration, because the runner reports a suite's test:start lazily (when its first subtest reports), which would otherwise record a time close to the suite's end. Fixes: https://github.com/nodejs/node/issues/64028 Signed-off-by: sangwook PR-URL: https://github.com/nodejs/node/pull/64029 Reviewed-By: Moshe Atlow Reviewed-By: Jacob Smith --- lib/internal/test_runner/reporter/junit.js | 8 ++++++++ test/common/assertSnapshot.js | 1 + .../test-runner/output/junit_reporter.snapshot | 12 ++++++------ test/parallel/test-runner-reporters.js | 6 ++++++ 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/internal/test_runner/reporter/junit.js b/lib/internal/test_runner/reporter/junit.js index 25f5667c59e273..130ff60af405ad 100644 --- a/lib/internal/test_runner/reporter/junit.js +++ b/lib/internal/test_runner/reporter/junit.js @@ -5,6 +5,9 @@ const { ArrayPrototypeMap, ArrayPrototypePush, ArrayPrototypeSome, + Date, + DateNow, + DatePrototypeToISOString, NumberPrototypeToFixed, ObjectEntries, RegExpPrototypeSymbolReplace, @@ -112,6 +115,11 @@ module.exports = async function* junitReporter(source) { currentTest.attrs.tests = nonCommentChildren.length; currentTest.attrs.failures = ArrayPrototypeFilter(currentTest.children, isFailure).length; currentTest.attrs.skipped = ArrayPrototypeFilter(currentTest.children, isSkipped).length; + // A suite's `test:start` is emitted lazily (when its first subtest + // reports), so derive the start time from the end minus the measured + // duration rather than stamping the (late) test:start moment. + currentTest.attrs.timestamp = + DatePrototypeToISOString(new Date(DateNow() - event.data.details.duration_ms)); currentTest.attrs.hostname = HOSTNAME; } else { currentTest.tag = 'testcase'; diff --git a/test/common/assertSnapshot.js b/test/common/assertSnapshot.js index 9a7482020e098a..4fdd0be0ee32ae 100644 --- a/test/common/assertSnapshot.js +++ b/test/common/assertSnapshot.js @@ -226,6 +226,7 @@ function replaceJunitDuration(str) { .replaceAll(/time="[0-9.]+"/g, 'time="*"') .replaceAll(/duration_ms [0-9.]+/g, 'duration_ms *') .replaceAll(`hostname="${hostname()}"`, 'hostname="HOSTNAME"') + .replaceAll(/timestamp="[^"]*"/g, 'timestamp="*"') .replaceAll(/file="[^"]*"/g, 'file="*"'); } diff --git a/test/fixtures/test-runner/output/junit_reporter.snapshot b/test/fixtures/test-runner/output/junit_reporter.snapshot index 1142b5b31ff2e7..cef5f0b52da186 100644 --- a/test/fixtures/test-runner/output/junit_reporter.snapshot +++ b/test/fixtures/test-runner/output/junit_reporter.snapshot @@ -128,7 +128,7 @@ true !== false - + Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail @@ -151,15 +151,15 @@ Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fail [Error [ERR_TEST_FAILURE]: Symbol(thrown symbol from sync throw non-error fail)] { code: 'ERR_TEST_FAILURE', failureType: 'testCodeFailure', cause: Symbol(thrown symbol from sync throw non-error fail) } - + - + - + @@ -266,7 +266,7 @@ Error [ERR_TEST_FAILURE]: thrown from callback async throw - + @@ -288,7 +288,7 @@ Error [ERR_TEST_FAILURE]: thrown from callback async throw } - + Error [ERR_TEST_FAILURE]: thrown from subtest sync throw fails at first diff --git a/test/parallel/test-runner-reporters.js b/test/parallel/test-runner-reporters.js index 50a47578a1da7e..7fed79d45b48fd 100644 --- a/test/parallel/test-runner-reporters.js +++ b/test/parallel/test-runner-reporters.js @@ -200,6 +200,12 @@ describe('node:test reporters', { concurrency: true }, () => { assert.strictEqual(child.stdout.toString(), ''); const fileContents = fs.readFileSync(file, 'utf8'); assert.match(fileContents, //); + // The exact timestamp format is intentionally not pinned here (still under + // discussion); assert only that the value is present and a real date. + const { 1: timestamp } = fileContents.match(/]*timestamp="([^"]+)"/) ?? []; + assert.ok(timestamp, 'testsuite should have a timestamp attribute'); + assert.match(timestamp, /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/); + assert.ok(!Number.isNaN(Date.parse(timestamp)), `expected a valid date, got ${timestamp}`); assert.match(fileContents, /\s*/); assert.match(fileContents, //); assert.match(fileContents, //); From eda91b6d01911dc2a46922eafd3ecd2cb179bb51 Mon Sep 17 00:00:00 2001 From: Yagiz Nizipli Date: Mon, 22 Jun 2026 13:18:16 -0400 Subject: [PATCH 005/131] src: avoid copying source string in TextEncoder.encode `EncodeUtf8String`, which backs `TextEncoder.prototype.encode()`, copied the entire source string out of the V8 heap into a `MaybeStackBuffer` (via `WriteOneByteV2`/`WriteV2`) before encoding, allocating on the heap for strings larger than the stack buffer. `EncodeInto` already avoids this by reading the flat content directly through `v8::String::ValueView`. Read the flat content via `ValueView` instead. Because `ValueView` holds a `DisallowGarbageCollection` scope, the backing store cannot be allocated while it is alive, so the view is used in two short scopes: one to validate and compute the exact UTF-8 length, and one to encode directly into the backing store after allocation. Flattening is cached on the string, so re-acquiring the view is cheap. The rare unpaired surrogate path still copies into a mutable buffer for in-place `to_well_formed_utf16`. benchmark/util/text-encoder.js (op=encode, n=1e6, 12 runs each): len=256 len=1024 len=8192 ascii +14.1% +23.5% +43.9% one-byte (latin1) +14.4% +22.2% +12.3% two-byte (utf-16) +16.7% +20.4% +15.5% len=32 uses the unchanged small-string path (~noise). The untouched encodeInto path stayed flat (-2.0%..+0.5%) across all configurations. Signed-off-by: Yagiz Nizipli PR-URL: https://github.com/nodejs/node/pull/63897 Reviewed-By: Anna Henningsen Reviewed-By: Filip Skokan --- src/encoding_binding.cc | 105 +++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 50 deletions(-) diff --git a/src/encoding_binding.cc b/src/encoding_binding.cc index f7bd93a98d05b5..8a445088b54aa8 100644 --- a/src/encoding_binding.cc +++ b/src/encoding_binding.cc @@ -340,53 +340,44 @@ void BindingData::EncodeUtf8String(const FunctionCallbackInfo& args) { size_t length = source->Length(); size_t utf8_length = 0; - bool is_one_byte = source->IsOneByte(); - - if (is_one_byte) { - // One-byte string (Latin1) - copy to buffer first, then process - MaybeStackBuffer latin1_buffer(length); - source->WriteOneByteV2(isolate, 0, length, latin1_buffer.out()); - - auto data = reinterpret_cast(latin1_buffer.out()); - - // Check if it's pure ASCII - if so, we can just copy - simdutf::result result = simdutf::validate_ascii_with_errors(data, length); - if (result.error == simdutf::SUCCESS) { - // Pure ASCII - direct copy - std::unique_ptr bs = ArrayBuffer::NewBackingStore( - isolate, length, BackingStoreInitializationMode::kUninitialized); - CHECK(bs); - memcpy(bs->Data(), data, length); - Local ab = ArrayBuffer::New(isolate, std::move(bs)); - args.GetReturnValue().Set(Uint8Array::New(ab, 0, length)); - return; - } - // Latin1 with non-ASCII characters - need conversion - utf8_length = simdutf::utf8_length_from_latin1(data, length); - std::unique_ptr bs = ArrayBuffer::NewBackingStore( - isolate, utf8_length, BackingStoreInitializationMode::kUninitialized); - CHECK(bs); - [[maybe_unused]] size_t written = simdutf::convert_latin1_to_utf8( - data, length, static_cast(bs->Data())); - DCHECK_EQ(written, utf8_length); - Local ab = ArrayBuffer::New(isolate, std::move(bs)); - args.GetReturnValue().Set(Uint8Array::New(ab, 0, utf8_length)); - return; + // Inspect the string's flat content directly to determine the encoding and + // the exact UTF-8 output size, without copying it out of the V8 heap. + // + // v8::String::ValueView holds a DisallowGarbageCollection scope, so it must + // be released before allocating the backing store below. Flattening is cached + // on the string, so re-acquiring the view for the conversion pass is cheap. + bool is_one_byte; + bool is_ascii = false; + bool is_well_formed = true; + { + v8::String::ValueView view(isolate, source); + is_one_byte = view.is_one_byte(); + if (is_one_byte) { + auto data = reinterpret_cast(view.data8()); + is_ascii = simdutf::validate_ascii_with_errors(data, length).error == + simdutf::SUCCESS; + utf8_length = + is_ascii ? length : simdutf::utf8_length_from_latin1(data, length); + } else { + auto data = reinterpret_cast(view.data16()); + is_well_formed = + simdutf::validate_utf16_with_errors(data, length).error == + simdutf::SUCCESS; + if (is_well_formed) { + utf8_length = simdutf::utf8_length_from_utf16(data, length); + } + } } - // Two-byte string (UTF-16) - copy to buffer first - MaybeStackBuffer utf16_buffer(length); - source->WriteV2(isolate, 0, length, utf16_buffer.out()); - - auto data = reinterpret_cast(utf16_buffer.out()); - - // Check for unpaired surrogates - simdutf::result validation_result = - simdutf::validate_utf16_with_errors(data, length); + // Rare path: two-byte string with unpaired surrogates. Copy into a mutable + // buffer, make it well-formed, then encode. + if (!is_well_formed) { + MaybeStackBuffer utf16_buffer(length); + source->WriteV2(isolate, 0, length, utf16_buffer.out()); + auto data = reinterpret_cast(utf16_buffer.out()); + simdutf::to_well_formed_utf16(data, length, data); - if (validation_result.error == simdutf::SUCCESS) { - // Valid UTF-16 - use the fast path utf8_length = simdutf::utf8_length_from_utf16(data, length); std::unique_ptr bs = ArrayBuffer::NewBackingStore( isolate, utf8_length, BackingStoreInitializationMode::kUninitialized); @@ -399,16 +390,30 @@ void BindingData::EncodeUtf8String(const FunctionCallbackInfo& args) { return; } - // Invalid UTF-16 with unpaired surrogates - convert to well-formed in place - simdutf::to_well_formed_utf16(data, length, data); - - utf8_length = simdutf::utf8_length_from_utf16(data, length); + // Common path: allocate the exact-size output, then re-acquire the flat + // content and encode directly into the backing store. std::unique_ptr bs = ArrayBuffer::NewBackingStore( isolate, utf8_length, BackingStoreInitializationMode::kUninitialized); CHECK(bs); - [[maybe_unused]] size_t written = simdutf::convert_utf16_to_utf8( - data, length, static_cast(bs->Data())); - DCHECK_EQ(written, utf8_length); + char* out = static_cast(bs->Data()); + { + v8::String::ValueView view(isolate, source); + if (is_one_byte) { + auto data = reinterpret_cast(view.data8()); + if (is_ascii) { + memcpy(out, data, length); + } else { + [[maybe_unused]] size_t written = + simdutf::convert_latin1_to_utf8(data, length, out); + DCHECK_EQ(written, utf8_length); + } + } else { + auto data = reinterpret_cast(view.data16()); + [[maybe_unused]] size_t written = + simdutf::convert_utf16_to_utf8(data, length, out); + DCHECK_EQ(written, utf8_length); + } + } Local ab = ArrayBuffer::New(isolate, std::move(bs)); args.GetReturnValue().Set(Uint8Array::New(ab, 0, utf8_length)); } From 55f48446c72fdc10043eb733a19aecc7928da543 Mon Sep 17 00:00:00 2001 From: Khafra Date: Mon, 22 Jun 2026 19:40:44 -0400 Subject: [PATCH 006/131] buffer: implement blob.textStream() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Matthew Aitken PR-URL: https://github.com/nodejs/node/pull/64036 Refs: https://github.com/w3c/FileAPI/commit/cd1d1da9a5375af0622af4b36e76c6e6bd9d130b Refs: https://github.com/nodejs/undici/commit/0d6ecc571095a6bff1c2ad4ee43dd6ae4e97411c Reviewed-By: René Reviewed-By: Matteo Collina Reviewed-By: Gürgün Dayıoğlu Reviewed-By: Luigi Pinca Reviewed-By: Mattias Buelens --- doc/api/buffer.md | 14 ++++++++++++++ lib/internal/blob.js | 20 ++++++++++++++++++++ test/parallel/test-blob.js | 21 ++++++++++++++++++++- 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/doc/api/buffer.md b/doc/api/buffer.md index a9f9a148fdcc11..4ffd229cefa34f 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -593,6 +593,18 @@ added: Returns a promise that fulfills with the contents of the `Blob` decoded as a UTF-8 string. +### `blob.textStream()` + + + +* Returns: {ReadableStream} + +Returns a new `ReadableStream` that allows the content of the `Blob` to be read +as a stream of UTF-8 decoded strings. It is equivalent to piping +[`blob.stream()`][] through a [`TextDecoderStream`][] set up with UTF-8. + ### `blob.type` -[^5]: Binaries produced on these systems require libstdc++12, available - from the [AIX toolbox][]. - [^6]: Binaries produced on these systems are compatible with glibc >= 2.28 and libstdc++ >= 6.0.25 (`GLIBCXX_3.4.25`). These are available on distributions natively supporting GCC 8.1 or higher, such as Debian 10, @@ -1152,7 +1149,6 @@ version of a dependency), please reserve and use a custom `NODE_MODULE_VERSION` by opening a pull request against the registry available at . -[AIX toolbox]: https://www.ibm.com/support/pages/aix-toolbox-open-source-software-overview [Developer Mode]: https://learn.microsoft.com/en-us/windows/advanced-settings/developer-mode [Python downloads]: https://www.python.org/downloads/ [Python versions]: https://devguide.python.org/versions/ From 4c91090b8b2fa069fa5c567076eee41c6f20ab71 Mon Sep 17 00:00:00 2001 From: parkhojeong Date: Mon, 18 May 2026 14:58:56 +0900 Subject: [PATCH 022/131] test: fix typo from funciton to function Signed-off-by: parkhojeong PR-URL: https://github.com/nodejs/node/pull/63403 Reviewed-By: Luigi Pinca Reviewed-By: Deokjin Kim --- test/embedding/test-embedding-snapshot-vm.js | 2 +- test/embedding/test-embedding-snapshot-worker.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/embedding/test-embedding-snapshot-vm.js b/test/embedding/test-embedding-snapshot-vm.js index 0d60059056ad2f..fdf09cf6be371d 100644 --- a/test/embedding/test-embedding-snapshot-vm.js +++ b/test/embedding/test-embedding-snapshot-vm.js @@ -27,7 +27,7 @@ const runSnapshotExecArgs = ['arg3', 'arg4']; tmpdir.refresh(); -// Build the snapshot with the vm-creating code in serialized main funciton. +// Build the snapshot with the vm-creating code in serialized main function. spawnSyncAndExitWithoutError( embedtest, ['--', ...buildSnapshotExecArgs, ...snapshotBlobArgs, '--embedder-snapshot-create'], diff --git a/test/embedding/test-embedding-snapshot-worker.js b/test/embedding/test-embedding-snapshot-worker.js index c6f665eed4d116..9349030fd505c2 100644 --- a/test/embedding/test-embedding-snapshot-worker.js +++ b/test/embedding/test-embedding-snapshot-worker.js @@ -27,7 +27,7 @@ const runSnapshotExecArgs = ['arg3', 'arg4']; tmpdir.refresh(); -// Build the snapshot with the worker-creating code in serialized main funciton. +// Build the snapshot with the worker-creating code in serialized main function. spawnSyncAndExitWithoutError( embedtest, ['--', ...buildSnapshotExecArgs, ...snapshotBlobArgs, '--embedder-snapshot-create'], From 1b4f21338008c11a3a3d4d9f3ad2e01e760f8327 Mon Sep 17 00:00:00 2001 From: parkhojeong Date: Mon, 18 May 2026 14:59:41 +0900 Subject: [PATCH 023/131] test: fix typo from overriden to overridden Signed-off-by: parkhojeong PR-URL: https://github.com/nodejs/node/pull/63403 Reviewed-By: Luigi Pinca Reviewed-By: Deokjin Kim --- .../test-http-set-global-proxy-from-env-override-fetch.mjs | 2 +- .../test-http-set-global-proxy-from-env-override-http.mjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/client-proxy/test-http-set-global-proxy-from-env-override-fetch.mjs b/test/client-proxy/test-http-set-global-proxy-from-env-override-fetch.mjs index 04bcbc33c50eda..511ac15ddb6c9f 100644 --- a/test/client-proxy/test-http-set-global-proxy-from-env-override-fetch.mjs +++ b/test/client-proxy/test-http-set-global-proxy-from-env-override-fetch.mjs @@ -25,7 +25,7 @@ await checkProxiedFetch({ shutdown(); proxy2.close(); -// Verify request did NOT go through original proxy, but the overriden one. +// Verify request did NOT go through original proxy, but the overridden one. assert.deepStrictEqual(proxyLogs, []); // FIXME(undici:4083): undici currently always tunnels the request over diff --git a/test/client-proxy/test-http-set-global-proxy-from-env-override-http.mjs b/test/client-proxy/test-http-set-global-proxy-from-env-override-http.mjs index a09d29831b58c6..a10502c88b059e 100644 --- a/test/client-proxy/test-http-set-global-proxy-from-env-override-http.mjs +++ b/test/client-proxy/test-http-set-global-proxy-from-env-override-http.mjs @@ -25,7 +25,7 @@ await checkProxiedRequest({ shutdown(); proxy2.close(); -// Verify request did NOT go through original proxy, but the overriden one. +// Verify request did NOT go through original proxy, but the overridden one. assert.deepStrictEqual(proxyLogs, []); const expectedLogs = [{ From 39e0c144553d36c5005ab59766736d6c48bf7247 Mon Sep 17 00:00:00 2001 From: Pablo Erhard <104538390+pabloerhard@users.noreply.github.com> Date: Wed, 24 Jun 2026 19:50:06 -0400 Subject: [PATCH 024/131] perf_hooks: sample delay per event loop iteration Add a samplePerIteration option to monitorEventLoopDelay that records event loop delay from libuv event loop iterations instead of the timer interval sampler. The default remains interval-based; existing uses of monitorEventLoopDelay() keep behaving the same unless the samplePerIteration option is passed through. Signed-off-by: Pablo Erhard PR-URL: https://github.com/nodejs/node/pull/62935 Reviewed-By: Bryan English Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell --- doc/api/perf_hooks.md | 49 +++-- lib/internal/perf/event_loop_delay.js | 7 +- src/env_properties.h | 1 + src/histogram.cc | 175 ++++++++++++++++-- src/histogram.h | 72 +++++++ src/node_perf.cc | 7 + src/node_task_queue.cc | 8 +- ...oks-monitor-event-loop-delay-fast-calls.js | 26 +++ .../test-performance-eventloopdelay.js | 105 +++++++++++ 9 files changed, 414 insertions(+), 36 deletions(-) create mode 100644 test/parallel/test-perf-hooks-monitor-event-loop-delay-fast-calls.js diff --git a/doc/api/perf_hooks.md b/doc/api/perf_hooks.md index fbd1d2e08a8c30..60c42ab1a8b8ba 100644 --- a/doc/api/perf_hooks.md +++ b/doc/api/perf_hooks.md @@ -1706,23 +1706,32 @@ are not guaranteed to reflect any correct state of the event loop. * `options` {Object} - * `resolution` {number} The sampling rate in milliseconds. Must be greater - than zero. **Default:** `10`. -* Returns: {IntervalHistogram} + * `samplePerIteration` {boolean} When `true`, samples are taken once per + event loop iteration. **Default:** `false`. + * `resolution` {number} The sampling rate in milliseconds for interval-based + sampling. Must be greater than zero. This option is ignored when + `samplePerIteration` is `true`. **Default:** `10`. +* Returns: {ELDHistogram} _This property is an extension by Node.js. It is not available in Web browsers._ -Creates an `IntervalHistogram` object that samples and reports the event loop -delay over time. The delays will be reported in nanoseconds. +Creates a histogram object that samples and reports the event loop delay over +time. The delays will be reported in nanoseconds. -Using a timer to detect approximate event loop delay works because the -execution of timers is tied specifically to the lifecycle of the libuv -event loop. That is, a delay in the loop will cause a delay in the execution -of the timer, and those delays are specifically what this API is intended to -detect. +By default, the histogram is updated by a timer using the configured +`resolution`. When `samplePerIteration` is `true`, samples are taken once per +event loop iteration using `uv_prepare_t` and `uv_check_t` hooks. In that mode, +the histogram does not keep the loop alive or force additional iterations when +the application is idle. +The two sampling modes produce significantly different results and should not +be compared directly. ```mjs import { monitorEventLoopDelay } from 'node:perf_hooks'; @@ -1999,9 +2008,10 @@ added: v11.10.0 The standard deviation of the recorded event loop delays. -## Class: `IntervalHistogram extends Histogram` +## Class: `ELDHistogram extends Histogram` -A `Histogram` that is periodically updated on a given interval. +A `Histogram` that records event loop delay, returned by +[`perf_hooks.monitorEventLoopDelay()`][]. ### `histogram.disable()` @@ -2011,7 +2021,7 @@ added: v11.10.0 * Returns: {boolean} -Disables the update interval timer. Returns `true` if the timer was +Disables event loop delay sampling. Returns `true` if sampling was stopped, `false` if it was already stopped. ### `histogram.enable()` @@ -2022,7 +2032,7 @@ added: v11.10.0 * Returns: {boolean} -Enables the update interval timer. Returns `true` if the timer was +Enables event loop delay sampling. Returns `true` if sampling was started, `false` if it was already started. ### `histogram[Symbol.dispose]()` @@ -2031,7 +2041,7 @@ started, `false` if it was already started. added: v24.2.0 --> -Disables the update interval timer when the histogram is disposed. +Disables event loop delay sampling when the histogram is disposed. ```js const { monitorEventLoopDelay } = require('node:perf_hooks'); @@ -2042,11 +2052,11 @@ const { monitorEventLoopDelay } = require('node:perf_hooks'); } ``` -### Cloning an `IntervalHistogram` +### Cloning an `ELDHistogram` -{IntervalHistogram} instances can be cloned via {MessagePort}. On the receiving -end, the histogram is cloned as a plain {Histogram} object that does not -implement the `enable()` and `disable()` methods. +{ELDHistogram} instances can be cloned via {MessagePort}. On the receiving end, +the histogram is cloned as a plain {Histogram} object that does not implement +the `enable()` and `disable()` methods. ## Class: `RecordableHistogram extends Histogram` @@ -2354,6 +2364,7 @@ dns.promises.resolve('localhost'); [`'exit'`]: process.md#event-exit [`child_process.spawnSync()`]: child_process.md#child_processspawnsynccommand-args-options [`perf_hooks.eventLoopUtilization()`]: #perf_hookseventlooputilizationutilization1-utilization2 +[`perf_hooks.monitorEventLoopDelay()`]: #perf_hooksmonitoreventloopdelayoptions [`perf_hooks.timerify()`]: #perf_hookstimerifyfn-options [`process.hrtime()`]: process.md#processhrtimetime [`timeOrigin`]: https://w3c.github.io/hr-time/#dom-performance-timeorigin diff --git a/lib/internal/perf/event_loop_delay.js b/lib/internal/perf/event_loop_delay.js index 17581b1310c5c0..ebf0017b70df85 100644 --- a/lib/internal/perf/event_loop_delay.js +++ b/lib/internal/perf/event_loop_delay.js @@ -18,6 +18,7 @@ const { } = internalBinding('performance'); const { + validateBoolean, validateInteger, validateObject, } = require('internal/validators'); @@ -74,6 +75,7 @@ class ELDHistogram extends Histogram { /** * @param {{ + * samplePerIteration : boolean, * resolution : number * }} [options] * @returns {ELDHistogram} @@ -81,14 +83,15 @@ class ELDHistogram extends Histogram { function monitorEventLoopDelay(options = kEmptyObject) { validateObject(options, 'options'); - const { resolution = 10 } = options; + const { samplePerIteration = false, resolution = 10 } = options; + validateBoolean(samplePerIteration, 'options.samplePerIteration'); validateInteger(resolution, 'options.resolution', 1); return ReflectConstruct( function() { markTransferMode(this, true, false); this[kEnabled] = false; - this[kHandle] = createELDHistogram(resolution); + this[kHandle] = createELDHistogram(resolution, samplePerIteration); this[kMap] = new SafeMap(); }, [], ELDHistogram); } diff --git a/src/env_properties.h b/src/env_properties.h index 9106d46d24eede..c0ccfe417b03a7 100644 --- a/src/env_properties.h +++ b/src/env_properties.h @@ -431,6 +431,7 @@ V(http2ping_constructor_template, v8::ObjectTemplate) \ V(i18n_converter_template, v8::ObjectTemplate) \ V(intervalhistogram_constructor_template, v8::FunctionTemplate) \ + V(iterationhistogram_constructor_template, v8::FunctionTemplate) \ V(iter_template, v8::DictionaryTemplate) \ V(js_transferable_constructor_template, v8::FunctionTemplate) \ V(libuv_stream_wrap_ctor_template, v8::FunctionTemplate) \ diff --git a/src/histogram.cc b/src/histogram.cc index 8752a419ec4030..5dd82c305bf7ae 100644 --- a/src/histogram.cc +++ b/src/histogram.cc @@ -25,6 +25,20 @@ using v8::String; using v8::Uint32; using v8::Value; +template +void StartHandleHistogram(Local receiver, bool reset) { + T* histogram; + ASSIGN_OR_RETURN_UNWRAP(&histogram, receiver); + histogram->OnStart(reset ? T::StartFlags::RESET : T::StartFlags::NONE); +} + +template +void StopHandleHistogram(Local receiver) { + T* histogram; + ASSIGN_OR_RETURN_UNWRAP(&histogram, receiver); + histogram->OnStop(); +} + Histogram::Histogram(const Options& options) { hdr_histogram* histogram; CHECK_EQ(0, hdr_init(options.lowest, @@ -68,6 +82,10 @@ CFunction IntervalHistogram::fast_start_( CFunction::Make(&IntervalHistogram::FastStart)); CFunction IntervalHistogram::fast_stop_( CFunction::Make(&IntervalHistogram::FastStop)); +CFunction IterationHistogram::fast_start_( + CFunction::Make(&IterationHistogram::FastStart)); +CFunction IterationHistogram::fast_stop_( + CFunction::Make(&IterationHistogram::FastStop)); void HistogramImpl::AddMethods(Isolate* isolate, Local tmpl) { // TODO(@jasnell): The bigint API variations do not yet support fast @@ -419,29 +437,157 @@ void IntervalHistogram::OnStop() { } void IntervalHistogram::Start(const FunctionCallbackInfo& args) { - IntervalHistogram* histogram; - ASSIGN_OR_RETURN_UNWRAP(&histogram, args.This()); - histogram->OnStart(args[0]->IsTrue() ? StartFlags::RESET : StartFlags::NONE); + StartHandleHistogram(args.This(), args[0]->IsTrue()); } void IntervalHistogram::FastStart(Local receiver, bool reset) { TRACK_V8_FAST_API_CALL("histogram.start"); - IntervalHistogram* histogram; - ASSIGN_OR_RETURN_UNWRAP(&histogram, receiver); - histogram->OnStart(reset ? StartFlags::RESET : StartFlags::NONE); + StartHandleHistogram(receiver, reset); } void IntervalHistogram::Stop(const FunctionCallbackInfo& args) { - IntervalHistogram* histogram; - ASSIGN_OR_RETURN_UNWRAP(&histogram, args.This()); - histogram->OnStop(); + StopHandleHistogram(args.This()); } void IntervalHistogram::FastStop(Local receiver) { TRACK_V8_FAST_API_CALL("histogram.stop"); - IntervalHistogram* histogram; - ASSIGN_OR_RETURN_UNWRAP(&histogram, receiver); - histogram->OnStop(); + StopHandleHistogram(receiver); +} + +Local IterationHistogram::GetConstructorTemplate( + Environment* env) { + Local tmpl = env->iterationhistogram_constructor_template(); + if (tmpl.IsEmpty()) { + Isolate* isolate = env->isolate(); + tmpl = NewFunctionTemplate(isolate, nullptr); + tmpl->Inherit(HandleWrap::GetConstructorTemplate(env)); + tmpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "Histogram")); + auto instance = tmpl->InstanceTemplate(); + instance->SetInternalFieldCount(IterationHistogram::kInternalFieldCount); + HistogramImpl::AddMethods(isolate, tmpl); + SetFastMethod(isolate, instance, "start", Start, &fast_start_); + SetFastMethod(isolate, instance, "stop", Stop, &fast_stop_); + env->set_iterationhistogram_constructor_template(tmpl); + } + return tmpl; +} + +void IterationHistogram::RegisterExternalReferences( + ExternalReferenceRegistry* registry) { + registry->Register(Start); + registry->Register(Stop); + registry->Register(fast_start_); + registry->Register(fast_stop_); + HistogramImpl::RegisterExternalReferences(registry); +} + +IterationHistogram::IterationHistogram(Environment* env, + Local wrap, + AsyncWrap::ProviderType type, + const Histogram::Options& options) + : HandleWrap( + env, wrap, reinterpret_cast(&check_handle_), type), + HistogramImpl(options) { + MakeWeak(); + wrap->SetAlignedPointerInInternalField( + HistogramImpl::InternalFields::kImplField, + static_cast(this), + EmbedderDataTag::kDefault); + uv_check_init(env->event_loop(), &check_handle_); + uv_prepare_init(env->event_loop(), &prepare_handle_); + uv_unref(reinterpret_cast(&check_handle_)); + uv_unref(reinterpret_cast(&prepare_handle_)); + prepare_handle_.data = this; +} + +BaseObjectPtr IterationHistogram::Create( + Environment* env, const Histogram::Options& options) { + Local obj; + if (!GetConstructorTemplate(env) + ->InstanceTemplate() + ->NewInstance(env->context()) + .ToLocal(&obj)) { + return nullptr; + } + + return MakeBaseObject( + env, obj, AsyncWrap::PROVIDER_ELDHISTOGRAM, options); +} + +void IterationHistogram::PrepareCB(uv_prepare_t* handle) { + IterationHistogram* self = static_cast(handle->data); + if (!self->enabled_) return; + self->prepare_time_ = uv_hrtime(); + self->timeout_ = uv_backend_timeout(handle->loop); +} + +void IterationHistogram::CheckCB(uv_check_t* handle) { + IterationHistogram* self = + ContainerOf(&IterationHistogram::check_handle_, handle); + if (!self->enabled_) return; + + uint64_t check_time = uv_hrtime(); + uint64_t poll_time = check_time - self->prepare_time_; + uint64_t latency = self->prepare_time_ - self->check_time_; + + if (self->timeout_ >= 0) { + uint64_t timeout_ns = static_cast(self->timeout_) * 1000 * 1000; + if (poll_time > timeout_ns) { + latency += poll_time - timeout_ns; + } + } + + self->histogram()->Record(latency == 0 ? 1 : latency); + self->check_time_ = check_time; +} + +void IterationHistogram::MemoryInfo(MemoryTracker* tracker) const { + tracker->TrackField("histogram", histogram()); +} + +void IterationHistogram::OnStart(StartFlags flags) { + if (enabled_ || IsHandleClosing()) return; + enabled_ = true; + if (flags == StartFlags::RESET) histogram()->Reset(); + check_time_ = uv_hrtime(); + prepare_time_ = check_time_; + timeout_ = 0; + uv_check_start(&check_handle_, CheckCB); + uv_prepare_start(&prepare_handle_, PrepareCB); + uv_unref(reinterpret_cast(&check_handle_)); + uv_unref(reinterpret_cast(&prepare_handle_)); +} + +void IterationHistogram::OnStop() { + if (!enabled_ || IsHandleClosing()) return; + enabled_ = false; + uv_check_stop(&check_handle_); + uv_prepare_stop(&prepare_handle_); +} + +void IterationHistogram::Close(Local close_callback) { + if (IsHandleClosing()) return; + OnStop(); + HandleWrap::Close(close_callback); + uv_close(reinterpret_cast(&prepare_handle_), nullptr); +} + +void IterationHistogram::Start(const FunctionCallbackInfo& args) { + StartHandleHistogram(args.This(), args[0]->IsTrue()); +} + +void IterationHistogram::FastStart(Local receiver, bool reset) { + TRACK_V8_FAST_API_CALL("histogram.eventLoopDelay.start"); + StartHandleHistogram(receiver, reset); +} + +void IterationHistogram::Stop(const FunctionCallbackInfo& args) { + StopHandleHistogram(args.This()); +} + +void IterationHistogram::FastStop(Local receiver) { + TRACK_V8_FAST_API_CALL("histogram.eventLoopDelay.stop"); + StopHandleHistogram(receiver); } void HistogramImpl::GetCount(const FunctionCallbackInfo& args) { @@ -607,6 +753,11 @@ HistogramImpl* HistogramImpl::FromJSObject(Local value) { HistogramImpl::kImplField, EmbedderDataTag::kDefault)); } +std::unique_ptr IterationHistogram::CloneForMessaging() + const { + return std::make_unique(histogram()); +} + std::unique_ptr IntervalHistogram::CloneForMessaging() const { return std::make_unique(histogram()); diff --git a/src/histogram.h b/src/histogram.h index 31c6564b9b1f12..b9f968e8347c2e 100644 --- a/src/histogram.h +++ b/src/histogram.h @@ -20,6 +20,11 @@ namespace node { class ExternalReferenceRegistry; +template +void StartHandleHistogram(v8::Local receiver, bool reset); +template +void StopHandleHistogram(v8::Local receiver); + constexpr int kDefaultHistogramFigures = 3; class Histogram : public MemoryRetainer { @@ -257,6 +262,11 @@ class IntervalHistogram final : public HandleWrap, public HistogramImpl { void OnStart(StartFlags flags = StartFlags::RESET); void OnStop(); + template + friend void StartHandleHistogram(v8::Local, bool); + template + friend void StopHandleHistogram(v8::Local); + bool enabled_ = false; int32_t interval_ = 0; std::function on_interval_; @@ -266,6 +276,68 @@ class IntervalHistogram final : public HandleWrap, public HistogramImpl { static v8::CFunction fast_stop_; }; +class IterationHistogram final : public HandleWrap, public HistogramImpl { + public: + enum InternalFields { + kInternalFieldCount = std::max( + HandleWrap::kInternalFieldCount, HistogramImpl::kInternalFieldCount), + }; + + enum class StartFlags { NONE, RESET }; + + static void RegisterExternalReferences(ExternalReferenceRegistry* registry); + + static v8::Local GetConstructorTemplate( + Environment* env); + + static BaseObjectPtr Create( + Environment* env, const Histogram::Options& options); + + IterationHistogram(Environment* env, + v8::Local wrap, + AsyncWrap::ProviderType type, + const Histogram::Options& options = Histogram::Options{}); + + static void Start(const v8::FunctionCallbackInfo& args); + static void Stop(const v8::FunctionCallbackInfo& args); + + static void FastStart(v8::Local receiver, bool reset); + static void FastStop(v8::Local receiver); + + BaseObject::TransferMode GetTransferMode() const override { + return TransferMode::kCloneable; + } + std::unique_ptr CloneForMessaging() const override; + + void Close( + v8::Local close_callback = v8::Local()) override; + + void MemoryInfo(MemoryTracker* tracker) const override; + SET_MEMORY_INFO_NAME(IterationHistogram) + SET_SELF_SIZE(IterationHistogram) + + private: + static void PrepareCB(uv_prepare_t* handle); + static void CheckCB(uv_check_t* handle); + void OnStart(StartFlags flags = StartFlags::RESET); + void OnStop(); + + template + friend void StartHandleHistogram(v8::Local, bool); + template + friend void StopHandleHistogram(v8::Local); + + bool enabled_ = false; + uv_prepare_t prepare_handle_; + uv_check_t check_handle_; + uint64_t prepare_time_ = 0; + uint64_t check_time_ = 0; + int64_t timeout_ = 0; + + static v8::CFunction fast_start_; + static v8::CFunction fast_stop_; +}; + } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS diff --git a/src/node_perf.cc b/src/node_perf.cc index ca1b2eaf1c18b3..177c2a7898543b 100644 --- a/src/node_perf.cc +++ b/src/node_perf.cc @@ -282,6 +282,12 @@ void CreateELDHistogram(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); int64_t interval = args[0].As()->Value(); CHECK_GT(interval, 0); + if (args[1]->IsTrue()) { + BaseObjectPtr histogram = + IterationHistogram::Create(env, Histogram::Options{1}); + args.GetReturnValue().Set(histogram->object()); + return; + } BaseObjectPtr histogram = IntervalHistogram::Create(env, interval, [](Histogram& histogram) { uint64_t delta = histogram.RecordDelta(); @@ -414,6 +420,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(fast_performance_now); HistogramBase::RegisterExternalReferences(registry); IntervalHistogram::RegisterExternalReferences(registry); + IterationHistogram::RegisterExternalReferences(registry); } } // namespace performance } // namespace node diff --git a/src/node_task_queue.cc b/src/node_task_queue.cc index 0d40f3914b101e..396ed5c4758c16 100644 --- a/src/node_task_queue.cc +++ b/src/node_task_queue.cc @@ -76,9 +76,11 @@ void PromiseRejectCallback(PromiseRejectMessage message) { value = Undefined(isolate); rejectionsHandledAfter++; TRACE_COUNTER2(TRACING_CATEGORY_NODE2(promises, rejections), - "rejections", - "unhandled", unhandledRejections, - "handledAfter", rejectionsHandledAfter); + "rejections", + "unhandled", + unhandledRejections, + "handledAfter", + rejectionsHandledAfter); } else { return; } diff --git a/test/parallel/test-perf-hooks-monitor-event-loop-delay-fast-calls.js b/test/parallel/test-perf-hooks-monitor-event-loop-delay-fast-calls.js new file mode 100644 index 00000000000000..1954f52e441557 --- /dev/null +++ b/test/parallel/test-perf-hooks-monitor-event-loop-delay-fast-calls.js @@ -0,0 +1,26 @@ +// Flags: --allow-natives-syntax --expose-internals --no-warnings +'use strict'; + +const common = require('../common'); +const assert = require('assert'); + +const { internalBinding } = require('internal/test/binding'); +const { createELDHistogram } = internalBinding('performance'); + +const histogram = createELDHistogram(1, true); + +function testFastMethods() { + histogram.start(true); + histogram.stop(); +} + +eval('%PrepareFunctionForOptimization(testFastMethods)'); +testFastMethods(); +eval('%OptimizeFunctionOnNextCall(testFastMethods)'); +testFastMethods(); + +if (common.isDebug) { + const { getV8FastApiCallCount } = internalBinding('debug'); + assert.strictEqual(getV8FastApiCallCount('histogram.eventLoopDelay.start'), 1); + assert.strictEqual(getV8FastApiCallCount('histogram.eventLoopDelay.stop'), 1); +} diff --git a/test/sequential/test-performance-eventloopdelay.js b/test/sequential/test-performance-eventloopdelay.js index 66493318f5651d..ddd33372ec5e8e 100644 --- a/test/sequential/test-performance-eventloopdelay.js +++ b/test/sequential/test-performance-eventloopdelay.js @@ -49,6 +49,16 @@ const { sleep } = require('internal/util'); } ); }); + + [null, 'a', 1, {}, []].forEach((i) => { + assert.throws( + () => monitorEventLoopDelay({ samplePerIteration: i }), + { + name: 'TypeError', + code: 'ERR_INVALID_ARG_TYPE', + } + ); + }); } { @@ -114,6 +124,101 @@ const { sleep } = require('internal/util'); spinAWhile(); } +{ + const histogram = monitorEventLoopDelay({ samplePerIteration: true }); + histogram.enable(); + setTimeout(common.mustCall(() => { + histogram.disable(); + assert(histogram.count > 0, + `Expected samples to be recorded, got count=${histogram.count}`); + assert(histogram.min > 0); + assert(histogram.max > 0); + assert(histogram.mean > 0); + assert(histogram.percentiles.size > 0); + for (let n = 1; n < 100; n = n + 10) { + assert(histogram.percentile(n) >= 0); + } + // reset() should restore the histogram to its initial state + histogram.reset(); + assert.strictEqual(histogram.count, 0); + assert.strictEqual(histogram.max, 0); + assert.strictEqual(histogram.min, 9223372036854776000); + assert(Number.isNaN(histogram.mean)); + assert(Number.isNaN(histogram.stddev)); + assert.strictEqual(histogram.percentiles.size, 1); + }), common.platformTimeout(20)); +} + +{ + // enable()/disable() return values for ELDHistogram (samplePerIteration: true) + const histogram = monitorEventLoopDelay({ samplePerIteration: true }); + assert.strictEqual(histogram.enable(), true); + assert.strictEqual(histogram.enable(), false); // Already enabled, no-op + assert.strictEqual(histogram.disable(), true); + assert.strictEqual(histogram.disable(), false); // Already disabled, no-op + // Re-enabling after disable should work + assert.strictEqual(histogram.enable(), true); + setTimeout(common.mustCall(() => { + histogram.disable(); + assert(histogram.count > 0, + `Expected samples after re-enable, got count=${histogram.count}`); + }), common.platformTimeout(20)); +} + +{ + // Verify that samplePerIteration records exactly one sample per event loop iteration. + const N = 10; + const histogram = monitorEventLoopDelay({ samplePerIteration: true }); + histogram.enable(); + + let iterations = 0; + const verify = common.mustCall(() => { + histogram.disable(); + assert( + histogram.count >= N - 1, + `Expected at least ${N - 1} samples for ${N} iterations, got ${histogram.count}` + ); + }); + + function tick() { + if (++iterations < N) { + setImmediate(tick); + } else { + verify(); + } + } + setImmediate(tick); +} + +{ + // samplePerIteration should sample per event loop iteration, independent of + // the timer resolution used by the legacy monitorEventLoopDelay path. + const N = 10; + const histogram = monitorEventLoopDelay({ + samplePerIteration: true, + resolution: 60 * 1000, + }); + histogram.enable(); + + let iterations = 0; + const verify = common.mustCall(() => { + histogram.disable(); + assert( + histogram.count >= N - 1, + `Expected samples despite large resolution, got count=${histogram.count}` + ); + }); + + function tick() { + if (++iterations < N) { + setImmediate(tick); + } else { + verify(); + } + } + setImmediate(tick); +} + // Make sure that the histogram instances can be garbage-collected without // and not just implicitly destroyed when the Environment is torn down. process.on('exit', global.gc); From 570952d4f305bf0db41d532cecd664483cc0ad08 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Wed, 24 Jun 2026 23:22:46 -0700 Subject: [PATCH 025/131] test: keep finalization close fixture ref alive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The close fixture expects the registered object to still be reachable when the process emits exit. Keep a strong reference outside setup() so the assertion does not depend on platform-specific GC timing. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.5 PR-URL: https://github.com/nodejs/node/pull/64085 Refs: https://github.com/nodejs/reliability/issues?q=%22test-process-finalization%22 Reviewed-By: Luigi Pinca Reviewed-By: Gürgün Dayıoğlu Reviewed-By: Stefan Stojanovic --- test/fixtures/process/close.mjs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/fixtures/process/close.mjs b/test/fixtures/process/close.mjs index 2f8e94878a3061..010670f893c0c0 100644 --- a/test/fixtures/process/close.mjs +++ b/test/fixtures/process/close.mjs @@ -1,7 +1,9 @@ import { strictEqual } from 'assert' +let obj + function setup() { - const obj = { foo: 'bar' } + obj = { foo: 'bar' } process.finalization.register(obj, shutdown) } @@ -14,5 +16,6 @@ function shutdown(obj) { setup() process.on('exit', function () { + strictEqual(obj.foo, 'bar') strictEqual(shutdownCalled, true) }) From 66f6ac0d865965c9168d32742fe974df6ddf8e59 Mon Sep 17 00:00:00 2001 From: Ivan Trubach Date: Thu, 25 Jun 2026 11:56:23 +0300 Subject: [PATCH 026/131] build: support setting an emulator from configure script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit V8’s JIT infrastructure requires binaries such as mksnapshot to be run during the build. However, these binaries must have the same bit-width as the host platform (e.g. a x86_64 build platform targeting ARMv6 needs to produce a 32-bit binary). To work around this issue, allow building the binaries for the host platform and running them on the build platform with an emulator. Based on Buildroot’s nodejs-src 0001-add-qemu-wrapper-support.patch. https://gitlab.com/buildroot.org/buildroot/-/blob/c1d5eada4d4db9eeaa1c44dd1dea95a67c8a70ca/package/nodejs/nodejs-src/0001-add-qemu-wrapper-support.patch PR-URL: https://github.com/nodejs/node/pull/53899 Reviewed-By: Antoine du Hamel Reviewed-By: Aviv Keller --- common.gypi | 1 + configure.py | 14 ++++++++++++++ node.gyp | 4 ++++ tools/v8_gypfiles/v8.gyp | 4 ++++ 4 files changed, 23 insertions(+) diff --git a/common.gypi b/common.gypi index 36b4b1138dbfd2..d903b57a8f7a04 100644 --- a/common.gypi +++ b/common.gypi @@ -14,6 +14,7 @@ 'enable_pgo_use%': '0', 'clang_profile_lib%': '', 'python%': 'python', + 'emulator%': [], 'node_shared%': 'false', 'node_enable_experimentals%': 'false', diff --git a/configure.py b/configure.py index cb237922a90697..c625ddd8789711 100755 --- a/configure.py +++ b/configure.py @@ -117,6 +117,12 @@ choices=valid_arch, help=f"CPU architecture to build for ({', '.join(valid_arch)})") +parser.add_argument('--emulator', + action='store', + dest='emulator', + default=None, + help='emulator command that can run executables built for the target system') + parser.add_argument('--cross-compiling', action='store_true', dest='cross_compiling', @@ -2936,6 +2942,14 @@ def make_bin_override(): # will fail to run python scripts. gyp_args += ['-Dpython=' + python] +if options.emulator is not None: + if not options.cross_compiling: + # Note that emulator is a list so we have to quote the variable. + gyp_args += ['-Demulator=' + shlex.quote(options.emulator)] + else: + # TODO: perhaps use emulator for tests? + warn('The `--emulator` option has no effect when cross-compiling.') + if not options.v8_disable_temporal_support or not options.shared_temporal_capi: cargo = os.environ.get('CARGO') if cargo: diff --git a/node.gyp b/node.gyp index 1779a57cce36d4..b9e13425b9ba9b 100644 --- a/node.gyp +++ b/node.gyp @@ -1073,6 +1073,7 @@ '<(SHARED_INTERMEDIATE_DIR)/node_javascript.cc', ], 'action': [ + '<@(emulator)', '<(node_js2c_exec)', '<@(_outputs)', 'lib', @@ -1139,6 +1140,7 @@ '<(SHARED_INTERMEDIATE_DIR)/node_snapshot.cc', ], 'action': [ + '<@(emulator)', '<(node_mksnapshot_exec)', '--build-snapshot', '<(node_snapshot_main)', @@ -1158,6 +1160,7 @@ '<(SHARED_INTERMEDIATE_DIR)/node_snapshot.cc', ], 'action': [ + '<@(emulator)', '<@(_inputs)', '<@(_outputs)', ], @@ -1816,6 +1819,7 @@ '<(PRODUCT_DIR)/<(node_core_target_name).def', ], 'action': [ + '<@(emulator)', '<(PRODUCT_DIR)/gen_node_def.exe', '<@(_inputs)', '<@(_outputs)', diff --git a/tools/v8_gypfiles/v8.gyp b/tools/v8_gypfiles/v8.gyp index 945aa0aa501df1..38732b4b34cf68 100644 --- a/tools/v8_gypfiles/v8.gyp +++ b/tools/v8_gypfiles/v8.gyp @@ -149,6 +149,7 @@ '<@(torque_outputs_inc)', ], 'action': [ + '<@(emulator)', '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)torque<(EXECUTABLE_SUFFIX)', '-o', '<(SHARED_INTERMEDIATE_DIR)/torque-generated', '-v8-root', '<(V8_ROOT)', @@ -269,6 +270,7 @@ 'action': [ '<(python)', '<(V8_ROOT)/tools/run.py', + '<@(emulator)', '<@(_inputs)', '<@(_outputs)', ], @@ -470,6 +472,7 @@ }], ], 'action': [ + '<@(emulator)', '>@(_inputs)', '>@(mksnapshot_flags)', ], @@ -1990,6 +1993,7 @@ 'action': [ '<(python)', '<(V8_ROOT)/tools/run.py', + '<@(emulator)', '<@(_inputs)', '<@(_outputs)', ], From 32bb554f5b77997c32420b61ad57e03eb8db72d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Thu, 25 Jun 2026 17:25:40 +0200 Subject: [PATCH 027/131] crypto: fix large DH generator validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Unfortunately, `std::optional<>` implements `operator<` in such a way that this check will fail for very large generators. Since `bn_g` is unsigned, if its value does not fit into a single word, we can be certain that it is at least 2. By only checking the value if it does indeed fit into a word, the check correctly ignores very large generators. Signed-off-by: Tobias Nießen PR-URL: https://github.com/nodejs/node/pull/64092 Reviewed-By: Filip Skokan Reviewed-By: Anna Henningsen --- src/crypto/crypto_dh.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/crypto_dh.cc b/src/crypto/crypto_dh.cc index fa8f36fa33c08f..e9116109a847d7 100644 --- a/src/crypto/crypto_dh.cc +++ b/src/crypto/crypto_dh.cc @@ -196,7 +196,7 @@ void New(const FunctionCallbackInfo& args) { #endif return ThrowCryptoError(env, ERR_get_error(), "Invalid generator"); } - if (bn_g.getWord() < 2) { + if (bn_g.getWord().has_value() && bn_g.getWord().value() < 2) { #ifndef OPENSSL_IS_BORINGSSL ERR_put_error(ERR_LIB_DH, 0, DH_R_BAD_GENERATOR, __FILE__, __LINE__); #else From 3bdd7e20be3d78ce13de5900b78ede66e579f39e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Thu, 25 Jun 2026 19:02:54 +0200 Subject: [PATCH 028/131] tls: handle large RSA exponents in X.509 cert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the exponent does not fit into a single word, previous versions of Node.js would report an incorrect value or, recently, return `null`. Change `GetExponentString()` to handle arbitrarily large RSA public exponents properly. Signed-off-by: Tobias Nießen PR-URL: https://github.com/nodejs/node/pull/64093 Refs: https://github.com/nodejs/node/pull/63895 Reviewed-By: Filip Skokan Reviewed-By: Anna Henningsen --- src/crypto/crypto_x509.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/crypto/crypto_x509.cc b/src/crypto/crypto_x509.cc index 426b1ed7d91860..7c680dc2c5eae9 100644 --- a/src/crypto/crypto_x509.cc +++ b/src/crypto/crypto_x509.cc @@ -689,12 +689,12 @@ MaybeLocal GetModulusString(Environment* env, const BIGNUM* n) { } MaybeLocal GetExponentString(Environment* env, const BIGNUM* e) { - auto exponent_word = BignumPointer::GetWord(e); - if (!exponent_word) return Null(env->isolate()); + if (e == nullptr) return Null(env->isolate()); auto bio = BIOPointer::NewMem(); if (!bio) [[unlikely]] return {}; - BIO_printf(bio.get(), "0x%" PRIx64, static_cast(*exponent_word)); + BIO_puts(bio.get(), "0x"); + BN_print(bio.get(), e); return ToV8Value(env->context(), bio); } From 12edf1d68db00f2c183ba043007bd44bdf6a661a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Thu, 25 Jun 2026 19:03:05 +0200 Subject: [PATCH 029/131] src: avoid redundant call to `std::get_if<>()` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tobias Nießen PR-URL: https://github.com/nodejs/node/pull/64094 Reviewed-By: Juan José Arboleda Reviewed-By: Filip Skokan Reviewed-By: Luigi Pinca Reviewed-By: Yagiz Nizipli Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: Edy Silva --- src/crypto/crypto_dh.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/crypto/crypto_dh.cc b/src/crypto/crypto_dh.cc index e9116109a847d7..cb49cc703426d3 100644 --- a/src/crypto/crypto_dh.cc +++ b/src/crypto/crypto_dh.cc @@ -449,10 +449,9 @@ EVPKeyCtxPointer DhKeyGenTraits::Setup(DhKeyPairGenConfig* params) { if (!dh) return {}; key_params = EVPKeyPointer::NewDH(std::move(dh)); - } else if (std::get_if(¶ms->params.prime)) { + } else if (int* prime_size = std::get_if(¶ms->params.prime)) { auto param_ctx = EVPKeyCtxPointer::NewFromID(EVP_PKEY_DH); #ifndef OPENSSL_IS_BORINGSSL - int* prime_size = std::get_if(¶ms->params.prime); if (!param_ctx.initForParamgen() || !param_ctx.setDhParameters(*prime_size, params->params.generator)) { return {}; From 7a17c50b7f918aa9cc3951a1ff6311b6fa94edde Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 25 Jun 2026 20:00:36 +0200 Subject: [PATCH 030/131] tools: update libffi updater script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Antoine du Hamel PR-URL: https://github.com/nodejs/node/pull/64046 Reviewed-By: Paolo Insogna Reviewed-By: René --- tools/dep_updaters/update-libffi.sh | 30 +++++++++++++---------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/tools/dep_updaters/update-libffi.sh b/tools/dep_updaters/update-libffi.sh index ba12a10cfb2480..dc96c9c3244909 100755 --- a/tools/dep_updaters/update-libffi.sh +++ b/tools/dep_updaters/update-libffi.sh @@ -1,5 +1,5 @@ #!/bin/sh -set -e +set -ex # Shell script to update libffi in the source tree to a specific version BASE_DIR=$(cd "$(dirname "$0")/../.." && pwd) @@ -26,13 +26,13 @@ const tarball = assets.find(({ name }) => name === tarballName); if (!tarball?.browser_download_url) throw new Error(`No release tarball found for ${tag_name}`); console.log(`${version} ${tarball.browser_download_url} ${tarballName}`); EOF -)" +)" # " IFS=' ' read -r NEW_VERSION NEW_VERSION_URL LIBFFI_TARBALL < Date: Thu, 25 Jun 2026 22:54:52 +0200 Subject: [PATCH 031/131] tools: update `build-shared/action.yml` to a reusable workflow Signed-off-by: Antoine du Hamel PR-URL: https://github.com/nodejs/node/pull/64059 Reviewed-By: Jithil P Ponnan Reviewed-By: Filip Skokan --- .github/actions/build-shared/action.yml | 65 ------------------ .github/workflows/build-shared.yml | 89 +++++++++++++++++++++++++ .github/workflows/test-shared.yml | 80 +++++++++------------- 3 files changed, 119 insertions(+), 115 deletions(-) delete mode 100644 .github/actions/build-shared/action.yml create mode 100644 .github/workflows/build-shared.yml diff --git a/.github/actions/build-shared/action.yml b/.github/actions/build-shared/action.yml deleted file mode 100644 index d809f3ec2cf76d..00000000000000 --- a/.github/actions/build-shared/action.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: Build Node.js (shared libraries) -description: > - Downloads the slim tarball built by the `build-tarball` job, extracts it, - installs Nix (+ cachix + sccache), then builds Node.js and runs the CI - test suite inside the pinned nix-shell. - -inputs: - extra-nix-flags: - description: Additional CLI arguments appended to the nix-shell invocation. - required: false - default: '' - cachix-auth-token: - description: Cachix auth token for nodejs.cachix.org. - required: false - default: '' - -runs: - using: composite - steps: - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - name: tarballs - path: tarballs - - - name: Extract tarball - shell: bash - run: | - tar xzf tarballs/*.tar.gz -C "$RUNNER_TEMP" - echo "TAR_DIR=$RUNNER_TEMP/$(basename tarballs/*.tar.gz .tar.gz)" >> "$GITHUB_ENV" - - - uses: cachix/install-nix-action@96951a368ba55167b55f1c916f7d416bac6505fe # v31.10.3 - with: - extra_nix_config: sandbox = true - - - uses: cachix/cachix-action@1eb2ef646ac0255473d23a5907ad7b04ce94065c # v17 - with: - name: nodejs - authToken: ${{ inputs.cachix-auth-token }} - - - name: Configure sccache - if: github.base_ref == 'main' || github.ref_name == 'main' - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - with: - script: | - core.exportVariable('SCCACHE_GHA_ENABLED', 'on'); - core.exportVariable('ACTIONS_CACHE_SERVICE_V2', 'on'); - core.exportVariable('ACTIONS_RESULTS_URL', process.env.ACTIONS_RESULTS_URL || ''); - core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); - core.exportVariable('NIX_SCCACHE', '(import {}).sccache'); - - - name: Build Node.js and run tests - shell: bash - run: | - nix-shell \ - -I "nixpkgs=$TAR_DIR/tools/nix/pkgs.nix" \ - --pure --keep TAR_DIR --keep FLAKY_TESTS \ - --keep SCCACHE_GHA_ENABLED --keep ACTIONS_CACHE_SERVICE_V2 --keep ACTIONS_RESULTS_URL --keep ACTIONS_RUNTIME_TOKEN \ - --arg loadJSBuiltinsDynamically false \ - --arg ccache "${NIX_SCCACHE:-null}" \ - --arg devTools '[]' \ - --arg benchmarkTools '[]' \ - ${{ inputs.extra-nix-flags }} \ - --run ' - make -C "$TAR_DIR" run-ci -j4 V=1 TEST_CI_ARGS="-p actions --measure-flakiness 9 --skip-tests=$CI_SKIP_TESTS" - ' "$TAR_DIR/shell.nix" diff --git a/.github/workflows/build-shared.yml b/.github/workflows/build-shared.yml new file mode 100644 index 00000000000000..61441571427eff --- /dev/null +++ b/.github/workflows/build-shared.yml @@ -0,0 +1,89 @@ +name: Build Node.js (shared libraries) + +on: + workflow_call: + inputs: + runner: + description: The runner to use for the job. + required: true + type: string + extra-nix-flags: + description: Additional CLI arguments appended to the nix-shell invocation. + required: false + type: string + default: '' + with-sccache: + description: Whether to enable sccache + required: false + type: boolean + default: false + v8-nar: + description: An optional name for the NAR archive for V8 that needs to be downloaded + required: false + type: string + default: '' + secrets: + CACHIX_AUTH_TOKEN: + description: Cachix auth token for nodejs.cachix.org. + required: false + +permissions: {} + +env: + FLAKY_TESTS: keep_retrying + +jobs: + build: + runs-on: ${{ inputs.runner }} + steps: + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: tarballs + path: tarballs + + - name: Extract tarball + shell: bash + run: | + tar xzf tarballs/*.tar.gz -C "$RUNNER_TEMP" + echo "TAR_DIR=$RUNNER_TEMP/$(basename tarballs/*.tar.gz .tar.gz)" >> "$GITHUB_ENV" + + - uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6 + with: + extra_nix_config: sandbox = true + + - uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17 + with: + name: nodejs + authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} + + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + if: inputs.v8-nar + with: + name: ${{ inputs.v8-nar }} + + - name: Configure sccache + if: inputs.with-sccache + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + script: | + core.exportVariable('SCCACHE_GHA_ENABLED', 'on'); + core.exportVariable('ACTIONS_CACHE_SERVICE_V2', 'on'); + core.exportVariable('ACTIONS_RESULTS_URL', process.env.ACTIONS_RESULTS_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + core.exportVariable('NIX_SCCACHE', '(import {}).sccache'); + + - name: Build Node.js and run tests + shell: bash + run: | + nix-shell \ + -I "nixpkgs=$TAR_DIR/tools/nix/pkgs.nix" \ + --pure --keep TAR_DIR --keep FLAKY_TESTS \ + --keep SCCACHE_GHA_ENABLED --keep ACTIONS_CACHE_SERVICE_V2 --keep ACTIONS_RESULTS_URL --keep ACTIONS_RUNTIME_TOKEN \ + --arg loadJSBuiltinsDynamically false \ + --arg ccache "${NIX_SCCACHE:-null}" \ + --arg devTools '[]' \ + --arg benchmarkTools '[]' \ + ${{ inputs.extra-nix-flags }} \ + --run ' + make -C "$TAR_DIR" run-ci -j4 V=1 TEST_CI_ARGS="-p actions --measure-flakiness 9 --skip-tests=$CI_SKIP_TESTS" + ' "$TAR_DIR/shell.nix" diff --git a/.github/workflows/test-shared.yml b/.github/workflows/test-shared.yml index fdaa560141c5f5..ef22c29f478c86 100644 --- a/.github/workflows/test-shared.yml +++ b/.github/workflows/test-shared.yml @@ -48,7 +48,7 @@ on: - vcbuild.bat - .** - '!.github/workflows/test-shared.yml' - - '!.github/actions/build-shared/**' + - '!.github/workflows/build-shared.yml' types: [opened, synchronize, reopened, ready_for_review] push: branches: @@ -100,15 +100,12 @@ on: - vcbuild.bat - .** - '!.github/workflows/test-shared.yml' - - '!.github/actions/build-shared/**' + - '!.github/workflows/build-shared.yml' concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true -env: - FLAKY_TESTS: keep_retrying - permissions: contents: read @@ -153,20 +150,15 @@ jobs: - runner: macos-latest system: aarch64-darwin name: '${{ matrix.system }}: with shared libraries' - runs-on: ${{ matrix.runner }} - steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - with: - persist-credentials: false - sparse-checkout: .github/actions - sparse-checkout-cone-mode: false - - uses: ./.github/actions/build-shared - name: Build and test Node.js - with: - cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} - extra-nix-flags: | - --arg useSeparateDerivationForV8 true \ - ${{ endsWith(matrix.system, '-darwin') && '--arg withAmaro false --arg withLief false --arg withSQLite false --arg withFFI false --arg extraConfigFlags ''["--without-inspector" "--without-node-options"]'' \' || '\' }} + uses: ./.github/workflows/build-shared.yml + with: + runner: ${{ matrix.runner }} + with-sccache: ${{ github.base_ref == 'main' || github.ref_name == 'main' }} + extra-nix-flags: | + --arg useSeparateDerivationForV8 true \ + ${{ endsWith(matrix.system, '-darwin') && '--arg withAmaro false --arg withLief false --arg withSQLite false --arg withFFI false --arg extraConfigFlags ''["--without-inspector" "--without-node-options"]'' \' || '\' }} + secrets: + CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} build-aarch64-linux-v8: needs: build-tarball @@ -249,34 +241,22 @@ jobs: matrix: openssl: ${{ fromJSON(needs.build-aarch64-linux-v8.outputs.matrix) }} name: 'aarch64-linux: with shared ${{ matrix.openssl.name }}' - runs-on: ubuntu-24.04-arm - continue-on-error: false - env: - OPENSSL_ATTR: ${{ matrix.openssl.attr }} - steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - with: - persist-credentials: false - sparse-checkout: .github/actions - sparse-checkout-cone-mode: false - - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - if: ${{ needs.build-aarch64-linux-v8.outputs.local-cache }} - with: - name: libv8-aarch64-linux.nar - - - uses: ./.github/actions/build-shared - name: Build and test Node.js - with: - cachix-auth-token: ${{ secrets.CACHIX_AUTH_TOKEN }} - # Override just the `openssl` attr of the default shared-lib set with - # the matrix-selected nixpkgs attribute (e.g. `openssl_3_6`). All - # other shared libs (brotli, cares, libuv, …) keep their defaults. - # `permittedInsecurePackages` whitelists just the matrix-selected - # release (e.g. `openssl-1.1.1w`) so EOL-with-extended-support - # cycles evaluate without relaxing nixpkgs' meta check globally. - extra-nix-flags: | - --arg useSeparateDerivationForV8 ${{ needs.build-aarch64-linux-v8.outputs.local-cache && '"$(nix-store --import < libv8-aarch64-linux.nar)"' || 'true' }} \ - --arg sharedLibDeps "(import $TAR_DIR/tools/nix/sharedLibDeps.nix {}) // { - openssl = (import $TAR_DIR/tools/nix/openssl-matrix.nix {}).$OPENSSL_ATTR; - }" \ + uses: ./.github/workflows/build-shared.yml + with: + runner: ubuntu-24.04-arm + v8-nar: ${{ needs.build-aarch64-linux-v8.outputs.local-cache && 'libv8-aarch64-linux.nar' }} + # Override just the `openssl` attr of the default shared-lib set with + # the matrix-selected nixpkgs attribute (e.g. `openssl_3_6`). All + # other shared libs (brotli, cares, libuv, …) keep their defaults. + # `permittedInsecurePackages` whitelists just the matrix-selected + # release (e.g. `openssl-1.1.1w`) so EOL-with-extended-support + # cycles evaluate without relaxing nixpkgs' meta check globally. + extra-nix-flags: | + --arg useSeparateDerivationForV8 ${{ needs.build-aarch64-linux-v8.outputs.local-cache && '"$(nix-store --import < libv8-aarch64-linux.nar)"' || 'true' }} \ + --arg sharedLibDeps "(import $TAR_DIR/tools/nix/sharedLibDeps.nix {}) // { + openssl = builtins.getAttr \"${{ + !contains(matrix.openssl.attr, '$') && !contains(matrix.openssl.attr, '\"') && !contains(matrix.openssl.attr, '\') && !contains(matrix.openssl.attr, '`') && matrix.openssl.attr + }}\" (import $TAR_DIR/tools/nix/openssl-matrix.nix {}); + }" \ + secrets: + CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} From feefd179e5a0b9ae6c0888de0c0fb4cbe6e57597 Mon Sep 17 00:00:00 2001 From: Kevin Gibbons Date: Mon, 11 May 2026 10:55:35 -0700 Subject: [PATCH 032/131] deps: V8: cherry-pick 1a391f98cc7a MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Original commit message: [api] Deprecate kPromiseRejectAfterResolved and kPromiseResolveAfterResolved These events will be removed soon. Bug: 42213031 Change-Id: Ie70474ff33c40c7d9cb0c2d0fbe6b75da3c53a22 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7774767 Commit-Queue: Kevin Gibbons Reviewed-by: Olivier Flückiger Reviewed-by: Leszek Swirski Cr-Commit-Position: refs/heads/main@{#107395} Refs: https://github.com/v8/v8/commit/1a391f98cc7a9196369f2d6cab7df35ffbe92c08 PR-URL: https://github.com/nodejs/node/pull/64101 Reviewed-By: Michaël Zasso Reviewed-By: Richard Lau Reviewed-By: Colin Ihrig Reviewed-By: Marco Ippolito --- common.gypi | 2 +- deps/v8/include/v8-promise.h | 6 ++++-- deps/v8/src/d8/d8.cc | 2 ++ deps/v8/src/runtime/runtime-promise.cc | 4 ++++ deps/v8/test/cctest/test-api.cc | 2 ++ deps/v8/test/inspector/isolate-data.cc | 13 +++++++++---- 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/common.gypi b/common.gypi index d903b57a8f7a04..09311647890cc4 100644 --- a/common.gypi +++ b/common.gypi @@ -41,7 +41,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.21', + 'v8_embedder_string': '-node.22', ##### V8 defaults for Node.js ##### diff --git a/deps/v8/include/v8-promise.h b/deps/v8/include/v8-promise.h index 36412c774d1b51..3d104f6623831e 100644 --- a/deps/v8/include/v8-promise.h +++ b/deps/v8/include/v8-promise.h @@ -158,8 +158,10 @@ using PromiseHook = void (*)(PromiseHookType type, Local promise, enum PromiseRejectEvent { kPromiseRejectWithNoHandler = 0, kPromiseHandlerAddedAfterReject = 1, - kPromiseRejectAfterResolved = 2, - kPromiseResolveAfterResolved = 3, + kPromiseRejectAfterResolved V8_DEPRECATED("These events are being removed") = + 2, + kPromiseResolveAfterResolved V8_DEPRECATED("These events are being removed") = + 3, }; class PromiseRejectMessage { diff --git a/deps/v8/src/d8/d8.cc b/deps/v8/src/d8/d8.cc index 02b03480f166de..88f0da12d2f770 100644 --- a/deps/v8/src/d8/d8.cc +++ b/deps/v8/src/d8/d8.cc @@ -4575,11 +4575,13 @@ static void PrintMessageCallback(Local message, Local error) { void Shell::PromiseRejectCallback(v8::PromiseRejectMessage data) { if (options.ignore_unhandled_promises) return; + START_ALLOW_USE_DEPRECATED(); if (data.GetEvent() == v8::kPromiseRejectAfterResolved || data.GetEvent() == v8::kPromiseResolveAfterResolved) { // Ignore reject/resolve after resolved. return; } + END_ALLOW_USE_DEPRECATED(); v8::Local promise = data.GetPromise(); v8::Isolate* isolate = v8::Isolate::GetCurrent(); PerIsolateData* isolate_data = PerIsolateData::Get(isolate); diff --git a/deps/v8/src/runtime/runtime-promise.cc b/deps/v8/src/runtime/runtime-promise.cc index 262b9aa5aa6974..57b5604c43884b 100644 --- a/deps/v8/src/runtime/runtime-promise.cc +++ b/deps/v8/src/runtime/runtime-promise.cc @@ -34,8 +34,10 @@ RUNTIME_FUNCTION(Runtime_PromiseRejectAfterResolved) { HandleScope scope(isolate); DirectHandle promise = args.at(0); DirectHandle reason = args.at(1); + START_ALLOW_USE_DEPRECATED(); isolate->ReportPromiseReject(promise, reason, v8::kPromiseRejectAfterResolved); + END_ALLOW_USE_DEPRECATED(); return ReadOnlyRoots(isolate).undefined_value(); } @@ -44,8 +46,10 @@ RUNTIME_FUNCTION(Runtime_PromiseResolveAfterResolved) { HandleScope scope(isolate); DirectHandle promise = args.at(0); DirectHandle resolution = args.at(1); + START_ALLOW_USE_DEPRECATED(); isolate->ReportPromiseReject(promise, resolution, v8::kPromiseResolveAfterResolved); + END_ALLOW_USE_DEPRECATED(); return ReadOnlyRoots(isolate).undefined_value(); } diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 8896acd700f829..174ec0f6af5fc3 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -16438,6 +16438,7 @@ void PromiseRejectCallback(v8::PromiseRejectMessage reject_message) { CHECK(reject_message.GetValue().IsEmpty()); break; } + START_ALLOW_USE_DEPRECATED(); case v8::kPromiseRejectAfterResolved: { promise_reject_after_resolved_counter++; break; @@ -16446,6 +16447,7 @@ void PromiseRejectCallback(v8::PromiseRejectMessage reject_message) { promise_resolve_after_resolved_counter++; break; } + END_ALLOW_USE_DEPRECATED(); } } diff --git a/deps/v8/test/inspector/isolate-data.cc b/deps/v8/test/inspector/isolate-data.cc index f067ba705a9490..6fefc1eb17c4fc 100644 --- a/deps/v8/test/inspector/isolate-data.cc +++ b/deps/v8/test/inspector/isolate-data.cc @@ -401,10 +401,15 @@ void InspectorIsolateData::PromiseRejectHandler(v8::PromiseRejectMessage data) { v8_inspector::StringView(reinterpret_cast(reason_str), strlen(reason_str))); return; - } else if (data.GetEvent() == v8::kPromiseRejectAfterResolved || - data.GetEvent() == v8::kPromiseResolveAfterResolved) { - // Ignore reject/resolve after resolved, like the blink handler. - return; + + } else { + START_ALLOW_USE_DEPRECATED(); + if (data.GetEvent() == v8::kPromiseRejectAfterResolved || + data.GetEvent() == v8::kPromiseResolveAfterResolved) { + // Ignore reject/resolve after resolved, like the blink handler. + return; + } + END_ALLOW_USE_DEPRECATED(); } v8::Local exception = data.GetValue(); From a640543a7c949ce8b7801067e0b6e6df62d66ee7 Mon Sep 17 00:00:00 2001 From: Kevin Gibbons Date: Thu, 11 Jun 2026 13:29:34 -0700 Subject: [PATCH 033/131] deps: V8: cherry-pick 0cc9eb22c0b0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Original commit message: [api] Remove PromiseResolveAfterResolved and PromiseRejectAfterResolved These were previously deprecated in https://crrev.com/c/7774767 Bug: 42213031 Change-Id: I07b802b743bf052611f30a61c1132231df22f0bd Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7897881 Commit-Queue: Olivier Flückiger Reviewed-by: Camillo Bruni Reviewed-by: Olivier Flückiger Cr-Commit-Position: refs/heads/main@{#108040} Refs: https://github.com/v8/v8/commit/0cc9eb22c0b0d132344b83b906f8a0e5aaa7b61e PR-URL: https://github.com/nodejs/node/pull/64101 Reviewed-By: Michaël Zasso Reviewed-By: Richard Lau Reviewed-By: Colin Ihrig Reviewed-By: Marco Ippolito --- common.gypi | 2 +- deps/v8/include/v8-promise.h | 6 ++--- .../builtins/promise-abstract-operations.tq | 10 ++------ deps/v8/src/d8/d8.cc | 7 ------ deps/v8/src/runtime/runtime-promise.cc | 24 ------------------- deps/v8/src/runtime/runtime.h | 2 -- deps/v8/test/cctest/test-api.cc | 16 ++++--------- deps/v8/test/inspector/isolate-data.cc | 8 ------- 8 files changed, 9 insertions(+), 66 deletions(-) diff --git a/common.gypi b/common.gypi index 09311647890cc4..360e15a6616c50 100644 --- a/common.gypi +++ b/common.gypi @@ -41,7 +41,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.22', + 'v8_embedder_string': '-node.23', ##### V8 defaults for Node.js ##### diff --git a/deps/v8/include/v8-promise.h b/deps/v8/include/v8-promise.h index 3d104f6623831e..b1f85e6e50ec7e 100644 --- a/deps/v8/include/v8-promise.h +++ b/deps/v8/include/v8-promise.h @@ -158,10 +158,8 @@ using PromiseHook = void (*)(PromiseHookType type, Local promise, enum PromiseRejectEvent { kPromiseRejectWithNoHandler = 0, kPromiseHandlerAddedAfterReject = 1, - kPromiseRejectAfterResolved V8_DEPRECATED("These events are being removed") = - 2, - kPromiseResolveAfterResolved V8_DEPRECATED("These events are being removed") = - 3, + kDeprecatedPromiseRejectAfterResolved V8_DEPRECATED("Removed event") = 2, + kDeprecatedPromiseResolveAfterResolved V8_DEPRECATED("Removed event") = 3, }; class PromiseRejectMessage { diff --git a/deps/v8/src/builtins/promise-abstract-operations.tq b/deps/v8/src/builtins/promise-abstract-operations.tq index f50b5b75a0f326..d2de7eaab52006 100644 --- a/deps/v8/src/builtins/promise-abstract-operations.tq +++ b/deps/v8/src/builtins/promise-abstract-operations.tq @@ -12,12 +12,6 @@ extern transitioning runtime RejectPromise( extern transitioning runtime PromiseRevokeReject( implicit context: Context)(JSPromise): JSAny; -extern transitioning runtime PromiseRejectAfterResolved( - implicit context: Context)(JSPromise, JSAny): JSAny; - -extern transitioning runtime PromiseResolveAfterResolved( - implicit context: Context)(JSPromise, JSAny): JSAny; - extern transitioning runtime PromiseRejectEventFromStack( implicit context: Context)(JSPromise, JSAny): JSAny; } @@ -406,7 +400,7 @@ transitioning javascript builtin PromiseCapabilityDefaultReject( // 4. If alreadyResolved.[[Value]] is true, return undefined. if (alreadyResolved == True) { - return runtime::PromiseRejectAfterResolved(promise, reason); + return Undefined; } // 5. Set alreadyResolved.[[Value]] to true. @@ -434,7 +428,7 @@ transitioning javascript builtin PromiseCapabilityDefaultResolve( // 4. If alreadyResolved.[[Value]] is true, return undefined. if (alreadyResolved == True) { - return runtime::PromiseResolveAfterResolved(promise, resolution); + return Undefined; } // 5. Set alreadyResolved.[[Value]] to true. diff --git a/deps/v8/src/d8/d8.cc b/deps/v8/src/d8/d8.cc index 88f0da12d2f770..1c33ca83c3695f 100644 --- a/deps/v8/src/d8/d8.cc +++ b/deps/v8/src/d8/d8.cc @@ -4575,13 +4575,6 @@ static void PrintMessageCallback(Local message, Local error) { void Shell::PromiseRejectCallback(v8::PromiseRejectMessage data) { if (options.ignore_unhandled_promises) return; - START_ALLOW_USE_DEPRECATED(); - if (data.GetEvent() == v8::kPromiseRejectAfterResolved || - data.GetEvent() == v8::kPromiseResolveAfterResolved) { - // Ignore reject/resolve after resolved. - return; - } - END_ALLOW_USE_DEPRECATED(); v8::Local promise = data.GetPromise(); v8::Isolate* isolate = v8::Isolate::GetCurrent(); PerIsolateData* isolate_data = PerIsolateData::Get(isolate); diff --git a/deps/v8/src/runtime/runtime-promise.cc b/deps/v8/src/runtime/runtime-promise.cc index 57b5604c43884b..3c9d7184189915 100644 --- a/deps/v8/src/runtime/runtime-promise.cc +++ b/deps/v8/src/runtime/runtime-promise.cc @@ -29,30 +29,6 @@ RUNTIME_FUNCTION(Runtime_PromiseRejectEventFromStack) { return ReadOnlyRoots(isolate).undefined_value(); } -RUNTIME_FUNCTION(Runtime_PromiseRejectAfterResolved) { - DCHECK_EQ(2, args.length()); - HandleScope scope(isolate); - DirectHandle promise = args.at(0); - DirectHandle reason = args.at(1); - START_ALLOW_USE_DEPRECATED(); - isolate->ReportPromiseReject(promise, reason, - v8::kPromiseRejectAfterResolved); - END_ALLOW_USE_DEPRECATED(); - return ReadOnlyRoots(isolate).undefined_value(); -} - -RUNTIME_FUNCTION(Runtime_PromiseResolveAfterResolved) { - DCHECK_EQ(2, args.length()); - HandleScope scope(isolate); - DirectHandle promise = args.at(0); - DirectHandle resolution = args.at(1); - START_ALLOW_USE_DEPRECATED(); - isolate->ReportPromiseReject(promise, resolution, - v8::kPromiseResolveAfterResolved); - END_ALLOW_USE_DEPRECATED(); - return ReadOnlyRoots(isolate).undefined_value(); -} - RUNTIME_FUNCTION(Runtime_PromiseRevokeReject) { DCHECK_EQ(1, args.length()); HandleScope scope(isolate); diff --git a/deps/v8/src/runtime/runtime.h b/deps/v8/src/runtime/runtime.h index 8c5eac0907b305..ee6cc6f20608ec 100644 --- a/deps/v8/src/runtime/runtime.h +++ b/deps/v8/src/runtime/runtime.h @@ -441,8 +441,6 @@ constexpr bool CanTriggerGC(T... properties) { F(PromiseRevokeReject, 1, 1) \ F(RejectPromise, 3, 1) \ F(ResolvePromise, 2, 1) \ - F(PromiseRejectAfterResolved, 2, 1) \ - F(PromiseResolveAfterResolved, 2, 1) \ F(ConstructSuppressedError, 3, 1) \ F(ConstructAggregateErrorHelper, 4, 1) \ F(ConstructInternalAggregateErrorHelper, -1 /* <= 5*/, 1) diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 174ec0f6af5fc3..ba7e079f411c1c 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -16381,8 +16381,6 @@ TEST(ErrorLevelWarning) { v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler; int promise_reject_counter = 0; int promise_revoke_counter = 0; -int promise_reject_after_resolved_counter = 0; -int promise_resolve_after_resolved_counter = 0; int promise_reject_msg_line_number = -1; int promise_reject_msg_column_number = -1; int promise_reject_line_number = -1; @@ -16439,12 +16437,12 @@ void PromiseRejectCallback(v8::PromiseRejectMessage reject_message) { break; } START_ALLOW_USE_DEPRECATED(); - case v8::kPromiseRejectAfterResolved: { - promise_reject_after_resolved_counter++; + case v8::kDeprecatedPromiseRejectAfterResolved: { + // Unreachable break; } - case v8::kPromiseResolveAfterResolved: { - promise_resolve_after_resolved_counter++; + case v8::kDeprecatedPromiseResolveAfterResolved: { + // Unreachable break; } END_ALLOW_USE_DEPRECATED(); @@ -16470,8 +16468,6 @@ v8::Local RejectValue() { void ResetPromiseStates() { promise_reject_counter = 0; promise_revoke_counter = 0; - promise_reject_after_resolved_counter = 0; - promise_resolve_after_resolved_counter = 0; promise_reject_msg_line_number = -1; promise_reject_msg_column_number = -1; promise_reject_line_number = -1; @@ -16710,8 +16706,6 @@ TEST(PromiseRejectCallback) { CHECK(!GetPromise("v0")->HasHandler()); CHECK_EQ(0, promise_reject_counter); CHECK_EQ(0, promise_revoke_counter); - CHECK_EQ(1, promise_reject_after_resolved_counter); - CHECK_EQ(0, promise_resolve_after_resolved_counter); ResetPromiseStates(); @@ -16728,8 +16722,6 @@ TEST(PromiseRejectCallback) { CHECK(!GetPromise("y0")->HasHandler()); CHECK_EQ(1, promise_reject_counter); CHECK_EQ(0, promise_revoke_counter); - CHECK_EQ(0, promise_reject_after_resolved_counter); - CHECK_EQ(1, promise_resolve_after_resolved_counter); // Test stack frames. env.isolate()->SetCaptureStackTraceForUncaughtExceptions(true); diff --git a/deps/v8/test/inspector/isolate-data.cc b/deps/v8/test/inspector/isolate-data.cc index 6fefc1eb17c4fc..91a497463053df 100644 --- a/deps/v8/test/inspector/isolate-data.cc +++ b/deps/v8/test/inspector/isolate-data.cc @@ -402,14 +402,6 @@ void InspectorIsolateData::PromiseRejectHandler(v8::PromiseRejectMessage data) { strlen(reason_str))); return; - } else { - START_ALLOW_USE_DEPRECATED(); - if (data.GetEvent() == v8::kPromiseRejectAfterResolved || - data.GetEvent() == v8::kPromiseResolveAfterResolved) { - // Ignore reject/resolve after resolved, like the blink handler. - return; - } - END_ALLOW_USE_DEPRECATED(); } v8::Local exception = data.GetValue(); From 879fdc4daf95e28e6c77de6c870101b6bc82a8fd Mon Sep 17 00:00:00 2001 From: Kevin Gibbons Date: Fri, 19 Jun 2026 09:21:04 -0700 Subject: [PATCH 034/131] deps: V8: backport da20a197a7f9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Original commit message: [builtins] Make Promise resolvers not keep resolved Promises alive Currently a Promise's resolve/reject functions unconditionally hold the Promise, plus a separate bit to track whether the Promise has been resolved. Instead, hold a single field with Promise|Undefined. This allows GC'ing a resolved Promise even if its resolvers are still alive. R=olivf@chromium.org Fixed: 42213031 Change-Id: Ice645dbabb79e63dfcac8ae843cad95439d7a1f1 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7646250 Reviewed-by: Darius Mercadier Commit-Queue: Kevin Gibbons Reviewed-by: Olivier Flückiger Cr-Commit-Position: refs/heads/main@{#108183} Refs: https://github.com/v8/v8/commit/da20a197a7f9c2045b1ee501a472072944a86332 Co-authored-by: Kevin Gibbons PR-URL: https://github.com/nodejs/node/pull/64101 Reviewed-By: Michaël Zasso Reviewed-By: Richard Lau Reviewed-By: Colin Ihrig Reviewed-By: Marco Ippolito --- common.gypi | 2 +- deps/v8/src/builtins/builtins-promise.h | 8 +-- .../builtins/promise-abstract-operations.tq | 69 ++++++++++--------- deps/v8/src/builtins/promise-all.tq | 9 +-- deps/v8/src/compiler/js-call-reducer.cc | 6 +- deps/v8/src/execution/isolate.cc | 9 ++- .../test/cctest/test-code-stub-assembler.cc | 6 +- .../mjsunit/regress/regress-crbug-42213031.js | 26 +++++++ 8 files changed, 83 insertions(+), 52 deletions(-) create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-42213031.js diff --git a/common.gypi b/common.gypi index 360e15a6616c50..bae09d8a5d6300 100644 --- a/common.gypi +++ b/common.gypi @@ -41,7 +41,7 @@ # Reset this number to 0 on major V8 upgrades. # Increment by one for each non-official patch applied to deps/v8. - 'v8_embedder_string': '-node.23', + 'v8_embedder_string': '-node.24', ##### V8 defaults for Node.js ##### diff --git a/deps/v8/src/builtins/builtins-promise.h b/deps/v8/src/builtins/builtins-promise.h index a775ea20411605..2f1ee5550940be 100644 --- a/deps/v8/src/builtins/builtins-promise.h +++ b/deps/v8/src/builtins/builtins-promise.h @@ -13,11 +13,9 @@ namespace internal { class PromiseBuiltins { public: enum PromiseResolvingFunctionContextSlot { - // The promise which resolve/reject callbacks fulfill. - kPromiseSlot = Context::MIN_CONTEXT_SLOTS, - - // Whether the callback was already invoked. - kAlreadyResolvedSlot, + // The promise which resolve/reject callbacks fulfill, or Undefined + // if already resolved. + kPromiseIfNotResolvedSlot = Context::MIN_CONTEXT_SLOTS, // Whether to trigger a debug event or not. Used in catch // prediction. diff --git a/deps/v8/src/builtins/promise-abstract-operations.tq b/deps/v8/src/builtins/promise-abstract-operations.tq index d2de7eaab52006..a1d246ee327549 100644 --- a/deps/v8/src/builtins/promise-abstract-operations.tq +++ b/deps/v8/src/builtins/promise-abstract-operations.tq @@ -265,8 +265,8 @@ const kPromiseCapabilitySize: type PromiseResolvingFunctionContext extends FunctionContext; extern enum PromiseResolvingFunctionContextSlot extends intptr constexpr 'PromiseBuiltins::PromiseResolvingFunctionContextSlot' { - kPromiseSlot: Slot, - kAlreadyResolvedSlot: Slot, + kPromiseIfNotResolvedSlot: + Slot, kDebugEventSlot: Slot, kPromiseContextLength } @@ -390,25 +390,29 @@ transitioning builtin NewPromiseCapability( transitioning javascript builtin PromiseCapabilityDefaultReject( js-implicit context: Context, receiver: JSAny)(reason: JSAny): JSAny { const context = %RawDownCast(context); - // 2. Let promise be F.[[Promise]]. - const promise = - *ContextSlot(context, PromiseResolvingFunctionContextSlot::kPromiseSlot); - - // 3. Let alreadyResolved be F.[[AlreadyResolved]]. - const alreadyResolved = *ContextSlot( - context, PromiseResolvingFunctionContextSlot::kAlreadyResolvedSlot); - - // 4. If alreadyResolved.[[Value]] is true, return undefined. - if (alreadyResolved == True) { - return Undefined; + // 2. Let promise be promiseOrEmpty.[[Value]]. + const promiseOrEmpty = + *ContextSlot( + context, PromiseResolvingFunctionContextSlot::kPromiseIfNotResolvedSlot); + + // 1. If promiseOrEmpty.[[Value]] is ~empty~, return undefined. + let promise: JSPromise; + typeswitch (promiseOrEmpty) { + case (Undefined): { + return Undefined; + } + case (p: JSPromise): { + promise = p; + } } - // 5. Set alreadyResolved.[[Value]] to true. + // 3. Set promiseOrEmpty.[[Value]] to ~empty~. *ContextSlot( - context, PromiseResolvingFunctionContextSlot::kAlreadyResolvedSlot) = - True; + context, PromiseResolvingFunctionContextSlot::kPromiseIfNotResolvedSlot) = + Undefined; - // 6. Return RejectPromise(promise, reason). + // 4. Perform RejectPromise(promise, reason). + // 5. Return undefined. const debugEvent = *ContextSlot( context, PromiseResolvingFunctionContextSlot::kDebugEventSlot); return RejectPromise(promise, reason, debugEvent); @@ -418,23 +422,26 @@ transitioning javascript builtin PromiseCapabilityDefaultReject( transitioning javascript builtin PromiseCapabilityDefaultResolve( js-implicit context: Context, receiver: JSAny)(resolution: JSAny): JSAny { const context = %RawDownCast(context); - // 2. Let promise be F.[[Promise]]. - const promise: JSPromise = - *ContextSlot(context, PromiseResolvingFunctionContextSlot::kPromiseSlot); - - // 3. Let alreadyResolved be F.[[AlreadyResolved]]. - const alreadyResolved: Boolean = *ContextSlot( - context, PromiseResolvingFunctionContextSlot::kAlreadyResolvedSlot); - - // 4. If alreadyResolved.[[Value]] is true, return undefined. - if (alreadyResolved == True) { - return Undefined; + // 2. Let promise be promiseOrEmpty.[[Value]]. + const promiseOrEmpty = + *ContextSlot( + context, PromiseResolvingFunctionContextSlot::kPromiseIfNotResolvedSlot); + + // 1. If promiseOrEmpty.[[Value]] is ~empty~, return undefined. + let promise: JSPromise; + typeswitch (promiseOrEmpty) { + case (Undefined): { + return Undefined; + } + case (p: JSPromise): { + promise = p; + } } - // 5. Set alreadyResolved.[[Value]] to true. + // 3. Set promiseOrEmpty.[[Value]] to ~empty~. *ContextSlot( - context, PromiseResolvingFunctionContextSlot::kAlreadyResolvedSlot) = - True; + context, PromiseResolvingFunctionContextSlot::kPromiseIfNotResolvedSlot) = + Undefined; // The rest of the logic (and the catch prediction) is // encapsulated in the dedicated ResolvePromise builtin. diff --git a/deps/v8/src/builtins/promise-all.tq b/deps/v8/src/builtins/promise-all.tq index b45d55bba5ab4b..440866706f5c0b 100644 --- a/deps/v8/src/builtins/promise-all.tq +++ b/deps/v8/src/builtins/promise-all.tq @@ -63,17 +63,14 @@ macro CreatePromiseResolvingFunctionsContext( nativeContext, PromiseResolvingFunctionContextSlot::kPromiseContextLength)); InitContextSlot( - resolveContext, PromiseResolvingFunctionContextSlot::kPromiseSlot, - promise); - InitContextSlot( - resolveContext, PromiseResolvingFunctionContextSlot::kAlreadyResolvedSlot, - False); + resolveContext, + PromiseResolvingFunctionContextSlot::kPromiseIfNotResolvedSlot, promise); InitContextSlot( resolveContext, PromiseResolvingFunctionContextSlot::kDebugEventSlot, debugEvent); static_assert( PromiseResolvingFunctionContextSlot::kPromiseContextLength == - ContextSlot::MIN_CONTEXT_SLOTS + 3); + ContextSlot::MIN_CONTEXT_SLOTS + 2); return resolveContext; } diff --git a/deps/v8/src/compiler/js-call-reducer.cc b/deps/v8/src/compiler/js-call-reducer.cc index ececdd1d7e95b0..e9f8a024edd6de 100644 --- a/deps/v8/src/compiler/js-call-reducer.cc +++ b/deps/v8/src/compiler/js-call-reducer.cc @@ -2543,10 +2543,8 @@ TNode PromiseBuiltinReducerAssembler::ReducePromiseConstructor( // Allocate a promise context for the closures below. TNode promise_context = CreateFunctionContext( native_context, context, PromiseBuiltins::kPromiseContextLength); - StoreContextNoCellSlot(promise_context, PromiseBuiltins::kPromiseSlot, - promise); - StoreContextNoCellSlot(promise_context, PromiseBuiltins::kAlreadyResolvedSlot, - FalseConstant()); + StoreContextNoCellSlot(promise_context, + PromiseBuiltins::kPromiseIfNotResolvedSlot, promise); StoreContextNoCellSlot(promise_context, PromiseBuiltins::kDebugEventSlot, TrueConstant()); diff --git a/deps/v8/src/execution/isolate.cc b/deps/v8/src/execution/isolate.cc index cebff6c533a49e..06fa14bf6b1002 100644 --- a/deps/v8/src/execution/isolate.cc +++ b/deps/v8/src/execution/isolate.cc @@ -1253,9 +1253,12 @@ void CaptureAsyncStackTrace(Isolate* isolate, DirectHandle promise, DirectHandle function( Cast(reaction->fulfill_handler()), isolate); DirectHandle context(function->context(), isolate); - promise = direct_handle( - Cast(context->GetNoCell(PromiseBuiltins::kPromiseSlot)), - isolate); + Tagged promise_or_undefined = + context->GetNoCell(PromiseBuiltins::kPromiseIfNotResolvedSlot); + if (!TryCast(direct_handle(promise_or_undefined, isolate), &promise)) { + DCHECK(IsUndefined(promise_or_undefined)); + return; + } } else { // We have some generic promise chain here, so try to // continue with the chained promise on the reaction diff --git a/deps/v8/test/cctest/test-code-stub-assembler.cc b/deps/v8/test/cctest/test-code-stub-assembler.cc index 32e8dc1b32c59c..3d8501a08bf299 100644 --- a/deps/v8/test/cctest/test-code-stub-assembler.cc +++ b/deps/v8/test/cctest/test-code-stub-assembler.cc @@ -3037,7 +3037,8 @@ TEST(CreatePromiseResolvingFunctionsContext) { DirectHandle context_js = Cast(result); CHECK_EQ(isolate->root(RootIndex::kEmptyScopeInfo), context_js->scope_info()); CHECK_EQ(*isolate->native_context(), context_js->native_context()); - CHECK(IsJSPromise(context_js->GetNoCell(PromiseBuiltins::kPromiseSlot))); + CHECK(IsJSPromise( + context_js->GetNoCell(PromiseBuiltins::kPromiseIfNotResolvedSlot))); CHECK_EQ(ReadOnlyRoots(isolate).false_value(), context_js->GetNoCell(PromiseBuiltins::kDebugEventSlot)); } @@ -3246,7 +3247,8 @@ TEST(NewPromiseCapability) { CHECK_EQ(*isolate->native_context(), callback_context->native_context()); CHECK_EQ(PromiseBuiltins::kPromiseContextLength, callback_context->length()); - CHECK_EQ(callback_context->GetNoCell(PromiseBuiltins::kPromiseSlot), + CHECK_EQ(callback_context->GetNoCell( + PromiseBuiltins::kPromiseIfNotResolvedSlot), result->promise()); } } diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-42213031.js b/deps/v8/test/mjsunit/regress/regress-crbug-42213031.js new file mode 100644 index 00000000000000..7bace045b021f0 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-42213031.js @@ -0,0 +1,26 @@ +// Copyright 2026 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --expose-gc + +const pending = new Promise(() => {}); + +(async function () { + let wr; + + await (async function () { + const payload = { }; + wr = new WeakRef(payload); + const resolved = Promise.resolve(payload); + // The pending Promise should not prevent GC of the race Promise once the race settles. + await Promise.race([pending, resolved]); + })(); + + await gc({ type: 'major', execution: 'async' }); + + assertEquals(undefined, wr.deref()); +})().catch((e) => { + console.error(e); + quit(1); +}); From dc052c095c7b9483097d1c8fb93043d886def60a Mon Sep 17 00:00:00 2001 From: Stephen Belanger Date: Fri, 26 Jun 2026 18:02:49 +0800 Subject: [PATCH 035/131] diagnostics_channel: return original thenable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes tracePromise return the original thenable to allow custom thenable types to retain their methods rather than producing the chained result type. Signed-off-by: Stephen Belanger PR-URL: https://github.com/nodejs/node/pull/62407 Reviewed-By: René Reviewed-By: James M Snell Reviewed-By: Gerhard Stöbich --- doc/api/diagnostics_channel.md | 15 +++--- lib/diagnostics_channel.js | 27 ++++++---- ...ing-channel-promise-spoofed-constructor.js | 52 +++++++++++++++++++ ...hannel-tracing-channel-promise-thenable.js | 8 ++- 4 files changed, 86 insertions(+), 16 deletions(-) create mode 100644 test/parallel/test-diagnostics-channel-tracing-channel-promise-spoofed-constructor.js diff --git a/doc/api/diagnostics_channel.md b/doc/api/diagnostics_channel.md index a7a1b4ee5a5bfd..a199c564bc42d2 100644 --- a/doc/api/diagnostics_channel.md +++ b/doc/api/diagnostics_channel.md @@ -948,20 +948,23 @@ added: - v19.9.0 - v18.19.0 changes: + - version: REPLACEME + pr-url: https://github.com/nodejs/node/pull/62407 + description: Non-native-Promise thenables are now returned as-is, + preserving their original type and methods. - version: v26.0.0 pr-url: https://github.com/nodejs/node/pull/61766 - description: Custom thenables will no longer be wrapped in native Promises. - Non-thenables will be returned with a warning. + description: Non-thenables will be returned with a warning. --> * `fn` {Function} Function to wrap a trace around * `context` {Object} Shared object to correlate trace events through * `thisArg` {any} The receiver to be used for the function call * `...args` {any} Optional arguments to pass to the function -* Returns: {any} The return value of the given function, or the result of - calling `.then(...)` on the return value if the tracing channel has active - subscribers. If the return value is not a Promise or thenable, then - it is returned as-is and a warning is emitted. +* Returns: {any} The return value of the given function. If the return value + is a Promise or thenable, tracing events will be published when it settles. + If the return value is not a Promise or thenable, it is returned as-is and + a warning is emitted. Trace an asynchronous function call which returns a {Promise} or [thenable object][]. This will always produce a [`start` event][] and diff --git a/lib/diagnostics_channel.js b/lib/diagnostics_channel.js index f0aedbd6ef29b6..7b78851208df66 100644 --- a/lib/diagnostics_channel.js +++ b/lib/diagnostics_channel.js @@ -10,8 +10,8 @@ const { ObjectDefineProperty, ObjectGetPrototypeOf, ObjectSetPrototypeOf, + PromisePrototype, PromisePrototypeThen, - PromiseReject, ReflectApply, SafeFinalizationRegistry, SafeMap, @@ -546,17 +546,21 @@ class TracingChannel { const { error } = this; const continuationWindow = this.#continuationWindow; - function reject(err) { + function onReject(err) { context.error = err; error.publish(context); // Use continuation window for asyncStart/asyncEnd // eslint-disable-next-line no-unused-vars using scope = continuationWindow.withScope(context); // TODO: Is there a way to have asyncEnd _after_ the continuation? - return PromiseReject(err); } - function resolve(result) { + function onRejectWithRethrow(err) { + onReject(err); + throw err; + } + + function onResolve(result) { context.result = result; // Use continuation window for asyncStart/asyncEnd // eslint-disable-next-line no-unused-vars @@ -576,12 +580,17 @@ class TracingChannel { context.result = result; return result; } - // For native Promises use PromisePrototypeThen to avoid user overrides. - if (isPromise(result)) { - return PromisePrototypeThen(result, resolve, reject); + // isPromise() matches sub-classes, but we need to match only direct + // instances of the native Promise type to safely use PromisePrototypeThen. + if (isPromise(result) && ObjectGetPrototypeOf(result) === PromisePrototype) { + return PromisePrototypeThen(result, onResolve, onRejectWithRethrow); } - // For custom thenables, call .then() directly to preserve the thenable type. - return result.then(resolve, reject); + // For non-native thenables, subscribe to the result but return the + // original thenable so the consumer can continue handling it directly. + // Non-native thenables don't have unhandledRejection tracking, so + // swallowing the rejection here doesn't change existing behaviour. + result.then(onResolve, onReject); + return result; } catch (err) { context.error = err; error.publish(context); diff --git a/test/parallel/test-diagnostics-channel-tracing-channel-promise-spoofed-constructor.js b/test/parallel/test-diagnostics-channel-tracing-channel-promise-spoofed-constructor.js new file mode 100644 index 00000000000000..973a50b87e19d2 --- /dev/null +++ b/test/parallel/test-diagnostics-channel-tracing-channel-promise-spoofed-constructor.js @@ -0,0 +1,52 @@ +'use strict'; + +const common = require('../common'); +const dc = require('diagnostics_channel'); +const assert = require('assert'); + +class SpoofedPromise extends Promise { + customMethod() { + return 'works'; + } +} + +const channel = dc.tracingChannel('test'); + +const expectedResult = { foo: 'bar' }; +const input = { foo: 'bar' }; +const thisArg = { baz: 'buz' }; + +function check(found) { + assert.strictEqual(found, input); +} + +function checkAsync(found) { + check(found); + assert.strictEqual(found.error, undefined); + assert.deepStrictEqual(found.result, expectedResult); +} + +const handlers = { + start: common.mustCall(check), + end: common.mustCall(check), + asyncStart: common.mustCall(checkAsync), + asyncEnd: common.mustCall(checkAsync), + error: common.mustNotCall() +}; + +channel.subscribe(handlers); + +let innerPromise; + +const result = channel.tracePromise(common.mustCall(function() { + innerPromise = SpoofedPromise.resolve(expectedResult); + // Spoof the constructor to try to trick the brand check + innerPromise.constructor = Promise; + return innerPromise; +}), input, thisArg); + +// Despite the spoofed constructor, the original subclass instance should be +// returned directly so that custom methods remain accessible. +assert(result instanceof SpoofedPromise); +assert.strictEqual(result, innerPromise); +assert.strictEqual(result.customMethod(), 'works'); diff --git a/test/parallel/test-diagnostics-channel-tracing-channel-promise-thenable.js b/test/parallel/test-diagnostics-channel-tracing-channel-promise-thenable.js index b93be1dd304c7d..18b38cec9f9949 100644 --- a/test/parallel/test-diagnostics-channel-tracing-channel-promise-thenable.js +++ b/test/parallel/test-diagnostics-channel-tracing-channel-promise-thenable.js @@ -12,6 +12,9 @@ class ResolvedThenable { then(resolve) { return new ResolvedThenable(resolve(this.#result)); } + customMethod() { + return this.#result; + } } const channel = dc.tracingChannel('test'); @@ -49,7 +52,10 @@ const result = channel.tracePromise(common.mustCall(function(value) { }), input, thisArg, expectedResult); assert(result instanceof ResolvedThenable); -assert.notStrictEqual(result, innerThenable); +// With branching then, the original thenable is returned directly so that +// extra methods defined on it remain accessible to the caller. +assert.strictEqual(result, innerThenable); +assert.deepStrictEqual(result.customMethod(), expectedResult); result.then(common.mustCall((value) => { assert.deepStrictEqual(value, expectedResult); })); From 7a16ccccd0aa8061e1dab6af75c70002733f348a Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Fri, 26 Jun 2026 12:24:20 +0200 Subject: [PATCH 036/131] doc: announce upcoming end of tier 2 support for macOS x64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Antoine du Hamel PR-URL: https://github.com/nodejs/node/pull/63931 Reviewed-By: Richard Lau Reviewed-By: Michaël Zasso Reviewed-By: Matteo Collina Reviewed-By: Daijiro Wachi Reviewed-By: Colin Ihrig Reviewed-By: René Reviewed-By: Rafael Gonzaga Reviewed-By: Stewart X Addison --- BUILDING.md | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/BUILDING.md b/BUILDING.md index 4e0629ac895b08..3455c9e80a04ca 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -104,25 +104,25 @@ Node.js does not support a platform version if a vendor has expired support for it. In other words, Node.js does not support running on End-of-Life (EoL) platforms. This is true regardless of entries in the table below. -| Operating System | Architectures | Versions | Support Type | Notes | -| ---------------- | ---------------- | --------------------------------- | ------------ | ---------------------------------------------- | -| GNU/Linux | x64 | kernel >= 4.18[^1], glibc >= 2.28 | Tier 1 | e.g. Ubuntu 20.04, Debian 10, RHEL 8 | -| GNU/Linux | x64 | kernel >= 3.10, musl >= 1.1.19 | Experimental | e.g. Alpine 3.8 | -| GNU/Linux | x86 | kernel >= 3.10, glibc >= 2.17 | Experimental | Downgraded as of Node.js 10 | -| GNU/Linux | arm64 | kernel >= 4.18[^1], glibc >= 2.28 | Tier 1 | e.g. Ubuntu 20.04, Debian 10, RHEL 8 | -| GNU/Linux | armv7 | kernel >= 4.18[^1], glibc >= 2.28 | Experimental | Downgraded as of Node.js 24 | -| GNU/Linux | ppc64le >=power9 | kernel >= 4.18[^1], glibc >= 2.28 | Tier 2 | e.g. Ubuntu 20.04, RHEL 8 | -| GNU/Linux | s390x >=z14 | kernel >= 4.18[^1], glibc >= 2.28 | Tier 2 | e.g. RHEL 8 | -| GNU/Linux | loong64 | kernel >= 5.19, glibc >= 2.36 | Experimental | | -| GNU/Linux | riscv64 | kernel >= 5.19, glibc >= 2.36 | Experimental | GCC >= 14 or Clang >= 19 for native builds[^5] | -| Windows | x64 | >= Windows 10/Server 2016 | Tier 1 | [^2],[^3] | -| Windows | arm64 | >= Windows 10 | Tier 2 | | -| macOS | x64 | >= 13.5 | Tier 2 | For notes about compilation see [^4] | -| macOS | arm64 | >= 13.5 | Tier 1 | | -| SmartOS | x64 | >= 18 | Tier 2 | | -| AIX | ppc64be >=power9 | >= 7.2 TL04 | Tier 2 | | -| FreeBSD | x64 | >= 13.2 | Experimental | | -| OpenHarmony | arm64 | >= 5.0 | Experimental | | +| Operating System | Architectures | Versions | Support Type | Notes | +| ---------------- | ---------------- | --------------------------------- | ------------ | ---------------------------------------------------------- | +| GNU/Linux | x64 | kernel >= 4.18[^1], glibc >= 2.28 | Tier 1 | e.g. Ubuntu 20.04, Debian 10, RHEL 8 | +| GNU/Linux | x64 | kernel >= 3.10, musl >= 1.1.19 | Experimental | e.g. Alpine 3.8 | +| GNU/Linux | x86 | kernel >= 3.10, glibc >= 2.17 | Experimental | Downgraded as of Node.js 10 | +| GNU/Linux | arm64 | kernel >= 4.18[^1], glibc >= 2.28 | Tier 1 | e.g. Ubuntu 20.04, Debian 10, RHEL 8 | +| GNU/Linux | armv7 | kernel >= 4.18[^1], glibc >= 2.28 | Experimental | Downgraded as of Node.js 24 | +| GNU/Linux | ppc64le >=power9 | kernel >= 4.18[^1], glibc >= 2.28 | Tier 2 | e.g. Ubuntu 20.04, RHEL 8 | +| GNU/Linux | s390x >=z14 | kernel >= 4.18[^1], glibc >= 2.28 | Tier 2 | e.g. RHEL 8 | +| GNU/Linux | loong64 | kernel >= 5.19, glibc >= 2.36 | Experimental | | +| GNU/Linux | riscv64 | kernel >= 5.19, glibc >= 2.36 | Experimental | GCC >= 14 or Clang >= 19 for native builds[^5] | +| Windows | x64 | >= Windows 10/Server 2016 | Tier 1 | [^2],[^3] | +| Windows | arm64 | >= Windows 10 | Tier 2 | | +| macOS | x64 | >= 13.5 | Tier 2 | Until early 2028[^8]. For notes about compilation see [^4] | +| macOS | arm64 | >= 13.5 | Tier 1 | | +| SmartOS | x64 | >= 18 | Tier 2 | | +| AIX | ppc64be >=power9 | >= 7.2 TL04 | Tier 2 | | +| FreeBSD | x64 | >= 13.2 | Experimental | | +| OpenHarmony | arm64 | >= 5.0 | Experimental | | @@ -154,6 +154,14 @@ platforms. This is true regardless of entries in the table below. Cross-compilation from x64 is unaffected (the code is behind `V8_HOST_ARCH_RISCV64`). +[^8]: Our macOS testing infrastructure provider has announced end of support for + Intel-based architecture for early 2028 at which time that platform will move to + experimental status as the Node.js project will no longer be able to test changes on any + Intel-based macOS version. When this change occurs the project intends to continue + creating universal binaries for versions of Node.js which are still in support which will + be compatible with both Apple Silicon-based and Intel-based macOS versions but + they will be untested. + ### Supported toolchains From c7e57f55a76108944680c8cd4629c36d639f8517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9?= Date: Fri, 26 Jun 2026 12:12:53 +0100 Subject: [PATCH 037/131] deps: c-ares: cherry-pick 8ba37af8e3fb Original commit message: Fixes #1056 The commit https://github.com/c-ares/c-ares/commit/1d1b3d4a808dff9359cacb4539ac1b775876dcb6 refactored the function to use wide strings, but didn't touch this check. Because an empty wide string would now be size 2 and not 1, the empty string would go on and cause the DNS domain list to be replaced with nothing. Signed-off-by: @dankmeme01 Refs: https://github.com/c-ares/c-ares/commit/8ba37af8e3fbcaad93f028cd9b36d06ff6d39543 PR-URL: https://github.com/nodejs/node/pull/64110 Fixes: https://github.com/nodejs/node/issues/62347 Reviewed-By: Luigi Pinca Reviewed-By: Tim Perry Reviewed-By: Colin Ihrig --- deps/cares/src/lib/ares_sysconfig_win.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/cares/src/lib/ares_sysconfig_win.c b/deps/cares/src/lib/ares_sysconfig_win.c index 35f4bd8e72ac9c..94a3817de348bb 100644 --- a/deps/cares/src/lib/ares_sysconfig_win.c +++ b/deps/cares/src/lib/ares_sysconfig_win.c @@ -106,7 +106,7 @@ static ares_bool_t get_REG_SZ(HKEY hKey, const WCHAR *leafKeyName, char **outptr /* Get the value for real */ res = RegQueryValueExW(hKey, leafKeyName, 0, NULL, (BYTE *)val, &size); - if (res != ERROR_SUCCESS || size == 1) { + if (res != ERROR_SUCCESS || size == sizeof(WCHAR)) { ares_free(val); return ARES_FALSE; } From b373202efc89c807f20b476926e90311ef9403e5 Mon Sep 17 00:00:00 2001 From: Efe Date: Fri, 26 Jun 2026 15:50:21 +0200 Subject: [PATCH 038/131] esm: add `--experimental-import-text` flag Signed-off-by: Efe Karasakal PR-URL: https://github.com/nodejs/node/pull/62300 Reviewed-By: Aviv Keller Reviewed-By: Ilyas Shabi Reviewed-By: Antoine du Hamel --- doc/api/cli.md | 13 +++++ doc/api/esm.md | 20 ++++++++ lib/internal/modules/esm/assert.js | 13 ++++- lib/internal/modules/esm/get_format.js | 25 ++++++++- lib/internal/modules/esm/loader.js | 2 +- lib/internal/modules/esm/translators.js | 11 ++++ src/node_options.cc | 5 ++ src/node_options.h | 1 + .../test-esm-import-attributes-errors.js | 5 ++ .../test-esm-import-attributes-errors.mjs | 5 ++ ...t-esm-import-attributes-validation-text.js | 19 +++++++ .../test-esm-import-text-disabled.mjs | 12 +++++ test/es-module/test-esm-import-text.mjs | 51 +++++++++++++++++++ 13 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 test/es-module/test-esm-import-attributes-validation-text.js create mode 100644 test/es-module/test-esm-import-text-disabled.mjs create mode 100644 test/es-module/test-esm-import-text.mjs diff --git a/doc/api/cli.md b/doc/api/cli.md index 7e77ac2d7f919f..e5d653337a870c 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -1255,6 +1255,18 @@ passing a second `parentURL` argument for contextual resolution. Previously gated the entire `import.meta.resolve` feature. +### `--experimental-import-text` + + + +> Stability: 1.0 - Early development + +Enable experimental support for importing modules with +`with { type: 'text' }`. + ### `--experimental-inspector-network-resource` @@ -1102,6 +1118,8 @@ Each Zstd-based class takes an `options` object. All options are optional. * `dictionary` {Buffer} Optional dictionary used to improve compression efficiency when compressing or decompressing data that shares common patterns with the dictionary. +* `rejectGarbageAfterEnd` {boolean} If `true`, decompression fails when + input remains after the first complete compressed stream. **Default:** `false` For example: diff --git a/lib/zlib.js b/lib/zlib.js index 342d210963987e..8ebc4fde142876 100644 --- a/lib/zlib.js +++ b/lib/zlib.js @@ -65,6 +65,7 @@ const { const { owner_symbol } = require('internal/async_hooks').symbols; const { checkRangesOrGetDefault, + validateBoolean, validateFunction, validateUint32, validateFiniteNumber, @@ -246,6 +247,13 @@ function ZlibBase(opts, mode, handle, { flush, finishFlush, fullFlush }) { opts.maxOutputLength, 'options.maxOutputLength', 1, kMaxLength, kMaxLength); + if (opts.rejectGarbageAfterEnd !== undefined) { + validateBoolean( + opts.rejectGarbageAfterEnd, + 'options.rejectGarbageAfterEnd', + ); + } + if (opts.encoding || opts.objectMode || opts.writableObjectMode) { opts = { ...opts }; opts.encoding = null; diff --git a/test/parallel/test-zlib-reject-garbage-after-end.js b/test/parallel/test-zlib-reject-garbage-after-end.js new file mode 100644 index 00000000000000..8039865f5f1193 --- /dev/null +++ b/test/parallel/test-zlib-reject-garbage-after-end.js @@ -0,0 +1,144 @@ +'use strict'; + +require('../common'); +const assert = require('assert'); +const test = require('node:test'); +const { finished } = require('stream/promises'); +const zlib = require('zlib'); + +const trailingJunkError = { + code: 'ERR_TRAILING_JUNK_AFTER_STREAM_END', + name: 'TypeError', +}; + +function callAsync(fn, input, options) { + return new Promise((resolve, reject) => { + fn(input, options, (err, result) => { + if (err) { + reject(err); + } else { + resolve(result); + } + }); + }); +} + +async function collect(stream, input) { + const chunks = []; + stream.on('data', (chunk) => chunks.push(chunk)); + stream.end(input); + await finished(stream); + return Buffer.concat(chunks); +} + +const cases = [ + { + label: 'inflate', + compress: zlib.deflateSync, + decompress: zlib.inflate, + decompressSync: zlib.inflateSync, + createDecompress: zlib.createInflate, + defaultOutput: 'a', + }, + { + label: 'inflateRaw', + compress: zlib.deflateRawSync, + decompress: zlib.inflateRaw, + decompressSync: zlib.inflateRawSync, + createDecompress: zlib.createInflateRaw, + defaultOutput: 'a', + }, + { + label: 'gunzip', + compress: zlib.gzipSync, + decompress: zlib.gunzip, + decompressSync: zlib.gunzipSync, + createDecompress: zlib.createGunzip, + defaultOutput: 'aa', + }, + { + label: 'unzip', + compress: zlib.gzipSync, + decompress: zlib.unzip, + decompressSync: zlib.unzipSync, + createDecompress: zlib.createUnzip, + defaultOutput: 'aa', + }, + { + label: 'brotli', + compress: zlib.brotliCompressSync, + decompress: zlib.brotliDecompress, + decompressSync: zlib.brotliDecompressSync, + createDecompress: zlib.createBrotliDecompress, + defaultOutput: 'a', + }, + { + label: 'zstd', + compress: zlib.zstdCompressSync, + decompress: zlib.zstdDecompress, + decompressSync: zlib.zstdDecompressSync, + createDecompress: zlib.createZstdDecompress, + defaultOutput: 'a', + }, +]; + +for (const { + label, + compress, + decompress, + decompressSync, + createDecompress, + defaultOutput, +} of cases) { + test(`rejectGarbageAfterEnd rejects trailing input for ${label}`, async () => { + const compressed = compress(Buffer.from('a')); + const withTrailingInput = Buffer.concat([compressed, compressed]); + + assert.strictEqual(decompressSync(withTrailingInput).toString(), defaultOutput); + assert.strictEqual( + (await callAsync(decompress, withTrailingInput)).toString(), + defaultOutput, + ); + assert.strictEqual( + (await collect(createDecompress(), withTrailingInput)).toString(), + defaultOutput, + ); + + assert.throws( + () => decompressSync(withTrailingInput, { rejectGarbageAfterEnd: true }), + trailingJunkError, + ); + await assert.rejects( + callAsync(decompress, withTrailingInput, { rejectGarbageAfterEnd: true }), + trailingJunkError, + ); + await assert.rejects( + collect( + createDecompress({ rejectGarbageAfterEnd: true }), + withTrailingInput, + ), + trailingJunkError, + ); + }); +} + +test('rejectGarbageAfterEnd must be a boolean', () => { + const compressed = zlib.deflateSync(Buffer.from('a')); + + for (const value of [1, 'true', null]) { + assert.throws( + () => zlib.inflateSync(compressed, { rejectGarbageAfterEnd: value }), + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + }, + ); + assert.throws( + () => zlib.createInflate({ rejectGarbageAfterEnd: value }), + { + code: 'ERR_INVALID_ARG_TYPE', + name: 'TypeError', + }, + ); + } +}); From 85fc79dd9b05fc3e42ac38f85eb0fa37eb5e2289 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 27 Jun 2026 16:10:05 +0200 Subject: [PATCH 045/131] doc: fix broken links and duplicate stability label Signed-off-by: Antoine du Hamel PR-URL: https://github.com/nodejs/node/pull/64130 Reviewed-By: Jacob Smith Reviewed-By: Luigi Pinca --- doc/api/http.md | 2 +- doc/api/modules.md | 2 +- doc/api/stream.md | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/doc/api/http.md b/doc/api/http.md index 43fa46e7d6ed09..33231bb47c7b8c 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -4773,4 +4773,4 @@ const agent2 = new http.Agent({ proxyEnv: process.env }); [`writable.uncork()`]: stream.md#writableuncork [`writable.write()`]: stream.md#writablewritechunk-encoding-callback [information event]: #event-information -[initial delay]: net.md#socketsetkeepaliveenable-initialdelay +[initial delay]: net.md#socketsetkeepaliveenable-initialdelay-interval-count diff --git a/doc/api/modules.md b/doc/api/modules.md index 63fe3f18b27133..0fb30b542e630c 100644 --- a/doc/api/modules.md +++ b/doc/api/modules.md @@ -477,7 +477,7 @@ RESOLVE_ESM_MATCH(MATCH) 3. THROW "not found" ``` -The "ESM resolver" is defined [in the ESM documentation](esm.md#resolver-algorithm-specification). +The "ESM resolver" is defined [in the ESM documentation](esm.md#resolution-and-loading-algorithm). ## Caching diff --git a/doc/api/stream.md b/doc/api/stream.md index 7f0311378e5cee..243f351db26a39 100644 --- a/doc/api/stream.md +++ b/doc/api/stream.md @@ -3034,8 +3034,6 @@ changes: description: Added support for webstreams. --> -> Stability: 2 - Stable - * `streams` {Stream\[]|Iterable\[]|AsyncIterable\[]|Function\[]| ReadableStream\[]|WritableStream\[]|TransformStream\[]|Duplex\[]|Function} * Returns: {stream.Duplex} From 7b010400087bad7ccafda5e34ba473eabcbf9973 Mon Sep 17 00:00:00 2001 From: Aviv Keller Date: Sat, 27 Jun 2026 14:39:44 -0400 Subject: [PATCH 046/131] meta: speed up stale bot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Aviv Keller PR-URL: https://github.com/nodejs/node/pull/64075 Reviewed-By: Antoine du Hamel Reviewed-By: Gürgün Dayıoğlu --- .github/workflows/stale.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 217dfcfbae36b4..ff698a2f086147 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -29,6 +29,7 @@ jobs: permissions: issues: write # for actions/stale to close stale issues pull-requests: write # for actions/stale to close stale PRs + actions: write # for actions/stale to cache stale saved state if: github.repository == 'nodejs/node' runs-on: ubuntu-slim steps: @@ -46,5 +47,5 @@ jobs: close-pr-message: ${{ format(env.CLOSE_MESSAGE, 'pull request') }} stale-pr-message: ${{ format(env.WARN_MESSAGE, 'pull request') }} # max requests it will send per run to the GitHub API before it deliberately exits to avoid hitting API rate limits - operations-per-run: 500 + operations-per-run: 2500 remove-stale-when-updated: true From 2a126647b0c8a5a645133789381d404e8b65fe6e Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Sun, 28 Jun 2026 12:11:44 +0200 Subject: [PATCH 047/131] doc: clarify vfs is not a sandbox MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Matteo Collina PR-URL: https://github.com/nodejs/node/pull/64143 Reviewed-By: René Reviewed-By: James M Snell Reviewed-By: Tobias Nießen Reviewed-By: Luigi Pinca Reviewed-By: Rafael Gonzaga --- SECURITY.md | 18 ++++++++++++++++++ doc/api/vfs.md | 39 ++++++++++++++++++++++++++++----------- 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 8444534c77bd15..f4dcddbf67da4e 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -421,6 +421,24 @@ The following are **not** vulnerabilities in Node.js: restrictions of their parent process. Passing an empty or modified `execArgv` to a worker does not grant it additional permissions. +#### Virtual File System (`node:vfs`) + +The experimental [Virtual File System](https://nodejs.org/api/vfs.html) +(`node:vfs`) is a virtualized file-system API for tests, fixtures, embedded +assets, and application-managed storage. It is **not** a sandbox, permission +system, or security boundary for untrusted code. + +Code that can load `node:vfs`, receive a `VirtualFileSystem` instance, install a +mount, choose a provider, or pass paths to VFS APIs is trusted application code. +A VFS mount only redirects matching file-system calls; it does not hide or +restrict access to the host file system. `RealFSProvider` root checks and +read-only providers are implementation behavior, not security guarantees. + +Reports that rely on using VFS to isolate untrusted JavaScript, native code, or +user-controlled paths are not considered Node.js vulnerabilities. Use OS-level +isolation, such as separate users, containers, or platform sandboxes, when a +security boundary is required. + #### V8 Sandbox The V8 sandbox is an in-process isolation mechanism internal to V8 that is not diff --git a/doc/api/vfs.md b/doc/api/vfs.md index d526c2f28f4266..90b8e9c303125a 100644 --- a/doc/api/vfs.md +++ b/doc/api/vfs.md @@ -10,10 +10,9 @@ added: v26.4.0 -The `node:vfs` module provides an in-memory virtual file system with a -`node:fs`-like API. It is useful for tests, fixtures, embedded assets, and other -scenarios where you need a self-contained file system without touching the -actual file-system. +The `node:vfs` module provides a virtual file system with a `node:fs`-like API. +It is useful for tests, fixtures, embedded assets, and other scenarios where you +need a self-contained file system without touching the actual file-system. To access it: @@ -28,6 +27,22 @@ const vfs = require('node:vfs'); This module is only available under the `node:` scheme, and only when Node.js is started with the `--experimental-vfs` flag. +## Security + +The VFS API is not a sandbox, permission system, or access-control mechanism. +It does not isolate untrusted code from the host file system or from other +Node.js capabilities. Code that can access a [`VirtualFileSystem`][] instance, +mount it, select its provider, or pass paths to it is trusted application code. + +Mounting a VFS only redirects supported [`node:fs`][] calls whose resolved paths +are under the mount point. It does not prevent code from using other paths or +other Node.js APIs to access resources available to the process. +[`RealFSProvider`][] maps VFS paths under its configured root and rejects paths +that resolve outside that root, but that check is not a security boundary. Do +not rely on VFS to run untrusted code; use operating-system-level isolation, +such as separate users, containers, or platform sandboxes, when a security +boundary is required. + ## Basic usage ```cjs @@ -68,7 +83,7 @@ const vfs = require('node:vfs'); const memoryVfs = vfs.create(); // Explicit provider -const realVfs = vfs.create(new vfs.RealFSProvider('/tmp/sandbox')); +const realVfs = vfs.create(new vfs.RealFSProvider('/tmp/vfs-root')); ``` ## Class: `VirtualFileSystem` @@ -257,10 +272,11 @@ myVfs.writeFileSync('/x.txt', 'fail'); // throws EROFS added: v26.4.0 --> -A provider that wraps a directory (i.e. one on the actual file system) and exposes its -contents through the VFS API. All VFS paths are resolved relative to -the root and verified to stay inside it; symbolic links resolving -outside the root are rejected. +A provider that wraps a directory (i.e. one on the actual file system) and +exposes its contents through the VFS API. All VFS paths are resolved relative to +the root and verified to stay inside it; symbolic links resolving outside the +root are rejected. This path mapping is not a sandbox or access-control +mechanism. ### `new RealFSProvider(rootPath)` @@ -274,8 +290,8 @@ added: v26.4.0 ```cjs const vfs = require('node:vfs'); -const realVfs = vfs.create(new vfs.RealFSProvider('/tmp/sandbox')); -realVfs.writeFileSync('/file.txt', 'hello'); // writes /tmp/sandbox/file.txt +const realVfs = vfs.create(new vfs.RealFSProvider('/tmp/vfs-root')); +realVfs.writeFileSync('/file.txt', 'hello'); // writes /tmp/vfs-root/file.txt ``` ### `realFSProvider.rootPath` @@ -303,6 +319,7 @@ fields use synthetic but stable values: * Times default to the moment the entry was created/last modified. [`MemoryProvider`]: #class-memoryprovider +[`RealFSProvider`]: #class-realfsprovider [`VirtualFileSystem`]: #class-virtualfilesystem [`VirtualProvider`]: #class-virtualprovider [`fs.BigIntStats`]: fs.md#class-fsbigintstats From f3db304588dee374ed7d8f785c71ddbc37c626c9 Mon Sep 17 00:00:00 2001 From: Richard Lau Date: Sun, 28 Jun 2026 16:44:52 +0100 Subject: [PATCH 048/131] doc: update list of people in `SECURITY.md` Update the list of people with access to: - Private security reports against Node.js. - Private security patches to Node.js. The latter by running `ncu-team sync SECURITY.md`. Signed-off-by: Richard Lau PR-URL: https://github.com/nodejs/node/pull/64152 Refs: https://github.com/nodejs/Release/issues/733 Refs: https://github.com/nodejs/TSC/issues/1760 Reviewed-By: Beth Griggs Reviewed-By: Antoine du Hamel Reviewed-By: Luigi Pinca Reviewed-By: Rafael Gonzaga Reviewed-By: Colin Ihrig Reviewed-By: Gireesh Punathil --- SECURITY.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/SECURITY.md b/SECURITY.md index f4dcddbf67da4e..e32ca8208adf87 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -550,6 +550,7 @@ In addition, these individuals have access: * [cjihrig](https://github.com/cjihrig) **Colin Ihrig** * [joesepi](https://github.com/joesepi) - **Joe Sepi** * [juanarbol](https://github.com/juanarbol) **Juan Jose Arboleda** +* [sxa](https://github.com/sxa) - **Stewart X Addison** * [ulisesgascon](https://github.com/ulisesgascon) **Ulises Gascón** * [vdeturckheim](https://github.com/vdeturckheim) - **Vladimir de Turckheim** @@ -564,6 +565,7 @@ the Node.js program on HackerOne. * [@anonrig](https://github.com/anonrig) - Yagiz Nizipli * [@bengl](https://github.com/bengl) - Bryan English * [@benjamingr](https://github.com/benjamingr) - Benjamin Gruenbaum +* [@BethGriggs](https://github.com/BethGriggs) - Beth Griggs * [@bmeck](https://github.com/bmeck) - Bradley Farias * [@bnoordhuis](https://github.com/bnoordhuis) - Ben Noordhuis * [@BridgeAR](https://github.com/BridgeAR) - Ruben Bridgewater @@ -586,6 +588,7 @@ the Node.js program on HackerOne. * [@ruyadorno](https://github.com/ruyadorno) - Ruy Adorno * [@santigimeno](https://github.com/santigimeno) - Santiago Gimeno * [@ShogunPanda](https://github.com/ShogunPanda) - Paolo Insogna +* [@sxa](https://github.com/sxa) - Stewart X Addison * [@targos](https://github.com/targos) - Michaël Zasso * [@tniessen](https://github.com/tniessen) - Tobias Nießen * [@UlisesGascon](https://github.com/UlisesGascon) - Ulises Gascón From ff9122c20c84f0c33df5065bae4511ea473f5672 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Mon, 29 Jun 2026 00:04:35 -0700 Subject: [PATCH 049/131] test: improve lcov reporter snapshot diagnostics Propagate failures from the nested LCOV reporter fixture process and make missing LCOV records fail with a targeted assertion instead of comparing against blank transformed output. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.5 PR-URL: https://github.com/nodejs/node/pull/64049 Refs: https://github.com/nodejs/reliability/issues?q=%22test-output-lcov-reporter%22 Reviewed-By: Moshe Atlow --- test/common/assertSnapshot.js | 19 ++++++++++++++++++- .../test-runner/output/lcov_reporter.js | 15 ++++++++++++++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/test/common/assertSnapshot.js b/test/common/assertSnapshot.js index 4fdd0be0ee32ae..c363ded73ef3e8 100644 --- a/test/common/assertSnapshot.js +++ b/test/common/assertSnapshot.js @@ -235,13 +235,30 @@ function replaceJunitDuration(str) { // This transform picks only the first line and then the lines from the test // file. function pickTestFileFromLcov(str) { + const expectedFile = 'output.js'; const lines = str.split(/\n/); const firstLineOfTestFile = lines.findIndex( - (line) => line.startsWith('SF:') && line.trim().endsWith('output.js'), + (line) => line.startsWith('SF:') && line.trim().endsWith(expectedFile), ); + + if (firstLineOfTestFile === -1) { + assert.fail( + `Could not find LCOV source record ending with ${expectedFile} ` + + `in LCOV output:\n${str || ''}`, + ); + } + const lastLineOfTestFile = lines.findIndex( (line, index) => index > firstLineOfTestFile && line.trim() === 'end_of_record', ); + + if (lastLineOfTestFile === -1) { + assert.fail( + `Could not find end_of_record for LCOV source record ending with ${expectedFile} ` + + `in LCOV output:\n${str}`, + ); + } + return ( lines[0] + '\n' + lines.slice(firstLineOfTestFile, lastLineOfTestFile + 1).join('\n') + '\n' ); diff --git a/test/fixtures/test-runner/output/lcov_reporter.js b/test/fixtures/test-runner/output/lcov_reporter.js index 832b5d2247965c..97919cb5c4c81f 100644 --- a/test/fixtures/test-runner/output/lcov_reporter.js +++ b/test/fixtures/test-runner/output/lcov_reporter.js @@ -3,7 +3,7 @@ require('../../../common'); const fixtures = require('../../../common/fixtures'); const spawn = require('node:child_process').spawn; -spawn( +const child = spawn( process.execPath, [ '--no-warnings', @@ -14,3 +14,16 @@ spawn( ], { stdio: 'inherit' }, ); + +child.on('error', (err) => { + throw err; +}); + +child.on('exit', (code, signal) => { + if (signal) { + process.kill(process.pid, signal); + return; + } + + process.exitCode = code ?? 1; +}); From 83b91ea6ec00c73ab35731a673133736cac472e7 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Mon, 29 Jun 2026 00:04:46 -0700 Subject: [PATCH 050/131] test_runner: filter execArgv fallback for child tests Apply the test runner propagation filter to execArgv entries that are not reported by the options binding. This prevents config-file and test-runner flags from leaking into isolated child tests while still preserving V8 flags. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.5 PR-URL: https://github.com/nodejs/node/pull/64056 Refs: https://github.com/nodejs/reliability/issues?q=%22test-runner-flag-propagation%22 Reviewed-By: Filip Skokan --- lib/internal/test_runner/runner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/test_runner/runner.js b/lib/internal/test_runner/runner.js index f9442be8ed164b..a4441ea31a9dc9 100644 --- a/lib/internal/test_runner/runner.js +++ b/lib/internal/test_runner/runner.js @@ -208,7 +208,7 @@ function getRunArgs(path, { forceExit, const nodeOptionsSet = new SafeSet(processNodeOptions); const unknownProcessExecArgv = ArrayPrototypeFilter( process.execArgv, - (arg) => !nodeOptionsSet.has(arg), + (arg, i, arr) => !nodeOptionsSet.has(arg) && filterExecArgv(arg, i, arr), ); ArrayPrototypePushApply(runArgs, unknownProcessExecArgv); From ff537ba858a6417362fa6a6529d2a0486739caaa Mon Sep 17 00:00:00 2001 From: YuSheng Chen Date: Mon, 29 Jun 2026 16:48:48 +0800 Subject: [PATCH 051/131] doc: update `Http2Server.close` & `Http2SecureServer.close` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Yu-Sheng Chen PR-URL: https://github.com/nodejs/node/pull/63298 Reviewed-By: Luigi Pinca Reviewed-By: Tim Perry Reviewed-By: Ethan Arrowood Reviewed-By: Ulises Gascón Reviewed-By: Matteo Collina --- doc/api/http2.md | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/doc/api/http2.md b/doc/api/http2.md index 581b7b48a4b049..0d2e9afabaf6d6 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -2441,10 +2441,7 @@ added: v8.4.0 * `callback` {Function} -Stops the server from establishing new sessions. This does not prevent new -request streams from being created due to the persistent nature of HTTP/2 -sessions. To gracefully shut down the server, call [`http2session.close()`][] on -all active sessions. +Stops the server from establishing new sessions and streams. If `callback` is provided, it is not invoked until all active sessions have been closed, although the server has already stopped allowing new sessions. See @@ -2725,10 +2722,7 @@ added: v8.4.0 * `callback` {Function} -Stops the server from establishing new sessions. This does not prevent new -request streams from being created due to the persistent nature of HTTP/2 -sessions. To gracefully shut down the server, call [`http2session.close()`][] on -all active sessions. +Stops the server from establishing new sessions and streams. If `callback` is provided, it is not invoked until all active sessions have been closed, although the server has already stopped allowing new sessions. See @@ -5053,7 +5047,6 @@ you need to implement any fall-back behavior yourself. [`http2.Server`]: #class-http2server [`http2.createSecureServer()`]: #http2createsecureserveroptions-onrequesthandler [`http2.createServer()`]: #http2createserveroptions-onrequesthandler -[`http2session.close()`]: #http2sessionclosecallback [`http2stream.pushStream()`]: #http2streampushstreamheaders-options-callback [`import()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import [`net.Server.close()`]: net.md#serverclosecallback From d0d8f0c77428e960dadc919737527da2bb18a392 Mon Sep 17 00:00:00 2001 From: "Node.js GitHub Bot" Date: Mon, 29 Jun 2026 06:21:42 -0400 Subject: [PATCH 052/131] test: update WPT for urlpattern to 11a459a2b1 PR-URL: https://github.com/nodejs/node/pull/64037 Reviewed-By: Filip Skokan Reviewed-By: Daijiro Wachi Reviewed-By: Luigi Pinca --- .../urlpattern/urlpattern-empty-regexp-group.html | 12 ++++++++++++ test/fixtures/wpt/versions.json | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/wpt/urlpattern/urlpattern-empty-regexp-group.html diff --git a/test/fixtures/wpt/urlpattern/urlpattern-empty-regexp-group.html b/test/fixtures/wpt/urlpattern/urlpattern-empty-regexp-group.html new file mode 100644 index 00000000000000..52918488044666 --- /dev/null +++ b/test/fixtures/wpt/urlpattern/urlpattern-empty-regexp-group.html @@ -0,0 +1,12 @@ + + + + diff --git a/test/fixtures/wpt/versions.json b/test/fixtures/wpt/versions.json index d88b42c22e72ba..32d186340386ab 100644 --- a/test/fixtures/wpt/versions.json +++ b/test/fixtures/wpt/versions.json @@ -76,7 +76,7 @@ "path": "url" }, "urlpattern": { - "commit": "23aac9278460a73394585ff5a15b6a04dfcd5ec8", + "commit": "11a459a2b1d411506d9230edf9f2ef32babfeb0b", "path": "urlpattern" }, "user-timing": { From 17228a861c23812adcd95e080d6a46e8fd47a068 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Mon, 29 Jun 2026 14:07:18 +0200 Subject: [PATCH 053/131] tools: add GHA benchmark runner Signed-off-by: Antoine du Hamel PR-URL: https://github.com/nodejs/node/pull/60293 Reviewed-By: Filip Skokan --- .github/workflows/benchmark.yml | 203 ++++++++++++++++++++++++++++++++ tools/nix/benchmarkTools.nix | 4 +- 2 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/benchmark.yml diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml new file mode 100644 index 00000000000000..2e0ea4680ade2a --- /dev/null +++ b/.github/workflows/benchmark.yml @@ -0,0 +1,203 @@ +name: Benchmark + +on: + workflow_dispatch: + inputs: + repo: + type: string + description: GitHub repository to fetch from (default to the current repo) + pr_id: + type: number + required: true + description: The PR to test + commit: + required: true + type: string + description: The expect HEAD of the PR + category: + required: true + type: string + description: The category (or categories) of tests to run, for example buffers, cluster etc. Maps to a folders in node/benchmark + filter: + type: string + description: A substring to restrict the benchmarks to run in a category. e.g. `net-c2c` + runs: + type: number + default: 30 + description: How many times to repeat each benchmark + +permissions: + contents: read + +jobs: + build: + strategy: + fail-fast: true + matrix: + include: + - runner: ubuntu-24.04 + system: x86_64-linux + - runner: ubuntu-24.04-arm + system: aarch64-linux + - runner: macos-15-intel + system: x86_64-darwin + - runner: macos-latest + system: aarch64-darwin + name: '${{ matrix.system }}: with shared libraries' + runs-on: ${{ matrix.runner }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: ${{ inputs.repo || github.repository }} + ref: refs/pull/${{ inputs.pr_id }}/merge + persist-credentials: false + fetch-depth: 2 + + - name: Validate PR head and roll back to base commit + run: | + [ "$(git rev-parse HEAD^2)" = "$EXPECTED_SHA" ] + git reset HEAD^ --hard + env: + EXPECTED_SHA: ${{ inputs.commit }} + + - uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6 + with: + extra_nix_config: sandbox = true + + - uses: cachix/cachix-action@5f2d7c5294214f71b873db4b969586b980625e71 # v17 + with: + # We do not pass any `authToken` to avoid polluting the cache with potentially untrusted code. + name: nodejs + + - name: Configure sccache + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 + with: + script: | + core.exportVariable('SCCACHE_GHA_VERSION', 'on'); + core.exportVariable('ACTIONS_CACHE_SERVICE_V2', 'on'); + core.exportVariable('ACTIONS_RESULTS_URL', process.env.ACTIONS_RESULTS_URL || ''); + core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + + - name: Build Node.js on the base commit + run: | + nix-shell \ + -I nixpkgs=./tools/nix/pkgs.nix \ + --pure --keep TAR_DIR --keep FLAKY_TESTS \ + --keep SCCACHE_GHA_ENABLED --keep ACTIONS_CACHE_SERVICE_V2 --keep ACTIONS_RESULTS_URL --keep ACTIONS_RUNTIME_TOKEN \ + --arg useSeparateDerivationForV8 true \ + --arg loadJSBuiltinsDynamically false \ + --arg ccache "${NIX_SCCACHE:-null}" \ + --arg devTools '[]' \ + --arg benchmarkTools '[]' \ + --run ' + make build-ci -j4 V=1 + ' + mv out/Release/node base_node + + - name: Checkout the merge commit + run: git reset FETCH_HEAD --hard + + - name: Re-build Node.js on the merge commit + # ccache is disabled here to avoid polluting the cache. Local build outputs should make this build relatively quick anyway. + run: | + nix-shell \ + -I nixpkgs=./tools/nix/pkgs.nix \ + --pure \ + --arg useSeparateDerivationForV8 true \ + --arg loadJSBuiltinsDynamically false \ + --arg ccache 'null' \ + --arg devTools '[]' \ + --arg benchmarkTools '[]' \ + --run ' + make -j4 V=1 + ' + + - name: Run benchmark + run: | + nix-shell \ + -I nixpkgs=./tools/nix/pkgs.nix \ + --pure --keep FILTER --keep LC_ALL --keep LANG \ + --arg loadJSBuiltinsDynamically false \ + --arg ccache 'null' \ + --arg icu 'null' \ + --arg sharedLibDeps '{}' \ + --arg devTools '[]' \ + --run ' + set -o pipefail + ./base_node benchmark/compare.js \ + --filter "$FILTER" \ + --runs ${{ inputs.runs }} \ + --old ./base_node --new ./node \ + -- ${{ inputs.category }} \ + | tee /dev/stderr \ + > ${{ matrix.system }}.csv + echo "> [!WARNING] " + echo "> Do not take GHA benchmark results as face value, always confirm them" + echo "> using a dedicated machine, e.g. Jenkins CI." + echo + echo "Benchmark results:" + echo + echo '"'"'```'"'"' + Rscript benchmark/compare.R < ${{ matrix.system }}.csv + echo '"'"'```'"'"' + echo + echo "> [!WARNING] " + echo "> Do not take GHA benchmark results as face value, always confirm them" + echo "> using a dedicated machine, e.g. Jenkins CI." + ' | tee /dev/stderr >> "$GITHUB_STEP_SUMMARY" + env: + FILTER: ${{ inputs.filter }} + + - name: Upload raw benchmark results + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: csv-${{ matrix.system }} + path: ${{ matrix.system }}.csv + + aggregate-results: + needs: build + name: Aggregate benchmark results + runs-on: ubuntu-slim + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + sparse-checkout: | + benchmark/*.R + tools/nix/*.nix + *.nix + sparse-checkout-cone-mode: false + + - name: Download benchmark raw results + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + pattern: csv-* + merge-multiple: true + path: raw-results + + - uses: cachix/install-nix-action@8aa03977d8d733052d78f4e008a241fd1dbf36b3 # v31.10.6 + with: + extra_nix_config: sandbox = true + + - name: Benchmark results + run: | + nix-shell \ + -I nixpkgs=./tools/nix/pkgs.nix \ + --pure \ + -E '(import {}).mkShell { buildInputs = import ./tools/nix/benchmarkTools.nix { withHttpBenchmarkDeps = false; }; }' \ + --run ' + export LC_ALL=C.UTF-8 + echo "> [!WARNING] " + echo "> Do not take GHA benchmark results as face value, always confirm them" + echo "> using a dedicated machine, e.g. Jenkins CI." + echo + echo "Benchmark results:" + echo + echo '"'"'```'"'"' + awk "FNR==1 && NR!=1{next;}{print}" raw-results/*.csv | Rscript benchmark/compare.R + echo '"'"'```'"'"' + echo + echo "> [!WARNING] " + echo "> Do not take GHA benchmark results as face value, always confirm them" + echo "> using a dedicated machine, e.g. Jenkins CI." + ' | tee /dev/stderr >> "$GITHUB_STEP_SUMMARY" diff --git a/tools/nix/benchmarkTools.nix b/tools/nix/benchmarkTools.nix index 62c744a552b7d1..7c37c423c2530a 100644 --- a/tools/nix/benchmarkTools.nix +++ b/tools/nix/benchmarkTools.nix @@ -1,9 +1,11 @@ { pkgs ? import ./pkgs.nix { }, + withHttpBenchmarkDeps ? true, }: [ pkgs.R pkgs.rPackages.ggplot2 pkgs.rPackages.plyr - pkgs.wrk ] +++ pkgs.lib.optional withHttpBenchmarkDeps pkgs.wrk +++ pkgs.lib.optional pkgs.stdenv.buildPlatform.isLinux pkgs.glibcLocales From fe5260cca7f19d6fa993740370bc05a21c4e3b9d Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Mon, 29 Jun 2026 15:56:30 +0200 Subject: [PATCH 054/131] meta: update status of past strategic initiatives Signed-off-by: Joyee Cheung PR-URL: https://github.com/nodejs/node/pull/63480 Reviewed-By: Stephen Belanger Reviewed-By: Antoine du Hamel Reviewed-By: Benjamin Gruenbaum Reviewed-By: Richard Lau Reviewed-By: Rafael Gonzaga Reviewed-By: Ruy Adorno Reviewed-By: Filip Skokan Reviewed-By: Chengzhong Wu --- doc/contributing/strategic-initiatives.md | 26 +++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/contributing/strategic-initiatives.md b/doc/contributing/strategic-initiatives.md index b148f7c95c8d10..c56876238ef0f9 100644 --- a/doc/contributing/strategic-initiatives.md +++ b/doc/contributing/strategic-initiatives.md @@ -6,21 +6,19 @@ agenda to ensure they are active and have the support they need. ## Current initiatives -| Initiative | Champion | Links | -| ---------------------- | -------------------------------- | ------------------------------------------------- | -| QUIC / HTTP3 | [James M Snell][jasnell] | | -| Shadow Realm | [Chengzhong Wu][legendecas] | | -| Startup Snapshot | [Joyee Cheung][joyeecheung] | | -| V8 Currency | [Michaël Zasso][targos] | | -| Next-10 | [Michael Dawson][mhdawson] | | -| Single executable apps | [Darshan Sen][RaisinTen] | | -| Performance | [Rafael Gonzaga][RafaelGSS] | | -| Primordials | [Benjamin Gruenbaum][benjamingr] | | +| Initiative | Champion | Links | +| ---------------------- | -------------------------------- | --------------------------------------------- | +| QUIC / HTTP3 | [James M Snell][jasnell] | | +| Shadow Realm | [Chengzhong Wu][legendecas] | | +| V8 Currency | [Michaël Zasso][targos] | | +| Next-10 | [Jacob Smith][JakobJingleheimer] | | +| Single executable apps | [Darshan Sen][RaisinTen] | | +| Performance | [Rafael Gonzaga][RafaelGSS] | |
-List of completed initiatives +List of past initiatives -## Completed initiatives +## Past initiatives | Initiative | Champion | Links | | ------------------ | -------------------------------- | -------------------------------------------------------------------- | @@ -34,16 +32,18 @@ agenda to ensure they are active and have the support they need. | npm Integration | Myles Borins | | | OpenSSL Evolution | Rod Vagg | | | Open Web Standards | Myles Borins, Joyee Cheung | | +| Primordials | [Benjamin Gruenbaum][benjamingr] | | +| Startup Snapshot | [Joyee Cheung][joyeecheung] | | | VM module fix | Franziska Hinkelmann | | | Workers | Anna Henningsen | |
+[JakobJingleheimer]: https://github.com/JakobJingleheimer [RafaelGSS]: https://github.com/RafaelGSS [RaisinTen]: https://github.com/RaisinTen [benjamingr]: https://github.com/benjamingr [jasnell]: https://github.com/jasnell [joyeecheung]: https://github.com/joyeecheung [legendecas]: https://github.com/legendecas -[mhdawson]: https://github.com/mhdawson [targos]: https://github.com/targos From dbb3126e5c815bb1b00bb37bdcd293bd903b5052 Mon Sep 17 00:00:00 2001 From: Chengzhong Wu Date: Mon, 29 Jun 2026 09:57:02 -0400 Subject: [PATCH 055/131] src: abstract tracing agent for both legacy and perfetto Signed-off-by: Chengzhong Wu PR-URL: https://github.com/nodejs/node/pull/64053 Refs: https://github.com/nodejs/diagnostics/issues/654 Reviewed-By: James M Snell --- node.gyp | 2 + src/env.cc | 12 +- src/inspector/tracing_agent.cc | 14 +- src/node_trace_events.cc | 14 +- src/node_v8_platform-inl.h | 113 ++--------- src/tracing/agent.cc | 254 ++---------------------- src/tracing/agent.h | 175 +++++------------ src/tracing/agent_legacy.cc | 320 +++++++++++++++++++++++++++++++ src/tracing/agent_legacy.h | 142 ++++++++++++++ src/tracing/node_trace_buffer.cc | 11 +- src/tracing/node_trace_buffer.h | 18 +- src/tracing/node_trace_writer.h | 6 +- src/tracing/trace_event.cc | 15 -- src/tracing/trace_event.h | 14 +- test/cctest/node_test_fixture.cc | 6 +- test/cctest/node_test_fixture.h | 3 +- test/fuzzers/fuzz_env.cc | 5 +- test/fuzzers/fuzz_strings.cc | 5 +- 18 files changed, 603 insertions(+), 526 deletions(-) create mode 100644 src/tracing/agent_legacy.cc create mode 100644 src/tracing/agent_legacy.h diff --git a/node.gyp b/node.gyp index b9e13425b9ba9b..8a6ab2cbe5b912 100644 --- a/node.gyp +++ b/node.gyp @@ -199,6 +199,7 @@ 'src/timers.cc', 'src/timer_wrap.cc', 'src/tracing/agent.cc', + 'src/tracing/agent_legacy.cc', 'src/tracing/node_trace_buffer.cc', 'src/tracing/node_trace_writer.cc', 'src/tracing/trace_event.cc', @@ -337,6 +338,7 @@ 'src/tcp_wrap.h', 'src/timers.h', 'src/tracing/agent.h', + 'src/tracing/agent_legacy.h', 'src/tracing/node_trace_buffer.h', 'src/tracing/node_trace_writer.h', 'src/tracing/trace_event.h', diff --git a/src/env.cc b/src/env.cc index 08f5f8807ca054..d6a859e7a35452 100644 --- a/src/env.cc +++ b/src/env.cc @@ -71,7 +71,6 @@ using v8::SnapshotCreator; using v8::StackTrace; using v8::String; using v8::Symbol; -using v8::TracingController; using v8::TryCatch; using v8::Uint32; using v8::Undefined; @@ -894,10 +893,9 @@ Environment::Environment(IsolateData* isolate_data, inspector_agent_ = std::make_unique(this); #endif - if (tracing::AgentWriterHandle* writer = GetTracingAgentWriter()) { + if (tracing::Agent* agent = tracing::Agent::GetInstance()) { trace_state_observer_ = std::make_unique(this); - if (TracingController* tracing_controller = writer->GetTracingController()) - tracing_controller->AddTraceStateObserver(trace_state_observer_.get()); + agent->AddTraceStateObserver(trace_state_observer_.get()); } destroy_async_id_list_.reserve(512); @@ -1064,10 +1062,8 @@ Environment::~Environment() { principal_realm_.reset(); if (trace_state_observer_) { - tracing::AgentWriterHandle* writer = GetTracingAgentWriter(); - CHECK_NOT_NULL(writer); - if (TracingController* tracing_controller = writer->GetTracingController()) - tracing_controller->RemoveTraceStateObserver(trace_state_observer_.get()); + if (tracing::Agent* agent = tracing::Agent::GetInstance()) + agent->RemoveTraceStateObserver(trace_state_observer_.get()); } TRACE_EVENT_NESTABLE_ASYNC_END0( diff --git a/src/inspector/tracing_agent.cc b/src/inspector/tracing_agent.cc index 40c8aea35c931c..cf1c1a52af4dcc 100644 --- a/src/inspector/tracing_agent.cc +++ b/src/inspector/tracing_agent.cc @@ -3,6 +3,7 @@ #include "main_thread_interface.h" #include "node_internals.h" #include "node_v8_platform-inl.h" +#include "tracing/agent_legacy.h" #include "v8.h" #include @@ -162,13 +163,14 @@ DispatchResponse TracingAgent::start( return DispatchResponse::InvalidRequest( "At least one category should be enabled"); - tracing::AgentWriterHandle* writer = GetTracingAgentWriter(); - if (writer != nullptr) { + auto* agent = + static_cast(tracing::Agent::GetInstance()); + if (agent != nullptr) { trace_writer_ = - writer->agent()->AddClient(categories_set, - std::make_unique( - frontend_object_id_, main_thread_), - tracing::Agent::kIgnoreDefaultCategories); + agent->AddClient(categories_set, + std::make_unique( + frontend_object_id_, main_thread_), + tracing::LegacyTracingAgent::kIgnoreDefaultCategories); } return DispatchResponse::Success(); } diff --git a/src/node_trace_events.cc b/src/node_trace_events.cc index ef659f1c39f7ee..bb0be77cce78e6 100644 --- a/src/node_trace_events.cc +++ b/src/node_trace_events.cc @@ -73,7 +73,7 @@ void NodeCategorySet::New(const FunctionCallbackInfo& args) { if (!*val) return; categories.emplace(*val); } - CHECK_NOT_NULL(GetTracingAgentWriter()); + CHECK_NOT_NULL(tracing::Agent::GetInstance()); new NodeCategorySet(env, args.This(), std::move(categories)); } @@ -85,8 +85,10 @@ void NodeCategorySet::Enable(const FunctionCallbackInfo& args) { if (!category_set->enabled_ && !categories.empty()) { // Starts the Tracing Agent if it wasn't started already (e.g. through // a command line flag.) - StartTracingAgent(); - GetTracingAgentWriter()->Enable(categories); + auto* agent = tracing::Agent::GetInstance(); + agent->StartTracing(per_process::cli_options->trace_event_categories); + tracing::AgentWriterHandle* writer = agent->GetDefaultWriterHandle(); + writer->Enable(categories); category_set->enabled_ = true; } } @@ -97,7 +99,9 @@ void NodeCategorySet::Disable(const FunctionCallbackInfo& args) { CHECK_NOT_NULL(category_set); const auto& categories = category_set->GetCategories(); if (category_set->enabled_ && !categories.empty()) { - GetTracingAgentWriter()->Disable(categories); + auto* agent = tracing::Agent::GetInstance(); + tracing::AgentWriterHandle* writer = agent->GetDefaultWriterHandle(); + writer->Disable(categories); category_set->enabled_ = false; } } @@ -105,7 +109,7 @@ void NodeCategorySet::Disable(const FunctionCallbackInfo& args) { void GetEnabledCategories(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); std::string categories = - GetTracingAgentWriter()->agent()->GetEnabledCategories(); + tracing::Agent::GetInstance()->GetEnabledCategories(); Local ret; if (!categories.empty() && ToV8Value(env->context(), categories, env->isolate()).ToLocal(&ret)) { diff --git a/src/node_v8_platform-inl.h b/src/node_v8_platform-inl.h index 57a725a988f445..9e05928e2a5755 100644 --- a/src/node_v8_platform-inl.h +++ b/src/node_v8_platform-inl.h @@ -4,63 +4,15 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include -#include #include "env-inl.h" #include "node.h" -#include "node_metadata.h" -#include "node_platform.h" #include "node_options.h" -#include "tracing/node_trace_writer.h" -#include "tracing/trace_event.h" -#include "tracing/traced_value.h" -#include "util.h" +#include "node_platform.h" +#include "tracing/agent.h" namespace node { -// Ensures that __metadata trace events are only emitted -// when tracing is enabled. -class NodeTraceStateObserver - : public v8::TracingController::TraceStateObserver { - public: - inline void OnTraceEnabled() override { - std::string title = GetProcessTitle(""); - if (!title.empty()) { - // Only emit the metadata event if the title can be retrieved - // successfully. Ignore it otherwise. - TRACE_EVENT_METADATA1( - "__metadata", "process_name", "name", TRACE_STR_COPY(title.c_str())); - } - TRACE_EVENT_METADATA1("__metadata", - "version", - "node", - per_process::metadata.versions.node.c_str()); - TRACE_EVENT_METADATA1( - "__metadata", "thread_name", "name", "JavaScriptMainThread"); - - tracing::ProcessMeta trace_process; - TRACE_EVENT_METADATA1("__metadata", - "node", - "process", - tracing::CastTracedValue(trace_process)); - // This only runs the first time tracing is enabled - controller_->RemoveTraceStateObserver(this); - } - - inline void OnTraceDisabled() override { - // Do nothing here. This should never be called because the - // observer removes itself when OnTraceEnabled() is called. - UNREACHABLE(); - } - - explicit NodeTraceStateObserver(v8::TracingController* controller) - : controller_(controller) {} - ~NodeTraceStateObserver() override = default; - - private: - v8::TracingController* controller_; -}; - struct V8Platform { bool initialized_ = false; @@ -68,20 +20,14 @@ struct V8Platform { inline void Initialize(int thread_pool_size) { CHECK(!initialized_); initialized_ = true; - tracing_agent_ = std::make_unique(); - node::tracing::TraceEventHelper::SetAgent(tracing_agent_.get()); - node::tracing::TracingController* controller = - tracing_agent_->GetTracingController(); - trace_state_observer_ = - std::make_unique(controller); - controller->AddTraceStateObserver(trace_state_observer_.get()); - tracing_file_writer_ = tracing_agent_->DefaultHandle(); + tracing_agent_ = tracing::Agent::CreateDefault(); // Only start the tracing agent if we enabled any tracing categories. if (!per_process::cli_options->trace_event_categories.empty()) { StartTracingAgent(); } // Tracing must be initialized before platform threads are created. - platform_ = new NodePlatform(thread_pool_size, controller); + platform_ = new NodePlatform(thread_pool_size, + tracing_agent_->GetTracingController()); v8::V8::InitializePlatform(platform_); } // Make sure V8Platform don not call into Libuv threadpool, @@ -90,7 +36,6 @@ struct V8Platform { if (!initialized_) return; initialized_ = false; - node::tracing::TraceEventHelper::SetAgent(nullptr); StopTracingAgent(); platform_->Shutdown(); delete platform_; @@ -98,8 +43,6 @@ struct V8Platform { // Destroy tracing after the platform (and platform threads) have been // stopped. tracing_agent_.reset(nullptr); - // The observer remove itself in OnTraceEnabled - trace_state_observer_.reset(nullptr); } inline void DrainVMTasks(v8::Isolate* isolate) { @@ -107,41 +50,19 @@ struct V8Platform { } inline void StartTracingAgent() { - constexpr auto convert_to_set = - [](auto& categories) -> std::set { - std::set out; - for (const auto& s : categories) { - out.emplace(std::string(s.data(), s.size())); - } - return out; - }; - // Attach a new NodeTraceWriter only if this function hasn't been called - // before. - if (tracing_file_writer_.IsDefaultHandle()) { - using std::operator""sv; - auto categories = std::views::split( - per_process::cli_options->trace_event_categories, ","sv); - - tracing_file_writer_ = tracing_agent_->AddClient( - convert_to_set(categories), - std::unique_ptr( - new tracing::NodeTraceWriter( - per_process::cli_options->trace_event_file_pattern)), - tracing::Agent::kUseDefaultCategories); - } + if (!initialized_) return; + tracing_agent_->StartTracing( + per_process::cli_options->trace_event_categories); } - inline void StopTracingAgent() { tracing_file_writer_.reset(); } - - inline tracing::AgentWriterHandle* GetTracingAgentWriter() { - return &tracing_file_writer_; + inline void StopTracingAgent() { + if (!initialized_) return; + tracing_agent_->StopTracing(); } inline NodePlatform* Platform() { return platform_; } - std::unique_ptr trace_state_observer_; - std::unique_ptr tracing_agent_; - tracing::AgentWriterHandle tracing_file_writer_; + std::unique_ptr tracing_agent_; NodePlatform* platform_; #else // !NODE_USE_V8_PLATFORM inline void Initialize(int thread_pool_size) {} @@ -156,8 +77,6 @@ struct V8Platform { } inline void StopTracingAgent() {} - inline tracing::AgentWriterHandle* GetTracingAgentWriter() { return nullptr; } - inline NodePlatform* Platform() { return nullptr; } #endif // !NODE_USE_V8_PLATFORM }; @@ -166,14 +85,6 @@ namespace per_process { extern struct V8Platform v8_platform; } -inline void StartTracingAgent() { - return per_process::v8_platform.StartTracingAgent(); -} - -inline tracing::AgentWriterHandle* GetTracingAgentWriter() { - return per_process::v8_platform.GetTracingAgentWriter(); -} - inline void DisposePlatform() { per_process::v8_platform.Dispose(); } diff --git a/src/tracing/agent.cc b/src/tracing/agent.cc index eddcf6c3bf91b7..69b956e9bc9d68 100644 --- a/src/tracing/agent.cc +++ b/src/tracing/agent.cc @@ -1,255 +1,33 @@ #include "tracing/agent.h" - -#include -#include "trace_event.h" -#include "tracing/node_trace_buffer.h" -#include "debug_utils-inl.h" -#include "env-inl.h" +#include "tracing/agent_legacy.h" +#include "tracing/trace_event.h" namespace node { namespace tracing { -class Agent::ScopedSuspendTracing { - public: - ScopedSuspendTracing(TracingController* controller, Agent* agent, - bool do_suspend = true) - : controller_(controller), agent_(do_suspend ? agent : nullptr) { - if (do_suspend) { - CHECK(agent_->started_); - controller->StopTracing(); - } - } - - ~ScopedSuspendTracing() { - if (agent_ == nullptr) return; - TraceConfig* config = agent_->CreateTraceConfig(); - if (config != nullptr) { - controller_->StartTracing(config); - } - } - - private: - TracingController* controller_; - Agent* agent_; -}; - namespace { - -std::set flatten( - const std::unordered_map>& map) { - std::set result; - for (const auto& id_value : map) - result.insert(id_value.second.begin(), id_value.second.end()); - return result; -} - +Agent* g_agent = nullptr; } // namespace -using v8::platform::tracing::TraceConfig; -using v8::platform::tracing::TraceWriter; -using std::string; - -Agent::Agent() : tracing_controller_(new TracingController()) { - tracing_controller_->Initialize(nullptr); - - CHECK_EQ(uv_loop_init(&tracing_loop_), 0); - CHECK_EQ(uv_async_init(&tracing_loop_, - &initialize_writer_async_, - [](uv_async_t* async) { - Agent* agent = ContainerOf(&Agent::initialize_writer_async_, async); - agent->InitializeWritersOnThread(); - }), 0); - uv_unref(reinterpret_cast(&initialize_writer_async_)); +Agent* Agent::GetInstance() { + return g_agent; } -void Agent::InitializeWritersOnThread() { - Mutex::ScopedLock lock(initialize_writer_mutex_); - while (!to_be_initialized_.empty()) { - AsyncTraceWriter* head = *to_be_initialized_.begin(); - head->InitializeOnThread(&tracing_loop_); - to_be_initialized_.erase(head); - } - initialize_writer_condvar_.Broadcast(lock); +void Agent::Deleter::operator()(Agent* agent) { + CHECK_EQ(agent, g_agent); + g_agent = nullptr; + TraceEventHelper::SetTracingController(nullptr); + delete agent; } -Agent::~Agent() { - categories_.clear(); - writers_.clear(); - - StopTracing(); - - uv_close(reinterpret_cast(&initialize_writer_async_), nullptr); - uv_run(&tracing_loop_, UV_RUN_ONCE); - CheckedUvLoopClose(&tracing_loop_); -} - -void Agent::Start() { - if (started_) - return; - - NodeTraceBuffer* trace_buffer_ = new NodeTraceBuffer( - NodeTraceBuffer::kBufferChunks, this, &tracing_loop_); - tracing_controller_->Initialize(trace_buffer_); - - // This thread should be created *after* async handles are created - // (within NodeTraceWriter and NodeTraceBuffer constructors). - // Otherwise the thread could shut down prematurely. - CHECK_EQ(0, - uv_thread_create( - &thread_, - [](void* arg) { - uv_thread_setname("TraceEventWorker"); - Agent* agent = static_cast(arg); - uv_run(&agent->tracing_loop_, UV_RUN_DEFAULT); - }, - this)); - started_ = true; -} - -AgentWriterHandle Agent::AddClient( - const std::set& categories, - std::unique_ptr writer, - enum UseDefaultCategoryMode mode) { - Start(); - - const std::set* use_categories = &categories; - - std::set categories_with_default; - if (mode == kUseDefaultCategories) { - categories_with_default.insert(categories.begin(), categories.end()); - categories_with_default.insert(categories_[kDefaultHandleId].begin(), - categories_[kDefaultHandleId].end()); - use_categories = &categories_with_default; - } - - ScopedSuspendTracing suspend(tracing_controller_.get(), this); - int id = next_writer_id_++; - AsyncTraceWriter* raw = writer.get(); - writers_[id] = std::move(writer); - categories_[id] = { use_categories->begin(), use_categories->end() }; - - { - Mutex::ScopedLock lock(initialize_writer_mutex_); - to_be_initialized_.insert(raw); - uv_async_send(&initialize_writer_async_); - while (to_be_initialized_.count(raw) > 0) - initialize_writer_condvar_.Wait(lock); - } - - return AgentWriterHandle(this, id); -} +std::unique_ptr Agent::CreateDefault() { + CHECK_NULL(g_agent); -AgentWriterHandle Agent::DefaultHandle() { - return AgentWriterHandle(this, kDefaultHandleId); -} - -void Agent::StopTracing() { - if (!started_) - return; - // Perform final Flush on TraceBuffer. We don't want the tracing controller - // to flush the buffer again on destruction of the V8::Platform. - tracing_controller_->StopTracing(); - tracing_controller_->Initialize(nullptr); - started_ = false; - - // Thread should finish when the tracing loop is stopped. - uv_thread_join(&thread_); -} - -void Agent::Disconnect(int client) { - if (client == kDefaultHandleId) return; - { - Mutex::ScopedLock lock(initialize_writer_mutex_); - to_be_initialized_.erase(writers_[client].get()); - } - ScopedSuspendTracing suspend(tracing_controller_.get(), this); - writers_.erase(client); - categories_.erase(client); -} - -void Agent::Enable(int id, const std::set& categories) { - if (categories.empty()) - return; - - ScopedSuspendTracing suspend(tracing_controller_.get(), this, - id != kDefaultHandleId); - categories_[id].insert(categories.begin(), categories.end()); -} - -void Agent::Disable(int id, const std::set& categories) { - ScopedSuspendTracing suspend(tracing_controller_.get(), this, - id != kDefaultHandleId); - std::multiset& writer_categories = categories_[id]; - for (const std::string& category : categories) { - auto it = writer_categories.find(category); - if (it != writer_categories.end()) - writer_categories.erase(it); - } -} - -TraceConfig* Agent::CreateTraceConfig() const { - if (categories_.empty()) - return nullptr; - TraceConfig* trace_config = new TraceConfig(); - for (const auto& category : flatten(categories_)) { - trace_config->AddIncludedCategory(category.c_str()); - } - return trace_config; -} - -std::string Agent::GetEnabledCategories() const { - std::string categories; - for (const std::string& category : flatten(categories_)) { - if (!categories.empty()) - categories += ','; - categories += category; - } - return categories; -} - -void Agent::AppendTraceEvent(TraceObject* trace_event) { - for (const auto& id_writer : writers_) - id_writer.second->AppendTraceEvent(trace_event); -} - -void Agent::AddMetadataEvent(std::unique_ptr event) { - Mutex::ScopedLock lock(metadata_events_mutex_); - metadata_events_.push_back(std::move(event)); -} - -void Agent::Flush(bool blocking) { - { - Mutex::ScopedLock lock(metadata_events_mutex_); - for (const auto& event : metadata_events_) - AppendTraceEvent(event.get()); - } - - for (const auto& id_writer : writers_) - id_writer.second->Flush(blocking); -} + auto agent = new LegacyTracingAgent(); -void TracingController::AddMetadataEvent( - const unsigned char* category_group_enabled, - const char* name, - int num_args, - const char** arg_names, - const unsigned char* arg_types, - const uint64_t* arg_values, - std::unique_ptr* convertable_values, - unsigned int flags) { - std::unique_ptr trace_event(new TraceObject); - trace_event->Initialize( - TRACE_EVENT_PHASE_METADATA, category_group_enabled, name, - node::tracing::kGlobalScope, // scope - node::tracing::kNoId, // id - node::tracing::kNoId, // bind_id - num_args, arg_names, arg_types, arg_values, convertable_values, - TRACE_EVENT_FLAG_NONE, - CurrentTimestampMicroseconds(), - CurrentCpuTimestampMicroseconds()); - Agent* node_agent = node::tracing::TraceEventHelper::GetAgent(); - if (node_agent != nullptr) - node_agent->AddMetadataEvent(std::move(trace_event)); + g_agent = agent; + TraceEventHelper::SetTracingController(agent->GetTracingController()); + return std::unique_ptr(agent); } } // namespace tracing diff --git a/src/tracing/agent.h b/src/tracing/agent.h index b542a849fe8da7..78203154c099a5 100644 --- a/src/tracing/agent.h +++ b/src/tracing/agent.h @@ -1,53 +1,65 @@ #ifndef SRC_TRACING_AGENT_H_ #define SRC_TRACING_AGENT_H_ -#include "libplatform/v8-tracing.h" -#include "uv.h" -#include "util.h" -#include "node_mutex.h" - -#include +#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +// This defines a compatible agent interface for both the legacy V8 +// tracing and the Perfetto tracing. The interface is designed to be +// used by the rest of the Node.js codebase that only generates +// trace events with the trace macros, or interacts with the tracing +// system. +// +// To generate trace events by API, or consume the tracing data, the +// caller should directly refer to the derived trace agent interfaces. +// +// This file should not include either `libplatform/v8-tracing.h` or +// `perfetto.h`. + +#include "v8-platform.h" + +#include #include #include -#include - -namespace v8 { -class ConvertableToTraceFormat; -class TracingController; -} // namespace v8 namespace node { namespace tracing { -using v8::platform::tracing::TraceConfig; -using v8::platform::tracing::TraceObject; - class Agent; +class AgentWriterHandle; -class AsyncTraceWriter { +class Agent { public: - virtual ~AsyncTraceWriter() = default; - virtual void AppendTraceEvent(TraceObject* trace_event) = 0; - virtual void Flush(bool blocking) = 0; - virtual void InitializeOnThread(uv_loop_t* loop) {} -}; + virtual ~Agent() = default; -class TracingController : public v8::platform::tracing::TracingController { - public: - TracingController() : v8::platform::tracing::TracingController() {} - - int64_t CurrentTimestampMicroseconds() override { - return uv_hrtime() / 1000; - } - void AddMetadataEvent( - const unsigned char* category_group_enabled, - const char* name, - int num_args, - const char** arg_names, - const unsigned char* arg_types, - const uint64_t* arg_values, - std::unique_ptr* convertable_values, - unsigned int flags); + virtual v8::TracingController* GetTracingController() = 0; + + // Returns a comma-separated list of enabled categories. + virtual std::string GetEnabledCategories() const = 0; + + // Called by V8Platform to start/stop file-based tracing. + virtual void StartTracing(const std::string& categories) = 0; + virtual void StopTracing() = 0; + + virtual AgentWriterHandle* GetDefaultWriterHandle() = 0; + + virtual void AddTraceStateObserver( + v8::TracingController::TraceStateObserver* observer) = 0; + virtual void RemoveTraceStateObserver( + v8::TracingController::TraceStateObserver* observer) = 0; + + struct Deleter { + void operator()(Agent* agent); + }; + static std::unique_ptr CreateDefault(); + static Agent* GetInstance(); + + private: + virtual void Disconnect(int client) = 0; + + virtual void Enable(int id, const std::set& categories) = 0; + virtual void Disable(int id, const std::set& categories) = 0; + + friend class AgentWriterHandle; }; class AgentWriterHandle { @@ -63,12 +75,8 @@ class AgentWriterHandle { inline void Enable(const std::set& categories); inline void Disable(const std::set& categories); - inline bool IsDefaultHandle(); - inline Agent* agent() { return agent_; } - inline v8::TracingController* GetTracingController(); - AgentWriterHandle(const AgentWriterHandle& other) = delete; AgentWriterHandle& operator=(const AgentWriterHandle& other) = delete; @@ -79,80 +87,7 @@ class AgentWriterHandle { int id_ = 0; friend class Agent; -}; - -class Agent { - public: - Agent(); - ~Agent(); - - TracingController* GetTracingController() { - TracingController* controller = tracing_controller_.get(); - CHECK_NOT_NULL(controller); - return controller; - } - - enum UseDefaultCategoryMode { - kUseDefaultCategories, - kIgnoreDefaultCategories - }; - - // Destroying the handle disconnects the client - AgentWriterHandle AddClient(const std::set& categories, - std::unique_ptr writer, - enum UseDefaultCategoryMode mode); - // A handle that is only used for managing the default categories - // (which can then implicitly be used through using `USE_DEFAULT_CATEGORIES` - // when adding a client later). - AgentWriterHandle DefaultHandle(); - - // Returns a comma-separated list of enabled categories. - std::string GetEnabledCategories() const; - - // Writes to all writers registered through AddClient(). - void AppendTraceEvent(TraceObject* trace_event); - - void AddMetadataEvent(std::unique_ptr event); - // Flushes all writers registered through AddClient(). - void Flush(bool blocking); - - TraceConfig* CreateTraceConfig() const; - - private: - friend class AgentWriterHandle; - - void InitializeWritersOnThread(); - - void Start(); - void StopTracing(); - void Disconnect(int client); - - void Enable(int id, const std::set& categories); - void Disable(int id, const std::set& categories); - - uv_thread_t thread_; - uv_loop_t tracing_loop_; - - bool started_ = false; - class ScopedSuspendTracing; - - // Each individual Writer has one id. - int next_writer_id_ = 1; - enum { kDefaultHandleId = -1 }; - // These maps store the original arguments to AddClient(), by id. - std::unordered_map> categories_; - std::unordered_map> writers_; - std::unique_ptr tracing_controller_; - - // Variables related to initializing per-event-loop properties of individual - // writers, such as libuv handles. - Mutex initialize_writer_mutex_; - ConditionVariable initialize_writer_condvar_; - uv_async_t initialize_writer_async_; - std::set to_be_initialized_; - - Mutex metadata_events_mutex_; - std::list> metadata_events_; + friend class LegacyTracingAgent; }; void AgentWriterHandle::reset() { @@ -181,15 +116,9 @@ void AgentWriterHandle::Disable(const std::set& categories) { if (agent_ != nullptr) agent_->Disable(id_, categories); } -bool AgentWriterHandle::IsDefaultHandle() { - return agent_ != nullptr && id_ == Agent::kDefaultHandleId; -} - -inline v8::TracingController* AgentWriterHandle::GetTracingController() { - return agent_ != nullptr ? agent_->GetTracingController() : nullptr; -} - } // namespace tracing } // namespace node +#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + #endif // SRC_TRACING_AGENT_H_ diff --git a/src/tracing/agent_legacy.cc b/src/tracing/agent_legacy.cc new file mode 100644 index 00000000000000..c6c4a1e1ada42f --- /dev/null +++ b/src/tracing/agent_legacy.cc @@ -0,0 +1,320 @@ +#include "tracing/agent_legacy.h" + +#include +#include +#include +#include "debug_utils-inl.h" +#include "env-inl.h" +#include "node_metadata.h" +#include "node_options.h" +#include "trace_event.h" +#include "tracing/node_trace_buffer.h" +#include "tracing/node_trace_writer.h" +#include "tracing/traced_value.h" + +namespace node { +namespace tracing { + +class LegacyTracingAgent::ScopedSuspendTracing { + public: + ScopedSuspendTracing(TracingController* controller, + LegacyTracingAgent* agent, + bool do_suspend = true) + : controller_(controller), agent_(do_suspend ? agent : nullptr) { + if (do_suspend) { + CHECK(agent_->started_); + controller->StopTracing(); + } + } + + ~ScopedSuspendTracing() { + if (agent_ == nullptr) return; + TraceConfig* config = agent_->CreateTraceConfig(); + if (config != nullptr) { + controller_->StartTracing(config); + } + } + + private: + TracingController* controller_; + LegacyTracingAgent* agent_; +}; + +namespace { + +std::set flatten( + const std::unordered_map>& map) { + std::set result; + for (const auto& id_value : map) + result.insert(id_value.second.begin(), id_value.second.end()); + return result; +} + +} // namespace + +using std::string; +using v8::platform::tracing::TraceConfig; +using v8::platform::tracing::TraceWriter; + +void NodeTraceStateObserver::OnTraceEnabled() { + std::string title = GetProcessTitle(""); + if (!title.empty()) { + TRACE_EVENT_METADATA1( + "__metadata", "process_name", "name", TRACE_STR_COPY(title.c_str())); + } + TRACE_EVENT_METADATA1("__metadata", + "version", + "node", + per_process::metadata.versions.node.c_str()); + TRACE_EVENT_METADATA1( + "__metadata", "thread_name", "name", "JavaScriptMainThread"); + + ProcessMeta trace_process; + TRACE_EVENT_METADATA1( + "__metadata", "node", "process", CastTracedValue(trace_process)); + // This only runs the first time tracing is enabled + controller_->RemoveTraceStateObserver(this); +} + +LegacyTracingAgent::LegacyTracingAgent() + : tracing_controller_(new TracingController()) { + tracing_controller_->Initialize(nullptr); + + trace_state_observer_ = + std::make_unique(tracing_controller_.get()); + tracing_controller_->AddTraceStateObserver(trace_state_observer_.get()); + tracing_file_writer_ = AgentWriterHandle(this, kDefaultHandleId); + + CHECK_EQ(uv_loop_init(&tracing_loop_), 0); + CHECK_EQ(uv_async_init(&tracing_loop_, + &initialize_writer_async_, + [](uv_async_t* async) { + LegacyTracingAgent* agent = ContainerOf( + &LegacyTracingAgent::initialize_writer_async_, + async); + agent->InitializeWritersOnThread(); + }), + 0); + uv_unref(reinterpret_cast(&initialize_writer_async_)); +} + +void LegacyTracingAgent::InitializeWritersOnThread() { + Mutex::ScopedLock lock(initialize_writer_mutex_); + while (!to_be_initialized_.empty()) { + AsyncTraceWriter* head = *to_be_initialized_.begin(); + head->InitializeOnThread(&tracing_loop_); + to_be_initialized_.erase(head); + } + initialize_writer_condvar_.Broadcast(lock); +} + +LegacyTracingAgent::~LegacyTracingAgent() { + StopTracing(); + + categories_.clear(); + writers_.clear(); + + Stop(); + + uv_close(reinterpret_cast(&initialize_writer_async_), nullptr); + uv_run(&tracing_loop_, UV_RUN_ONCE); + CheckedUvLoopClose(&tracing_loop_); +} + +void LegacyTracingAgent::Start() { + if (started_) return; + + NodeTraceBuffer* trace_buffer_ = + new NodeTraceBuffer(NodeTraceBuffer::kBufferChunks, this, &tracing_loop_); + tracing_controller_->Initialize(trace_buffer_); + + // This thread should be created *after* async handles are created + // (within NodeTraceWriter and NodeTraceBuffer constructors). + // Otherwise the thread could shut down prematurely. + CHECK_EQ(0, + uv_thread_create( + &thread_, + [](void* arg) { + uv_thread_setname("TraceEventWorker"); + LegacyTracingAgent* agent = + static_cast(arg); + uv_run(&agent->tracing_loop_, UV_RUN_DEFAULT); + }, + this)); + started_ = true; +} + +AgentWriterHandle LegacyTracingAgent::AddClient( + const std::set& categories, + std::unique_ptr writer, + enum UseDefaultCategoryMode mode) { + Start(); + + const std::set* use_categories = &categories; + + std::set categories_with_default; + if (mode == kUseDefaultCategories) { + categories_with_default.insert(categories.begin(), categories.end()); + categories_with_default.insert(categories_[kDefaultHandleId].begin(), + categories_[kDefaultHandleId].end()); + use_categories = &categories_with_default; + } + + ScopedSuspendTracing suspend(tracing_controller_.get(), this); + int id = next_writer_id_++; + AsyncTraceWriter* raw = writer.get(); + writers_[id] = std::move(writer); + categories_[id] = {use_categories->begin(), use_categories->end()}; + + { + Mutex::ScopedLock lock(initialize_writer_mutex_); + to_be_initialized_.insert(raw); + uv_async_send(&initialize_writer_async_); + while (to_be_initialized_.count(raw) > 0) + initialize_writer_condvar_.Wait(lock); + } + + return AgentWriterHandle(this, id); +} + +void LegacyTracingAgent::Stop() { + if (!started_) return; + // Perform final Flush on TraceBuffer. We don't want the tracing controller + // to flush the buffer again on destruction of the V8::Platform. + tracing_controller_->StopTracing(); + tracing_controller_->Initialize(nullptr); + started_ = false; + + // Thread should finish when the tracing loop is stopped. + uv_thread_join(&thread_); +} + +void LegacyTracingAgent::Disconnect(int client) { + if (client == kDefaultHandleId) return; + { + Mutex::ScopedLock lock(initialize_writer_mutex_); + to_be_initialized_.erase(writers_[client].get()); + } + ScopedSuspendTracing suspend(tracing_controller_.get(), this); + writers_.erase(client); + categories_.erase(client); +} + +void LegacyTracingAgent::Enable(int id, + const std::set& categories) { + if (categories.empty()) return; + + ScopedSuspendTracing suspend( + tracing_controller_.get(), this, id != kDefaultHandleId); + categories_[id].insert(categories.begin(), categories.end()); +} + +void LegacyTracingAgent::Disable(int id, + const std::set& categories) { + ScopedSuspendTracing suspend( + tracing_controller_.get(), this, id != kDefaultHandleId); + std::multiset& writer_categories = categories_[id]; + for (const std::string& category : categories) { + auto it = writer_categories.find(category); + if (it != writer_categories.end()) writer_categories.erase(it); + } +} + +TraceConfig* LegacyTracingAgent::CreateTraceConfig() const { + if (categories_.empty()) return nullptr; + TraceConfig* trace_config = new TraceConfig(); + for (const auto& category : flatten(categories_)) { + trace_config->AddIncludedCategory(category.c_str()); + } + return trace_config; +} + +std::string LegacyTracingAgent::GetEnabledCategories() const { + std::string categories; + for (const std::string& category : flatten(categories_)) { + if (!categories.empty()) categories += ','; + categories += category; + } + return categories; +} + +void LegacyTracingAgent::AppendTraceEvent(TraceObject* trace_event) { + for (const auto& id_writer : writers_) + id_writer.second->AppendTraceEvent(trace_event); +} + +void LegacyTracingAgent::AddMetadataEvent(std::unique_ptr event) { + Mutex::ScopedLock lock(metadata_events_mutex_); + metadata_events_.push_back(std::move(event)); +} + +void LegacyTracingAgent::Flush(bool blocking) { + { + Mutex::ScopedLock lock(metadata_events_mutex_); + for (const auto& event : metadata_events_) AppendTraceEvent(event.get()); + } + + for (const auto& id_writer : writers_) id_writer.second->Flush(blocking); +} + +void LegacyTracingAgent::StartTracing(const std::string& categories) { + // Attach a new NodeTraceWriter only if this function hasn't been called + // before. + if (tracing_file_writer_.id_ != LegacyTracingAgent::kDefaultHandleId) return; + + using std::operator""sv; + auto parts = std::views::split(categories, ","sv); + + std::set categories_set; + for (const auto& s : parts) { + categories_set.emplace(std::string(s.data(), s.size())); + } + + tracing_file_writer_ = + AddClient(categories_set, + std::unique_ptr(new NodeTraceWriter( + per_process::cli_options->trace_event_file_pattern)), + kUseDefaultCategories); +} + +void LegacyTracingAgent::StopTracing() { + tracing_file_writer_.reset(); + tracing_file_writer_ = AgentWriterHandle(this, kDefaultHandleId); +} + +AgentWriterHandle* LegacyTracingAgent::GetDefaultWriterHandle() { + return &tracing_file_writer_; +} + +void TracingController::AddMetadataEvent( + const unsigned char* category_group_enabled, + const char* name, + int num_args, + const char** arg_names, + const unsigned char* arg_types, + const uint64_t* arg_values, + std::unique_ptr* convertable_values, + unsigned int flags) { + std::unique_ptr trace_event(new TraceObject); + trace_event->Initialize(TRACE_EVENT_PHASE_METADATA, + category_group_enabled, + name, + node::tracing::kGlobalScope, // scope + node::tracing::kNoId, // id + node::tracing::kNoId, // bind_id + num_args, + arg_names, + arg_types, + arg_values, + convertable_values, + TRACE_EVENT_FLAG_NONE, + CurrentTimestampMicroseconds(), + CurrentCpuTimestampMicroseconds()); + LegacyTracingAgent* node_agent = + static_cast(Agent::GetInstance()); + if (node_agent != nullptr) + node_agent->AddMetadataEvent(std::move(trace_event)); +} + +} // namespace tracing +} // namespace node diff --git a/src/tracing/agent_legacy.h b/src/tracing/agent_legacy.h new file mode 100644 index 00000000000000..4b2a728dc28a53 --- /dev/null +++ b/src/tracing/agent_legacy.h @@ -0,0 +1,142 @@ +#ifndef SRC_TRACING_AGENT_LEGACY_H_ +#define SRC_TRACING_AGENT_LEGACY_H_ + +#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +// This is an implementation of the legacy V8 tracing agent +// defined in `libplatform/v8-tracing.h`. + +#include "libplatform/v8-tracing.h" +#include "node_mutex.h" +#include "tracing/agent.h" +#include "util.h" +#include "uv.h" + +#include +#include +#include +#include + +namespace node { +namespace tracing { + +using v8::platform::tracing::TraceConfig; +using v8::platform::tracing::TraceObject; + +class AsyncTraceWriter { + public: + virtual ~AsyncTraceWriter() = default; + virtual void AppendTraceEvent(TraceObject* trace_event) = 0; + virtual void Flush(bool blocking) = 0; + virtual void InitializeOnThread(uv_loop_t* loop) {} +}; + +class TracingController : public v8::platform::tracing::TracingController { + public: + TracingController() : v8::platform::tracing::TracingController() {} + + int64_t CurrentTimestampMicroseconds() override { return uv_hrtime() / 1000; } + void AddMetadataEvent( + const unsigned char* category_group_enabled, + const char* name, + int num_args, + const char** arg_names, + const unsigned char* arg_types, + const uint64_t* arg_values, + std::unique_ptr* convertable_values, + unsigned int flags); +}; + +class NodeTraceStateObserver + : public v8::TracingController::TraceStateObserver { + public: + void OnTraceEnabled() override; + void OnTraceDisabled() override { UNREACHABLE(); } + + explicit NodeTraceStateObserver(v8::TracingController* controller) + : controller_(controller) {} + ~NodeTraceStateObserver() override = default; + + private: + v8::TracingController* controller_; +}; + +class LegacyTracingAgent final : public Agent { + public: + enum UseDefaultCategoryMode { + kUseDefaultCategories, + kIgnoreDefaultCategories + }; + + LegacyTracingAgent(); + ~LegacyTracingAgent() override; + + TracingController* GetTracingController() override { + TracingController* controller = tracing_controller_.get(); + CHECK_NOT_NULL(controller); + return controller; + } + + AgentWriterHandle AddClient(const std::set& categories, + std::unique_ptr writer, + enum UseDefaultCategoryMode mode); + std::string GetEnabledCategories() const override; + void AppendTraceEvent(TraceObject* trace_event); + void AddMetadataEvent(std::unique_ptr event); + void Flush(bool blocking); + TraceConfig* CreateTraceConfig() const; + + void StartTracing(const std::string& categories) override; + void StopTracing() override; + AgentWriterHandle* GetDefaultWriterHandle() override; + + void AddTraceStateObserver( + v8::TracingController::TraceStateObserver* observer) override { + tracing_controller_->AddTraceStateObserver(observer); + } + void RemoveTraceStateObserver( + v8::TracingController::TraceStateObserver* observer) override { + tracing_controller_->RemoveTraceStateObserver(observer); + } + + private: + static constexpr int kDefaultHandleId = -1; + + void Disconnect(int client) override; + + void Enable(int id, const std::set& categories) override; + void Disable(int id, const std::set& categories) override; + + void InitializeWritersOnThread(); + void Start(); + void Stop(); + + uv_thread_t thread_; + uv_loop_t tracing_loop_; + + bool started_ = false; + class ScopedSuspendTracing; + + int next_writer_id_ = 1; + std::unordered_map> categories_; + std::unordered_map> writers_; + std::unique_ptr tracing_controller_; + + Mutex initialize_writer_mutex_; + ConditionVariable initialize_writer_condvar_; + uv_async_t initialize_writer_async_; + std::set to_be_initialized_; + + Mutex metadata_events_mutex_; + std::list> metadata_events_; + + AgentWriterHandle tracing_file_writer_; + std::unique_ptr trace_state_observer_; +}; + +} // namespace tracing +} // namespace node + +#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + +#endif // SRC_TRACING_AGENT_LEGACY_H_ diff --git a/src/tracing/node_trace_buffer.cc b/src/tracing/node_trace_buffer.cc index e187a1d78c8197..4e2b1226b05b2e 100644 --- a/src/tracing/node_trace_buffer.cc +++ b/src/tracing/node_trace_buffer.cc @@ -6,10 +6,10 @@ namespace node { namespace tracing { -InternalTraceBuffer::InternalTraceBuffer(size_t max_chunks, uint32_t id, - Agent* agent) - : flushing_(false), max_chunks_(max_chunks), - agent_(agent), id_(id) { +InternalTraceBuffer::InternalTraceBuffer(size_t max_chunks, + uint32_t id, + LegacyTracingAgent* agent) + : flushing_(false), max_chunks_(max_chunks), agent_(agent), id_(id) { chunks_.resize(max_chunks); } @@ -96,7 +96,8 @@ void InternalTraceBuffer::ExtractHandle( } NodeTraceBuffer::NodeTraceBuffer(size_t max_chunks, - Agent* agent, uv_loop_t* tracing_loop) + LegacyTracingAgent* agent, + uv_loop_t* tracing_loop) : tracing_loop_(tracing_loop), buffer1_(max_chunks, 0, agent), buffer2_(max_chunks, 1, agent) { diff --git a/src/tracing/node_trace_buffer.h b/src/tracing/node_trace_buffer.h index 18e4f43efaae3a..d9f4b221c91f2a 100644 --- a/src/tracing/node_trace_buffer.h +++ b/src/tracing/node_trace_buffer.h @@ -1,9 +1,11 @@ #ifndef SRC_TRACING_NODE_TRACE_BUFFER_H_ #define SRC_TRACING_NODE_TRACE_BUFFER_H_ -#include "tracing/agent.h" -#include "node_mutex.h" +#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + #include "libplatform/v8-tracing.h" +#include "node_mutex.h" +#include "tracing/agent_legacy.h" #include @@ -19,7 +21,9 @@ class NodeTraceBuffer; class InternalTraceBuffer { public: - InternalTraceBuffer(size_t max_chunks, uint32_t id, Agent* agent); + InternalTraceBuffer(size_t max_chunks, + uint32_t id, + LegacyTracingAgent* agent); TraceObject* AddTraceEvent(uint64_t* handle); TraceObject* GetEventByHandle(uint64_t handle); @@ -41,7 +45,7 @@ class InternalTraceBuffer { Mutex mutex_; bool flushing_; size_t max_chunks_; - Agent* agent_; + LegacyTracingAgent* agent_; std::vector> chunks_; size_t total_chunks_ = 0; uint32_t current_chunk_seq_ = 1; @@ -50,7 +54,9 @@ class InternalTraceBuffer { class NodeTraceBuffer : public TraceBuffer { public: - NodeTraceBuffer(size_t max_chunks, Agent* agent, uv_loop_t* tracing_loop); + NodeTraceBuffer(size_t max_chunks, + LegacyTracingAgent* agent, + uv_loop_t* tracing_loop); ~NodeTraceBuffer() override; TraceObject* AddTraceEvent(uint64_t* handle) override; @@ -80,4 +86,6 @@ class NodeTraceBuffer : public TraceBuffer { } // namespace tracing } // namespace node +#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + #endif // SRC_TRACING_NODE_TRACE_BUFFER_H_ diff --git a/src/tracing/node_trace_writer.h b/src/tracing/node_trace_writer.h index cd965d77b7859f..02efb2c75a84a4 100644 --- a/src/tracing/node_trace_writer.h +++ b/src/tracing/node_trace_writer.h @@ -1,11 +1,13 @@ #ifndef SRC_TRACING_NODE_TRACE_WRITER_H_ #define SRC_TRACING_NODE_TRACE_WRITER_H_ +#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + #include #include #include "libplatform/v8-tracing.h" -#include "tracing/agent.h" +#include "tracing/agent_legacy.h" #include "uv.h" namespace node { @@ -72,4 +74,6 @@ class NodeTraceWriter : public AsyncTraceWriter { } // namespace tracing } // namespace node +#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS + #endif // SRC_TRACING_NODE_TRACE_WRITER_H_ diff --git a/src/tracing/trace_event.cc b/src/tracing/trace_event.cc index 35acb8a9a8fd10..59306fafb3a10d 100644 --- a/src/tracing/trace_event.cc +++ b/src/tracing/trace_event.cc @@ -4,23 +4,8 @@ namespace node { namespace tracing { -Agent* g_agent = nullptr; v8::TracingController* g_controller = nullptr; -void TraceEventHelper::SetAgent(Agent* agent) { - if (agent) { - g_agent = agent; - g_controller = agent->GetTracingController(); - } else { - g_agent = nullptr; - g_controller = nullptr; - } -} - -Agent* TraceEventHelper::GetAgent() { - return g_agent; -} - v8::TracingController* TraceEventHelper::GetTracingController() { return g_controller; } diff --git a/src/tracing/trace_event.h b/src/tracing/trace_event.h index a662a081dc3bf3..a0f8c695ea0160 100644 --- a/src/tracing/trace_event.h +++ b/src/tracing/trace_event.h @@ -6,7 +6,7 @@ #define SRC_TRACING_TRACE_EVENT_H_ #include "v8-platform.h" -#include "tracing/agent.h" +#include "tracing/agent_legacy.h" #include "trace_event_common.h" #include @@ -315,9 +315,6 @@ class TraceEventHelper { static v8::TracingController* GetTracingController(); static void SetTracingController(v8::TracingController* controller); - static Agent* GetAgent(); - static void SetAgent(Agent* agent); - static inline const uint8_t* GetCategoryGroupEnabled(const char* group) { v8::TracingController* controller = GetTracingController(); static const uint8_t disabled = 0; @@ -517,11 +514,12 @@ static V8_INLINE void AddMetadataEventImpl( static_cast(arg_values[1]))); } node::tracing::Agent* agent = - node::tracing::TraceEventHelper::GetAgent(); + node::tracing::Agent::GetInstance(); if (agent == nullptr) return; - return agent->GetTracingController()->AddMetadataEvent( - category_group_enabled, name, num_args, arg_names, arg_types, arg_values, - arg_convertibles, flags); + static_cast( + agent->GetTracingController()) + ->AddMetadataEvent(category_group_enabled, name, num_args, arg_names, + arg_types, arg_values, arg_convertibles, flags); } // Define SetTraceValue for each allowed type. It stores the type and diff --git a/test/cctest/node_test_fixture.cc b/test/cctest/node_test_fixture.cc index 6b75e88d14c2b0..0da5a908e5f38e 100644 --- a/test/cctest/node_test_fixture.cc +++ b/test/cctest/node_test_fixture.cc @@ -12,10 +12,8 @@ node::IsolateData* EnvironmentTestFixture::isolate_data_ = nullptr; void NodeTestEnvironment::SetUp() { NodeZeroIsolateTestFixture::tracing_agent = - std::make_unique(); - node::tracing::TraceEventHelper::SetAgent( - NodeZeroIsolateTestFixture::tracing_agent.get()); - node::tracing::TracingController* tracing_controller = + node::tracing::Agent::CreateDefault(); + v8::TracingController* tracing_controller = NodeZeroIsolateTestFixture::tracing_agent->GetTracingController(); static constexpr int kV8ThreadPoolSize = 4; NodeZeroIsolateTestFixture::platform.reset( diff --git a/test/cctest/node_test_fixture.h b/test/cctest/node_test_fixture.h index d3ec9d25a3ddf7..56245bde417e7c 100644 --- a/test/cctest/node_test_fixture.h +++ b/test/cctest/node_test_fixture.h @@ -57,7 +57,8 @@ struct Argv { using ArrayBufferUniquePtr = std::unique_ptr; -using TracingAgentUniquePtr = std::unique_ptr; +using TracingAgentUniquePtr = + std::unique_ptr; using NodePlatformUniquePtr = std::unique_ptr; class NodeTestEnvironment final : public ::testing::Environment { diff --git a/test/fuzzers/fuzz_env.cc b/test/fuzzers/fuzz_env.cc index 326d82ae20e03d..e2169296550da6 100644 --- a/test/fuzzers/fuzz_env.cc +++ b/test/fuzzers/fuzz_env.cc @@ -35,9 +35,8 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { node::InitializeNodeWithArgs(&node_argv, &exec_argv, &errors); - tracing_agent = std::make_unique(); - node::tracing::TraceEventHelper::SetAgent(tracing_agent.get()); - node::tracing::TracingController* tracing_controller = + tracing_agent = node::tracing::Agent::CreateDefault(); + v8::TracingController* tracing_controller = tracing_agent->GetTracingController(); CHECK_EQ(0, uv_loop_init(¤t_loop)); static constexpr int kV8ThreadPoolSize = 4; diff --git a/test/fuzzers/fuzz_strings.cc b/test/fuzzers/fuzz_strings.cc index 2226a471f3bef9..92b386d2ecd4a7 100644 --- a/test/fuzzers/fuzz_strings.cc +++ b/test/fuzzers/fuzz_strings.cc @@ -42,9 +42,8 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { node::InitializeNodeWithArgs(&node_argv, &exec_argv, &errors); - tracing_agent = std::make_unique(); - node::tracing::TraceEventHelper::SetAgent(tracing_agent.get()); - node::tracing::TracingController* tracing_controller = + tracing_agent = node::tracing::Agent::CreateDefault(); + v8::TracingController* tracing_controller = tracing_agent->GetTracingController(); CHECK_EQ(0, uv_loop_init(¤t_loop)); static constexpr int kV8ThreadPoolSize = 4; From 657a35f5a24349cebc82ac555f40d26264d5b2fe Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Mon, 29 Jun 2026 15:57:19 +0200 Subject: [PATCH 056/131] tools: validate version number in release proposal commit message lint Signed-off-by: Antoine du Hamel PR-URL: https://github.com/nodejs/node/pull/64070 Reviewed-By: Marco Ippolito Reviewed-By: Richard Lau --- .github/workflows/lint-release-proposal.yml | 22 +++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/.github/workflows/lint-release-proposal.yml b/.github/workflows/lint-release-proposal.yml index 62ba257ac2ae84..93c67df521d289 100644 --- a/.github/workflows/lint-release-proposal.yml +++ b/.github/workflows/lint-release-proposal.yml @@ -28,13 +28,24 @@ jobs: persist-credentials: false fetch-depth: 2 - name: Lint release commit title format + id: commit-message-parse run: | - EXPECTED_TITLE='^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}, Version [[:digit:]]+\.[[:digit:]]+\.[[:digit:]]+ (\(Current|'.+' \(LTS)\)$' + VERSION=$(${CXX:-cc} -E -dM src/node_version.h | awk ' + $2 == "NODE_MAJOR_VERSION" { maj = $3 } + $2 == "NODE_MINOR_VERSION" { min = $3 } + $2 == "NODE_PATCH_VERSION" { pat = $3 } + $2 == "NODE_VERSION_LTS_CODENAME" { gsub(/^"|"$/, "'"'"'",$3); lts = $3 } + END { if (maj) print maj "\\." min "\\." pat " " (lts != "'"''"'" ? lts " \\(LTS" : "\\(Current" ) "\\)" } + ') + MAJOR=${VERSION%%\\.*} + EXPECTED_TITLE='^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}, Version '"$VERSION"'$' echo "Expected commit title format: $EXPECTED_TITLE" COMMIT_SUBJECT="$(git --no-pager log -1 --format=%s)" - echo "Actual: $ACTUAL" + echo "Actual: $COMMIT_SUBJECT" echo "$COMMIT_SUBJECT" | grep -q -E "$EXPECTED_TITLE" - echo "COMMIT_SUBJECT=$COMMIT_SUBJECT" >> "$GITHUB_ENV" + + echo "COMMIT_SUBJECT=$COMMIT_SUBJECT" >> "$GITHUB_OUTPUT" + echo "MAJOR=$MAJOR" >> "$GITHUB_OUTPUT" - name: Lint release commit message trailers run: | EXPECTED_TRAILER="^$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/pull/[[:digit:]]+\$" @@ -54,8 +65,6 @@ jobs: SKIP_XZ=1 make release-only - name: Lint release commit content run: | - MAJOR="$(awk '/^#define NODE_MAJOR_VERSION / { print $3 }' src/node_version.h)" - echo "Checking for expected files in the release commit:" missing_expected= for expected in CHANGELOG.md src/node_version.h doc/changelogs/; do @@ -81,7 +90,6 @@ jobs: run: | EXPECTED_CHANGELOG_TITLE_INTRO="## $COMMIT_SUBJECT, @" echo "Expected CHANGELOG section title: $EXPECTED_CHANGELOG_TITLE_INTRO" - MAJOR="$(awk '/^#define NODE_MAJOR_VERSION / { print $3 }' src/node_version.h)" CHANGELOG_PATH="doc/changelogs/CHANGELOG_V${MAJOR}.md" CHANGELOG_TITLE="$(grep "$EXPECTED_CHANGELOG_TITLE_INTRO" "$CHANGELOG_PATH")" echo "Actual: $CHANGELOG_TITLE" @@ -106,4 +114,6 @@ jobs: done shell: bash # See https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#exit-codes-and-error-action-preference, we want the pipefail option. env: + COMMIT_SUBJECT: ${{ steps.commit-message-parse.outputs.COMMIT_SUBJECT }} + MAJOR: ${{ steps.commit-message-parse.outputs.MAJOR }} GH_TOKEN: ${{ github.token }} From 92859b8097149a3b4cc406bfe71b504af70eb8b5 Mon Sep 17 00:00:00 2001 From: Chengzhong Wu Date: Mon, 29 Jun 2026 16:25:55 -0400 Subject: [PATCH 057/131] vm: fix copying PropertyDescriptor This fixes a long-standing issue that `ContextifyContext::PropertyDefinerCallback` incorrectly copies the `const PropertyDescriptor& desc`, assigning value to be `undefined` when no value present on the `PropertyDescriptor`. This is revealed after https://github.com/nodejs/node/pull/63549 because returning `kYes` tells V8 that the definer handled it, and V8 no longer fixes it up. Signed-off-by: Chengzhong Wu PR-URL: https://github.com/nodejs/node/pull/64073 Fixes: https://github.com/nodejs/node/issues/64008 Reviewed-By: Edy Silva --- src/node_contextify.cc | 70 ++++++++++--------- ...test-vm-property-definer-partial-update.js | 56 +++++++++++++++ 2 files changed, 92 insertions(+), 34 deletions(-) create mode 100644 test/parallel/test-vm-property-definer-partial-update.js diff --git a/src/node_contextify.cc b/src/node_contextify.cc index 40ed019a73d83b..dcfaf02c7e55f3 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -89,6 +89,36 @@ using v8::Symbol; using v8::UnboundScript; using v8::Value; +// This is a helper function mediates deleted v8::PropertyDescriptor copy/move. +// The `Fn` receives a mutable reference of a stack allocated +// PropertyDescriptor, copied from the passed in const reference of +// PropertyDescriptor. +template +auto WithPropertyDescriptorCopied(Isolate* isolate, + const PropertyDescriptor& desc, + Fn&& callback) { + auto apply_attrs = [&](PropertyDescriptor& d) { + if (desc.has_enumerable()) d.set_enumerable(desc.enumerable()); + if (desc.has_configurable()) d.set_configurable(desc.configurable()); + return callback(d); + }; + if (desc.has_get() || desc.has_set()) { + PropertyDescriptor d( + desc.has_get() ? desc.get() : Undefined(isolate).As(), + desc.has_set() ? desc.set() : Undefined(isolate).As()); + return apply_attrs(d); + } else if (desc.has_value()) { + if (desc.has_writable()) { + PropertyDescriptor d(desc.value(), desc.writable()); + return apply_attrs(d); + } + PropertyDescriptor d(desc.value()); + return apply_attrs(d); + } + PropertyDescriptor d; + return apply_attrs(d); +} + // The vm module executes code in a sandboxed environment with a different // global object than the rest of the code. This is achieved by applying // every call that changes or queries a property on the global `this` in the @@ -692,41 +722,13 @@ Intercepted ContextifyContext::PropertyDefinerCallback( Local sandbox = ctx->sandbox(); - auto define_prop_on_sandbox = - [&] (PropertyDescriptor* desc_for_sandbox) { - if (desc.has_enumerable()) { - desc_for_sandbox->set_enumerable(desc.enumerable()); - } - if (desc.has_configurable()) { - desc_for_sandbox->set_configurable(desc.configurable()); - } - return sandbox->DefineProperty(context, property, *desc_for_sandbox); - }; + auto result = + WithPropertyDescriptorCopied(isolate, desc, [&](PropertyDescriptor& d) { + return sandbox->DefineProperty(context, property, d); + }); - if (desc.has_get() || desc.has_set()) { - PropertyDescriptor desc_for_sandbox( - desc.has_get() ? desc.get() : Undefined(isolate).As(), - desc.has_set() ? desc.set() : Undefined(isolate).As()); - - if (define_prop_on_sandbox(&desc_for_sandbox).FromMaybe(false)) - return Intercepted::kYes; - return Intercepted::kNo; - } else { - Local value = - desc.has_value() ? desc.value() : Undefined(isolate).As(); - - Maybe result; - if (desc.has_writable()) { - PropertyDescriptor desc_for_sandbox(value, desc.writable()); - result = define_prop_on_sandbox(&desc_for_sandbox); - } else { - PropertyDescriptor desc_for_sandbox(value); - result = define_prop_on_sandbox(&desc_for_sandbox); - } - - if (result.FromMaybe(false)) return Intercepted::kYes; - return Intercepted::kNo; - } + if (result.FromMaybe(false)) return Intercepted::kYes; + return Intercepted::kNo; } // static diff --git a/test/parallel/test-vm-property-definer-partial-update.js b/test/parallel/test-vm-property-definer-partial-update.js new file mode 100644 index 00000000000000..b2291b00a2ba73 --- /dev/null +++ b/test/parallel/test-vm-property-definer-partial-update.js @@ -0,0 +1,56 @@ +'use strict'; + +require('../common'); +const vm = require('vm'); +const assert = require('assert'); + +// Object.defineProperty should only modify specified attributes and preserve +// unspecified ones. Regression test for https://github.com/nodejs/node/issues/64008 +{ + const context = {}; + vm.createContext(context); + + // Changing enumerable should preserve value. + vm.runInContext(` + globalThis.a1 = 1; + Object.defineProperty(globalThis, 'a1', { enumerable: false }); + Object.defineProperty(globalThis, 'a2', { + value: 2, enumerable: false, configurable: true, + }); + Object.defineProperty(globalThis, 'a2', { enumerable: true }); + `, context); + assert.strictEqual(context.a1, 1); + assert.strictEqual( + Object.getOwnPropertyDescriptor(context, 'a1').enumerable, false); + assert.strictEqual(context.a2, 2); + assert.strictEqual( + Object.getOwnPropertyDescriptor(context, 'a2').enumerable, true); + + // Changing writable should preserve value. + vm.runInContext(` + globalThis.b1 = 1; + Object.defineProperty(globalThis, 'b1', { writable: false }); + Object.defineProperty(globalThis, 'b2', { + value: 2, writable: false, configurable: true, + }); + Object.defineProperty(globalThis, 'b2', { writable: true }); + `, context); + assert.strictEqual(context.b1, 1); + assert.strictEqual(context.b2, 2); + + // Changing value should preserve enumerable. + vm.runInContext(` + globalThis.c1 = 1; + Object.defineProperty(globalThis, 'c1', { value: 2 }); + Object.defineProperty(globalThis, 'c2', { + value: 1, enumerable: false, configurable: true, + }); + Object.defineProperty(globalThis, 'c2', { value: 2 }); + `, context); + assert.strictEqual(context.c1, 2); + assert.strictEqual( + Object.getOwnPropertyDescriptor(context, 'c1').enumerable, true); + assert.strictEqual(context.c2, 2); + assert.strictEqual( + Object.getOwnPropertyDescriptor(context, 'c2').enumerable, false); +} From 6b8dc58e6e482d13c6b036dc67d872ac5ad63e2f Mon Sep 17 00:00:00 2001 From: "Node.js GitHub Bot" Date: Mon, 29 Jun 2026 17:59:21 -0400 Subject: [PATCH 058/131] meta: move one or more collaborators to emeritus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/64057 Reviewed-By: Michaël Zasso Reviewed-By: Richard Lau Reviewed-By: Marco Ippolito Reviewed-By: Colin Ihrig Reviewed-By: Luigi Pinca --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c2012523eb199a..f93cfa6d492b47 100644 --- a/README.md +++ b/README.md @@ -405,8 +405,6 @@ For information about the governance of the Node.js project, see **Tim Perry** <> (he/him) * [pmarchini](https://github.com/pmarchini) - **Pietro Marchini** <> (he/him) -* [puskin](https://github.com/puskin) - - **Giovanni Bucci** <> (he/him) * [Qard](https://github.com/Qard) - **Stephen Belanger** <> (he/him) * [RafaelGSS](https://github.com/RafaelGSS) - @@ -653,6 +651,8 @@ For information about the governance of the Node.js project, see **Prince John Wesley** <> * [psmarshall](https://github.com/psmarshall) - **Peter Marshall** <> (he/him) +* [puskin](https://github.com/puskin) - + **Giovanni Bucci** <> (he/him) * [puzpuzpuz](https://github.com/puzpuzpuz) - **Andrey Pechkurov** <> (he/him) * [refack](https://github.com/refack) - From 74e3aa24ba1bf65a3e31115b9fdd32dede5ba691 Mon Sep 17 00:00:00 2001 From: "Node.js GitHub Bot" Date: Mon, 29 Jun 2026 21:25:55 -0400 Subject: [PATCH 059/131] deps: update sqlite to 3.53.3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/64180 Reviewed-By: Matteo Collina Reviewed-By: Gürgün Dayıoğlu Reviewed-By: Colin Ihrig Reviewed-By: Luigi Pinca --- deps/sqlite/sqlite3.c | 781 +++++++++++++++++++++++++++--------------- deps/sqlite/sqlite3.h | 16 +- 2 files changed, 518 insertions(+), 279 deletions(-) diff --git a/deps/sqlite/sqlite3.c b/deps/sqlite/sqlite3.c index 07658778788f36..09f3e4a9f82914 100644 --- a/deps/sqlite/sqlite3.c +++ b/deps/sqlite/sqlite3.c @@ -1,6 +1,6 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.53.2. By combining all the individual C code files into this +** version 3.53.3. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements @@ -18,7 +18,7 @@ ** separate file. This file contains only code for the core SQLite library. ** ** The content in this amalgamation comes from Fossil check-in -** d6e03d8c777cfa2d35e3b60d8ec3e0187f3e with changes in files: +** d4c0e51e4aeb96955b99185ab9cde75c339e with changes in files: ** ** */ @@ -467,12 +467,12 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.53.2" -#define SQLITE_VERSION_NUMBER 3053002 -#define SQLITE_SOURCE_ID "2026-06-03 19:12:13 d6e03d8c777cfa2d35e3b60d8ec3e0187f3e9f99d8e2ee9cac695fd6fcdf1a24" +#define SQLITE_VERSION "3.53.3" +#define SQLITE_VERSION_NUMBER 3053003 +#define SQLITE_SOURCE_ID "2026-06-26 20:14:12 d4c0e51e4aeb96955b99185ab9cde75c339e2c29c3f3f12428d364a10d782c62" #define SQLITE_SCM_BRANCH "branch-3.53" -#define SQLITE_SCM_TAGS "release version-3.53.2" -#define SQLITE_SCM_DATETIME "2026-06-03T19:12:13.350Z" +#define SQLITE_SCM_TAGS "release version-3.53.3" +#define SQLITE_SCM_DATETIME "2026-06-26T20:14:12.354Z" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -4687,7 +4687,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** or in an ORDER BY or GROUP BY clause.)^ ** ** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(
SQLITE_LIMIT_EXPR_DEPTH
-**
The maximum depth of the parse tree on any expression.
)^ +**
The maximum depth of the parse tree on any expression and +** the maximum nesting depth for subqueries and VIEWs
)^ ** ** [[SQLITE_LIMIT_PARSER_DEPTH]] ^(
SQLITE_LIMIT_PARSER_DEPTH
**
The maximum depth of the LALR(1) parser stack used to analyze @@ -4718,7 +4719,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); **
The maximum index number of any [parameter] in an SQL statement.)^ ** ** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(
SQLITE_LIMIT_TRIGGER_DEPTH
-**
The maximum depth of recursion for triggers.
)^ +**
The maximum depth of recursion for triggers, and the maximum +** nesting depth for separate triggers.
)^ ** ** [[SQLITE_LIMIT_WORKER_THREADS]] ^(
SQLITE_LIMIT_WORKER_THREADS
**
The maximum number of auxiliary worker threads that a single @@ -15800,6 +15802,13 @@ SQLITE_PRIVATE void sqlite3HashClear(Hash*); # define offsetof(ST,M) ((size_t)((char*)&((ST*)0)->M - (char*)0)) #endif +/* +** sizeof64() is like sizeof(), but always returns a 64-bit value, even +** on 32-bit builds. This can help to avoid overflow by ensuring 64-bit +** arithmetic is used consistently in both 32-bit and 64-bit builds. +*/ +#define sizeof64(X) ((sqlite3_int64)sizeof(X)) + /* ** Work around C99 "flex-array" syntax for pre-C99 compilers, so as ** to avoid complaints from -fsanitize=strict-bounds. @@ -17161,7 +17170,7 @@ SQLITE_PRIVATE int sqlite3BtreeCheckpoint(Btree*, int, int *, int *); SQLITE_PRIVATE const char *sqlite3BtreeGetFilename(Btree *); SQLITE_PRIVATE const char *sqlite3BtreeGetJournalname(Btree *); -SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree *, Btree *); +SQLITE_PRIVATE int sqlite3BtreeCopyFile(Btree*, Btree*); SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *); @@ -20919,6 +20928,7 @@ struct Parse { int szOpAlloc; /* Bytes of memory space allocated for Vdbe.aOp[] */ int iSelfTab; /* Table associated with an index on expr, or negative ** of the base register during check-constraint eval */ + int nNestSel; /* Number of nested SELECT statements and/or VIEWs */ int nLabel; /* The *negative* of the number of labels used */ int nLabelAlloc; /* Number of slots in aLabel */ int *aLabel; /* Space to hold the labels */ @@ -39575,16 +39585,17 @@ int kvvfsDecode(const char *a, char *aOut, int nOut){ while( 1 ){ c = kvvfsHexValue[aIn[i]]; if( c<0 ){ - int n = 0; - int mult = 1; + sqlite3_int64 n = 0; + sqlite3_int64 mult = 1; c = aIn[i]; if( c==0 ) break; while( c>='a' && c<='z' ){ n += (c - 'a')*mult; + if( n>nOut ) return -1 /* oversized/malformed input */; mult *= 26; c = aIn[++i]; } - if( j+n>nOut ) return -1; + if( j+n>nOut ) return -1 /* oversized/malformed input */; memset(&aOut[j], 0, n); j += n; if( c==0 || mult==1 ) break; /* progress stalled if mult==1 */ @@ -39620,7 +39631,7 @@ static void kvvfsDecodeJournal( i = 0; mult = 1; while( (c = zTxt[i++])>='a' && c<='z' ){ - n += (zTxt[i] - 'a')*mult; + n += (c - 'a')*mult; mult *= 26; } sqlite3_free(pFile->aJrnl); @@ -39666,9 +39677,7 @@ static int kvvfsClose(sqlite3_file *pProtoFile){ pFile->isJournal ? "journal" : "db")); sqlite3_free(pFile->aJrnl); sqlite3_free(pFile->aData); -#ifdef SQLITE_WASM memset(pFile, 0, sizeof(*pFile)); -#endif return SQLITE_OK; } @@ -39698,6 +39707,7 @@ static int kvvfsReadJrnl( aTxt, szTxt+1); if( rc>=0 ){ kvvfsDecodeJournal(pFile, aTxt, szTxt); + rc = 0; } sqlite3_free(aTxt); if( rc ) return rc; @@ -49761,10 +49771,8 @@ static struct win_syscall { #define osWaitForSingleObjectEx ((DWORD(WINAPI*)(HANDLE,DWORD, \ BOOL))aSyscall[63].pCurrent) - { "GetNativeSystemInfo", (SYSCALL)GetNativeSystemInfo, 0 }, - -#define osGetNativeSystemInfo ((VOID(WINAPI*)( \ - LPSYSTEM_INFO))aSyscall[64].pCurrent) + { "GetNativeSystemInfo", (SYSCALL)0, 0 }, + /* ^^^^^^^^^^^^^^^^^^^----------------^------- placeholder only */ #if defined(SQLITE_WIN32_HAS_ANSI) { "OutputDebugStringA", (SYSCALL)OutputDebugStringA, 0 }, @@ -53019,11 +53027,29 @@ SQLITE_API int sqlite3_win_test_unc_locking = 0; /* ** Return true if the string passed as the only argument is likely -** to be a UNC path. In other words, if it starts with "\\". +** to be a UNC path. Return false if note. +** +** Return true if: +** +** (1) The name begins with "\\" +** (2) But does not begin with "\\?\C:\" where C can be any alphabetic +** character. +** +** For testing, also return true in all cases if the global variable +** sqlite3_win_test_unc_locking is true. */ static int winIsUNCPath(const char *zFile){ if( zFile[0]=='\\' && zFile[1]=='\\' ){ - return 1; + if( zFile[2]=='?' + && zFile[3]=='\\' + && sqlite3Isalpha(zFile[4]) + && zFile[5]==':' + && winIsDirSep(zFile[6]) + ){ + return sqlite3_win_test_unc_locking; + }else{ + return 1; + } } return sqlite3_win_test_unc_locking; } @@ -56039,7 +56065,7 @@ SQLITE_API unsigned char *sqlite3_serialize( sqlite3_int64 sz; int szPage = 0; sqlite3_stmt *pStmt = 0; - unsigned char *pOut; + unsigned char *pOut = 0; char *zSql; int rc; @@ -56049,12 +56075,13 @@ SQLITE_API unsigned char *sqlite3_serialize( return 0; } #endif + sqlite3_mutex_enter(db->mutex); if( zSchema==0 ) zSchema = db->aDb[0].zDbSName; p = memdbFromDbSchema(db, zSchema); iDb = sqlite3FindDbName(db, zSchema); if( piSize ) *piSize = -1; - if( iDb<0 ) return 0; + if( iDb<0 ) goto serialize_out; if( p ){ MemStore *pStore = p->pStore; assert( pStore->pMutex==0 ); @@ -56065,19 +56092,17 @@ SQLITE_API unsigned char *sqlite3_serialize( pOut = sqlite3_malloc64( pStore->sz ); if( pOut ) memcpy(pOut, pStore->aData, pStore->sz); } - return pOut; + goto serialize_out; } pBt = db->aDb[iDb].pBt; - if( pBt==0 ) return 0; + if( pBt==0 ) goto serialize_out; szPage = sqlite3BtreeGetPageSize(pBt); zSql = sqlite3_mprintf("PRAGMA \"%w\".page_count", zSchema); rc = zSql ? sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0) : SQLITE_NOMEM; sqlite3_free(zSql); - if( rc ) return 0; + if( rc ) goto serialize_out; rc = sqlite3_step(pStmt); - if( rc!=SQLITE_ROW ){ - pOut = 0; - }else{ + if( rc==SQLITE_ROW ){ sz = sqlite3_column_int64(pStmt, 0)*szPage; if( sz==0 ){ sqlite3_reset(pStmt); @@ -56111,6 +56136,9 @@ SQLITE_API unsigned char *sqlite3_serialize( } } sqlite3_finalize(pStmt); + + serialize_out: + sqlite3_mutex_leave(db->mutex); return pOut; } @@ -57964,22 +57992,24 @@ static int pcache1InitBulk(PCache1 *pCache){ if( szBulk > pCache->szAlloc*(i64)pCache->nMax ){ szBulk = pCache->szAlloc*(i64)pCache->nMax; } - zBulk = pCache->pBulk = sqlite3Malloc( szBulk ); - sqlite3EndBenignMalloc(); - if( zBulk ){ - int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc; - do{ - PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage]; - pX->page.pBuf = zBulk; - pX->page.pExtra = (u8*)pX + ROUND8(sizeof(*pX)); - assert( EIGHT_BYTE_ALIGNMENT( pX->page.pExtra ) ); - pX->isBulkLocal = 1; - pX->isAnchor = 0; - pX->pNext = pCache->pFree; - pX->pLruPrev = 0; /* Initializing this saves a valgrind error */ - pCache->pFree = pX; - zBulk += pCache->szAlloc; - }while( --nBulk ); + if( szBulk>=pCache->szAlloc ){ + zBulk = pCache->pBulk = sqlite3Malloc( szBulk ); + sqlite3EndBenignMalloc(); + if( zBulk ){ + int nBulk = sqlite3MallocSize(zBulk)/pCache->szAlloc; + do{ + PgHdr1 *pX = (PgHdr1*)&zBulk[pCache->szPage]; + pX->page.pBuf = zBulk; + pX->page.pExtra = (u8*)pX + ROUND8(sizeof(*pX)); + assert( EIGHT_BYTE_ALIGNMENT( pX->page.pExtra ) ); + pX->isBulkLocal = 1; + pX->isAnchor = 0; + pX->pNext = pCache->pFree; + pX->pLruPrev = 0; /* Initializing this saves a valgrind error */ + pCache->pFree = pX; + zBulk += pCache->szAlloc; + }while( --nBulk ); + } } return pCache->pFree!=0; } @@ -60877,39 +60907,43 @@ static void checkPage(PgHdr *pPg){ #endif /* SQLITE_CHECK_PAGES */ /* -** When this is called the journal file for pager pPager must be open. -** This function attempts to read a super-journal file name from the -** end of the file and, if successful, copies it into memory supplied -** by the caller. See comments above writeSuperJournal() for the format -** used to store a super-journal file name at the end of a journal file. -** -** zSuper must point to a buffer of at least nSuper bytes allocated by -** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is -** enough space to write the super-journal name). If the super-journal -** name in the journal is longer than nSuper bytes (including a -** nul-terminator), then this is handled as if no super-journal name -** were present in the journal. +** Free a buffer allocated by the readSuperJournal() function. +*/ +static void freeSuperJournal(char *zSuper){ + if( zSuper ){ + sqlite3_free(&zSuper[-4]); + } +} + +/* +** Parameter pJrnl is a file-handle open on a journal file. This function +** attempts to read a super-journal file name from the end of the journal +** file. If successful, it sets output parameter (*pzSuper) to point to a +** buffer containing the super-journal name as a nul-terminated string. +** The caller is responsible for freeing the buffer using freeSuperJournal(). ** -** If a super-journal file name is present at the end of the journal -** file, then it is copied into the buffer pointed to by zSuper. A -** nul-terminator byte is appended to the buffer following the -** super-journal file name. +** Refer to comments above writeSuperJournal() for the format used to store +** a super-journal file name at the end of a journal file. ** -** If it is determined that no super-journal file name is present -** zSuper[0] is set to 0 and SQLITE_OK returned. +** Parameter nSuper is passed the maximum allowable size of the super journal +** name in bytes. If the super-journal name in the journal is longer than +** nSuper bytes (including a nul-terminator), then this is handled as if no +** super-journal name were present in the journal. ** -** If an error occurs while reading from the journal file, an SQLite -** error code is returned. +** If there is no super-journal name at the end of pJrnl, (*pzSuper) is +** set to 0 and SQLITE_OK is returned. Or, if an error occurs while reading +** the super-journal name, an SQLite error code is returned and (*pzSuper) +** is set to 0. */ -static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u64 nSuper){ +static int readSuperJournal(sqlite3_file *pJrnl, u64 nSuper, char **pzSuper){ int rc; /* Return code */ u32 len; /* Length in bytes of super-journal name */ i64 szJ; /* Total size in bytes of journal file pJrnl */ u32 cksum; /* MJ checksum value read from journal */ - u32 u; /* Unsigned loop counter */ unsigned char aMagic[8]; /* A buffer to hold the magic header */ - zSuper[0] = '\0'; + char *zOut = 0; + *pzSuper = 0; if( SQLITE_OK!=(rc = sqlite3OsFileSize(pJrnl, &szJ)) || szJ<16 || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-16, &len)) @@ -60919,27 +60953,34 @@ static int readSuperJournal(sqlite3_file *pJrnl, char *zSuper, u64 nSuper){ || SQLITE_OK!=(rc = read32bits(pJrnl, szJ-12, &cksum)) || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8)) || memcmp(aMagic, aJournalMagic, 8) - || SQLITE_OK!=(rc = sqlite3OsRead(pJrnl, zSuper, len, szJ-16-len)) ){ return rc; } - /* See if the checksum matches the super-journal name */ - for(u=0; uzJournal */ + + /* Check if this looks like a real super-journal name. If it does not, + ** return SQLITE_OK without attempting to delete it. This is to limit + ** the degree to which a crafted journal file can be used to cause + ** SQLite to delete arbitrary files. */ + if( pagerIsSuperJrnlName(zSuper)==0 ){ + return SQLITE_OK; + } /* Allocate space for both the pJournal and pSuper file descriptors. ** If successful, open the super-journal file for reading. @@ -62169,9 +62251,8 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){ */ rc = sqlite3OsFileSize(pSuper, &nSuperJournal); if( rc!=SQLITE_OK ) goto delsuper_out; - nSuperPtr = 1 + (i64)pVfs->mxPathname; - assert( nSuperJournal>=0 && nSuperPtr>0 ); - zFree = sqlite3Malloc(4 + nSuperJournal + 2 + nSuperPtr + 2); + assert( nSuperJournal>=0 ); + zFree = sqlite3Malloc(4 + nSuperJournal + 2); if( !zFree ){ rc = SQLITE_NOMEM_BKPT; goto delsuper_out; @@ -62180,7 +62261,6 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){ } zFree[0] = zFree[1] = zFree[2] = zFree[3] = 0; zSuperJournal = &zFree[4]; - zSuperPtr = &zSuperJournal[nSuperJournal+2]; rc = sqlite3OsRead(pSuper, zSuperJournal, (int)nSuperJournal, 0); if( rc!=SQLITE_OK ) goto delsuper_out; zSuperJournal[nSuperJournal] = 0; @@ -62188,43 +62268,56 @@ static int pager_delsuper(Pager *pPager, const char *zSuper){ zJournal = zSuperJournal; while( (zJournal-zSuperJournal)zJournal)==0 ){ + bSeen = 1; + }else{ + int exists; + rc = sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS, &exists); if( rc!=SQLITE_OK ){ goto delsuper_out; } + if( exists ){ + char *zSuperPtr = 0; - rc = readSuperJournal(pJournal, zSuperPtr, nSuperPtr); - sqlite3OsClose(pJournal); - if( rc!=SQLITE_OK ){ - goto delsuper_out; - } + /* One of the journals pointed to by the super-journal exists. + ** Open it and check if it points at the super-journal. If + ** so, return without deleting the super-journal file. + ** NB: zJournal is really a MAIN_JOURNAL. But call it a + ** SUPER_JOURNAL here so that the VFS will not send the zJournal + ** name into sqlite3_database_file_object(). + */ + int c; + int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_SUPER_JOURNAL); + rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0); + if( rc!=SQLITE_OK ){ + goto delsuper_out; + } - c = zSuperPtr[0]!=0 && strcmp(zSuperPtr, zSuper)==0; - if( c ){ - /* We have a match. Do not delete the super-journal file. */ - goto delsuper_out; + rc = readSuperJournal(pJournal, 1+(u64)pVfs->mxPathname, &zSuperPtr); + sqlite3OsClose(pJournal); + if( rc!=SQLITE_OK ){ + assert( zSuperPtr==0 ); + goto delsuper_out; + } + + c = zSuperPtr!=0 && strcmp(zSuperPtr, zSuper)==0; + freeSuperJournal(zSuperPtr); + if( c ){ + /* We have a match. Do not delete the super-journal file. */ + goto delsuper_out; + } } } zJournal += (sqlite3Strlen30(zJournal)+1); } sqlite3OsClose(pSuper); - rc = sqlite3OsDelete(pVfs, zSuper, 0); + if( bSeen ){ + /* Only delete the super-journal if bSeen is true - indicating that + ** the super-journal contained a pointer to this database's journal + ** file. */ + rc = sqlite3OsDelete(pVfs, zSuper, 0); + } delsuper_out: sqlite3_free(zFree); @@ -62429,19 +62522,11 @@ static int pager_playback(Pager *pPager, int isHot){ ** If a super-journal file name is specified, but the file is not ** present on disk, then the journal is not hot and does not need to be ** played back. - ** - ** TODO: Technically the following is an error because it assumes that - ** buffer Pager.pTmpSpace is (mxPathname+1) bytes or larger. i.e. that - ** ((pPager->pageSize+8) >= pPager->pVfs->mxPathname+1). Using os_unix.c, - ** mxPathname is 512, which is the same as the minimum allowable value - ** for pageSize, and so this assumption holds. But it might not for some - ** custom VFS. */ - zSuper = pPager->pTmpSpace; - rc = readSuperJournal(pPager->jfd, zSuper, 1+(i64)pPager->pVfs->mxPathname); - if( rc==SQLITE_OK && zSuper[0] ){ + */ + rc = readSuperJournal(pPager->jfd, 1+(i64)pPager->pVfs->mxPathname, &zSuper); + if( rc==SQLITE_OK && zSuper ){ rc = sqlite3OsAccess(pVfs, zSuper, SQLITE_ACCESS_EXISTS, &res); } - zSuper = 0; if( rc!=SQLITE_OK || !res ){ goto end_playback; } @@ -62570,30 +62655,20 @@ static int pager_playback(Pager *pPager, int isHot){ */ pPager->changeCountDone = pPager->tempFile; - if( rc==SQLITE_OK ){ - /* Leave 4 bytes of space before the super-journal filename in memory. - ** This is because it may end up being passed to sqlite3OsOpen(), in - ** which case it requires 4 0x00 bytes in memory immediately before - ** the filename. */ - zSuper = &pPager->pTmpSpace[4]; - rc = readSuperJournal(pPager->jfd, zSuper, 1+(i64)pPager->pVfs->mxPathname); - testcase( rc!=SQLITE_OK ); - } if( rc==SQLITE_OK && (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN) ){ rc = sqlite3PagerSync(pPager, 0); } if( rc==SQLITE_OK ){ - rc = pager_end_transaction(pPager, zSuper[0]!='\0', 0); + rc = pager_end_transaction(pPager, zSuper!=0, 0); testcase( rc!=SQLITE_OK ); } - if( rc==SQLITE_OK && zSuper[0] && res ){ + if( rc==SQLITE_OK && zSuper && res ){ /* If there was a super-journal and this routine will return success, ** see if it is possible to delete the super-journal. */ - assert( zSuper==&pPager->pTmpSpace[4] ); - memset(pPager->pTmpSpace, 0, 4); + assert( memcmp(&zSuper[-4], "\0\0\0\0", 4)==0 ); rc = pager_delsuper(pPager, zSuper); testcase( rc!=SQLITE_OK ); } @@ -62606,6 +62681,7 @@ static int pager_playback(Pager *pPager, int isHot){ ** back a journal created by a process with a different sector size ** value. Reset it to the correct value for this process. */ + freeSuperJournal(zSuper); setSectorSize(pPager); return rc; } @@ -68465,6 +68541,12 @@ static int walDecodeFrame( return 0; } + /* Need a valid page size + */ + if( !pWal->szPage ){ + return 0; + } + /* A frame is only valid if a checksum of the WAL header, ** all prior frames, the first 16 bytes of this frame-header, ** and the frame-data matches the checksum in the last 8 @@ -70319,7 +70401,7 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){ /* Allocate a buffer to read frames into */ assert( (pWal->szPage & (pWal->szPage-1))==0 ); - assert( pWal->szPage>=512 && pWal->szPage<=65536 ); + assert( (pWal->szPage>=512 && pWal->szPage<=65536) || pWal->szPage==0 ); szFrame = pWal->szPage + WAL_FRAME_HDRSIZE; aFrame = (u8 *)sqlite3_malloc64(szFrame); if( aFrame==0 ){ @@ -72817,6 +72899,9 @@ struct IntegrityCk { u32 *heap; /* Min-heap used for analyzing cell coverage */ sqlite3 *db; /* Database connection running the check */ i64 nRow; /* Number of rows visited in current tree */ +#ifdef SQLITE_DEBUG + u32 mxHeap; /* Maximum number of entries in the Min-heap */ +#endif }; /* @@ -75278,8 +75363,12 @@ static int btreeComputeFreeSpace(MemPage *pPage){ } next = get2byte(&data[pc]); size = get2byte(&data[pc+2]); + if( size<4 ){ + /* Minimum freeblock size is 4 */ + return SQLITE_CORRUPT_PAGE(pPage); + } nFree = nFree + size; - if( next<=pc+size+3 ) break; + if( next0 ){ @@ -79112,14 +79201,14 @@ static int indexCellCompare( /* This branch runs if the record-size field of the cell is a ** single byte varint and the record fits entirely on the main ** b-tree page. */ - testcase( pCell+nCell+1==pPage->aDataEnd ); + if( pCell + nCell >= pPage->aDataEnd ) return 99; c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); }else if( !(pCell[1] & 0x80) && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal ){ /* The record-size field is a 2 byte varint and the record ** fits entirely on the main b-tree page. */ - testcase( pCell+nCell+2==pPage->aDataEnd ); + if( pCell + nCell >= pPage->aDataEnd ) return 99; c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); }else{ /* If the record extends into overflow pages, do not attempt @@ -79281,14 +79370,17 @@ SQLITE_PRIVATE int sqlite3BtreeIndexMoveto( /* This branch runs if the record-size field of the cell is a ** single byte varint and the record fits entirely on the main ** b-tree page. */ - testcase( pCell+nCell+1==pPage->aDataEnd ); + if( pCell + nCell >= pPage->aDataEnd ){ + rc = SQLITE_CORRUPT_PAGE(pPage); + goto moveto_index_finish; + } c = xRecordCompare(nCell, (void*)&pCell[1], pIdxKey); }else if( !(pCell[1] & 0x80) && (nCell = ((nCell&0x7f)<<7) + pCell[1])<=pPage->maxLocal + && pCell + nCell < pPage->aDataEnd ){ /* The record-size field is a 2 byte varint and the record ** fits entirely on the main b-tree page. */ - testcase( pCell+nCell+2==pPage->aDataEnd ); c = xRecordCompare(nCell, (void*)&pCell[2], pIdxKey); }else{ /* The record flows over onto one or more overflow pages. In @@ -84153,6 +84245,7 @@ static int checkTreePage( } }else{ /* Populate the coverage-checking heap for leaf pages */ + assert( heap[0] < pCheck->mxHeap ); btreeHeapInsert(heap, (pc<<16)|(pc+info.nSize-1)); } } @@ -84172,6 +84265,7 @@ static int checkTreePage( u32 size; pc = get2byteAligned(&data[cellStart+i*2]); size = pPage->xCellSize(pPage, &data[pc]); + assert( heap[0] < pCheck->mxHeap ); btreeHeapInsert(heap, (pc<<16)|(pc+size-1)); } } @@ -84188,6 +84282,7 @@ static int checkTreePage( assert( (u32)i<=usableSize-4 ); /* Enforced by btreeComputeFreeSpace() */ size = get2byte(&data[i+2]); assert( (u32)(i+size)<=usableSize ); /* due to btreeComputeFreeSpace() */ + assert( heap[0] < pCheck->mxHeap ); btreeHeapInsert(heap, (((u32)i)<<16)|(i+size-1)); /* EVIDENCE-OF: R-58208-19414 The first 2 bytes of a freeblock are a ** big-endian integer which is the offset in the b-tree page of the next @@ -84322,6 +84417,9 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck( goto integrity_ck_cleanup; } sCheck.heap = (u32*)sqlite3PageMalloc( pBt->pageSize ); +#ifdef SQLITE_DEBUG + sCheck.mxHeap = pBt->pageSize/4 - 1; +#endif if( sCheck.heap==0 ){ checkOom(&sCheck); goto integrity_ck_cleanup; @@ -84739,6 +84837,7 @@ SQLITE_PRIVATE int sqlite3BtreeConnectionCount(Btree *p){ */ struct sqlite3_backup { sqlite3* pDestDb; /* Destination database handle */ + char *zDestDb; Btree *pDest; /* Destination b-tree file */ u32 iDestSchema; /* Original schema cookie in destination */ int bDestLocked; /* True once a write-transaction is open on pDest */ @@ -84828,10 +84927,8 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ ** Attempt to set the page size of the destination to match the page size ** of the source. */ -static int setDestPgsz(sqlite3_backup *p){ - int rc; - rc = sqlite3BtreeSetPageSize(p->pDest,sqlite3BtreeGetPageSize(p->pSrc),0,0); - return rc; +static int setDestPgsz(Btree *pDest, Btree *pSrc){ + return sqlite3BtreeSetPageSize(pDest, sqlite3BtreeGetPageSize(pSrc), 0, 0); } /* @@ -84888,27 +84985,37 @@ SQLITE_API sqlite3_backup *sqlite3_backup_init( ); p = 0; }else { + int nDest = sqlite3Strlen30(zDestDb); + /* Allocate space for a new sqlite3_backup object... ** EVIDENCE-OF: R-64852-21591 The sqlite3_backup object is created by a ** call to sqlite3_backup_init() and is destroyed by a call to ** sqlite3_backup_finish(). */ - p = (sqlite3_backup *)sqlite3MallocZero(sizeof(sqlite3_backup)); + p = (sqlite3_backup*)sqlite3MallocZero(sizeof(sqlite3_backup)+nDest+1); if( !p ){ sqlite3Error(pDestDb, SQLITE_NOMEM_BKPT); + }else{ + p->zDestDb = (char*)&p[1]; + memcpy(p->zDestDb, zDestDb, nDest); } } /* If the allocation succeeded, populate the new object. */ if( p ){ + /* Do not store the pointer to the destination b-tree at this point. + ** This is because there is nothing preventing it from being detached + ** or otherwise freed before the first call to sqlite3_backup_step() + ** on this object. The source b-tree does not have this problem, as + ** incrementing Btree.nBackup (see below) effectively locks the object. */ + Btree *pDest = findBtree(pDestDb, pDestDb, zDestDb); p->pSrc = findBtree(pDestDb, pSrcDb, zSrcDb); - p->pDest = findBtree(pDestDb, pDestDb, zDestDb); p->pDestDb = pDestDb; p->pSrcDb = pSrcDb; p->iNext = 1; p->isAttached = 0; - if( 0==p->pSrc || 0==p->pDest - || checkReadTransaction(pDestDb, p->pDest)!=SQLITE_OK + if( 0==p->pSrc || 0==pDest + || checkReadTransaction(pDestDb, pDest)!=SQLITE_OK ){ /* One (or both) of the named databases did not exist or an OOM ** error was hit. Or there is a transaction open on the destination @@ -85032,7 +85139,7 @@ static void attachBackupObject(sqlite3_backup *p){ */ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ int rc; - int destMode; /* Destination journal mode */ + int destMode = 0; /* Destination journal mode */ int pgszSrc = 0; /* Source page size */ int pgszDest = 0; /* Destination page size */ @@ -85048,7 +85155,8 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ rc = p->rc; if( !isFatalError(rc) ){ Pager * const pSrcPager = sqlite3BtreePager(p->pSrc); /* Source pager */ - Pager * const pDestPager = sqlite3BtreePager(p->pDest); /* Dest pager */ + Btree * pDest = 0; /* Dest btree */ + Pager * pDestPager = 0; /* Dest pager */ int ii; /* Iterator variable */ int nSrcPage = -1; /* Size of source db in pages */ int bCloseTrans = 0; /* True if src db requires unlocking */ @@ -85062,6 +85170,7 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ rc = SQLITE_OK; } + /* If there is no open read-transaction on the source database, open ** one now. If a transaction is opened here, then it will be closed ** before this function exits. @@ -85071,34 +85180,48 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ bCloseTrans = 1; } + /* Locate the destination btree and pager. */ + if( (pDest = p->pDest)==0 ){ + pDest = findBtree(p->pDestDb, p->pDestDb, p->zDestDb); + } + if( pDest==0 ){ + rc = SQLITE_ERROR; + }else{ + pDestPager = sqlite3BtreePager(pDest); + } + /* If the destination database has not yet been locked (i.e. if this ** is the first call to backup_step() for the current backup operation), ** try to set its page size to the same as the source database. This ** is especially important on ZipVFS systems, as in that case it is ** not possible to create a database file that uses one page size by ** writing to it with another. */ - if( p->bDestLocked==0 && rc==SQLITE_OK && setDestPgsz(p)==SQLITE_NOMEM ){ + if( p->bDestLocked==0 && rc==SQLITE_OK + && setDestPgsz(pDest, p->pSrc)==SQLITE_NOMEM + ){ rc = SQLITE_NOMEM; } /* Lock the destination database, if it is not locked already. */ if( SQLITE_OK==rc && p->bDestLocked==0 - && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(p->pDest, 2, + && SQLITE_OK==(rc = sqlite3BtreeBeginTrans(pDest, 2, (int*)&p->iDestSchema)) ){ p->bDestLocked = 1; + p->pDest = pDest; } /* Do not allow backup if the destination database is in WAL mode ** and the page sizes are different between source and destination */ - pgszSrc = sqlite3BtreeGetPageSize(p->pSrc); - pgszDest = sqlite3BtreeGetPageSize(p->pDest); - destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest)); - if( SQLITE_OK==rc - && (destMode==PAGER_JOURNALMODE_WAL || sqlite3PagerIsMemdb(pDestPager)) - && pgszSrc!=pgszDest - ){ - rc = SQLITE_READONLY; + if( rc==SQLITE_OK ){ + pgszSrc = sqlite3BtreeGetPageSize(p->pSrc); + pgszDest = sqlite3BtreeGetPageSize(p->pDest); + destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest)); + if( (destMode==PAGER_JOURNALMODE_WAL || sqlite3PagerIsMemdb(pDestPager)) + && pgszSrc!=pgszDest + ){ + rc = SQLITE_READONLY; + } } /* Now that there is a read-lock on the source database, query the @@ -85316,7 +85439,9 @@ SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){ } /* If a transaction is still open on the Btree, roll it back. */ - sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0); + if( p->pDest ){ + sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0); + } /* Set the error code of the destination database handle. */ rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc; @@ -93584,8 +93709,14 @@ SQLITE_PRIVATE const char *sqlite3VdbeFuncName(const sqlite3_context *pCtx){ ** added or changed. */ SQLITE_API int sqlite3_expired(sqlite3_stmt *pStmt){ - Vdbe *p = (Vdbe*)pStmt; - return p==0 || p->expired; + int iRet = 1; + if( pStmt ){ + Vdbe *p = (Vdbe*)pStmt; + sqlite3_mutex_enter(p->db->mutex); + iRet = p->expired; + sqlite3_mutex_leave(p->db->mutex); + } + return iRet; } #endif @@ -116880,7 +117011,7 @@ static void sqlite3ExprCodeIN( Expr *p = sqlite3VectorFieldSubexpr(pExpr->pLeft, i); if( pParse->nErr ) goto sqlite3ExprCodeIN_oom_error; if( sqlite3ExprCanBeNull(p) ){ - sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+i, destStep2); + sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+aiMap[i], destStep2); VdbeCoverage(v); } } @@ -116964,8 +117095,8 @@ static void sqlite3ExprCodeIN( ** ...)" is the collating sequence of x.". */ pColl = sqlite3ExprCollSeq(pParse, p); } - sqlite3VdbeAddOp3(v, OP_Column, iTab, i, r3); - sqlite3VdbeAddOp4(v, OP_Ne, rLhs+i, destNotNull, r3, + sqlite3VdbeAddOp3(v, OP_Column, iTab, aiMap[i], r3); + sqlite3VdbeAddOp4(v, OP_Ne, rLhs+aiMap[i], destNotNull, r3, (void*)pColl, P4_COLLSEQ); VdbeCoverage(v); sqlite3ReleaseTempReg(pParse, r3); @@ -125304,9 +125435,9 @@ static int loadStatTbl( } pIdx->nSampleCol = nIdxCol; pIdx->mxSample = nSample; - nByte = ROUND8(sizeof(IndexSample) * nSample); - nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample; - nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */ + nByte = ROUND8(sizeof64(IndexSample) * nSample); + nByte += sizeof64(tRowcnt) * nIdxCol * 3 * nSample; + nByte += nIdxCol * sizeof64(tRowcnt); /* Space for Index.aAvgEq[] */ pIdx->aSample = sqlite3DbMallocZero(db, nByte); if( pIdx->aSample==0 ){ @@ -125314,7 +125445,7 @@ static int loadStatTbl( return SQLITE_NOMEM_BKPT; } pPtr = (u8*)pIdx->aSample; - pPtr += ROUND8(nSample*sizeof(pIdx->aSample[0])); + pPtr += ROUND8(nSample*sizeof64(pIdx->aSample[0])); pSpace = (tRowcnt*)pPtr; assert( EIGHT_BYTE_ALIGNMENT( pSpace ) ); pIdx->aAvgEq = pSpace; pSpace += nIdxCol; @@ -136786,7 +136917,7 @@ static void percentSort(double *a, unsigned int n){ i++; } }while( in/2 ){ + if( iLt>(int)(n/2) ){ if( n-iGt>=2 ) percentSort(a+iGt, n-iGt); n = iLt; }else{ @@ -151303,6 +151434,13 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect, c sqlite3 *db = pParse->db; u64 savedFlags; + pParse->nNestSel++; +#if SQLITE_MAX_EXPR_DEPTH>0 + if( pParse->nNestSel >= db->aLimit[SQLITE_LIMIT_EXPR_DEPTH] ){ + sqlite3ErrorMsg(pParse, "VIEWs and/or subqueries nested too deep"); + return 0; + } +#endif savedFlags = db->flags; db->flags &= ~(u64)SQLITE_FullColNames; db->flags |= SQLITE_ShortColNames; @@ -151324,6 +151462,8 @@ SQLITE_PRIVATE Table *sqlite3ResultSetOfSelect(Parse *pParse, Select *pSelect, c sqlite3DeleteTable(db, pTab); return 0; } + pParse->nNestSel--; + assert( pParse->nNestSel>=0 ); return pTab; } @@ -159267,7 +159407,7 @@ static TriggerPrg *codeRowTrigger( Table *pTab, /* The table pTrigger is attached to */ int orconf /* ON CONFLICT policy to code trigger program with */ ){ - Parse *pTop = sqlite3ParseToplevel(pParse); + Parse *pTop; /* Top level Parse object */ sqlite3 *db = pParse->db; /* Database handle */ TriggerPrg *pPrg; /* Value to return */ Expr *pWhen = 0; /* Duplicate of trigger WHEN expression */ @@ -159276,10 +159416,24 @@ static TriggerPrg *codeRowTrigger( SubProgram *pProgram = 0; /* Sub-vdbe for trigger program */ int iEndTrigger = 0; /* Label to jump to if WHEN is false */ Parse sSubParse; /* Parse context for sub-vdbe */ + int nDepth; /* Trigger depth */ + /* Ensure that triggers are not chained too deep. This test is linear + ** in the chaining depth, but sensible code ought not be chaining + ** triggers excessively, so that shouldn't be a problem. + */ + pTop = pParse; + for(nDepth=0; pTop->pOuterParse; pTop = pTop->pOuterParse, nDepth++){} + if( nDepth>=db->aLimit[SQLITE_LIMIT_TRIGGER_DEPTH] ){ + sqlite3ErrorMsg(pParse, "triggers nested too deep"); + return 0; + } + + pTop = sqlite3ParseToplevel(pParse); assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) ); assert( pTop->pVdbe ); + /* Allocate the TriggerPrg and SubProgram objects. To ensure that they ** are freed if an error occurs, link them into the Parse.pTriggerPrg ** list of the top-level Parse object sooner rather than later. */ @@ -161280,7 +161434,8 @@ SQLITE_PRIVATE void sqlite3UpsertDoUpdate( /* excluded.* columns of type REAL need to be converted to a hard real */ for(i=0; inCol; i++){ if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){ - sqlite3VdbeAddOp1(v, OP_RealAffinity, pTop->regData+i); + int iStorage = pTop->regData + sqlite3TableColumnToStorage(pTab, i); + sqlite3VdbeAddOp1(v, OP_RealAffinity, iStorage); } } sqlite3Update(pParse, pSrc, sqlite3ExprListDup(db,pUpsert->pUpsertSet,0), @@ -161868,6 +162023,7 @@ SQLITE_API int sqlite3_drop_modules(sqlite3 *db, const char** azNames){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif + sqlite3_mutex_enter(db->mutex); for(pThis=sqliteHashFirst(&db->aModule); pThis; pThis=pNext){ Module *pMod = (Module*)sqliteHashData(pThis); pNext = sqliteHashNext(pThis); @@ -161878,6 +162034,7 @@ SQLITE_API int sqlite3_drop_modules(sqlite3 *db, const char** azNames){ } createModule(db, pMod->zName, 0, 0, 0); } + sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } @@ -167252,7 +167409,10 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){ static void markTermAsChild(WhereClause *pWC, int iChild, int iParent){ pWC->a[iChild].iParent = iParent; pWC->a[iChild].truthProb = pWC->a[iParent].truthProb; + assert( pWC->a[iParent].nChild < UMXV(pWC->a[0].nChild) ); pWC->a[iParent].nChild++; + testcase( pWC->a[iParent].nChild == UMXV(pWC->a[0].nChild) ); + } /* @@ -168029,6 +168189,7 @@ static void exprAnalyze( pList = pExpr->x.pList; assert( pList!=0 ); assert( pList->nExpr==2 ); + assert( pWC->a[idxTerm].nChild==0 ); for(i=0; i<2; i++){ Expr *pNewExpr; int idxNew; @@ -168239,8 +168400,11 @@ static void exprAnalyze( && pExpr->x.pSelect->pWin==0 #endif && pWC->op==TK_AND + && pExpr->x.pSelect->pEList->nExpr <= UMXV(pTerm->nChild) + /* ^-- See bug 2026-06-04T10:00:49Z */ ){ int i; + assert( pTerm->nChild==0 ); for(i=0; ipLeft); i++){ int idxNew; idxNew = whereClauseInsert(pWC, pExpr, TERM_VIRTUAL|TERM_SLICE); @@ -188309,13 +188473,17 @@ static int nocaseCollatingFunc( ** Return the ROWID of the most recent insert */ SQLITE_API sqlite_int64 sqlite3_last_insert_rowid(sqlite3 *db){ + i64 iRet; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif - return db->lastRowid; + sqlite3_mutex_enter(db->mutex); + iRet = db->lastRowid; + sqlite3_mutex_leave(db->mutex); + return iRet; } /* @@ -188337,13 +188505,17 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3 *db, sqlite3_int64 iRowid) ** Return the number of changes in the most recent call to sqlite3_exec(). */ SQLITE_API sqlite3_int64 sqlite3_changes64(sqlite3 *db){ + i64 iRet; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif - return db->nChange; + sqlite3_mutex_enter(db->mutex); + iRet = db->nChange; + sqlite3_mutex_leave(db->mutex); + return iRet; } SQLITE_API int sqlite3_changes(sqlite3 *db){ return (int)sqlite3_changes64(db); @@ -188353,13 +188525,17 @@ SQLITE_API int sqlite3_changes(sqlite3 *db){ ** Return the number of changes since the database handle was opened. */ SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3 *db){ + i64 iRet; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif - return db->nTotalChange; + sqlite3_mutex_enter(db->mutex); + iRet = db->nTotalChange; + sqlite3_mutex_leave(db->mutex); + return iRet; } SQLITE_API int sqlite3_total_changes(sqlite3 *db){ return (int)sqlite3_total_changes64(db); @@ -189042,6 +189218,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){ #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif + sqlite3_mutex_enter(db->mutex); if( ms>0 ){ sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback, (void*)db); @@ -189052,6 +189229,7 @@ SQLITE_API int sqlite3_busy_timeout(sqlite3 *db, int ms){ }else{ sqlite3_busy_handler(db, 0, 0); } + sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } @@ -189957,9 +190135,11 @@ SQLITE_API int sqlite3_set_errmsg(sqlite3 *db, int errcode, const char *zMsg){ */ SQLITE_API int sqlite3_error_offset(sqlite3 *db){ int iOffset = -1; - if( db && sqlite3SafetyCheckSickOrOk(db) && db->errCode ){ + if( db && sqlite3SafetyCheckSickOrOk(db) ){ sqlite3_mutex_enter(db->mutex); - iOffset = db->errByteOffset; + if( db->errCode ){ + iOffset = db->errByteOffset; + } sqlite3_mutex_leave(db->mutex); } return iOffset; @@ -190013,25 +190193,43 @@ SQLITE_API const void *sqlite3_errmsg16(sqlite3 *db){ ** passed to this function, we assume a malloc() failed during sqlite3_open(). */ SQLITE_API int sqlite3_errcode(sqlite3 *db){ - if( db && !sqlite3SafetyCheckSickOrOk(db) ){ + int iRet; + if( !db ) return SQLITE_NOMEM_BKPT; + if( !sqlite3SafetyCheckSickOrOk(db) ){ return SQLITE_MISUSE_BKPT; } - if( !db || db->mallocFailed ){ - return SQLITE_NOMEM_BKPT; + sqlite3_mutex_enter(db->mutex); + if( db->mallocFailed ){ + iRet = SQLITE_NOMEM_BKPT; + }else{ + iRet = db->errCode & db->errMask; } - return db->errCode & db->errMask; + sqlite3_mutex_leave(db->mutex); + return iRet; } SQLITE_API int sqlite3_extended_errcode(sqlite3 *db){ - if( db && !sqlite3SafetyCheckSickOrOk(db) ){ + int iRet; + if( !db ) return SQLITE_NOMEM_BKPT; + if( !sqlite3SafetyCheckSickOrOk(db) ){ return SQLITE_MISUSE_BKPT; } - if( !db || db->mallocFailed ){ - return SQLITE_NOMEM_BKPT; + sqlite3_mutex_enter(db->mutex); + if( db->mallocFailed ){ + iRet = SQLITE_NOMEM_BKPT; + }else{ + iRet = db->errCode; } - return db->errCode; + sqlite3_mutex_leave(db->mutex); + return iRet; } SQLITE_API int sqlite3_system_errno(sqlite3 *db){ - return db ? db->iSysErrno : 0; + int iRet = 0; + if( db ){ + sqlite3_mutex_enter(db->mutex); + iRet = db->iSysErrno; + sqlite3_mutex_leave(db->mutex); + } + return iRet; } /* @@ -190226,6 +190424,7 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ if( limitId<0 || limitId>=SQLITE_N_LIMIT ){ return -1; } + sqlite3_mutex_enter(db->mutex); oldLimit = db->aLimit[limitId]; if( newLimit>=0 ){ /* IMP: R-52476-28732 */ if( newLimit>aHardLimit[limitId] ){ @@ -190235,6 +190434,7 @@ SQLITE_API int sqlite3_limit(sqlite3 *db, int limitId, int newLimit){ } db->aLimit[limitId] = newLimit; } + sqlite3_mutex_leave(db->mutex); return oldLimit; /* IMP: R-53341-35419 */ } @@ -190277,7 +190477,7 @@ SQLITE_PRIVATE int sqlite3ParseUri( const char *zVfs = zDefaultVfs; char *zFile; char c; - int nUri = sqlite3Strlen30(zUri); + i64 nUri = strlen(zUri); assert( *pzErrMsg==0 ); @@ -190287,8 +190487,8 @@ SQLITE_PRIVATE int sqlite3ParseUri( ){ char *zOpt; int eState; /* Parser state when parsing URI */ - int iIn; /* Input character index */ - int iOut = 0; /* Output character index */ + i64 iIn; /* Input character index */ + i64 iOut = 0; /* Output character index */ u64 nByte = nUri+8; /* Bytes of space to allocate */ /* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen @@ -190322,7 +190522,7 @@ SQLITE_PRIVATE int sqlite3ParseUri( while( zUri[iIn] && zUri[iIn]!='/' ) iIn++; if( iIn!=7 && (iIn!=16 || memcmp("localhost", &zUri[7], 9)) ){ *pzErrMsg = sqlite3_mprintf("invalid uri authority: %.*s", - iIn-7, &zUri[7]); + (int)(iIn-7), &zUri[7]); rc = SQLITE_ERROR; goto parse_uri_out; } @@ -190397,11 +190597,11 @@ SQLITE_PRIVATE int sqlite3ParseUri( ** here. Options that are interpreted here include "vfs" and those that ** correspond to flags that may be passed to the sqlite3_open_v2() ** method. */ - zOpt = &zFile[sqlite3Strlen30(zFile)+1]; + zOpt = &zFile[strlen(zFile)+1]; while( zOpt[0] ){ - int nOpt = sqlite3Strlen30(zOpt); + i64 nOpt = strlen(zOpt); char *zVal = &zOpt[nOpt+1]; - int nVal = sqlite3Strlen30(zVal); + i64 nVal = strlen(zVal); if( nOpt==3 && memcmp("vfs", zOpt, 3)==0 ){ zVfs = zVal; @@ -190447,7 +190647,7 @@ SQLITE_PRIVATE int sqlite3ParseUri( int mode = 0; for(i=0; aMode[i].z; i++){ const char *z = aMode[i].z; - if( nVal==sqlite3Strlen30(z) && 0==memcmp(zVal, z, nVal) ){ + if( nVal==(i64)strlen(z) && 0==memcmp(zVal, z, nVal) ){ mode = aMode[i].mode; break; } @@ -191132,13 +191332,17 @@ SQLITE_API int sqlite3_global_recover(void){ ** by the next COMMIT or ROLLBACK. */ SQLITE_API int sqlite3_get_autocommit(sqlite3 *db){ + int iRet; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif - return db->autoCommit; + sqlite3_mutex_enter(db->mutex); + iRet = db->autoCommit; + sqlite3_mutex_leave(db->mutex); + return iRet; } /* @@ -192163,17 +192367,19 @@ SQLITE_PRIVATE Btree *sqlite3DbNameToBtree(sqlite3 *db, const char *zDbName){ ** of range. */ SQLITE_API const char *sqlite3_db_name(sqlite3 *db, int N){ + const char *zRet = 0; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ (void)SQLITE_MISUSE_BKPT; return 0; } #endif - if( N<0 || N>=db->nDb ){ - return 0; - }else{ - return db->aDb[N].zDbSName; + sqlite3_mutex_enter(db->mutex); + if( N>=0 && NnDb ){ + zRet = db->aDb[N].zDbSName; } + sqlite3_mutex_leave(db->mutex); + return zRet; } /* @@ -195795,8 +196001,13 @@ static void fts3PutDeltaVarint( sqlite3_int64 iVal /* Write this value to the list */ ){ assert_fts3_nc( iVal-*piPrev > 0 || (*piPrev==0 && iVal==0) ); - *pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev); - *piPrev = iVal; + if( iVal-(*piPrev)>=0 ){ + /* Refuse to write a negative delta integer. This only happens with a + ** corrupt db (see the assert above) and can cause buffer overwrites + ** in some cases. */ + *pp += sqlite3Fts3PutVarint(*pp, iVal-*piPrev); + *piPrev = iVal; + } } /* @@ -198150,6 +198361,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){ char *p1; char *p2; char *aOut; + i64 nAlloc = (i64)nPoslist*2 + FTS3_BUFFER_PADDING; if( nMaxUndeferred>iPrev ){ p1 = aPoslist; @@ -198161,7 +198373,7 @@ static int fts3EvalDeferredPhrase(Fts3Cursor *pCsr, Fts3Phrase *pPhrase){ nDistance = iPrev - nMaxUndeferred; } - aOut = (char *)sqlite3Fts3MallocZero(((i64)nPoslist)+FTS3_BUFFER_PADDING); + aOut = (char *)sqlite3Fts3MallocZero(nAlloc); if( !aOut ){ sqlite3_free(aPoslist); return SQLITE_NOMEM; @@ -207216,6 +207428,10 @@ static void fts3ReadEndBlockField( for(/* no-op */; zText[i]>='0' && zText[i]<='9'; i++){ iVal = iVal*10 + (zText[i] - '0'); } + + /* This if() clause is just to avoid an integer overflow. The record is + ** corrupt in this case. */ + if( (i64)iVal==SMALLEST_INT64 ) iMul = 1; *pnByte = ((i64)iVal * (i64)iMul); } } @@ -208442,7 +208658,7 @@ static int fts3IncrmergeLoad( return FTS_CORRUPT_VTAB; } - pWriter->nLeafEst = (int)((iEnd - iStart) + 1)/FTS_MAX_APPENDABLE_HEIGHT; + pWriter->nLeafEst = (int)(((iEnd - iStart)+1)/FTS_MAX_APPENDABLE_HEIGHT); pWriter->iStart = iStart; pWriter->iEnd = iEnd; pWriter->iAbsLevel = iAbsLevel; @@ -218556,7 +218772,7 @@ struct RtreeCursor { sqlite3_stmt *pReadAux; /* Statement to read aux-data */ RtreeSearchPoint sPoint; /* Cached next search point */ RtreeNode *aNode[RTREE_CACHE_SZ]; /* Rtree node cache */ - u32 anQueue[RTREE_MAX_DEPTH+1]; /* Number of queued entries by iLevel */ + u32 anQueue[RTREE_MAX_DEPTH+2]; /* Number of queued entries by iLevel */ }; /* Return the Rtree of a RtreeCursor */ @@ -219011,6 +219227,9 @@ static int nodeAcquire( rc = SQLITE_CORRUPT_VTAB; RTREE_IS_CORRUPT(pRtree); } + }else if( iNode<=0 ){ + RTREE_IS_CORRUPT(pRtree); + rc = SQLITE_CORRUPT_VTAB; }else if( pRtree->iNodeSize==sqlite3_blob_bytes(pRtree->pNodeBlob) ){ pNode = (RtreeNode *)sqlite3_malloc64(sizeof(RtreeNode)+pRtree->iNodeSize); if( !pNode ){ @@ -219036,7 +219255,7 @@ static int nodeAcquire( */ if( rc==SQLITE_OK && pNode && iNode==1 ){ pRtree->iDepth = readInt16(pNode->zData); - if( pRtree->iDepth>RTREE_MAX_DEPTH ){ + if( pRtree->iDepth>=RTREE_MAX_DEPTH ){ rc = SQLITE_CORRUPT_VTAB; RTREE_IS_CORRUPT(pRtree); } @@ -226599,16 +226818,26 @@ static unsigned int rbuDeltaGetInt(const char **pz, int *pLen){ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, 36, -1, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, -1, -1, -1, 63, -1, + + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; unsigned int v = 0; int c; unsigned char *z = (unsigned char*)*pz; - unsigned char *zStart = z; - while( (c = zValue[0x7f&*(z++)])>=0 ){ - v = (v<<6) + c; + unsigned char *zEnd = z + (*pLen); + while( z=0 ){ + v = (v<<6) + c; + z++; } - z--; - *pLen -= (int)(z - zStart); + + *pLen -= (int)(z - (unsigned char*)*pz); *pz = (char*)z; return v; } @@ -226684,7 +226913,7 @@ static int rbuDeltaApply( #endif limit = rbuDeltaGetInt(&zDelta, &lenDelta); - if( *zDelta!='\n' ){ + if( lenDelta<=0 || *zDelta!='\n' ){ /* ERROR: size integer not terminated by "\n" */ return -1; } @@ -226692,11 +226921,12 @@ static int rbuDeltaApply( while( *zDelta && lenDelta>0 ){ unsigned int cnt, ofst; cnt = rbuDeltaGetInt(&zDelta, &lenDelta); + if( lenDelta<=0 ) return -1; switch( zDelta[0] ){ case '@': { zDelta++; lenDelta--; ofst = rbuDeltaGetInt(&zDelta, &lenDelta); - if( lenDelta>0 && zDelta[0]!=',' ){ + if( lenDelta>0 || zDelta[0]!=',' ){ /* ERROR: copy command not terminated by ',' */ return -1; } @@ -226721,7 +226951,7 @@ static int rbuDeltaApply( /* ERROR: insert command gives an output larger than predicted */ return -1; } - if( (int)cnt>lenDelta ){ + if( (i64)cnt>(i64)lenDelta ){ /* ERROR: insert count exceeds size of delta */ return -1; } @@ -226759,7 +226989,7 @@ static int rbuDeltaApply( static int rbuDeltaOutputSize(const char *zDelta, int lenDelta){ int size; size = rbuDeltaGetInt(&zDelta, &lenDelta); - if( *zDelta!='\n' ){ + if( lenDelta<=0 || *zDelta!='\n' ){ /* ERROR: size integer not terminated by "\n" */ return -1; } @@ -226807,7 +227037,7 @@ static void rbuFossilDeltaFunc( return; } - aOut = sqlite3_malloc(nOut+1); + aOut = sqlite3_malloc64((i64)nOut+1); if( aOut==0 ){ sqlite3_result_error_nomem(context); }else{ @@ -234986,7 +235216,7 @@ static void sessionAppendStr( int *pRc ){ int nStr = sqlite3Strlen30(zStr); - if( 0==sessionBufferGrow(p, nStr+1, pRc) ){ + if( 0==sessionBufferGrow(p, (i64)nStr+1, pRc) ){ memcpy(&p->aBuf[p->nBuf], zStr, nStr); p->nBuf += nStr; p->aBuf[p->nBuf] = 0x00; @@ -240384,14 +240614,17 @@ static void sessionAppendRecordMerge( u8 *a2, int n2, /* Record 2 */ int *pRc /* IN/OUT: error code */ ){ - sessionBufferGrow(pBuf, n1+n2, pRc); + u8 *a1Eof = &a1[n1]; + u8 *a2Eof = &a2[n2]; + + sessionBufferGrow(pBuf, (i64)n1+n2, pRc); if( *pRc==SQLITE_OK ){ int i; u8 *pOut = &pBuf->aBuf[pBuf->nBuf]; for(i=0; i0 && (*a1==0 || *a1==0xFF)) ){ memcpy(pOut, a2, nn2); pOut += nn2; }else{ @@ -240433,7 +240666,7 @@ static void sessionAppendPartialUpdate( u8 *aChange, int nChange, /* Record to rebase against */ int *pRc /* IN/OUT: Return Code */ ){ - sessionBufferGrow(pBuf, 2+nRec+nChange, pRc); + sessionBufferGrow(pBuf, (i64)2+nRec+nChange, pRc); if( *pRc==SQLITE_OK ){ int bData = 0; u8 *pOut = &pBuf->aBuf[pBuf->nBuf]; @@ -244773,7 +245006,7 @@ static void fts5SnippetFunction( int rc = SQLITE_OK; /* Return code */ int iCol; /* 1st argument to snippet() */ const char *zEllips; /* 4th argument to snippet() */ - int nToken; /* 5th argument to snippet() */ + i64 nToken; /* 5th argument to snippet() */ int nInst = 0; /* Number of instance matches this row */ int i; /* Used to iterate through instances */ int nPhrase; /* Number of phrases in query */ @@ -244798,7 +245031,7 @@ static void fts5SnippetFunction( ctx.zClose = fts5ValueToText(apVal[2]); ctx.iRangeEnd = -1; zEllips = fts5ValueToText(apVal[3]); - nToken = sqlite3_value_int(apVal[4]); + nToken = (int)(MIN( MAX(sqlite3_value_int64(apVal[4]), 0), 64)); iBestCol = (iCol>=0 ? iCol : 0); nPhrase = pApi->xPhraseCount(pFts); @@ -247514,7 +247747,7 @@ static int fts5ExprNearIsMatch(int *pRc, Fts5ExprNearset *pNear){ i64 iPos = a[i].reader.iPos; Fts5PoslistWriter *pWriter = &a[i].writer; if( a[i].pOut->n==0 || iPos!=pWriter->iPrev ){ - sqlite3Fts5PoslistWriterAppend(a[i].pOut, pWriter, iPos); + sqlite3Fts5PoslistSafeAppend(a[i].pOut, &pWriter->iPrev, iPos); } } @@ -248465,10 +248698,10 @@ static int fts5ParseTokenize( memset(pSyn, 0, (size_t)nByte); pSyn->pTerm = ((char*)pSyn) + sizeof(Fts5ExprTerm) + sizeof(Fts5Buffer); pSyn->nFullTerm = pSyn->nQueryTerm = nToken; + memcpy(pSyn->pTerm, pToken, nToken); if( pCtx->pConfig->bTokendata ){ pSyn->nQueryTerm = (int)strlen(pSyn->pTerm); } - memcpy(pSyn->pTerm, pToken, nToken); pSyn->pSynonym = pPhrase->aTerm[pPhrase->nTerm-1].pSynonym; pPhrase->aTerm[pPhrase->nTerm-1].pSynonym = pSyn; } @@ -251751,7 +251984,7 @@ static int fts5StructureDecode( i += fts5GetVarint32(&pData[i], nTotal); if( nTotalnMerge ) rc = FTS5_CORRUPT; pLvl->aSeg = (Fts5StructureSegment*)sqlite3Fts5MallocZero(&rc, - nTotal * sizeof(Fts5StructureSegment) + (i64)nTotal * sizeof(Fts5StructureSegment) ); nSegment -= nTotal; } @@ -252707,7 +252940,7 @@ static void fts5SegIterReverseNewPage(Fts5Index *p, Fts5SegIter *pIter){ while( p->rc==SQLITE_OK && pIter->iLeafPgno>pIter->iTermLeafPgno ){ Fts5Data *pNew; pIter->iLeafPgno--; - pNew = fts5DataRead(p, FTS5_SEGMENT_ROWID( + pNew = fts5LeafRead(p, FTS5_SEGMENT_ROWID( pIter->pSeg->iSegid, pIter->iLeafPgno )); if( pNew ){ @@ -258575,8 +258808,8 @@ static void fts5IndexTombstoneRebuild( ){ const int MINSLOT = 32; int nSlotPerPage = MAX(MINSLOT, (p->pConfig->pgsz - 8) / szKey); - int nSlot = 0; /* Number of slots in each output page */ - int nOut = 0; + i64 nSlot = 0; /* Number of slots in each output page */ + i64 nOut = 0; /* Figure out how many output pages (nOut) and how many slots per ** page (nSlot). There are three possibilities: @@ -258601,23 +258834,26 @@ static void fts5IndexTombstoneRebuild( nSlot = MINSLOT; }else if( pSeg->nPgTombstone==1 ){ /* Case 2. */ - int nElem = (int)fts5GetU32(&pData1->p[4]); + u32 nElem = fts5GetU32(&pData1->p[4]); assert( pData1 && iPg1==0 ); - nOut = 1; - nSlot = MAX(nElem*4, MINSLOT); - if( nSlot>nSlotPerPage ) nOut = 0; + if( nElem>((u32)nSlotPerPage/4) ){ + nOut = 0; + }else{ + nOut = 1; + nSlot = MAX((i64)nElem*4, MINSLOT); + } } if( nOut==0 ){ /* Case 3. */ - nOut = (pSeg->nPgTombstone * 2 + 1); + nOut = ((i64)pSeg->nPgTombstone * 2 + 1); nSlot = nSlotPerPage; } /* Allocate the required array and output pages */ while( 1 ){ int res = 0; - int ii = 0; - int szPage = 0; + i64 ii = 0; + i64 szPage = 0; Fts5Data **apOut = 0; /* Allocate space for the new hash table */ @@ -259122,9 +259358,13 @@ static void fts5IndexIntegrityCheckSegment( FTS5_CORRUPT_ROWID(p, iRow); }else{ iOff += fts5GetVarint32(&pLeaf->p[iOff], nTerm); - res = fts5Memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm)); - if( res==0 ) res = nTerm - nIdxTerm; - if( res<0 ) FTS5_CORRUPT_ROWID(p, iRow); + if( iOff+nTerm>pLeaf->szLeaf ){ + FTS5_CORRUPT_ROWID(p, iRow); + }else{ + res = fts5Memcmp(&pLeaf->p[iOff], zIdxTerm, MIN(nTerm, nIdxTerm)); + if( res==0 ) res = nTerm - nIdxTerm; + if( res<0 ) FTS5_CORRUPT_ROWID(p, iRow); + } } fts5IntegrityCheckPgidx(p, iRow, pLeaf); @@ -259155,7 +259395,7 @@ static void fts5IndexIntegrityCheckSegment( /* Check any rowid-less pages that occur before the current leaf. */ for(iPg=iPrevLeaf+1; iPgeContent==FTS5_CONTENT_NORMAL || pConfig->eContent==FTS5_CONTENT_UNINDEXED ){ - int nDefn = 32 + pConfig->nCol*10; - char *zDefn = sqlite3_malloc64(32 + (sqlite3_int64)pConfig->nCol * 20); - if( zDefn==0 ){ - rc = SQLITE_NOMEM; - }else{ - int i; - int iOff; - sqlite3_snprintf(nDefn, zDefn, "id INTEGER PRIMARY KEY"); - iOff = (int)strlen(zDefn); - for(i=0; inCol; i++){ - if( pConfig->eContent==FTS5_CONTENT_NORMAL - || pConfig->abUnindexed[i] - ){ - sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", c%d", i); - iOff += (int)strlen(&zDefn[iOff]); - } + int i = 0; + char *zDefn = 0; + sqlite3_str *pDefn = sqlite3_str_new(pConfig->db); + + sqlite3_str_appendf(pDefn, "id INTEGER PRIMARY KEY"); + for(i=0; inCol; i++){ + if( pConfig->eContent==FTS5_CONTENT_NORMAL || pConfig->abUnindexed[i] ){ + sqlite3_str_appendf(pDefn, ", c%d", i); } - if( pConfig->bLocale ){ - for(i=0; inCol; i++){ - if( pConfig->abUnindexed[i]==0 ){ - sqlite3_snprintf(nDefn-iOff, &zDefn[iOff], ", l%d", i); - iOff += (int)strlen(&zDefn[iOff]); - } + } + if( pConfig->bLocale ){ + for(i=0; inCol; i++){ + if( pConfig->abUnindexed[i]==0 ){ + sqlite3_str_appendf(pDefn, ", l%d", i); } } + } + zDefn = sqlite3_str_finish(pDefn); + + if( zDefn ){ rc = sqlite3Fts5CreateTable(pConfig, "content", zDefn, 0, pzErr); + sqlite3_free(zDefn); + }else{ + rc = SQLITE_NOMEM; } - sqlite3_free(zDefn); } if( rc==SQLITE_OK && pConfig->bColumnsize ){ diff --git a/deps/sqlite/sqlite3.h b/deps/sqlite/sqlite3.h index ebf25a28b8568d..00b22d9b107cde 100644 --- a/deps/sqlite/sqlite3.h +++ b/deps/sqlite/sqlite3.h @@ -146,12 +146,12 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.53.2" -#define SQLITE_VERSION_NUMBER 3053002 -#define SQLITE_SOURCE_ID "2026-06-03 19:12:13 d6e03d8c777cfa2d35e3b60d8ec3e0187f3e9f99d8e2ee9cac695fd6fcdf1a24" +#define SQLITE_VERSION "3.53.3" +#define SQLITE_VERSION_NUMBER 3053003 +#define SQLITE_SOURCE_ID "2026-06-26 20:14:12 d4c0e51e4aeb96955b99185ab9cde75c339e2c29c3f3f12428d364a10d782c62" #define SQLITE_SCM_BRANCH "branch-3.53" -#define SQLITE_SCM_TAGS "release version-3.53.2" -#define SQLITE_SCM_DATETIME "2026-06-03T19:12:13.350Z" +#define SQLITE_SCM_TAGS "release version-3.53.3" +#define SQLITE_SCM_DATETIME "2026-06-26T20:14:12.354Z" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -4366,7 +4366,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); ** or in an ORDER BY or GROUP BY clause.
)^ ** ** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(
SQLITE_LIMIT_EXPR_DEPTH
-**
The maximum depth of the parse tree on any expression.
)^ +**
The maximum depth of the parse tree on any expression and +** the maximum nesting depth for subqueries and VIEWs
)^ ** ** [[SQLITE_LIMIT_PARSER_DEPTH]] ^(
SQLITE_LIMIT_PARSER_DEPTH
**
The maximum depth of the LALR(1) parser stack used to analyze @@ -4397,7 +4398,8 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal); **
The maximum index number of any [parameter] in an SQL statement.)^ ** ** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(
SQLITE_LIMIT_TRIGGER_DEPTH
-**
The maximum depth of recursion for triggers.
)^ +**
The maximum depth of recursion for triggers, and the maximum +** nesting depth for separate triggers.
)^ ** ** [[SQLITE_LIMIT_WORKER_THREADS]] ^(
SQLITE_LIMIT_WORKER_THREADS
**
The maximum number of auxiliary worker threads that a single From 2e500ba7b08f8dd6bc01900e31e13b82a5cfcd14 Mon Sep 17 00:00:00 2001 From: "Node.js GitHub Bot" Date: Mon, 29 Jun 2026 21:26:08 -0400 Subject: [PATCH 060/131] deps: update googletest to 8b53336594cc52213c6c2c7a0b29194fa896d039 PR-URL: https://github.com/nodejs/node/pull/64181 Reviewed-By: Luigi Pinca Reviewed-By: Antoine du Hamel Reviewed-By: Colin Ihrig --- .../include/gtest/gtest-assertion-result.h | 3 +- .../googletest/include/gtest/gtest-matchers.h | 49 +++++++++---------- .../googletest/include/gtest/gtest-printers.h | 6 +-- deps/googletest/include/gtest/gtest.h | 4 +- 4 files changed, 29 insertions(+), 33 deletions(-) diff --git a/deps/googletest/include/gtest/gtest-assertion-result.h b/deps/googletest/include/gtest/gtest-assertion-result.h index 52a6d62c77ec2f..7a5e223fa211e0 100644 --- a/deps/googletest/include/gtest/gtest-assertion-result.h +++ b/deps/googletest/include/gtest/gtest-assertion-result.h @@ -161,8 +161,7 @@ class GTEST_API_ [[nodiscard]] AssertionResult { template explicit AssertionResult( const T& success, - typename std::enable_if< - !std::is_convertible::value>::type* + std::enable_if_t>* /*enabler*/ = nullptr) : success_(success) {} diff --git a/deps/googletest/include/gtest/gtest-matchers.h b/deps/googletest/include/gtest/gtest-matchers.h index 6d2ab14d2ad9bd..d7bdd047f1a6f1 100644 --- a/deps/googletest/include/gtest/gtest-matchers.h +++ b/deps/googletest/include/gtest/gtest-matchers.h @@ -277,8 +277,8 @@ class [[nodiscard]] MatcherBase : private MatcherDescriberInterface { Init(impl); } - template ::type::is_gtest_matcher> + template ::is_gtest_matcher> MatcherBase(M&& m) : vtable_(nullptr), buffer_() { // NOLINT Init(std::forward(m)); } @@ -363,11 +363,10 @@ class [[nodiscard]] MatcherBase : private MatcherDescriberInterface { // from the impl, but some users really want to get their impl back when // they call GetDescriber(). // We use std::get on a tuple as a workaround of not having `if constexpr`. - return std::get<( - std::is_convertible::value - ? 1 - : 0)>(std::make_tuple(&m, &P::Get(m))); + return std::get<(std::is_convertible_v + ? 1 + : 0)>(std::make_tuple(&m, &P::Get(m))); } template @@ -396,8 +395,8 @@ class [[nodiscard]] MatcherBase : private MatcherDescriberInterface { template static constexpr bool IsInlined() { return sizeof(M) <= sizeof(Buffer) && alignof(M) <= alignof(Buffer) && - std::is_trivially_copy_constructible::value && - std::is_trivially_destructible::value; + std::is_trivially_copy_constructible_v && + std::is_trivially_destructible_v; } template ()> @@ -444,7 +443,7 @@ class [[nodiscard]] MatcherBase : private MatcherDescriberInterface { template void Init(M&& m) { - using MM = typename std::decay::type; + using MM = std::decay_t; using Policy = ValuePolicy; vtable_ = GetVTable(); Policy::Init(*this, std::forward(m)); @@ -473,14 +472,12 @@ class [[nodiscard]] Matcher : public internal::MatcherBase { : internal::MatcherBase(impl) {} template - explicit Matcher( - const MatcherInterface* impl, - typename std::enable_if::value>::type* = - nullptr) + explicit Matcher(const MatcherInterface* impl, + std::enable_if_t>* = nullptr) : internal::MatcherBase(impl) {} - template ::type::is_gtest_matcher> + template ::is_gtest_matcher> Matcher(M&& m) : internal::MatcherBase(std::forward(m)) {} // NOLINT // Implicit constructor here allows people to write @@ -509,8 +506,8 @@ Matcher : public internal::MatcherBase { explicit Matcher(const MatcherInterface* impl) : internal::MatcherBase(impl) {} - template ::type::is_gtest_matcher> + template ::is_gtest_matcher> Matcher(M&& m) // NOLINT : internal::MatcherBase(std::forward(m)) {} @@ -533,8 +530,8 @@ Matcher : public internal::MatcherBase { explicit Matcher(const MatcherInterface* impl) : internal::MatcherBase(impl) {} - template ::type::is_gtest_matcher> + template ::is_gtest_matcher> Matcher(M&& m) // NOLINT : internal::MatcherBase(std::forward(m)) {} @@ -559,8 +556,8 @@ class GTEST_API_ [[nodiscard]] Matcher explicit Matcher(const MatcherInterface* impl) : internal::MatcherBase(impl) {} - template ::type::is_gtest_matcher> + template ::is_gtest_matcher> Matcher(M&& m) // NOLINT : internal::MatcherBase(std::forward(m)) { } @@ -587,8 +584,8 @@ class GTEST_API_ [[nodiscard]] Matcher explicit Matcher(const MatcherInterface* impl) : internal::MatcherBase(impl) {} - template ::type::is_gtest_matcher> + template ::is_gtest_matcher> Matcher(M&& m) // NOLINT : internal::MatcherBase(std::forward(m)) {} @@ -815,8 +812,8 @@ class [[nodiscard]] ImplicitCastEqMatcher { StoredRhs stored_rhs_; }; -template ::value>::type> +template >> using StringLike = T; // Implements polymorphic matchers MatchesRegex(regex) and diff --git a/deps/googletest/include/gtest/gtest-printers.h b/deps/googletest/include/gtest/gtest-printers.h index d1704bb7580a96..a13815733effde 100644 --- a/deps/googletest/include/gtest/gtest-printers.h +++ b/deps/googletest/include/gtest/gtest-printers.h @@ -863,8 +863,8 @@ void PrintTupleTo(const T& t, std::integral_constant, GTEST_INTENTIONAL_CONST_COND_POP_() *os << ", "; } - UniversalPrinter::type>::Print( - std::get(t), os); + UniversalPrinter>::Print(std::get(t), + os); } template @@ -1218,7 +1218,7 @@ template Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { Strings result; TersePrintPrefixToStrings( - value, std::integral_constant::value>(), + value, std::integral_constant>(), &result); return result; } diff --git a/deps/googletest/include/gtest/gtest.h b/deps/googletest/include/gtest/gtest.h index f4a91ee44d0aeb..a7193379b9ffaa 100644 --- a/deps/googletest/include/gtest/gtest.h +++ b/deps/googletest/include/gtest/gtest.h @@ -2164,7 +2164,7 @@ class GTEST_API_ [[nodiscard]] ScopedTrace { // to cause a compiler error. template constexpr bool StaticAssertTypeEq() noexcept { - static_assert(std::is_same::value, "T1 and T2 are not the same type"); + static_assert(std::is_same_v, "T1 and T2 are not the same type"); return true; } @@ -2310,7 +2310,7 @@ template TestInfo* RegisterTest(const char* test_suite_name, const char* test_name, const char* type_param, const char* value_param, const char* file, int line, Factory factory) { - using TestT = typename std::remove_pointer::type; + using TestT = std::remove_pointer_t; class FactoryImpl : public internal::TestFactoryBase { public: From af9102980134b851abead1d918510ffd14b97865 Mon Sep 17 00:00:00 2001 From: "Node.js GitHub Bot" Date: Mon, 29 Jun 2026 21:26:21 -0400 Subject: [PATCH 061/131] deps: update nghttp3 to 1.17.0 PR-URL: https://github.com/nodejs/node/pull/64182 Reviewed-By: Matteo Collina Reviewed-By: Tim Perry --- .../nghttp3/lib/includes/nghttp3/nghttp3.h | 88 + .../nghttp3/lib/includes/nghttp3/version.h | 4 +- deps/ngtcp2/nghttp3/lib/nghttp3_conn.c | 22 + deps/ngtcp2/nghttp3/lib/nghttp3_conv.c | 9 + deps/ngtcp2/nghttp3/lib/nghttp3_conv.h | 40 - deps/ngtcp2/nghttp3/lib/nghttp3_http.c | 9 +- .../nghttp3/lib/nghttp3_qpack_huffman.c | 8 +- .../nghttp3/lib/nghttp3_qpack_huffman.h | 25 +- .../nghttp3/lib/nghttp3_qpack_huffman_data.c | 8227 +++++++++-------- deps/ngtcp2/nghttp3/lib/nghttp3_str.c | 132 +- deps/ngtcp2/nghttp3/lib/nghttp3_str.h | 10 + deps/ngtcp2/nghttp3/lib/sfparse/sfparse.c | 38 +- deps/ngtcp2/nghttp3/lib/sfparse/sfparse.h | 4 +- 13 files changed, 4351 insertions(+), 4265 deletions(-) diff --git a/deps/ngtcp2/nghttp3/lib/includes/nghttp3/nghttp3.h b/deps/ngtcp2/nghttp3/lib/includes/nghttp3/nghttp3.h index db001e15369119..83999a34d17b81 100644 --- a/deps/ngtcp2/nghttp3/lib/includes/nghttp3/nghttp3.h +++ b/deps/ngtcp2/nghttp3/lib/includes/nghttp3/nghttp3.h @@ -2625,6 +2625,25 @@ NGHTTP3_EXTERN nghttp3_ssize nghttp3_conn_writev_stream(nghttp3_conn *conn, NGHTTP3_EXTERN int nghttp3_conn_add_write_offset(nghttp3_conn *conn, int64_t stream_id, size_t n); +/** + * @function + * + * `nghttp3_conn_is_stream_flushed` returns nonzero if all stream data + * for a stream identified by |stream_id| so far have been accepted by + * QUIC stack. This means that the cumulative number of bytes that + * `nghttp3_conn_add_write_offset` notified covers all stream data + * currently held. This does not mean more stream data cannot be + * submitted to this stream via :type:`nghttp3_read_data_callback` and + * all stream data have been acknowledged. + * + * If there is no stream identified by |stream_id|, this function + * returns nonzero. + * + * .. version-added:: 1.17.0 + */ +NGHTTP3_EXTERN int nghttp3_conn_is_stream_flushed(const nghttp3_conn *conn, + int64_t stream_id); + /** * @function * @@ -3418,6 +3437,75 @@ NGHTTP3_EXTERN const nghttp3_info *nghttp3_version(int least_version); */ NGHTTP3_EXTERN int nghttp3_err_is_fatal(int liberr); +/** + * @function + * + * `nghttp3_get_uvarint` reads variable-length unsigned integer from + * the buffer pointed by |p|, and stores it in the object pointed by + * |dest| in host byte order. It returns |p| plus the number of bytes + * read from |p|. This function assumes that |p| points to the buffer + * that contains a valid variable-length unsigned integer. Use + * `nghttp3_get_uvarintlen` to get the number of bytes to successfully + * decode an integer. + * + * .. version-added:: 1.17.0 + */ +NGHTTP3_EXTERN const uint8_t *nghttp3_get_uvarint(uint64_t *dest, + const uint8_t *p); + +/** + * @function + * + * `nghttp3_get_uvarintlen` returns the required number of bytes to + * read variable-length unsigned integer starting at |p|. |p| must + * not be NULL. This function only reads the single byte from the + * buffer pointed by |p|, and determines the number of bytes to read. + * + * .. version-added:: 1.17.0 + */ +NGHTTP3_EXTERN size_t nghttp3_get_uvarintlen(const uint8_t *p); + +/** + * @function + * + * `nghttp3_get_varint` reads variable-length unsigned integer from + * the buffer pointed by |p|, and stores it in the object pointed by + * |dest| in host byte order. It returns |p| plus the number of bytes + * read from |p|. This function assumes that |p| points to the buffer + * that contains a valid variable-length unsigned integer. Use + * `nghttp3_get_uvarintlen` to get the number of bytes to successfully + * decode an integer. + * + * .. version-added:: 1.17.0 + */ +NGHTTP3_EXTERN const uint8_t *nghttp3_get_varint(int64_t *dest, + const uint8_t *p); + +/** + * @function + * + * `nghttp3_put_uvarint` writes |n| to the buffer pointed by |p| using + * variable-length unsigned integer encoding. It returns the one + * beyond of the last written position. This function assumes that + * the buffer pointed by |p| has sufficient capacity to encode |n|. + * To know the required capacity, use `nghttp3_put_uvarintlen`. |n| + * must be less than or equal to (1 << 62) - 1. + * + * .. version-added:: 1.17.0 + */ +NGHTTP3_EXTERN uint8_t *nghttp3_put_uvarint(uint8_t *p, uint64_t n); + +/** + * @function + * + * `nghttp3_put_uvarintlen` returns the required number of bytes to + * encode |n| in variable-length unsigned integer encoding. |n| must + * be less than or equal to (1 << 62) - 1. + * + * .. version-added:: 1.17.0 + */ +NGHTTP3_EXTERN size_t nghttp3_put_uvarintlen(uint64_t n); + /* * Versioned function wrappers */ diff --git a/deps/ngtcp2/nghttp3/lib/includes/nghttp3/version.h b/deps/ngtcp2/nghttp3/lib/includes/nghttp3/version.h index a0b397f05a8275..6f9f04e7426b95 100644 --- a/deps/ngtcp2/nghttp3/lib/includes/nghttp3/version.h +++ b/deps/ngtcp2/nghttp3/lib/includes/nghttp3/version.h @@ -31,7 +31,7 @@ * * Version number of the nghttp3 library release. */ -#define NGHTTP3_VERSION "1.16.0" +#define NGHTTP3_VERSION "1.17.0" /** * @macro @@ -41,6 +41,6 @@ * number, 8 bits for minor and 8 bits for patch. Version 1.2.3 * becomes 0x010203. */ -#define NGHTTP3_VERSION_NUM 0x011000 +#define NGHTTP3_VERSION_NUM 0x011100 #endif /* !defined(NGHTTP3_VERSION_H) */ diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_conn.c b/deps/ngtcp2/nghttp3/lib/nghttp3_conn.c index 05f6973bcafb26..d1b6355bb7e036 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_conn.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_conn.c @@ -2979,3 +2979,25 @@ int nghttp3_conn_is_drained2(const nghttp3_conn *conn) { nghttp3_stream_outq_write_done(conn->tx.ctrl) && nghttp3_ringbuf_len(&conn->tx.ctrl->frq) == 0; } + +int nghttp3_conn_is_stream_flushed(const nghttp3_conn *conn, + int64_t stream_id) { + nghttp3_stream *stream = nghttp3_conn_find_stream(conn, stream_id); + const nghttp3_frame *fr; + + if (!stream) { + return 1; + } + + if (!nghttp3_stream_outq_write_done(stream)) { + return 0; + } + + if (nghttp3_ringbuf_len(&stream->frq) == 0) { + return 1; + } + + fr = nghttp3_ringbuf_get(&stream->frq, 0); + + return fr->hd.type == NGHTTP3_FRAME_DATA; +} diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_conv.c b/deps/ngtcp2/nghttp3/lib/nghttp3_conv.c index 2a89a3c76e6c13..031ac78d815f85 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_conv.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_conv.c @@ -70,6 +70,15 @@ size_t nghttp3_get_uvarintlen(const uint8_t *p) { return (size_t)(1U << (*p >> 6)); } +const uint8_t *nghttp3_get_varint(int64_t *dest, const uint8_t *p) { + uint64_t n; + + p = nghttp3_get_uvarint(&n, p); + *dest = (int64_t)n; + + return p; +} + uint8_t *nghttp3_put_uint64be(uint8_t *p, uint64_t n) { n = nghttp3_htonl64(n); return nghttp3_cpymem(p, (const uint8_t *)&n, sizeof(n)); diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_conv.h b/deps/ngtcp2/nghttp3/lib/nghttp3_conv.h index 47856131049945..bd1c518fa6638d 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_conv.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_conv.h @@ -92,34 +92,6 @@ # define ntohs(N) _byteswap_ushort(N) #endif /* defined(WIN32) */ -/* - * nghttp3_get_uvarint reads variable-length unsigned integer from - * |p|, and stores it in the buffer pointed by |dest| in host byte - * order. It returns |p| plus the number of bytes read from |p|. - */ -const uint8_t *nghttp3_get_uvarint(uint64_t *dest, const uint8_t *p); - -/* - * nghttp3_get_uvarintlen returns the required number of bytes to read - * variable-length integer starting at |p|. - */ -size_t nghttp3_get_uvarintlen(const uint8_t *p); - -/* - * nghttp3_get_varint reads variable-length unsigned integer from |p|, - * and stores it in the buffer pointed by |dest| in host byte order. - * It returns |p| plus the number of bytes read from |p|. - */ -static inline const uint8_t *nghttp3_get_varint(int64_t *dest, - const uint8_t *p) { - uint64_t n; - - p = nghttp3_get_uvarint(&n, p); - *dest = (int64_t)n; - - return p; -} - /* * nghttp3_put_uint64be writes |n| in host byte order in |p| in * network byte order. It returns the one beyond of the last written @@ -141,18 +113,6 @@ uint8_t *nghttp3_put_uint32be(uint8_t *p, uint32_t n); */ uint8_t *nghttp3_put_uint16be(uint8_t *p, uint16_t n); -/* - * nghttp3_put_uvarint writes |n| in |p| using variable-length integer - * encoding. It returns the one beyond of the last written position. - */ -uint8_t *nghttp3_put_uvarint(uint8_t *p, uint64_t n); - -/* - * nghttp3_put_uvarintlen returns the required number of bytes to - * encode |n|. - */ -size_t nghttp3_put_uvarintlen(uint64_t n); - /* * nghttp3_ord_stream_id returns the ordinal number of |stream_id|. */ diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_http.c b/deps/ngtcp2/nghttp3/lib/nghttp3_http.c index 95e1474f9aef5e..4194a404b33f97 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_http.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_http.c @@ -36,12 +36,9 @@ #include "nghttp3_macro.h" #include "nghttp3_conv.h" #include "nghttp3_unreachable.h" +#include "nghttp3_str.h" #include "sfparse/sfparse.h" -static uint8_t downcase(uint8_t c) { - return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c; -} - /* * memieq returns 1 if the data pointed by |a| of length |n| equals to * |b| of the same length in case-insensitive manner. The data @@ -52,7 +49,7 @@ static int memieq(const void *a, const void *b, size_t n) { const uint8_t *aa = a, *bb = b; for (i = 0; i < n; ++i) { - if (aa[i] != downcase(bb[i])) { + if (aa[i] != nghttp3_downcase_byte(bb[i])) { return 0; } } @@ -704,7 +701,7 @@ int nghttp3_check_header_name(const uint8_t *name, size_t len) { --len; } for (last = name + len; name != last; ++name) { - if (!VALID_HD_NAME_CHARS[*name]) { + if (VALID_HD_NAME_CHARS[*name] != 1) { return 0; } } diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman.c b/deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman.c index b784ca9970c0b4..618e95cc4ee235 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman.c @@ -80,7 +80,7 @@ uint8_t *nghttp3_qpack_huffman_encode(uint8_t *dest, const uint8_t *src, void nghttp3_qpack_huffman_decode_context_init( nghttp3_qpack_huffman_decode_context *ctx) { *ctx = (nghttp3_qpack_huffman_decode_context){ - .flags = NGHTTP3_QPACK_HUFFMAN_ACCEPTED, + .flags = NGHTTP3_QPACK_HUFFMAN_FLAG_ACCEPTED, }; } @@ -103,12 +103,12 @@ nghttp3_qpack_huffman_decode(nghttp3_qpack_huffman_decode_context *ctx, for (; src != end;) { c = *src++; t = qpack_huffman_decode_table[t.fstate][c >> 4]; - if (t.flags & NGHTTP3_QPACK_HUFFMAN_SYM) { + if (t.flags & NGHTTP3_QPACK_HUFFMAN_FLAG_SYM) { *p++ = t.sym; } t = qpack_huffman_decode_table[t.fstate][c & 0xFU]; - if (t.flags & NGHTTP3_QPACK_HUFFMAN_SYM) { + if (t.flags & NGHTTP3_QPACK_HUFFMAN_FLAG_SYM) { *p++ = t.sym; } } @@ -116,7 +116,7 @@ nghttp3_qpack_huffman_decode(nghttp3_qpack_huffman_decode_context *ctx, ctx->fstate = t.fstate; ctx->flags = t.flags; - if (fin && !(ctx->flags & NGHTTP3_QPACK_HUFFMAN_ACCEPTED)) { + if (fin && !(ctx->flags & NGHTTP3_QPACK_HUFFMAN_FLAG_ACCEPTED)) { return NGHTTP3_ERR_QPACK_FATAL; } diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman.h b/deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman.h index 2fce4de6f011ec..a7d788dcb964be 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman.h @@ -46,25 +46,24 @@ size_t nghttp3_qpack_huffman_encode_count(const uint8_t *src, size_t len); uint8_t *nghttp3_qpack_huffman_encode(uint8_t *dest, const uint8_t *src, size_t srclen); -typedef enum nghttp3_qpack_huffman_decode_flag { - /* FSA accepts this state as the end of huffman encoding - sequence. */ - NGHTTP3_QPACK_HUFFMAN_ACCEPTED = 1, - /* This state emits symbol */ - NGHTTP3_QPACK_HUFFMAN_SYM = 1 << 1, -} nghttp3_qpack_huffman_decode_flag; +/* NGHTTP3_QPACK_HUFFMAN_FLAG_ACCEPTED indicates that FSA accepts this + state as the end of huffman encoding sequence. */ +#define NGHTTP3_QPACK_HUFFMAN_FLAG_ACCEPTED 0x01U +/* NGHTTP3_QPACK_HUFFMAN_FLAG_SYM indicates that this state emits + symbol */ +#define NGHTTP3_QPACK_HUFFMAN_FLAG_SYM 0x02U typedef struct nghttp3_qpack_huffman_decode_node { /* fstate is the current huffman decoding state, which is actually the node ID of internal huffman tree with - nghttp3_qpack_huffman_decode_flag OR-ed. We have 257 leaf nodes, - but they are identical to root node other than emitting a symbol, - so we have 256 internal nodes [1..256], inclusive. The node ID - 256 is a special node and it is a terminal state that means - decoding failed. */ + NGHTTP3_QPACK_HUFFMAN_FLAG_* flags OR-ed. We have 257 leaf + nodes, but they are identical to root node other than emitting a + symbol, so we have 256 internal nodes [1..256], inclusive. The + node ID 256 is a special node and it is a terminal state that + means decoding failed. */ uint16_t fstate; uint8_t flags; - /* symbol if NGHTTP3_QPACK_HUFFMAN_SYM flag set */ + /* symbol if NGHTTP3_QPACK_HUFFMAN_FLAG_SYM flag set */ uint8_t sym; } nghttp3_qpack_huffman_decode_node; diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman_data.c b/deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman_data.c index ffe8fcafadb667..9a6614a1539783 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman_data.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_qpack_huffman_data.c @@ -92,4890 +92,4891 @@ const nghttp3_qpack_huffman_sym huffman_sym_table[] = { {27, 0xFFFFFCE0U}, {27, 0xFFFFFD00U}, {27, 0xFFFFFD20U}, {27, 0xFFFFFD40U}, {27, 0xFFFFFD60U}, {28, 0xFFFFFFE0U}, {27, 0xFFFFFD80U}, {27, 0xFFFFFDA0U}, {27, 0xFFFFFDC0U}, {27, 0xFFFFFDE0U}, {27, 0xFFFFFE00U}, {26, 0xFFFFFB80U}, - {30, 0xFFFFFFFCU}}; + {30, 0xFFFFFFFCU}, +}; const nghttp3_qpack_huffman_decode_node qpack_huffman_decode_table[][16] = { /* 0 */ { - {0x04, 0, 0}, - {0x05, 0, 0}, - {0x07, 0, 0}, - {0x08, 0, 0}, - {0x0B, 0, 0}, - {0x0C, 0, 0}, - {0x10, 0, 0}, - {0x13, 0, 0}, - {0x19, 0, 0}, - {0x1C, 0, 0}, - {0x20, 0, 0}, - {0x23, 0, 0}, - {0x2A, 0, 0}, - {0x31, 0, 0}, - {0x39, 0, 0}, - {0x40, 1, 0}, + {0x04, 0x00, 0x00}, + {0x05, 0x00, 0x00}, + {0x07, 0x00, 0x00}, + {0x08, 0x00, 0x00}, + {0x0B, 0x00, 0x00}, + {0x0C, 0x00, 0x00}, + {0x10, 0x00, 0x00}, + {0x13, 0x00, 0x00}, + {0x19, 0x00, 0x00}, + {0x1C, 0x00, 0x00}, + {0x20, 0x00, 0x00}, + {0x23, 0x00, 0x00}, + {0x2A, 0x00, 0x00}, + {0x31, 0x00, 0x00}, + {0x39, 0x00, 0x00}, + {0x40, 0x01, 0x00}, }, /* 1 */ { - {0x00, 3, 48}, - {0x00, 3, 49}, - {0x00, 3, 50}, - {0x00, 3, 97}, - {0x00, 3, 99}, - {0x00, 3, 101}, - {0x00, 3, 105}, - {0x00, 3, 111}, - {0x00, 3, 115}, - {0x00, 3, 116}, - {0x0D, 0, 0}, - {0x0E, 0, 0}, - {0x11, 0, 0}, - {0x12, 0, 0}, - {0x14, 0, 0}, - {0x15, 0, 0}, + {0x00, 0x03, 0x30}, + {0x00, 0x03, 0x31}, + {0x00, 0x03, 0x32}, + {0x00, 0x03, 0x61}, + {0x00, 0x03, 0x63}, + {0x00, 0x03, 0x65}, + {0x00, 0x03, 0x69}, + {0x00, 0x03, 0x6F}, + {0x00, 0x03, 0x73}, + {0x00, 0x03, 0x74}, + {0x0D, 0x00, 0x00}, + {0x0E, 0x00, 0x00}, + {0x11, 0x00, 0x00}, + {0x12, 0x00, 0x00}, + {0x14, 0x00, 0x00}, + {0x15, 0x00, 0x00}, }, /* 2 */ { - {0x01, 2, 48}, - {0x16, 3, 48}, - {0x01, 2, 49}, - {0x16, 3, 49}, - {0x01, 2, 50}, - {0x16, 3, 50}, - {0x01, 2, 97}, - {0x16, 3, 97}, - {0x01, 2, 99}, - {0x16, 3, 99}, - {0x01, 2, 101}, - {0x16, 3, 101}, - {0x01, 2, 105}, - {0x16, 3, 105}, - {0x01, 2, 111}, - {0x16, 3, 111}, + {0x01, 0x02, 0x30}, + {0x16, 0x03, 0x30}, + {0x01, 0x02, 0x31}, + {0x16, 0x03, 0x31}, + {0x01, 0x02, 0x32}, + {0x16, 0x03, 0x32}, + {0x01, 0x02, 0x61}, + {0x16, 0x03, 0x61}, + {0x01, 0x02, 0x63}, + {0x16, 0x03, 0x63}, + {0x01, 0x02, 0x65}, + {0x16, 0x03, 0x65}, + {0x01, 0x02, 0x69}, + {0x16, 0x03, 0x69}, + {0x01, 0x02, 0x6F}, + {0x16, 0x03, 0x6F}, }, /* 3 */ { - {0x02, 2, 48}, - {0x09, 2, 48}, - {0x17, 2, 48}, - {0x28, 3, 48}, - {0x02, 2, 49}, - {0x09, 2, 49}, - {0x17, 2, 49}, - {0x28, 3, 49}, - {0x02, 2, 50}, - {0x09, 2, 50}, - {0x17, 2, 50}, - {0x28, 3, 50}, - {0x02, 2, 97}, - {0x09, 2, 97}, - {0x17, 2, 97}, - {0x28, 3, 97}, + {0x02, 0x02, 0x30}, + {0x09, 0x02, 0x30}, + {0x17, 0x02, 0x30}, + {0x28, 0x03, 0x30}, + {0x02, 0x02, 0x31}, + {0x09, 0x02, 0x31}, + {0x17, 0x02, 0x31}, + {0x28, 0x03, 0x31}, + {0x02, 0x02, 0x32}, + {0x09, 0x02, 0x32}, + {0x17, 0x02, 0x32}, + {0x28, 0x03, 0x32}, + {0x02, 0x02, 0x61}, + {0x09, 0x02, 0x61}, + {0x17, 0x02, 0x61}, + {0x28, 0x03, 0x61}, }, /* 4 */ { - {0x03, 2, 48}, - {0x06, 2, 48}, - {0x0A, 2, 48}, - {0x0F, 2, 48}, - {0x18, 2, 48}, - {0x1F, 2, 48}, - {0x29, 2, 48}, - {0x38, 3, 48}, - {0x03, 2, 49}, - {0x06, 2, 49}, - {0x0A, 2, 49}, - {0x0F, 2, 49}, - {0x18, 2, 49}, - {0x1F, 2, 49}, - {0x29, 2, 49}, - {0x38, 3, 49}, + {0x03, 0x02, 0x30}, + {0x06, 0x02, 0x30}, + {0x0A, 0x02, 0x30}, + {0x0F, 0x02, 0x30}, + {0x18, 0x02, 0x30}, + {0x1F, 0x02, 0x30}, + {0x29, 0x02, 0x30}, + {0x38, 0x03, 0x30}, + {0x03, 0x02, 0x31}, + {0x06, 0x02, 0x31}, + {0x0A, 0x02, 0x31}, + {0x0F, 0x02, 0x31}, + {0x18, 0x02, 0x31}, + {0x1F, 0x02, 0x31}, + {0x29, 0x02, 0x31}, + {0x38, 0x03, 0x31}, }, /* 5 */ { - {0x03, 2, 50}, - {0x06, 2, 50}, - {0x0A, 2, 50}, - {0x0F, 2, 50}, - {0x18, 2, 50}, - {0x1F, 2, 50}, - {0x29, 2, 50}, - {0x38, 3, 50}, - {0x03, 2, 97}, - {0x06, 2, 97}, - {0x0A, 2, 97}, - {0x0F, 2, 97}, - {0x18, 2, 97}, - {0x1F, 2, 97}, - {0x29, 2, 97}, - {0x38, 3, 97}, + {0x03, 0x02, 0x32}, + {0x06, 0x02, 0x32}, + {0x0A, 0x02, 0x32}, + {0x0F, 0x02, 0x32}, + {0x18, 0x02, 0x32}, + {0x1F, 0x02, 0x32}, + {0x29, 0x02, 0x32}, + {0x38, 0x03, 0x32}, + {0x03, 0x02, 0x61}, + {0x06, 0x02, 0x61}, + {0x0A, 0x02, 0x61}, + {0x0F, 0x02, 0x61}, + {0x18, 0x02, 0x61}, + {0x1F, 0x02, 0x61}, + {0x29, 0x02, 0x61}, + {0x38, 0x03, 0x61}, }, /* 6 */ { - {0x02, 2, 99}, - {0x09, 2, 99}, - {0x17, 2, 99}, - {0x28, 3, 99}, - {0x02, 2, 101}, - {0x09, 2, 101}, - {0x17, 2, 101}, - {0x28, 3, 101}, - {0x02, 2, 105}, - {0x09, 2, 105}, - {0x17, 2, 105}, - {0x28, 3, 105}, - {0x02, 2, 111}, - {0x09, 2, 111}, - {0x17, 2, 111}, - {0x28, 3, 111}, + {0x02, 0x02, 0x63}, + {0x09, 0x02, 0x63}, + {0x17, 0x02, 0x63}, + {0x28, 0x03, 0x63}, + {0x02, 0x02, 0x65}, + {0x09, 0x02, 0x65}, + {0x17, 0x02, 0x65}, + {0x28, 0x03, 0x65}, + {0x02, 0x02, 0x69}, + {0x09, 0x02, 0x69}, + {0x17, 0x02, 0x69}, + {0x28, 0x03, 0x69}, + {0x02, 0x02, 0x6F}, + {0x09, 0x02, 0x6F}, + {0x17, 0x02, 0x6F}, + {0x28, 0x03, 0x6F}, }, /* 7 */ { - {0x03, 2, 99}, - {0x06, 2, 99}, - {0x0A, 2, 99}, - {0x0F, 2, 99}, - {0x18, 2, 99}, - {0x1F, 2, 99}, - {0x29, 2, 99}, - {0x38, 3, 99}, - {0x03, 2, 101}, - {0x06, 2, 101}, - {0x0A, 2, 101}, - {0x0F, 2, 101}, - {0x18, 2, 101}, - {0x1F, 2, 101}, - {0x29, 2, 101}, - {0x38, 3, 101}, + {0x03, 0x02, 0x63}, + {0x06, 0x02, 0x63}, + {0x0A, 0x02, 0x63}, + {0x0F, 0x02, 0x63}, + {0x18, 0x02, 0x63}, + {0x1F, 0x02, 0x63}, + {0x29, 0x02, 0x63}, + {0x38, 0x03, 0x63}, + {0x03, 0x02, 0x65}, + {0x06, 0x02, 0x65}, + {0x0A, 0x02, 0x65}, + {0x0F, 0x02, 0x65}, + {0x18, 0x02, 0x65}, + {0x1F, 0x02, 0x65}, + {0x29, 0x02, 0x65}, + {0x38, 0x03, 0x65}, }, /* 8 */ { - {0x03, 2, 105}, - {0x06, 2, 105}, - {0x0A, 2, 105}, - {0x0F, 2, 105}, - {0x18, 2, 105}, - {0x1F, 2, 105}, - {0x29, 2, 105}, - {0x38, 3, 105}, - {0x03, 2, 111}, - {0x06, 2, 111}, - {0x0A, 2, 111}, - {0x0F, 2, 111}, - {0x18, 2, 111}, - {0x1F, 2, 111}, - {0x29, 2, 111}, - {0x38, 3, 111}, + {0x03, 0x02, 0x69}, + {0x06, 0x02, 0x69}, + {0x0A, 0x02, 0x69}, + {0x0F, 0x02, 0x69}, + {0x18, 0x02, 0x69}, + {0x1F, 0x02, 0x69}, + {0x29, 0x02, 0x69}, + {0x38, 0x03, 0x69}, + {0x03, 0x02, 0x6F}, + {0x06, 0x02, 0x6F}, + {0x0A, 0x02, 0x6F}, + {0x0F, 0x02, 0x6F}, + {0x18, 0x02, 0x6F}, + {0x1F, 0x02, 0x6F}, + {0x29, 0x02, 0x6F}, + {0x38, 0x03, 0x6F}, }, /* 9 */ { - {0x01, 2, 115}, - {0x16, 3, 115}, - {0x01, 2, 116}, - {0x16, 3, 116}, - {0x00, 3, 32}, - {0x00, 3, 37}, - {0x00, 3, 45}, - {0x00, 3, 46}, - {0x00, 3, 47}, - {0x00, 3, 51}, - {0x00, 3, 52}, - {0x00, 3, 53}, - {0x00, 3, 54}, - {0x00, 3, 55}, - {0x00, 3, 56}, - {0x00, 3, 57}, + {0x01, 0x02, 0x73}, + {0x16, 0x03, 0x73}, + {0x01, 0x02, 0x74}, + {0x16, 0x03, 0x74}, + {0x00, 0x03, 0x20}, + {0x00, 0x03, 0x25}, + {0x00, 0x03, 0x2D}, + {0x00, 0x03, 0x2E}, + {0x00, 0x03, 0x2F}, + {0x00, 0x03, 0x33}, + {0x00, 0x03, 0x34}, + {0x00, 0x03, 0x35}, + {0x00, 0x03, 0x36}, + {0x00, 0x03, 0x37}, + {0x00, 0x03, 0x38}, + {0x00, 0x03, 0x39}, }, /* 10 */ { - {0x02, 2, 115}, - {0x09, 2, 115}, - {0x17, 2, 115}, - {0x28, 3, 115}, - {0x02, 2, 116}, - {0x09, 2, 116}, - {0x17, 2, 116}, - {0x28, 3, 116}, - {0x01, 2, 32}, - {0x16, 3, 32}, - {0x01, 2, 37}, - {0x16, 3, 37}, - {0x01, 2, 45}, - {0x16, 3, 45}, - {0x01, 2, 46}, - {0x16, 3, 46}, + {0x02, 0x02, 0x73}, + {0x09, 0x02, 0x73}, + {0x17, 0x02, 0x73}, + {0x28, 0x03, 0x73}, + {0x02, 0x02, 0x74}, + {0x09, 0x02, 0x74}, + {0x17, 0x02, 0x74}, + {0x28, 0x03, 0x74}, + {0x01, 0x02, 0x20}, + {0x16, 0x03, 0x20}, + {0x01, 0x02, 0x25}, + {0x16, 0x03, 0x25}, + {0x01, 0x02, 0x2D}, + {0x16, 0x03, 0x2D}, + {0x01, 0x02, 0x2E}, + {0x16, 0x03, 0x2E}, }, /* 11 */ { - {0x03, 2, 115}, - {0x06, 2, 115}, - {0x0A, 2, 115}, - {0x0F, 2, 115}, - {0x18, 2, 115}, - {0x1F, 2, 115}, - {0x29, 2, 115}, - {0x38, 3, 115}, - {0x03, 2, 116}, - {0x06, 2, 116}, - {0x0A, 2, 116}, - {0x0F, 2, 116}, - {0x18, 2, 116}, - {0x1F, 2, 116}, - {0x29, 2, 116}, - {0x38, 3, 116}, + {0x03, 0x02, 0x73}, + {0x06, 0x02, 0x73}, + {0x0A, 0x02, 0x73}, + {0x0F, 0x02, 0x73}, + {0x18, 0x02, 0x73}, + {0x1F, 0x02, 0x73}, + {0x29, 0x02, 0x73}, + {0x38, 0x03, 0x73}, + {0x03, 0x02, 0x74}, + {0x06, 0x02, 0x74}, + {0x0A, 0x02, 0x74}, + {0x0F, 0x02, 0x74}, + {0x18, 0x02, 0x74}, + {0x1F, 0x02, 0x74}, + {0x29, 0x02, 0x74}, + {0x38, 0x03, 0x74}, }, /* 12 */ { - {0x02, 2, 32}, - {0x09, 2, 32}, - {0x17, 2, 32}, - {0x28, 3, 32}, - {0x02, 2, 37}, - {0x09, 2, 37}, - {0x17, 2, 37}, - {0x28, 3, 37}, - {0x02, 2, 45}, - {0x09, 2, 45}, - {0x17, 2, 45}, - {0x28, 3, 45}, - {0x02, 2, 46}, - {0x09, 2, 46}, - {0x17, 2, 46}, - {0x28, 3, 46}, + {0x02, 0x02, 0x20}, + {0x09, 0x02, 0x20}, + {0x17, 0x02, 0x20}, + {0x28, 0x03, 0x20}, + {0x02, 0x02, 0x25}, + {0x09, 0x02, 0x25}, + {0x17, 0x02, 0x25}, + {0x28, 0x03, 0x25}, + {0x02, 0x02, 0x2D}, + {0x09, 0x02, 0x2D}, + {0x17, 0x02, 0x2D}, + {0x28, 0x03, 0x2D}, + {0x02, 0x02, 0x2E}, + {0x09, 0x02, 0x2E}, + {0x17, 0x02, 0x2E}, + {0x28, 0x03, 0x2E}, }, /* 13 */ { - {0x03, 2, 32}, - {0x06, 2, 32}, - {0x0A, 2, 32}, - {0x0F, 2, 32}, - {0x18, 2, 32}, - {0x1F, 2, 32}, - {0x29, 2, 32}, - {0x38, 3, 32}, - {0x03, 2, 37}, - {0x06, 2, 37}, - {0x0A, 2, 37}, - {0x0F, 2, 37}, - {0x18, 2, 37}, - {0x1F, 2, 37}, - {0x29, 2, 37}, - {0x38, 3, 37}, + {0x03, 0x02, 0x20}, + {0x06, 0x02, 0x20}, + {0x0A, 0x02, 0x20}, + {0x0F, 0x02, 0x20}, + {0x18, 0x02, 0x20}, + {0x1F, 0x02, 0x20}, + {0x29, 0x02, 0x20}, + {0x38, 0x03, 0x20}, + {0x03, 0x02, 0x25}, + {0x06, 0x02, 0x25}, + {0x0A, 0x02, 0x25}, + {0x0F, 0x02, 0x25}, + {0x18, 0x02, 0x25}, + {0x1F, 0x02, 0x25}, + {0x29, 0x02, 0x25}, + {0x38, 0x03, 0x25}, }, /* 14 */ { - {0x03, 2, 45}, - {0x06, 2, 45}, - {0x0A, 2, 45}, - {0x0F, 2, 45}, - {0x18, 2, 45}, - {0x1F, 2, 45}, - {0x29, 2, 45}, - {0x38, 3, 45}, - {0x03, 2, 46}, - {0x06, 2, 46}, - {0x0A, 2, 46}, - {0x0F, 2, 46}, - {0x18, 2, 46}, - {0x1F, 2, 46}, - {0x29, 2, 46}, - {0x38, 3, 46}, + {0x03, 0x02, 0x2D}, + {0x06, 0x02, 0x2D}, + {0x0A, 0x02, 0x2D}, + {0x0F, 0x02, 0x2D}, + {0x18, 0x02, 0x2D}, + {0x1F, 0x02, 0x2D}, + {0x29, 0x02, 0x2D}, + {0x38, 0x03, 0x2D}, + {0x03, 0x02, 0x2E}, + {0x06, 0x02, 0x2E}, + {0x0A, 0x02, 0x2E}, + {0x0F, 0x02, 0x2E}, + {0x18, 0x02, 0x2E}, + {0x1F, 0x02, 0x2E}, + {0x29, 0x02, 0x2E}, + {0x38, 0x03, 0x2E}, }, /* 15 */ { - {0x01, 2, 47}, - {0x16, 3, 47}, - {0x01, 2, 51}, - {0x16, 3, 51}, - {0x01, 2, 52}, - {0x16, 3, 52}, - {0x01, 2, 53}, - {0x16, 3, 53}, - {0x01, 2, 54}, - {0x16, 3, 54}, - {0x01, 2, 55}, - {0x16, 3, 55}, - {0x01, 2, 56}, - {0x16, 3, 56}, - {0x01, 2, 57}, - {0x16, 3, 57}, + {0x01, 0x02, 0x2F}, + {0x16, 0x03, 0x2F}, + {0x01, 0x02, 0x33}, + {0x16, 0x03, 0x33}, + {0x01, 0x02, 0x34}, + {0x16, 0x03, 0x34}, + {0x01, 0x02, 0x35}, + {0x16, 0x03, 0x35}, + {0x01, 0x02, 0x36}, + {0x16, 0x03, 0x36}, + {0x01, 0x02, 0x37}, + {0x16, 0x03, 0x37}, + {0x01, 0x02, 0x38}, + {0x16, 0x03, 0x38}, + {0x01, 0x02, 0x39}, + {0x16, 0x03, 0x39}, }, /* 16 */ { - {0x02, 2, 47}, - {0x09, 2, 47}, - {0x17, 2, 47}, - {0x28, 3, 47}, - {0x02, 2, 51}, - {0x09, 2, 51}, - {0x17, 2, 51}, - {0x28, 3, 51}, - {0x02, 2, 52}, - {0x09, 2, 52}, - {0x17, 2, 52}, - {0x28, 3, 52}, - {0x02, 2, 53}, - {0x09, 2, 53}, - {0x17, 2, 53}, - {0x28, 3, 53}, + {0x02, 0x02, 0x2F}, + {0x09, 0x02, 0x2F}, + {0x17, 0x02, 0x2F}, + {0x28, 0x03, 0x2F}, + {0x02, 0x02, 0x33}, + {0x09, 0x02, 0x33}, + {0x17, 0x02, 0x33}, + {0x28, 0x03, 0x33}, + {0x02, 0x02, 0x34}, + {0x09, 0x02, 0x34}, + {0x17, 0x02, 0x34}, + {0x28, 0x03, 0x34}, + {0x02, 0x02, 0x35}, + {0x09, 0x02, 0x35}, + {0x17, 0x02, 0x35}, + {0x28, 0x03, 0x35}, }, /* 17 */ { - {0x03, 2, 47}, - {0x06, 2, 47}, - {0x0A, 2, 47}, - {0x0F, 2, 47}, - {0x18, 2, 47}, - {0x1F, 2, 47}, - {0x29, 2, 47}, - {0x38, 3, 47}, - {0x03, 2, 51}, - {0x06, 2, 51}, - {0x0A, 2, 51}, - {0x0F, 2, 51}, - {0x18, 2, 51}, - {0x1F, 2, 51}, - {0x29, 2, 51}, - {0x38, 3, 51}, + {0x03, 0x02, 0x2F}, + {0x06, 0x02, 0x2F}, + {0x0A, 0x02, 0x2F}, + {0x0F, 0x02, 0x2F}, + {0x18, 0x02, 0x2F}, + {0x1F, 0x02, 0x2F}, + {0x29, 0x02, 0x2F}, + {0x38, 0x03, 0x2F}, + {0x03, 0x02, 0x33}, + {0x06, 0x02, 0x33}, + {0x0A, 0x02, 0x33}, + {0x0F, 0x02, 0x33}, + {0x18, 0x02, 0x33}, + {0x1F, 0x02, 0x33}, + {0x29, 0x02, 0x33}, + {0x38, 0x03, 0x33}, }, /* 18 */ { - {0x03, 2, 52}, - {0x06, 2, 52}, - {0x0A, 2, 52}, - {0x0F, 2, 52}, - {0x18, 2, 52}, - {0x1F, 2, 52}, - {0x29, 2, 52}, - {0x38, 3, 52}, - {0x03, 2, 53}, - {0x06, 2, 53}, - {0x0A, 2, 53}, - {0x0F, 2, 53}, - {0x18, 2, 53}, - {0x1F, 2, 53}, - {0x29, 2, 53}, - {0x38, 3, 53}, + {0x03, 0x02, 0x34}, + {0x06, 0x02, 0x34}, + {0x0A, 0x02, 0x34}, + {0x0F, 0x02, 0x34}, + {0x18, 0x02, 0x34}, + {0x1F, 0x02, 0x34}, + {0x29, 0x02, 0x34}, + {0x38, 0x03, 0x34}, + {0x03, 0x02, 0x35}, + {0x06, 0x02, 0x35}, + {0x0A, 0x02, 0x35}, + {0x0F, 0x02, 0x35}, + {0x18, 0x02, 0x35}, + {0x1F, 0x02, 0x35}, + {0x29, 0x02, 0x35}, + {0x38, 0x03, 0x35}, }, /* 19 */ { - {0x02, 2, 54}, - {0x09, 2, 54}, - {0x17, 2, 54}, - {0x28, 3, 54}, - {0x02, 2, 55}, - {0x09, 2, 55}, - {0x17, 2, 55}, - {0x28, 3, 55}, - {0x02, 2, 56}, - {0x09, 2, 56}, - {0x17, 2, 56}, - {0x28, 3, 56}, - {0x02, 2, 57}, - {0x09, 2, 57}, - {0x17, 2, 57}, - {0x28, 3, 57}, + {0x02, 0x02, 0x36}, + {0x09, 0x02, 0x36}, + {0x17, 0x02, 0x36}, + {0x28, 0x03, 0x36}, + {0x02, 0x02, 0x37}, + {0x09, 0x02, 0x37}, + {0x17, 0x02, 0x37}, + {0x28, 0x03, 0x37}, + {0x02, 0x02, 0x38}, + {0x09, 0x02, 0x38}, + {0x17, 0x02, 0x38}, + {0x28, 0x03, 0x38}, + {0x02, 0x02, 0x39}, + {0x09, 0x02, 0x39}, + {0x17, 0x02, 0x39}, + {0x28, 0x03, 0x39}, }, /* 20 */ { - {0x03, 2, 54}, - {0x06, 2, 54}, - {0x0A, 2, 54}, - {0x0F, 2, 54}, - {0x18, 2, 54}, - {0x1F, 2, 54}, - {0x29, 2, 54}, - {0x38, 3, 54}, - {0x03, 2, 55}, - {0x06, 2, 55}, - {0x0A, 2, 55}, - {0x0F, 2, 55}, - {0x18, 2, 55}, - {0x1F, 2, 55}, - {0x29, 2, 55}, - {0x38, 3, 55}, + {0x03, 0x02, 0x36}, + {0x06, 0x02, 0x36}, + {0x0A, 0x02, 0x36}, + {0x0F, 0x02, 0x36}, + {0x18, 0x02, 0x36}, + {0x1F, 0x02, 0x36}, + {0x29, 0x02, 0x36}, + {0x38, 0x03, 0x36}, + {0x03, 0x02, 0x37}, + {0x06, 0x02, 0x37}, + {0x0A, 0x02, 0x37}, + {0x0F, 0x02, 0x37}, + {0x18, 0x02, 0x37}, + {0x1F, 0x02, 0x37}, + {0x29, 0x02, 0x37}, + {0x38, 0x03, 0x37}, }, /* 21 */ { - {0x03, 2, 56}, - {0x06, 2, 56}, - {0x0A, 2, 56}, - {0x0F, 2, 56}, - {0x18, 2, 56}, - {0x1F, 2, 56}, - {0x29, 2, 56}, - {0x38, 3, 56}, - {0x03, 2, 57}, - {0x06, 2, 57}, - {0x0A, 2, 57}, - {0x0F, 2, 57}, - {0x18, 2, 57}, - {0x1F, 2, 57}, - {0x29, 2, 57}, - {0x38, 3, 57}, + {0x03, 0x02, 0x38}, + {0x06, 0x02, 0x38}, + {0x0A, 0x02, 0x38}, + {0x0F, 0x02, 0x38}, + {0x18, 0x02, 0x38}, + {0x1F, 0x02, 0x38}, + {0x29, 0x02, 0x38}, + {0x38, 0x03, 0x38}, + {0x03, 0x02, 0x39}, + {0x06, 0x02, 0x39}, + {0x0A, 0x02, 0x39}, + {0x0F, 0x02, 0x39}, + {0x18, 0x02, 0x39}, + {0x1F, 0x02, 0x39}, + {0x29, 0x02, 0x39}, + {0x38, 0x03, 0x39}, }, /* 22 */ { - {0x1A, 0, 0}, - {0x1B, 0, 0}, - {0x1D, 0, 0}, - {0x1E, 0, 0}, - {0x21, 0, 0}, - {0x22, 0, 0}, - {0x24, 0, 0}, - {0x25, 0, 0}, - {0x2B, 0, 0}, - {0x2E, 0, 0}, - {0x32, 0, 0}, - {0x35, 0, 0}, - {0x3A, 0, 0}, - {0x3D, 0, 0}, - {0x41, 0, 0}, - {0x44, 1, 0}, + {0x1A, 0x00, 0x00}, + {0x1B, 0x00, 0x00}, + {0x1D, 0x00, 0x00}, + {0x1E, 0x00, 0x00}, + {0x21, 0x00, 0x00}, + {0x22, 0x00, 0x00}, + {0x24, 0x00, 0x00}, + {0x25, 0x00, 0x00}, + {0x2B, 0x00, 0x00}, + {0x2E, 0x00, 0x00}, + {0x32, 0x00, 0x00}, + {0x35, 0x00, 0x00}, + {0x3A, 0x00, 0x00}, + {0x3D, 0x00, 0x00}, + {0x41, 0x00, 0x00}, + {0x44, 0x01, 0x00}, }, /* 23 */ { - {0x00, 3, 61}, - {0x00, 3, 65}, - {0x00, 3, 95}, - {0x00, 3, 98}, - {0x00, 3, 100}, - {0x00, 3, 102}, - {0x00, 3, 103}, - {0x00, 3, 104}, - {0x00, 3, 108}, - {0x00, 3, 109}, - {0x00, 3, 110}, - {0x00, 3, 112}, - {0x00, 3, 114}, - {0x00, 3, 117}, - {0x26, 0, 0}, - {0x27, 0, 0}, + {0x00, 0x03, 0x3D}, + {0x00, 0x03, 0x41}, + {0x00, 0x03, 0x5F}, + {0x00, 0x03, 0x62}, + {0x00, 0x03, 0x64}, + {0x00, 0x03, 0x66}, + {0x00, 0x03, 0x67}, + {0x00, 0x03, 0x68}, + {0x00, 0x03, 0x6C}, + {0x00, 0x03, 0x6D}, + {0x00, 0x03, 0x6E}, + {0x00, 0x03, 0x70}, + {0x00, 0x03, 0x72}, + {0x00, 0x03, 0x75}, + {0x26, 0x00, 0x00}, + {0x27, 0x00, 0x00}, }, /* 24 */ { - {0x01, 2, 61}, - {0x16, 3, 61}, - {0x01, 2, 65}, - {0x16, 3, 65}, - {0x01, 2, 95}, - {0x16, 3, 95}, - {0x01, 2, 98}, - {0x16, 3, 98}, - {0x01, 2, 100}, - {0x16, 3, 100}, - {0x01, 2, 102}, - {0x16, 3, 102}, - {0x01, 2, 103}, - {0x16, 3, 103}, - {0x01, 2, 104}, - {0x16, 3, 104}, + {0x01, 0x02, 0x3D}, + {0x16, 0x03, 0x3D}, + {0x01, 0x02, 0x41}, + {0x16, 0x03, 0x41}, + {0x01, 0x02, 0x5F}, + {0x16, 0x03, 0x5F}, + {0x01, 0x02, 0x62}, + {0x16, 0x03, 0x62}, + {0x01, 0x02, 0x64}, + {0x16, 0x03, 0x64}, + {0x01, 0x02, 0x66}, + {0x16, 0x03, 0x66}, + {0x01, 0x02, 0x67}, + {0x16, 0x03, 0x67}, + {0x01, 0x02, 0x68}, + {0x16, 0x03, 0x68}, }, /* 25 */ { - {0x02, 2, 61}, - {0x09, 2, 61}, - {0x17, 2, 61}, - {0x28, 3, 61}, - {0x02, 2, 65}, - {0x09, 2, 65}, - {0x17, 2, 65}, - {0x28, 3, 65}, - {0x02, 2, 95}, - {0x09, 2, 95}, - {0x17, 2, 95}, - {0x28, 3, 95}, - {0x02, 2, 98}, - {0x09, 2, 98}, - {0x17, 2, 98}, - {0x28, 3, 98}, + {0x02, 0x02, 0x3D}, + {0x09, 0x02, 0x3D}, + {0x17, 0x02, 0x3D}, + {0x28, 0x03, 0x3D}, + {0x02, 0x02, 0x41}, + {0x09, 0x02, 0x41}, + {0x17, 0x02, 0x41}, + {0x28, 0x03, 0x41}, + {0x02, 0x02, 0x5F}, + {0x09, 0x02, 0x5F}, + {0x17, 0x02, 0x5F}, + {0x28, 0x03, 0x5F}, + {0x02, 0x02, 0x62}, + {0x09, 0x02, 0x62}, + {0x17, 0x02, 0x62}, + {0x28, 0x03, 0x62}, }, /* 26 */ { - {0x03, 2, 61}, - {0x06, 2, 61}, - {0x0A, 2, 61}, - {0x0F, 2, 61}, - {0x18, 2, 61}, - {0x1F, 2, 61}, - {0x29, 2, 61}, - {0x38, 3, 61}, - {0x03, 2, 65}, - {0x06, 2, 65}, - {0x0A, 2, 65}, - {0x0F, 2, 65}, - {0x18, 2, 65}, - {0x1F, 2, 65}, - {0x29, 2, 65}, - {0x38, 3, 65}, + {0x03, 0x02, 0x3D}, + {0x06, 0x02, 0x3D}, + {0x0A, 0x02, 0x3D}, + {0x0F, 0x02, 0x3D}, + {0x18, 0x02, 0x3D}, + {0x1F, 0x02, 0x3D}, + {0x29, 0x02, 0x3D}, + {0x38, 0x03, 0x3D}, + {0x03, 0x02, 0x41}, + {0x06, 0x02, 0x41}, + {0x0A, 0x02, 0x41}, + {0x0F, 0x02, 0x41}, + {0x18, 0x02, 0x41}, + {0x1F, 0x02, 0x41}, + {0x29, 0x02, 0x41}, + {0x38, 0x03, 0x41}, }, /* 27 */ { - {0x03, 2, 95}, - {0x06, 2, 95}, - {0x0A, 2, 95}, - {0x0F, 2, 95}, - {0x18, 2, 95}, - {0x1F, 2, 95}, - {0x29, 2, 95}, - {0x38, 3, 95}, - {0x03, 2, 98}, - {0x06, 2, 98}, - {0x0A, 2, 98}, - {0x0F, 2, 98}, - {0x18, 2, 98}, - {0x1F, 2, 98}, - {0x29, 2, 98}, - {0x38, 3, 98}, + {0x03, 0x02, 0x5F}, + {0x06, 0x02, 0x5F}, + {0x0A, 0x02, 0x5F}, + {0x0F, 0x02, 0x5F}, + {0x18, 0x02, 0x5F}, + {0x1F, 0x02, 0x5F}, + {0x29, 0x02, 0x5F}, + {0x38, 0x03, 0x5F}, + {0x03, 0x02, 0x62}, + {0x06, 0x02, 0x62}, + {0x0A, 0x02, 0x62}, + {0x0F, 0x02, 0x62}, + {0x18, 0x02, 0x62}, + {0x1F, 0x02, 0x62}, + {0x29, 0x02, 0x62}, + {0x38, 0x03, 0x62}, }, /* 28 */ { - {0x02, 2, 100}, - {0x09, 2, 100}, - {0x17, 2, 100}, - {0x28, 3, 100}, - {0x02, 2, 102}, - {0x09, 2, 102}, - {0x17, 2, 102}, - {0x28, 3, 102}, - {0x02, 2, 103}, - {0x09, 2, 103}, - {0x17, 2, 103}, - {0x28, 3, 103}, - {0x02, 2, 104}, - {0x09, 2, 104}, - {0x17, 2, 104}, - {0x28, 3, 104}, + {0x02, 0x02, 0x64}, + {0x09, 0x02, 0x64}, + {0x17, 0x02, 0x64}, + {0x28, 0x03, 0x64}, + {0x02, 0x02, 0x66}, + {0x09, 0x02, 0x66}, + {0x17, 0x02, 0x66}, + {0x28, 0x03, 0x66}, + {0x02, 0x02, 0x67}, + {0x09, 0x02, 0x67}, + {0x17, 0x02, 0x67}, + {0x28, 0x03, 0x67}, + {0x02, 0x02, 0x68}, + {0x09, 0x02, 0x68}, + {0x17, 0x02, 0x68}, + {0x28, 0x03, 0x68}, }, /* 29 */ { - {0x03, 2, 100}, - {0x06, 2, 100}, - {0x0A, 2, 100}, - {0x0F, 2, 100}, - {0x18, 2, 100}, - {0x1F, 2, 100}, - {0x29, 2, 100}, - {0x38, 3, 100}, - {0x03, 2, 102}, - {0x06, 2, 102}, - {0x0A, 2, 102}, - {0x0F, 2, 102}, - {0x18, 2, 102}, - {0x1F, 2, 102}, - {0x29, 2, 102}, - {0x38, 3, 102}, + {0x03, 0x02, 0x64}, + {0x06, 0x02, 0x64}, + {0x0A, 0x02, 0x64}, + {0x0F, 0x02, 0x64}, + {0x18, 0x02, 0x64}, + {0x1F, 0x02, 0x64}, + {0x29, 0x02, 0x64}, + {0x38, 0x03, 0x64}, + {0x03, 0x02, 0x66}, + {0x06, 0x02, 0x66}, + {0x0A, 0x02, 0x66}, + {0x0F, 0x02, 0x66}, + {0x18, 0x02, 0x66}, + {0x1F, 0x02, 0x66}, + {0x29, 0x02, 0x66}, + {0x38, 0x03, 0x66}, }, /* 30 */ { - {0x03, 2, 103}, - {0x06, 2, 103}, - {0x0A, 2, 103}, - {0x0F, 2, 103}, - {0x18, 2, 103}, - {0x1F, 2, 103}, - {0x29, 2, 103}, - {0x38, 3, 103}, - {0x03, 2, 104}, - {0x06, 2, 104}, - {0x0A, 2, 104}, - {0x0F, 2, 104}, - {0x18, 2, 104}, - {0x1F, 2, 104}, - {0x29, 2, 104}, - {0x38, 3, 104}, + {0x03, 0x02, 0x67}, + {0x06, 0x02, 0x67}, + {0x0A, 0x02, 0x67}, + {0x0F, 0x02, 0x67}, + {0x18, 0x02, 0x67}, + {0x1F, 0x02, 0x67}, + {0x29, 0x02, 0x67}, + {0x38, 0x03, 0x67}, + {0x03, 0x02, 0x68}, + {0x06, 0x02, 0x68}, + {0x0A, 0x02, 0x68}, + {0x0F, 0x02, 0x68}, + {0x18, 0x02, 0x68}, + {0x1F, 0x02, 0x68}, + {0x29, 0x02, 0x68}, + {0x38, 0x03, 0x68}, }, /* 31 */ { - {0x01, 2, 108}, - {0x16, 3, 108}, - {0x01, 2, 109}, - {0x16, 3, 109}, - {0x01, 2, 110}, - {0x16, 3, 110}, - {0x01, 2, 112}, - {0x16, 3, 112}, - {0x01, 2, 114}, - {0x16, 3, 114}, - {0x01, 2, 117}, - {0x16, 3, 117}, - {0x00, 3, 58}, - {0x00, 3, 66}, - {0x00, 3, 67}, - {0x00, 3, 68}, + {0x01, 0x02, 0x6C}, + {0x16, 0x03, 0x6C}, + {0x01, 0x02, 0x6D}, + {0x16, 0x03, 0x6D}, + {0x01, 0x02, 0x6E}, + {0x16, 0x03, 0x6E}, + {0x01, 0x02, 0x70}, + {0x16, 0x03, 0x70}, + {0x01, 0x02, 0x72}, + {0x16, 0x03, 0x72}, + {0x01, 0x02, 0x75}, + {0x16, 0x03, 0x75}, + {0x00, 0x03, 0x3A}, + {0x00, 0x03, 0x42}, + {0x00, 0x03, 0x43}, + {0x00, 0x03, 0x44}, }, /* 32 */ { - {0x02, 2, 108}, - {0x09, 2, 108}, - {0x17, 2, 108}, - {0x28, 3, 108}, - {0x02, 2, 109}, - {0x09, 2, 109}, - {0x17, 2, 109}, - {0x28, 3, 109}, - {0x02, 2, 110}, - {0x09, 2, 110}, - {0x17, 2, 110}, - {0x28, 3, 110}, - {0x02, 2, 112}, - {0x09, 2, 112}, - {0x17, 2, 112}, - {0x28, 3, 112}, + {0x02, 0x02, 0x6C}, + {0x09, 0x02, 0x6C}, + {0x17, 0x02, 0x6C}, + {0x28, 0x03, 0x6C}, + {0x02, 0x02, 0x6D}, + {0x09, 0x02, 0x6D}, + {0x17, 0x02, 0x6D}, + {0x28, 0x03, 0x6D}, + {0x02, 0x02, 0x6E}, + {0x09, 0x02, 0x6E}, + {0x17, 0x02, 0x6E}, + {0x28, 0x03, 0x6E}, + {0x02, 0x02, 0x70}, + {0x09, 0x02, 0x70}, + {0x17, 0x02, 0x70}, + {0x28, 0x03, 0x70}, }, /* 33 */ { - {0x03, 2, 108}, - {0x06, 2, 108}, - {0x0A, 2, 108}, - {0x0F, 2, 108}, - {0x18, 2, 108}, - {0x1F, 2, 108}, - {0x29, 2, 108}, - {0x38, 3, 108}, - {0x03, 2, 109}, - {0x06, 2, 109}, - {0x0A, 2, 109}, - {0x0F, 2, 109}, - {0x18, 2, 109}, - {0x1F, 2, 109}, - {0x29, 2, 109}, - {0x38, 3, 109}, + {0x03, 0x02, 0x6C}, + {0x06, 0x02, 0x6C}, + {0x0A, 0x02, 0x6C}, + {0x0F, 0x02, 0x6C}, + {0x18, 0x02, 0x6C}, + {0x1F, 0x02, 0x6C}, + {0x29, 0x02, 0x6C}, + {0x38, 0x03, 0x6C}, + {0x03, 0x02, 0x6D}, + {0x06, 0x02, 0x6D}, + {0x0A, 0x02, 0x6D}, + {0x0F, 0x02, 0x6D}, + {0x18, 0x02, 0x6D}, + {0x1F, 0x02, 0x6D}, + {0x29, 0x02, 0x6D}, + {0x38, 0x03, 0x6D}, }, /* 34 */ { - {0x03, 2, 110}, - {0x06, 2, 110}, - {0x0A, 2, 110}, - {0x0F, 2, 110}, - {0x18, 2, 110}, - {0x1F, 2, 110}, - {0x29, 2, 110}, - {0x38, 3, 110}, - {0x03, 2, 112}, - {0x06, 2, 112}, - {0x0A, 2, 112}, - {0x0F, 2, 112}, - {0x18, 2, 112}, - {0x1F, 2, 112}, - {0x29, 2, 112}, - {0x38, 3, 112}, + {0x03, 0x02, 0x6E}, + {0x06, 0x02, 0x6E}, + {0x0A, 0x02, 0x6E}, + {0x0F, 0x02, 0x6E}, + {0x18, 0x02, 0x6E}, + {0x1F, 0x02, 0x6E}, + {0x29, 0x02, 0x6E}, + {0x38, 0x03, 0x6E}, + {0x03, 0x02, 0x70}, + {0x06, 0x02, 0x70}, + {0x0A, 0x02, 0x70}, + {0x0F, 0x02, 0x70}, + {0x18, 0x02, 0x70}, + {0x1F, 0x02, 0x70}, + {0x29, 0x02, 0x70}, + {0x38, 0x03, 0x70}, }, /* 35 */ { - {0x02, 2, 114}, - {0x09, 2, 114}, - {0x17, 2, 114}, - {0x28, 3, 114}, - {0x02, 2, 117}, - {0x09, 2, 117}, - {0x17, 2, 117}, - {0x28, 3, 117}, - {0x01, 2, 58}, - {0x16, 3, 58}, - {0x01, 2, 66}, - {0x16, 3, 66}, - {0x01, 2, 67}, - {0x16, 3, 67}, - {0x01, 2, 68}, - {0x16, 3, 68}, + {0x02, 0x02, 0x72}, + {0x09, 0x02, 0x72}, + {0x17, 0x02, 0x72}, + {0x28, 0x03, 0x72}, + {0x02, 0x02, 0x75}, + {0x09, 0x02, 0x75}, + {0x17, 0x02, 0x75}, + {0x28, 0x03, 0x75}, + {0x01, 0x02, 0x3A}, + {0x16, 0x03, 0x3A}, + {0x01, 0x02, 0x42}, + {0x16, 0x03, 0x42}, + {0x01, 0x02, 0x43}, + {0x16, 0x03, 0x43}, + {0x01, 0x02, 0x44}, + {0x16, 0x03, 0x44}, }, /* 36 */ { - {0x03, 2, 114}, - {0x06, 2, 114}, - {0x0A, 2, 114}, - {0x0F, 2, 114}, - {0x18, 2, 114}, - {0x1F, 2, 114}, - {0x29, 2, 114}, - {0x38, 3, 114}, - {0x03, 2, 117}, - {0x06, 2, 117}, - {0x0A, 2, 117}, - {0x0F, 2, 117}, - {0x18, 2, 117}, - {0x1F, 2, 117}, - {0x29, 2, 117}, - {0x38, 3, 117}, + {0x03, 0x02, 0x72}, + {0x06, 0x02, 0x72}, + {0x0A, 0x02, 0x72}, + {0x0F, 0x02, 0x72}, + {0x18, 0x02, 0x72}, + {0x1F, 0x02, 0x72}, + {0x29, 0x02, 0x72}, + {0x38, 0x03, 0x72}, + {0x03, 0x02, 0x75}, + {0x06, 0x02, 0x75}, + {0x0A, 0x02, 0x75}, + {0x0F, 0x02, 0x75}, + {0x18, 0x02, 0x75}, + {0x1F, 0x02, 0x75}, + {0x29, 0x02, 0x75}, + {0x38, 0x03, 0x75}, }, /* 37 */ { - {0x02, 2, 58}, - {0x09, 2, 58}, - {0x17, 2, 58}, - {0x28, 3, 58}, - {0x02, 2, 66}, - {0x09, 2, 66}, - {0x17, 2, 66}, - {0x28, 3, 66}, - {0x02, 2, 67}, - {0x09, 2, 67}, - {0x17, 2, 67}, - {0x28, 3, 67}, - {0x02, 2, 68}, - {0x09, 2, 68}, - {0x17, 2, 68}, - {0x28, 3, 68}, + {0x02, 0x02, 0x3A}, + {0x09, 0x02, 0x3A}, + {0x17, 0x02, 0x3A}, + {0x28, 0x03, 0x3A}, + {0x02, 0x02, 0x42}, + {0x09, 0x02, 0x42}, + {0x17, 0x02, 0x42}, + {0x28, 0x03, 0x42}, + {0x02, 0x02, 0x43}, + {0x09, 0x02, 0x43}, + {0x17, 0x02, 0x43}, + {0x28, 0x03, 0x43}, + {0x02, 0x02, 0x44}, + {0x09, 0x02, 0x44}, + {0x17, 0x02, 0x44}, + {0x28, 0x03, 0x44}, }, /* 38 */ { - {0x03, 2, 58}, - {0x06, 2, 58}, - {0x0A, 2, 58}, - {0x0F, 2, 58}, - {0x18, 2, 58}, - {0x1F, 2, 58}, - {0x29, 2, 58}, - {0x38, 3, 58}, - {0x03, 2, 66}, - {0x06, 2, 66}, - {0x0A, 2, 66}, - {0x0F, 2, 66}, - {0x18, 2, 66}, - {0x1F, 2, 66}, - {0x29, 2, 66}, - {0x38, 3, 66}, + {0x03, 0x02, 0x3A}, + {0x06, 0x02, 0x3A}, + {0x0A, 0x02, 0x3A}, + {0x0F, 0x02, 0x3A}, + {0x18, 0x02, 0x3A}, + {0x1F, 0x02, 0x3A}, + {0x29, 0x02, 0x3A}, + {0x38, 0x03, 0x3A}, + {0x03, 0x02, 0x42}, + {0x06, 0x02, 0x42}, + {0x0A, 0x02, 0x42}, + {0x0F, 0x02, 0x42}, + {0x18, 0x02, 0x42}, + {0x1F, 0x02, 0x42}, + {0x29, 0x02, 0x42}, + {0x38, 0x03, 0x42}, }, /* 39 */ { - {0x03, 2, 67}, - {0x06, 2, 67}, - {0x0A, 2, 67}, - {0x0F, 2, 67}, - {0x18, 2, 67}, - {0x1F, 2, 67}, - {0x29, 2, 67}, - {0x38, 3, 67}, - {0x03, 2, 68}, - {0x06, 2, 68}, - {0x0A, 2, 68}, - {0x0F, 2, 68}, - {0x18, 2, 68}, - {0x1F, 2, 68}, - {0x29, 2, 68}, - {0x38, 3, 68}, + {0x03, 0x02, 0x43}, + {0x06, 0x02, 0x43}, + {0x0A, 0x02, 0x43}, + {0x0F, 0x02, 0x43}, + {0x18, 0x02, 0x43}, + {0x1F, 0x02, 0x43}, + {0x29, 0x02, 0x43}, + {0x38, 0x03, 0x43}, + {0x03, 0x02, 0x44}, + {0x06, 0x02, 0x44}, + {0x0A, 0x02, 0x44}, + {0x0F, 0x02, 0x44}, + {0x18, 0x02, 0x44}, + {0x1F, 0x02, 0x44}, + {0x29, 0x02, 0x44}, + {0x38, 0x03, 0x44}, }, /* 40 */ { - {0x2C, 0, 0}, - {0x2D, 0, 0}, - {0x2F, 0, 0}, - {0x30, 0, 0}, - {0x33, 0, 0}, - {0x34, 0, 0}, - {0x36, 0, 0}, - {0x37, 0, 0}, - {0x3B, 0, 0}, - {0x3C, 0, 0}, - {0x3E, 0, 0}, - {0x3F, 0, 0}, - {0x42, 0, 0}, - {0x43, 0, 0}, - {0x45, 0, 0}, - {0x48, 1, 0}, + {0x2C, 0x00, 0x00}, + {0x2D, 0x00, 0x00}, + {0x2F, 0x00, 0x00}, + {0x30, 0x00, 0x00}, + {0x33, 0x00, 0x00}, + {0x34, 0x00, 0x00}, + {0x36, 0x00, 0x00}, + {0x37, 0x00, 0x00}, + {0x3B, 0x00, 0x00}, + {0x3C, 0x00, 0x00}, + {0x3E, 0x00, 0x00}, + {0x3F, 0x00, 0x00}, + {0x42, 0x00, 0x00}, + {0x43, 0x00, 0x00}, + {0x45, 0x00, 0x00}, + {0x48, 0x01, 0x00}, }, /* 41 */ { - {0x00, 3, 69}, - {0x00, 3, 70}, - {0x00, 3, 71}, - {0x00, 3, 72}, - {0x00, 3, 73}, - {0x00, 3, 74}, - {0x00, 3, 75}, - {0x00, 3, 76}, - {0x00, 3, 77}, - {0x00, 3, 78}, - {0x00, 3, 79}, - {0x00, 3, 80}, - {0x00, 3, 81}, - {0x00, 3, 82}, - {0x00, 3, 83}, - {0x00, 3, 84}, + {0x00, 0x03, 0x45}, + {0x00, 0x03, 0x46}, + {0x00, 0x03, 0x47}, + {0x00, 0x03, 0x48}, + {0x00, 0x03, 0x49}, + {0x00, 0x03, 0x4A}, + {0x00, 0x03, 0x4B}, + {0x00, 0x03, 0x4C}, + {0x00, 0x03, 0x4D}, + {0x00, 0x03, 0x4E}, + {0x00, 0x03, 0x4F}, + {0x00, 0x03, 0x50}, + {0x00, 0x03, 0x51}, + {0x00, 0x03, 0x52}, + {0x00, 0x03, 0x53}, + {0x00, 0x03, 0x54}, }, /* 42 */ { - {0x01, 2, 69}, - {0x16, 3, 69}, - {0x01, 2, 70}, - {0x16, 3, 70}, - {0x01, 2, 71}, - {0x16, 3, 71}, - {0x01, 2, 72}, - {0x16, 3, 72}, - {0x01, 2, 73}, - {0x16, 3, 73}, - {0x01, 2, 74}, - {0x16, 3, 74}, - {0x01, 2, 75}, - {0x16, 3, 75}, - {0x01, 2, 76}, - {0x16, 3, 76}, + {0x01, 0x02, 0x45}, + {0x16, 0x03, 0x45}, + {0x01, 0x02, 0x46}, + {0x16, 0x03, 0x46}, + {0x01, 0x02, 0x47}, + {0x16, 0x03, 0x47}, + {0x01, 0x02, 0x48}, + {0x16, 0x03, 0x48}, + {0x01, 0x02, 0x49}, + {0x16, 0x03, 0x49}, + {0x01, 0x02, 0x4A}, + {0x16, 0x03, 0x4A}, + {0x01, 0x02, 0x4B}, + {0x16, 0x03, 0x4B}, + {0x01, 0x02, 0x4C}, + {0x16, 0x03, 0x4C}, }, /* 43 */ { - {0x02, 2, 69}, - {0x09, 2, 69}, - {0x17, 2, 69}, - {0x28, 3, 69}, - {0x02, 2, 70}, - {0x09, 2, 70}, - {0x17, 2, 70}, - {0x28, 3, 70}, - {0x02, 2, 71}, - {0x09, 2, 71}, - {0x17, 2, 71}, - {0x28, 3, 71}, - {0x02, 2, 72}, - {0x09, 2, 72}, - {0x17, 2, 72}, - {0x28, 3, 72}, + {0x02, 0x02, 0x45}, + {0x09, 0x02, 0x45}, + {0x17, 0x02, 0x45}, + {0x28, 0x03, 0x45}, + {0x02, 0x02, 0x46}, + {0x09, 0x02, 0x46}, + {0x17, 0x02, 0x46}, + {0x28, 0x03, 0x46}, + {0x02, 0x02, 0x47}, + {0x09, 0x02, 0x47}, + {0x17, 0x02, 0x47}, + {0x28, 0x03, 0x47}, + {0x02, 0x02, 0x48}, + {0x09, 0x02, 0x48}, + {0x17, 0x02, 0x48}, + {0x28, 0x03, 0x48}, }, /* 44 */ { - {0x03, 2, 69}, - {0x06, 2, 69}, - {0x0A, 2, 69}, - {0x0F, 2, 69}, - {0x18, 2, 69}, - {0x1F, 2, 69}, - {0x29, 2, 69}, - {0x38, 3, 69}, - {0x03, 2, 70}, - {0x06, 2, 70}, - {0x0A, 2, 70}, - {0x0F, 2, 70}, - {0x18, 2, 70}, - {0x1F, 2, 70}, - {0x29, 2, 70}, - {0x38, 3, 70}, + {0x03, 0x02, 0x45}, + {0x06, 0x02, 0x45}, + {0x0A, 0x02, 0x45}, + {0x0F, 0x02, 0x45}, + {0x18, 0x02, 0x45}, + {0x1F, 0x02, 0x45}, + {0x29, 0x02, 0x45}, + {0x38, 0x03, 0x45}, + {0x03, 0x02, 0x46}, + {0x06, 0x02, 0x46}, + {0x0A, 0x02, 0x46}, + {0x0F, 0x02, 0x46}, + {0x18, 0x02, 0x46}, + {0x1F, 0x02, 0x46}, + {0x29, 0x02, 0x46}, + {0x38, 0x03, 0x46}, }, /* 45 */ { - {0x03, 2, 71}, - {0x06, 2, 71}, - {0x0A, 2, 71}, - {0x0F, 2, 71}, - {0x18, 2, 71}, - {0x1F, 2, 71}, - {0x29, 2, 71}, - {0x38, 3, 71}, - {0x03, 2, 72}, - {0x06, 2, 72}, - {0x0A, 2, 72}, - {0x0F, 2, 72}, - {0x18, 2, 72}, - {0x1F, 2, 72}, - {0x29, 2, 72}, - {0x38, 3, 72}, + {0x03, 0x02, 0x47}, + {0x06, 0x02, 0x47}, + {0x0A, 0x02, 0x47}, + {0x0F, 0x02, 0x47}, + {0x18, 0x02, 0x47}, + {0x1F, 0x02, 0x47}, + {0x29, 0x02, 0x47}, + {0x38, 0x03, 0x47}, + {0x03, 0x02, 0x48}, + {0x06, 0x02, 0x48}, + {0x0A, 0x02, 0x48}, + {0x0F, 0x02, 0x48}, + {0x18, 0x02, 0x48}, + {0x1F, 0x02, 0x48}, + {0x29, 0x02, 0x48}, + {0x38, 0x03, 0x48}, }, /* 46 */ { - {0x02, 2, 73}, - {0x09, 2, 73}, - {0x17, 2, 73}, - {0x28, 3, 73}, - {0x02, 2, 74}, - {0x09, 2, 74}, - {0x17, 2, 74}, - {0x28, 3, 74}, - {0x02, 2, 75}, - {0x09, 2, 75}, - {0x17, 2, 75}, - {0x28, 3, 75}, - {0x02, 2, 76}, - {0x09, 2, 76}, - {0x17, 2, 76}, - {0x28, 3, 76}, + {0x02, 0x02, 0x49}, + {0x09, 0x02, 0x49}, + {0x17, 0x02, 0x49}, + {0x28, 0x03, 0x49}, + {0x02, 0x02, 0x4A}, + {0x09, 0x02, 0x4A}, + {0x17, 0x02, 0x4A}, + {0x28, 0x03, 0x4A}, + {0x02, 0x02, 0x4B}, + {0x09, 0x02, 0x4B}, + {0x17, 0x02, 0x4B}, + {0x28, 0x03, 0x4B}, + {0x02, 0x02, 0x4C}, + {0x09, 0x02, 0x4C}, + {0x17, 0x02, 0x4C}, + {0x28, 0x03, 0x4C}, }, /* 47 */ { - {0x03, 2, 73}, - {0x06, 2, 73}, - {0x0A, 2, 73}, - {0x0F, 2, 73}, - {0x18, 2, 73}, - {0x1F, 2, 73}, - {0x29, 2, 73}, - {0x38, 3, 73}, - {0x03, 2, 74}, - {0x06, 2, 74}, - {0x0A, 2, 74}, - {0x0F, 2, 74}, - {0x18, 2, 74}, - {0x1F, 2, 74}, - {0x29, 2, 74}, - {0x38, 3, 74}, + {0x03, 0x02, 0x49}, + {0x06, 0x02, 0x49}, + {0x0A, 0x02, 0x49}, + {0x0F, 0x02, 0x49}, + {0x18, 0x02, 0x49}, + {0x1F, 0x02, 0x49}, + {0x29, 0x02, 0x49}, + {0x38, 0x03, 0x49}, + {0x03, 0x02, 0x4A}, + {0x06, 0x02, 0x4A}, + {0x0A, 0x02, 0x4A}, + {0x0F, 0x02, 0x4A}, + {0x18, 0x02, 0x4A}, + {0x1F, 0x02, 0x4A}, + {0x29, 0x02, 0x4A}, + {0x38, 0x03, 0x4A}, }, /* 48 */ { - {0x03, 2, 75}, - {0x06, 2, 75}, - {0x0A, 2, 75}, - {0x0F, 2, 75}, - {0x18, 2, 75}, - {0x1F, 2, 75}, - {0x29, 2, 75}, - {0x38, 3, 75}, - {0x03, 2, 76}, - {0x06, 2, 76}, - {0x0A, 2, 76}, - {0x0F, 2, 76}, - {0x18, 2, 76}, - {0x1F, 2, 76}, - {0x29, 2, 76}, - {0x38, 3, 76}, + {0x03, 0x02, 0x4B}, + {0x06, 0x02, 0x4B}, + {0x0A, 0x02, 0x4B}, + {0x0F, 0x02, 0x4B}, + {0x18, 0x02, 0x4B}, + {0x1F, 0x02, 0x4B}, + {0x29, 0x02, 0x4B}, + {0x38, 0x03, 0x4B}, + {0x03, 0x02, 0x4C}, + {0x06, 0x02, 0x4C}, + {0x0A, 0x02, 0x4C}, + {0x0F, 0x02, 0x4C}, + {0x18, 0x02, 0x4C}, + {0x1F, 0x02, 0x4C}, + {0x29, 0x02, 0x4C}, + {0x38, 0x03, 0x4C}, }, /* 49 */ { - {0x01, 2, 77}, - {0x16, 3, 77}, - {0x01, 2, 78}, - {0x16, 3, 78}, - {0x01, 2, 79}, - {0x16, 3, 79}, - {0x01, 2, 80}, - {0x16, 3, 80}, - {0x01, 2, 81}, - {0x16, 3, 81}, - {0x01, 2, 82}, - {0x16, 3, 82}, - {0x01, 2, 83}, - {0x16, 3, 83}, - {0x01, 2, 84}, - {0x16, 3, 84}, + {0x01, 0x02, 0x4D}, + {0x16, 0x03, 0x4D}, + {0x01, 0x02, 0x4E}, + {0x16, 0x03, 0x4E}, + {0x01, 0x02, 0x4F}, + {0x16, 0x03, 0x4F}, + {0x01, 0x02, 0x50}, + {0x16, 0x03, 0x50}, + {0x01, 0x02, 0x51}, + {0x16, 0x03, 0x51}, + {0x01, 0x02, 0x52}, + {0x16, 0x03, 0x52}, + {0x01, 0x02, 0x53}, + {0x16, 0x03, 0x53}, + {0x01, 0x02, 0x54}, + {0x16, 0x03, 0x54}, }, /* 50 */ { - {0x02, 2, 77}, - {0x09, 2, 77}, - {0x17, 2, 77}, - {0x28, 3, 77}, - {0x02, 2, 78}, - {0x09, 2, 78}, - {0x17, 2, 78}, - {0x28, 3, 78}, - {0x02, 2, 79}, - {0x09, 2, 79}, - {0x17, 2, 79}, - {0x28, 3, 79}, - {0x02, 2, 80}, - {0x09, 2, 80}, - {0x17, 2, 80}, - {0x28, 3, 80}, + {0x02, 0x02, 0x4D}, + {0x09, 0x02, 0x4D}, + {0x17, 0x02, 0x4D}, + {0x28, 0x03, 0x4D}, + {0x02, 0x02, 0x4E}, + {0x09, 0x02, 0x4E}, + {0x17, 0x02, 0x4E}, + {0x28, 0x03, 0x4E}, + {0x02, 0x02, 0x4F}, + {0x09, 0x02, 0x4F}, + {0x17, 0x02, 0x4F}, + {0x28, 0x03, 0x4F}, + {0x02, 0x02, 0x50}, + {0x09, 0x02, 0x50}, + {0x17, 0x02, 0x50}, + {0x28, 0x03, 0x50}, }, /* 51 */ { - {0x03, 2, 77}, - {0x06, 2, 77}, - {0x0A, 2, 77}, - {0x0F, 2, 77}, - {0x18, 2, 77}, - {0x1F, 2, 77}, - {0x29, 2, 77}, - {0x38, 3, 77}, - {0x03, 2, 78}, - {0x06, 2, 78}, - {0x0A, 2, 78}, - {0x0F, 2, 78}, - {0x18, 2, 78}, - {0x1F, 2, 78}, - {0x29, 2, 78}, - {0x38, 3, 78}, + {0x03, 0x02, 0x4D}, + {0x06, 0x02, 0x4D}, + {0x0A, 0x02, 0x4D}, + {0x0F, 0x02, 0x4D}, + {0x18, 0x02, 0x4D}, + {0x1F, 0x02, 0x4D}, + {0x29, 0x02, 0x4D}, + {0x38, 0x03, 0x4D}, + {0x03, 0x02, 0x4E}, + {0x06, 0x02, 0x4E}, + {0x0A, 0x02, 0x4E}, + {0x0F, 0x02, 0x4E}, + {0x18, 0x02, 0x4E}, + {0x1F, 0x02, 0x4E}, + {0x29, 0x02, 0x4E}, + {0x38, 0x03, 0x4E}, }, /* 52 */ { - {0x03, 2, 79}, - {0x06, 2, 79}, - {0x0A, 2, 79}, - {0x0F, 2, 79}, - {0x18, 2, 79}, - {0x1F, 2, 79}, - {0x29, 2, 79}, - {0x38, 3, 79}, - {0x03, 2, 80}, - {0x06, 2, 80}, - {0x0A, 2, 80}, - {0x0F, 2, 80}, - {0x18, 2, 80}, - {0x1F, 2, 80}, - {0x29, 2, 80}, - {0x38, 3, 80}, + {0x03, 0x02, 0x4F}, + {0x06, 0x02, 0x4F}, + {0x0A, 0x02, 0x4F}, + {0x0F, 0x02, 0x4F}, + {0x18, 0x02, 0x4F}, + {0x1F, 0x02, 0x4F}, + {0x29, 0x02, 0x4F}, + {0x38, 0x03, 0x4F}, + {0x03, 0x02, 0x50}, + {0x06, 0x02, 0x50}, + {0x0A, 0x02, 0x50}, + {0x0F, 0x02, 0x50}, + {0x18, 0x02, 0x50}, + {0x1F, 0x02, 0x50}, + {0x29, 0x02, 0x50}, + {0x38, 0x03, 0x50}, }, /* 53 */ { - {0x02, 2, 81}, - {0x09, 2, 81}, - {0x17, 2, 81}, - {0x28, 3, 81}, - {0x02, 2, 82}, - {0x09, 2, 82}, - {0x17, 2, 82}, - {0x28, 3, 82}, - {0x02, 2, 83}, - {0x09, 2, 83}, - {0x17, 2, 83}, - {0x28, 3, 83}, - {0x02, 2, 84}, - {0x09, 2, 84}, - {0x17, 2, 84}, - {0x28, 3, 84}, + {0x02, 0x02, 0x51}, + {0x09, 0x02, 0x51}, + {0x17, 0x02, 0x51}, + {0x28, 0x03, 0x51}, + {0x02, 0x02, 0x52}, + {0x09, 0x02, 0x52}, + {0x17, 0x02, 0x52}, + {0x28, 0x03, 0x52}, + {0x02, 0x02, 0x53}, + {0x09, 0x02, 0x53}, + {0x17, 0x02, 0x53}, + {0x28, 0x03, 0x53}, + {0x02, 0x02, 0x54}, + {0x09, 0x02, 0x54}, + {0x17, 0x02, 0x54}, + {0x28, 0x03, 0x54}, }, /* 54 */ { - {0x03, 2, 81}, - {0x06, 2, 81}, - {0x0A, 2, 81}, - {0x0F, 2, 81}, - {0x18, 2, 81}, - {0x1F, 2, 81}, - {0x29, 2, 81}, - {0x38, 3, 81}, - {0x03, 2, 82}, - {0x06, 2, 82}, - {0x0A, 2, 82}, - {0x0F, 2, 82}, - {0x18, 2, 82}, - {0x1F, 2, 82}, - {0x29, 2, 82}, - {0x38, 3, 82}, + {0x03, 0x02, 0x51}, + {0x06, 0x02, 0x51}, + {0x0A, 0x02, 0x51}, + {0x0F, 0x02, 0x51}, + {0x18, 0x02, 0x51}, + {0x1F, 0x02, 0x51}, + {0x29, 0x02, 0x51}, + {0x38, 0x03, 0x51}, + {0x03, 0x02, 0x52}, + {0x06, 0x02, 0x52}, + {0x0A, 0x02, 0x52}, + {0x0F, 0x02, 0x52}, + {0x18, 0x02, 0x52}, + {0x1F, 0x02, 0x52}, + {0x29, 0x02, 0x52}, + {0x38, 0x03, 0x52}, }, /* 55 */ { - {0x03, 2, 83}, - {0x06, 2, 83}, - {0x0A, 2, 83}, - {0x0F, 2, 83}, - {0x18, 2, 83}, - {0x1F, 2, 83}, - {0x29, 2, 83}, - {0x38, 3, 83}, - {0x03, 2, 84}, - {0x06, 2, 84}, - {0x0A, 2, 84}, - {0x0F, 2, 84}, - {0x18, 2, 84}, - {0x1F, 2, 84}, - {0x29, 2, 84}, - {0x38, 3, 84}, + {0x03, 0x02, 0x53}, + {0x06, 0x02, 0x53}, + {0x0A, 0x02, 0x53}, + {0x0F, 0x02, 0x53}, + {0x18, 0x02, 0x53}, + {0x1F, 0x02, 0x53}, + {0x29, 0x02, 0x53}, + {0x38, 0x03, 0x53}, + {0x03, 0x02, 0x54}, + {0x06, 0x02, 0x54}, + {0x0A, 0x02, 0x54}, + {0x0F, 0x02, 0x54}, + {0x18, 0x02, 0x54}, + {0x1F, 0x02, 0x54}, + {0x29, 0x02, 0x54}, + {0x38, 0x03, 0x54}, }, /* 56 */ { - {0x00, 3, 85}, - {0x00, 3, 86}, - {0x00, 3, 87}, - {0x00, 3, 89}, - {0x00, 3, 106}, - {0x00, 3, 107}, - {0x00, 3, 113}, - {0x00, 3, 118}, - {0x00, 3, 119}, - {0x00, 3, 120}, - {0x00, 3, 121}, - {0x00, 3, 122}, - {0x46, 0, 0}, - {0x47, 0, 0}, - {0x49, 0, 0}, - {0x4A, 1, 0}, + {0x00, 0x03, 0x55}, + {0x00, 0x03, 0x56}, + {0x00, 0x03, 0x57}, + {0x00, 0x03, 0x59}, + {0x00, 0x03, 0x6A}, + {0x00, 0x03, 0x6B}, + {0x00, 0x03, 0x71}, + {0x00, 0x03, 0x76}, + {0x00, 0x03, 0x77}, + {0x00, 0x03, 0x78}, + {0x00, 0x03, 0x79}, + {0x00, 0x03, 0x7A}, + {0x46, 0x00, 0x00}, + {0x47, 0x00, 0x00}, + {0x49, 0x00, 0x00}, + {0x4A, 0x01, 0x00}, }, /* 57 */ { - {0x01, 2, 85}, - {0x16, 3, 85}, - {0x01, 2, 86}, - {0x16, 3, 86}, - {0x01, 2, 87}, - {0x16, 3, 87}, - {0x01, 2, 89}, - {0x16, 3, 89}, - {0x01, 2, 106}, - {0x16, 3, 106}, - {0x01, 2, 107}, - {0x16, 3, 107}, - {0x01, 2, 113}, - {0x16, 3, 113}, - {0x01, 2, 118}, - {0x16, 3, 118}, + {0x01, 0x02, 0x55}, + {0x16, 0x03, 0x55}, + {0x01, 0x02, 0x56}, + {0x16, 0x03, 0x56}, + {0x01, 0x02, 0x57}, + {0x16, 0x03, 0x57}, + {0x01, 0x02, 0x59}, + {0x16, 0x03, 0x59}, + {0x01, 0x02, 0x6A}, + {0x16, 0x03, 0x6A}, + {0x01, 0x02, 0x6B}, + {0x16, 0x03, 0x6B}, + {0x01, 0x02, 0x71}, + {0x16, 0x03, 0x71}, + {0x01, 0x02, 0x76}, + {0x16, 0x03, 0x76}, }, /* 58 */ { - {0x02, 2, 85}, - {0x09, 2, 85}, - {0x17, 2, 85}, - {0x28, 3, 85}, - {0x02, 2, 86}, - {0x09, 2, 86}, - {0x17, 2, 86}, - {0x28, 3, 86}, - {0x02, 2, 87}, - {0x09, 2, 87}, - {0x17, 2, 87}, - {0x28, 3, 87}, - {0x02, 2, 89}, - {0x09, 2, 89}, - {0x17, 2, 89}, - {0x28, 3, 89}, + {0x02, 0x02, 0x55}, + {0x09, 0x02, 0x55}, + {0x17, 0x02, 0x55}, + {0x28, 0x03, 0x55}, + {0x02, 0x02, 0x56}, + {0x09, 0x02, 0x56}, + {0x17, 0x02, 0x56}, + {0x28, 0x03, 0x56}, + {0x02, 0x02, 0x57}, + {0x09, 0x02, 0x57}, + {0x17, 0x02, 0x57}, + {0x28, 0x03, 0x57}, + {0x02, 0x02, 0x59}, + {0x09, 0x02, 0x59}, + {0x17, 0x02, 0x59}, + {0x28, 0x03, 0x59}, }, /* 59 */ { - {0x03, 2, 85}, - {0x06, 2, 85}, - {0x0A, 2, 85}, - {0x0F, 2, 85}, - {0x18, 2, 85}, - {0x1F, 2, 85}, - {0x29, 2, 85}, - {0x38, 3, 85}, - {0x03, 2, 86}, - {0x06, 2, 86}, - {0x0A, 2, 86}, - {0x0F, 2, 86}, - {0x18, 2, 86}, - {0x1F, 2, 86}, - {0x29, 2, 86}, - {0x38, 3, 86}, + {0x03, 0x02, 0x55}, + {0x06, 0x02, 0x55}, + {0x0A, 0x02, 0x55}, + {0x0F, 0x02, 0x55}, + {0x18, 0x02, 0x55}, + {0x1F, 0x02, 0x55}, + {0x29, 0x02, 0x55}, + {0x38, 0x03, 0x55}, + {0x03, 0x02, 0x56}, + {0x06, 0x02, 0x56}, + {0x0A, 0x02, 0x56}, + {0x0F, 0x02, 0x56}, + {0x18, 0x02, 0x56}, + {0x1F, 0x02, 0x56}, + {0x29, 0x02, 0x56}, + {0x38, 0x03, 0x56}, }, /* 60 */ { - {0x03, 2, 87}, - {0x06, 2, 87}, - {0x0A, 2, 87}, - {0x0F, 2, 87}, - {0x18, 2, 87}, - {0x1F, 2, 87}, - {0x29, 2, 87}, - {0x38, 3, 87}, - {0x03, 2, 89}, - {0x06, 2, 89}, - {0x0A, 2, 89}, - {0x0F, 2, 89}, - {0x18, 2, 89}, - {0x1F, 2, 89}, - {0x29, 2, 89}, - {0x38, 3, 89}, + {0x03, 0x02, 0x57}, + {0x06, 0x02, 0x57}, + {0x0A, 0x02, 0x57}, + {0x0F, 0x02, 0x57}, + {0x18, 0x02, 0x57}, + {0x1F, 0x02, 0x57}, + {0x29, 0x02, 0x57}, + {0x38, 0x03, 0x57}, + {0x03, 0x02, 0x59}, + {0x06, 0x02, 0x59}, + {0x0A, 0x02, 0x59}, + {0x0F, 0x02, 0x59}, + {0x18, 0x02, 0x59}, + {0x1F, 0x02, 0x59}, + {0x29, 0x02, 0x59}, + {0x38, 0x03, 0x59}, }, /* 61 */ { - {0x02, 2, 106}, - {0x09, 2, 106}, - {0x17, 2, 106}, - {0x28, 3, 106}, - {0x02, 2, 107}, - {0x09, 2, 107}, - {0x17, 2, 107}, - {0x28, 3, 107}, - {0x02, 2, 113}, - {0x09, 2, 113}, - {0x17, 2, 113}, - {0x28, 3, 113}, - {0x02, 2, 118}, - {0x09, 2, 118}, - {0x17, 2, 118}, - {0x28, 3, 118}, + {0x02, 0x02, 0x6A}, + {0x09, 0x02, 0x6A}, + {0x17, 0x02, 0x6A}, + {0x28, 0x03, 0x6A}, + {0x02, 0x02, 0x6B}, + {0x09, 0x02, 0x6B}, + {0x17, 0x02, 0x6B}, + {0x28, 0x03, 0x6B}, + {0x02, 0x02, 0x71}, + {0x09, 0x02, 0x71}, + {0x17, 0x02, 0x71}, + {0x28, 0x03, 0x71}, + {0x02, 0x02, 0x76}, + {0x09, 0x02, 0x76}, + {0x17, 0x02, 0x76}, + {0x28, 0x03, 0x76}, }, /* 62 */ { - {0x03, 2, 106}, - {0x06, 2, 106}, - {0x0A, 2, 106}, - {0x0F, 2, 106}, - {0x18, 2, 106}, - {0x1F, 2, 106}, - {0x29, 2, 106}, - {0x38, 3, 106}, - {0x03, 2, 107}, - {0x06, 2, 107}, - {0x0A, 2, 107}, - {0x0F, 2, 107}, - {0x18, 2, 107}, - {0x1F, 2, 107}, - {0x29, 2, 107}, - {0x38, 3, 107}, + {0x03, 0x02, 0x6A}, + {0x06, 0x02, 0x6A}, + {0x0A, 0x02, 0x6A}, + {0x0F, 0x02, 0x6A}, + {0x18, 0x02, 0x6A}, + {0x1F, 0x02, 0x6A}, + {0x29, 0x02, 0x6A}, + {0x38, 0x03, 0x6A}, + {0x03, 0x02, 0x6B}, + {0x06, 0x02, 0x6B}, + {0x0A, 0x02, 0x6B}, + {0x0F, 0x02, 0x6B}, + {0x18, 0x02, 0x6B}, + {0x1F, 0x02, 0x6B}, + {0x29, 0x02, 0x6B}, + {0x38, 0x03, 0x6B}, }, /* 63 */ { - {0x03, 2, 113}, - {0x06, 2, 113}, - {0x0A, 2, 113}, - {0x0F, 2, 113}, - {0x18, 2, 113}, - {0x1F, 2, 113}, - {0x29, 2, 113}, - {0x38, 3, 113}, - {0x03, 2, 118}, - {0x06, 2, 118}, - {0x0A, 2, 118}, - {0x0F, 2, 118}, - {0x18, 2, 118}, - {0x1F, 2, 118}, - {0x29, 2, 118}, - {0x38, 3, 118}, + {0x03, 0x02, 0x71}, + {0x06, 0x02, 0x71}, + {0x0A, 0x02, 0x71}, + {0x0F, 0x02, 0x71}, + {0x18, 0x02, 0x71}, + {0x1F, 0x02, 0x71}, + {0x29, 0x02, 0x71}, + {0x38, 0x03, 0x71}, + {0x03, 0x02, 0x76}, + {0x06, 0x02, 0x76}, + {0x0A, 0x02, 0x76}, + {0x0F, 0x02, 0x76}, + {0x18, 0x02, 0x76}, + {0x1F, 0x02, 0x76}, + {0x29, 0x02, 0x76}, + {0x38, 0x03, 0x76}, }, /* 64 */ { - {0x01, 2, 119}, - {0x16, 3, 119}, - {0x01, 2, 120}, - {0x16, 3, 120}, - {0x01, 2, 121}, - {0x16, 3, 121}, - {0x01, 2, 122}, - {0x16, 3, 122}, - {0x00, 3, 38}, - {0x00, 3, 42}, - {0x00, 3, 44}, - {0x00, 3, 59}, - {0x00, 3, 88}, - {0x00, 3, 90}, - {0x4B, 0, 0}, - {0x4E, 0, 0}, + {0x01, 0x02, 0x77}, + {0x16, 0x03, 0x77}, + {0x01, 0x02, 0x78}, + {0x16, 0x03, 0x78}, + {0x01, 0x02, 0x79}, + {0x16, 0x03, 0x79}, + {0x01, 0x02, 0x7A}, + {0x16, 0x03, 0x7A}, + {0x00, 0x03, 0x26}, + {0x00, 0x03, 0x2A}, + {0x00, 0x03, 0x2C}, + {0x00, 0x03, 0x3B}, + {0x00, 0x03, 0x58}, + {0x00, 0x03, 0x5A}, + {0x4B, 0x00, 0x00}, + {0x4E, 0x00, 0x00}, }, /* 65 */ { - {0x02, 2, 119}, - {0x09, 2, 119}, - {0x17, 2, 119}, - {0x28, 3, 119}, - {0x02, 2, 120}, - {0x09, 2, 120}, - {0x17, 2, 120}, - {0x28, 3, 120}, - {0x02, 2, 121}, - {0x09, 2, 121}, - {0x17, 2, 121}, - {0x28, 3, 121}, - {0x02, 2, 122}, - {0x09, 2, 122}, - {0x17, 2, 122}, - {0x28, 3, 122}, + {0x02, 0x02, 0x77}, + {0x09, 0x02, 0x77}, + {0x17, 0x02, 0x77}, + {0x28, 0x03, 0x77}, + {0x02, 0x02, 0x78}, + {0x09, 0x02, 0x78}, + {0x17, 0x02, 0x78}, + {0x28, 0x03, 0x78}, + {0x02, 0x02, 0x79}, + {0x09, 0x02, 0x79}, + {0x17, 0x02, 0x79}, + {0x28, 0x03, 0x79}, + {0x02, 0x02, 0x7A}, + {0x09, 0x02, 0x7A}, + {0x17, 0x02, 0x7A}, + {0x28, 0x03, 0x7A}, }, /* 66 */ { - {0x03, 2, 119}, - {0x06, 2, 119}, - {0x0A, 2, 119}, - {0x0F, 2, 119}, - {0x18, 2, 119}, - {0x1F, 2, 119}, - {0x29, 2, 119}, - {0x38, 3, 119}, - {0x03, 2, 120}, - {0x06, 2, 120}, - {0x0A, 2, 120}, - {0x0F, 2, 120}, - {0x18, 2, 120}, - {0x1F, 2, 120}, - {0x29, 2, 120}, - {0x38, 3, 120}, + {0x03, 0x02, 0x77}, + {0x06, 0x02, 0x77}, + {0x0A, 0x02, 0x77}, + {0x0F, 0x02, 0x77}, + {0x18, 0x02, 0x77}, + {0x1F, 0x02, 0x77}, + {0x29, 0x02, 0x77}, + {0x38, 0x03, 0x77}, + {0x03, 0x02, 0x78}, + {0x06, 0x02, 0x78}, + {0x0A, 0x02, 0x78}, + {0x0F, 0x02, 0x78}, + {0x18, 0x02, 0x78}, + {0x1F, 0x02, 0x78}, + {0x29, 0x02, 0x78}, + {0x38, 0x03, 0x78}, }, /* 67 */ { - {0x03, 2, 121}, - {0x06, 2, 121}, - {0x0A, 2, 121}, - {0x0F, 2, 121}, - {0x18, 2, 121}, - {0x1F, 2, 121}, - {0x29, 2, 121}, - {0x38, 3, 121}, - {0x03, 2, 122}, - {0x06, 2, 122}, - {0x0A, 2, 122}, - {0x0F, 2, 122}, - {0x18, 2, 122}, - {0x1F, 2, 122}, - {0x29, 2, 122}, - {0x38, 3, 122}, + {0x03, 0x02, 0x79}, + {0x06, 0x02, 0x79}, + {0x0A, 0x02, 0x79}, + {0x0F, 0x02, 0x79}, + {0x18, 0x02, 0x79}, + {0x1F, 0x02, 0x79}, + {0x29, 0x02, 0x79}, + {0x38, 0x03, 0x79}, + {0x03, 0x02, 0x7A}, + {0x06, 0x02, 0x7A}, + {0x0A, 0x02, 0x7A}, + {0x0F, 0x02, 0x7A}, + {0x18, 0x02, 0x7A}, + {0x1F, 0x02, 0x7A}, + {0x29, 0x02, 0x7A}, + {0x38, 0x03, 0x7A}, }, /* 68 */ { - {0x01, 2, 38}, - {0x16, 3, 38}, - {0x01, 2, 42}, - {0x16, 3, 42}, - {0x01, 2, 44}, - {0x16, 3, 44}, - {0x01, 2, 59}, - {0x16, 3, 59}, - {0x01, 2, 88}, - {0x16, 3, 88}, - {0x01, 2, 90}, - {0x16, 3, 90}, - {0x4C, 0, 0}, - {0x4D, 0, 0}, - {0x4F, 0, 0}, - {0x51, 0, 0}, + {0x01, 0x02, 0x26}, + {0x16, 0x03, 0x26}, + {0x01, 0x02, 0x2A}, + {0x16, 0x03, 0x2A}, + {0x01, 0x02, 0x2C}, + {0x16, 0x03, 0x2C}, + {0x01, 0x02, 0x3B}, + {0x16, 0x03, 0x3B}, + {0x01, 0x02, 0x58}, + {0x16, 0x03, 0x58}, + {0x01, 0x02, 0x5A}, + {0x16, 0x03, 0x5A}, + {0x4C, 0x00, 0x00}, + {0x4D, 0x00, 0x00}, + {0x4F, 0x00, 0x00}, + {0x51, 0x00, 0x00}, }, /* 69 */ { - {0x02, 2, 38}, - {0x09, 2, 38}, - {0x17, 2, 38}, - {0x28, 3, 38}, - {0x02, 2, 42}, - {0x09, 2, 42}, - {0x17, 2, 42}, - {0x28, 3, 42}, - {0x02, 2, 44}, - {0x09, 2, 44}, - {0x17, 2, 44}, - {0x28, 3, 44}, - {0x02, 2, 59}, - {0x09, 2, 59}, - {0x17, 2, 59}, - {0x28, 3, 59}, + {0x02, 0x02, 0x26}, + {0x09, 0x02, 0x26}, + {0x17, 0x02, 0x26}, + {0x28, 0x03, 0x26}, + {0x02, 0x02, 0x2A}, + {0x09, 0x02, 0x2A}, + {0x17, 0x02, 0x2A}, + {0x28, 0x03, 0x2A}, + {0x02, 0x02, 0x2C}, + {0x09, 0x02, 0x2C}, + {0x17, 0x02, 0x2C}, + {0x28, 0x03, 0x2C}, + {0x02, 0x02, 0x3B}, + {0x09, 0x02, 0x3B}, + {0x17, 0x02, 0x3B}, + {0x28, 0x03, 0x3B}, }, /* 70 */ { - {0x03, 2, 38}, - {0x06, 2, 38}, - {0x0A, 2, 38}, - {0x0F, 2, 38}, - {0x18, 2, 38}, - {0x1F, 2, 38}, - {0x29, 2, 38}, - {0x38, 3, 38}, - {0x03, 2, 42}, - {0x06, 2, 42}, - {0x0A, 2, 42}, - {0x0F, 2, 42}, - {0x18, 2, 42}, - {0x1F, 2, 42}, - {0x29, 2, 42}, - {0x38, 3, 42}, + {0x03, 0x02, 0x26}, + {0x06, 0x02, 0x26}, + {0x0A, 0x02, 0x26}, + {0x0F, 0x02, 0x26}, + {0x18, 0x02, 0x26}, + {0x1F, 0x02, 0x26}, + {0x29, 0x02, 0x26}, + {0x38, 0x03, 0x26}, + {0x03, 0x02, 0x2A}, + {0x06, 0x02, 0x2A}, + {0x0A, 0x02, 0x2A}, + {0x0F, 0x02, 0x2A}, + {0x18, 0x02, 0x2A}, + {0x1F, 0x02, 0x2A}, + {0x29, 0x02, 0x2A}, + {0x38, 0x03, 0x2A}, }, /* 71 */ { - {0x03, 2, 44}, - {0x06, 2, 44}, - {0x0A, 2, 44}, - {0x0F, 2, 44}, - {0x18, 2, 44}, - {0x1F, 2, 44}, - {0x29, 2, 44}, - {0x38, 3, 44}, - {0x03, 2, 59}, - {0x06, 2, 59}, - {0x0A, 2, 59}, - {0x0F, 2, 59}, - {0x18, 2, 59}, - {0x1F, 2, 59}, - {0x29, 2, 59}, - {0x38, 3, 59}, + {0x03, 0x02, 0x2C}, + {0x06, 0x02, 0x2C}, + {0x0A, 0x02, 0x2C}, + {0x0F, 0x02, 0x2C}, + {0x18, 0x02, 0x2C}, + {0x1F, 0x02, 0x2C}, + {0x29, 0x02, 0x2C}, + {0x38, 0x03, 0x2C}, + {0x03, 0x02, 0x3B}, + {0x06, 0x02, 0x3B}, + {0x0A, 0x02, 0x3B}, + {0x0F, 0x02, 0x3B}, + {0x18, 0x02, 0x3B}, + {0x1F, 0x02, 0x3B}, + {0x29, 0x02, 0x3B}, + {0x38, 0x03, 0x3B}, }, /* 72 */ { - {0x02, 2, 88}, - {0x09, 2, 88}, - {0x17, 2, 88}, - {0x28, 3, 88}, - {0x02, 2, 90}, - {0x09, 2, 90}, - {0x17, 2, 90}, - {0x28, 3, 90}, - {0x00, 3, 33}, - {0x00, 3, 34}, - {0x00, 3, 40}, - {0x00, 3, 41}, - {0x00, 3, 63}, - {0x50, 0, 0}, - {0x52, 0, 0}, - {0x54, 0, 0}, + {0x02, 0x02, 0x58}, + {0x09, 0x02, 0x58}, + {0x17, 0x02, 0x58}, + {0x28, 0x03, 0x58}, + {0x02, 0x02, 0x5A}, + {0x09, 0x02, 0x5A}, + {0x17, 0x02, 0x5A}, + {0x28, 0x03, 0x5A}, + {0x00, 0x03, 0x21}, + {0x00, 0x03, 0x22}, + {0x00, 0x03, 0x28}, + {0x00, 0x03, 0x29}, + {0x00, 0x03, 0x3F}, + {0x50, 0x00, 0x00}, + {0x52, 0x00, 0x00}, + {0x54, 0x00, 0x00}, }, /* 73 */ { - {0x03, 2, 88}, - {0x06, 2, 88}, - {0x0A, 2, 88}, - {0x0F, 2, 88}, - {0x18, 2, 88}, - {0x1F, 2, 88}, - {0x29, 2, 88}, - {0x38, 3, 88}, - {0x03, 2, 90}, - {0x06, 2, 90}, - {0x0A, 2, 90}, - {0x0F, 2, 90}, - {0x18, 2, 90}, - {0x1F, 2, 90}, - {0x29, 2, 90}, - {0x38, 3, 90}, + {0x03, 0x02, 0x58}, + {0x06, 0x02, 0x58}, + {0x0A, 0x02, 0x58}, + {0x0F, 0x02, 0x58}, + {0x18, 0x02, 0x58}, + {0x1F, 0x02, 0x58}, + {0x29, 0x02, 0x58}, + {0x38, 0x03, 0x58}, + {0x03, 0x02, 0x5A}, + {0x06, 0x02, 0x5A}, + {0x0A, 0x02, 0x5A}, + {0x0F, 0x02, 0x5A}, + {0x18, 0x02, 0x5A}, + {0x1F, 0x02, 0x5A}, + {0x29, 0x02, 0x5A}, + {0x38, 0x03, 0x5A}, }, /* 74 */ { - {0x01, 2, 33}, - {0x16, 3, 33}, - {0x01, 2, 34}, - {0x16, 3, 34}, - {0x01, 2, 40}, - {0x16, 3, 40}, - {0x01, 2, 41}, - {0x16, 3, 41}, - {0x01, 2, 63}, - {0x16, 3, 63}, - {0x00, 3, 39}, - {0x00, 3, 43}, - {0x00, 3, 124}, - {0x53, 0, 0}, - {0x55, 0, 0}, - {0x58, 0, 0}, + {0x01, 0x02, 0x21}, + {0x16, 0x03, 0x21}, + {0x01, 0x02, 0x22}, + {0x16, 0x03, 0x22}, + {0x01, 0x02, 0x28}, + {0x16, 0x03, 0x28}, + {0x01, 0x02, 0x29}, + {0x16, 0x03, 0x29}, + {0x01, 0x02, 0x3F}, + {0x16, 0x03, 0x3F}, + {0x00, 0x03, 0x27}, + {0x00, 0x03, 0x2B}, + {0x00, 0x03, 0x7C}, + {0x53, 0x00, 0x00}, + {0x55, 0x00, 0x00}, + {0x58, 0x00, 0x00}, }, /* 75 */ { - {0x02, 2, 33}, - {0x09, 2, 33}, - {0x17, 2, 33}, - {0x28, 3, 33}, - {0x02, 2, 34}, - {0x09, 2, 34}, - {0x17, 2, 34}, - {0x28, 3, 34}, - {0x02, 2, 40}, - {0x09, 2, 40}, - {0x17, 2, 40}, - {0x28, 3, 40}, - {0x02, 2, 41}, - {0x09, 2, 41}, - {0x17, 2, 41}, - {0x28, 3, 41}, + {0x02, 0x02, 0x21}, + {0x09, 0x02, 0x21}, + {0x17, 0x02, 0x21}, + {0x28, 0x03, 0x21}, + {0x02, 0x02, 0x22}, + {0x09, 0x02, 0x22}, + {0x17, 0x02, 0x22}, + {0x28, 0x03, 0x22}, + {0x02, 0x02, 0x28}, + {0x09, 0x02, 0x28}, + {0x17, 0x02, 0x28}, + {0x28, 0x03, 0x28}, + {0x02, 0x02, 0x29}, + {0x09, 0x02, 0x29}, + {0x17, 0x02, 0x29}, + {0x28, 0x03, 0x29}, }, /* 76 */ { - {0x03, 2, 33}, - {0x06, 2, 33}, - {0x0A, 2, 33}, - {0x0F, 2, 33}, - {0x18, 2, 33}, - {0x1F, 2, 33}, - {0x29, 2, 33}, - {0x38, 3, 33}, - {0x03, 2, 34}, - {0x06, 2, 34}, - {0x0A, 2, 34}, - {0x0F, 2, 34}, - {0x18, 2, 34}, - {0x1F, 2, 34}, - {0x29, 2, 34}, - {0x38, 3, 34}, + {0x03, 0x02, 0x21}, + {0x06, 0x02, 0x21}, + {0x0A, 0x02, 0x21}, + {0x0F, 0x02, 0x21}, + {0x18, 0x02, 0x21}, + {0x1F, 0x02, 0x21}, + {0x29, 0x02, 0x21}, + {0x38, 0x03, 0x21}, + {0x03, 0x02, 0x22}, + {0x06, 0x02, 0x22}, + {0x0A, 0x02, 0x22}, + {0x0F, 0x02, 0x22}, + {0x18, 0x02, 0x22}, + {0x1F, 0x02, 0x22}, + {0x29, 0x02, 0x22}, + {0x38, 0x03, 0x22}, }, /* 77 */ { - {0x03, 2, 40}, - {0x06, 2, 40}, - {0x0A, 2, 40}, - {0x0F, 2, 40}, - {0x18, 2, 40}, - {0x1F, 2, 40}, - {0x29, 2, 40}, - {0x38, 3, 40}, - {0x03, 2, 41}, - {0x06, 2, 41}, - {0x0A, 2, 41}, - {0x0F, 2, 41}, - {0x18, 2, 41}, - {0x1F, 2, 41}, - {0x29, 2, 41}, - {0x38, 3, 41}, + {0x03, 0x02, 0x28}, + {0x06, 0x02, 0x28}, + {0x0A, 0x02, 0x28}, + {0x0F, 0x02, 0x28}, + {0x18, 0x02, 0x28}, + {0x1F, 0x02, 0x28}, + {0x29, 0x02, 0x28}, + {0x38, 0x03, 0x28}, + {0x03, 0x02, 0x29}, + {0x06, 0x02, 0x29}, + {0x0A, 0x02, 0x29}, + {0x0F, 0x02, 0x29}, + {0x18, 0x02, 0x29}, + {0x1F, 0x02, 0x29}, + {0x29, 0x02, 0x29}, + {0x38, 0x03, 0x29}, }, /* 78 */ { - {0x02, 2, 63}, - {0x09, 2, 63}, - {0x17, 2, 63}, - {0x28, 3, 63}, - {0x01, 2, 39}, - {0x16, 3, 39}, - {0x01, 2, 43}, - {0x16, 3, 43}, - {0x01, 2, 124}, - {0x16, 3, 124}, - {0x00, 3, 35}, - {0x00, 3, 62}, - {0x56, 0, 0}, - {0x57, 0, 0}, - {0x59, 0, 0}, - {0x5A, 0, 0}, + {0x02, 0x02, 0x3F}, + {0x09, 0x02, 0x3F}, + {0x17, 0x02, 0x3F}, + {0x28, 0x03, 0x3F}, + {0x01, 0x02, 0x27}, + {0x16, 0x03, 0x27}, + {0x01, 0x02, 0x2B}, + {0x16, 0x03, 0x2B}, + {0x01, 0x02, 0x7C}, + {0x16, 0x03, 0x7C}, + {0x00, 0x03, 0x23}, + {0x00, 0x03, 0x3E}, + {0x56, 0x00, 0x00}, + {0x57, 0x00, 0x00}, + {0x59, 0x00, 0x00}, + {0x5A, 0x00, 0x00}, }, /* 79 */ { - {0x03, 2, 63}, - {0x06, 2, 63}, - {0x0A, 2, 63}, - {0x0F, 2, 63}, - {0x18, 2, 63}, - {0x1F, 2, 63}, - {0x29, 2, 63}, - {0x38, 3, 63}, - {0x02, 2, 39}, - {0x09, 2, 39}, - {0x17, 2, 39}, - {0x28, 3, 39}, - {0x02, 2, 43}, - {0x09, 2, 43}, - {0x17, 2, 43}, - {0x28, 3, 43}, + {0x03, 0x02, 0x3F}, + {0x06, 0x02, 0x3F}, + {0x0A, 0x02, 0x3F}, + {0x0F, 0x02, 0x3F}, + {0x18, 0x02, 0x3F}, + {0x1F, 0x02, 0x3F}, + {0x29, 0x02, 0x3F}, + {0x38, 0x03, 0x3F}, + {0x02, 0x02, 0x27}, + {0x09, 0x02, 0x27}, + {0x17, 0x02, 0x27}, + {0x28, 0x03, 0x27}, + {0x02, 0x02, 0x2B}, + {0x09, 0x02, 0x2B}, + {0x17, 0x02, 0x2B}, + {0x28, 0x03, 0x2B}, }, /* 80 */ { - {0x03, 2, 39}, - {0x06, 2, 39}, - {0x0A, 2, 39}, - {0x0F, 2, 39}, - {0x18, 2, 39}, - {0x1F, 2, 39}, - {0x29, 2, 39}, - {0x38, 3, 39}, - {0x03, 2, 43}, - {0x06, 2, 43}, - {0x0A, 2, 43}, - {0x0F, 2, 43}, - {0x18, 2, 43}, - {0x1F, 2, 43}, - {0x29, 2, 43}, - {0x38, 3, 43}, + {0x03, 0x02, 0x27}, + {0x06, 0x02, 0x27}, + {0x0A, 0x02, 0x27}, + {0x0F, 0x02, 0x27}, + {0x18, 0x02, 0x27}, + {0x1F, 0x02, 0x27}, + {0x29, 0x02, 0x27}, + {0x38, 0x03, 0x27}, + {0x03, 0x02, 0x2B}, + {0x06, 0x02, 0x2B}, + {0x0A, 0x02, 0x2B}, + {0x0F, 0x02, 0x2B}, + {0x18, 0x02, 0x2B}, + {0x1F, 0x02, 0x2B}, + {0x29, 0x02, 0x2B}, + {0x38, 0x03, 0x2B}, }, /* 81 */ { - {0x02, 2, 124}, - {0x09, 2, 124}, - {0x17, 2, 124}, - {0x28, 3, 124}, - {0x01, 2, 35}, - {0x16, 3, 35}, - {0x01, 2, 62}, - {0x16, 3, 62}, - {0x00, 3, 0}, - {0x00, 3, 36}, - {0x00, 3, 64}, - {0x00, 3, 91}, - {0x00, 3, 93}, - {0x00, 3, 126}, - {0x5B, 0, 0}, - {0x5C, 0, 0}, + {0x02, 0x02, 0x7C}, + {0x09, 0x02, 0x7C}, + {0x17, 0x02, 0x7C}, + {0x28, 0x03, 0x7C}, + {0x01, 0x02, 0x23}, + {0x16, 0x03, 0x23}, + {0x01, 0x02, 0x3E}, + {0x16, 0x03, 0x3E}, + {0x00, 0x03, 0x00}, + {0x00, 0x03, 0x24}, + {0x00, 0x03, 0x40}, + {0x00, 0x03, 0x5B}, + {0x00, 0x03, 0x5D}, + {0x00, 0x03, 0x7E}, + {0x5B, 0x00, 0x00}, + {0x5C, 0x00, 0x00}, }, /* 82 */ { - {0x03, 2, 124}, - {0x06, 2, 124}, - {0x0A, 2, 124}, - {0x0F, 2, 124}, - {0x18, 2, 124}, - {0x1F, 2, 124}, - {0x29, 2, 124}, - {0x38, 3, 124}, - {0x02, 2, 35}, - {0x09, 2, 35}, - {0x17, 2, 35}, - {0x28, 3, 35}, - {0x02, 2, 62}, - {0x09, 2, 62}, - {0x17, 2, 62}, - {0x28, 3, 62}, + {0x03, 0x02, 0x7C}, + {0x06, 0x02, 0x7C}, + {0x0A, 0x02, 0x7C}, + {0x0F, 0x02, 0x7C}, + {0x18, 0x02, 0x7C}, + {0x1F, 0x02, 0x7C}, + {0x29, 0x02, 0x7C}, + {0x38, 0x03, 0x7C}, + {0x02, 0x02, 0x23}, + {0x09, 0x02, 0x23}, + {0x17, 0x02, 0x23}, + {0x28, 0x03, 0x23}, + {0x02, 0x02, 0x3E}, + {0x09, 0x02, 0x3E}, + {0x17, 0x02, 0x3E}, + {0x28, 0x03, 0x3E}, }, /* 83 */ { - {0x03, 2, 35}, - {0x06, 2, 35}, - {0x0A, 2, 35}, - {0x0F, 2, 35}, - {0x18, 2, 35}, - {0x1F, 2, 35}, - {0x29, 2, 35}, - {0x38, 3, 35}, - {0x03, 2, 62}, - {0x06, 2, 62}, - {0x0A, 2, 62}, - {0x0F, 2, 62}, - {0x18, 2, 62}, - {0x1F, 2, 62}, - {0x29, 2, 62}, - {0x38, 3, 62}, + {0x03, 0x02, 0x23}, + {0x06, 0x02, 0x23}, + {0x0A, 0x02, 0x23}, + {0x0F, 0x02, 0x23}, + {0x18, 0x02, 0x23}, + {0x1F, 0x02, 0x23}, + {0x29, 0x02, 0x23}, + {0x38, 0x03, 0x23}, + {0x03, 0x02, 0x3E}, + {0x06, 0x02, 0x3E}, + {0x0A, 0x02, 0x3E}, + {0x0F, 0x02, 0x3E}, + {0x18, 0x02, 0x3E}, + {0x1F, 0x02, 0x3E}, + {0x29, 0x02, 0x3E}, + {0x38, 0x03, 0x3E}, }, /* 84 */ { - {0x01, 2, 0}, - {0x16, 3, 0}, - {0x01, 2, 36}, - {0x16, 3, 36}, - {0x01, 2, 64}, - {0x16, 3, 64}, - {0x01, 2, 91}, - {0x16, 3, 91}, - {0x01, 2, 93}, - {0x16, 3, 93}, - {0x01, 2, 126}, - {0x16, 3, 126}, - {0x00, 3, 94}, - {0x00, 3, 125}, - {0x5D, 0, 0}, - {0x5E, 0, 0}, + {0x01, 0x02, 0x00}, + {0x16, 0x03, 0x00}, + {0x01, 0x02, 0x24}, + {0x16, 0x03, 0x24}, + {0x01, 0x02, 0x40}, + {0x16, 0x03, 0x40}, + {0x01, 0x02, 0x5B}, + {0x16, 0x03, 0x5B}, + {0x01, 0x02, 0x5D}, + {0x16, 0x03, 0x5D}, + {0x01, 0x02, 0x7E}, + {0x16, 0x03, 0x7E}, + {0x00, 0x03, 0x5E}, + {0x00, 0x03, 0x7D}, + {0x5D, 0x00, 0x00}, + {0x5E, 0x00, 0x00}, }, /* 85 */ { - {0x02, 2, 0}, - {0x09, 2, 0}, - {0x17, 2, 0}, - {0x28, 3, 0}, - {0x02, 2, 36}, - {0x09, 2, 36}, - {0x17, 2, 36}, - {0x28, 3, 36}, - {0x02, 2, 64}, - {0x09, 2, 64}, - {0x17, 2, 64}, - {0x28, 3, 64}, - {0x02, 2, 91}, - {0x09, 2, 91}, - {0x17, 2, 91}, - {0x28, 3, 91}, + {0x02, 0x02, 0x00}, + {0x09, 0x02, 0x00}, + {0x17, 0x02, 0x00}, + {0x28, 0x03, 0x00}, + {0x02, 0x02, 0x24}, + {0x09, 0x02, 0x24}, + {0x17, 0x02, 0x24}, + {0x28, 0x03, 0x24}, + {0x02, 0x02, 0x40}, + {0x09, 0x02, 0x40}, + {0x17, 0x02, 0x40}, + {0x28, 0x03, 0x40}, + {0x02, 0x02, 0x5B}, + {0x09, 0x02, 0x5B}, + {0x17, 0x02, 0x5B}, + {0x28, 0x03, 0x5B}, }, /* 86 */ { - {0x03, 2, 0}, - {0x06, 2, 0}, - {0x0A, 2, 0}, - {0x0F, 2, 0}, - {0x18, 2, 0}, - {0x1F, 2, 0}, - {0x29, 2, 0}, - {0x38, 3, 0}, - {0x03, 2, 36}, - {0x06, 2, 36}, - {0x0A, 2, 36}, - {0x0F, 2, 36}, - {0x18, 2, 36}, - {0x1F, 2, 36}, - {0x29, 2, 36}, - {0x38, 3, 36}, + {0x03, 0x02, 0x00}, + {0x06, 0x02, 0x00}, + {0x0A, 0x02, 0x00}, + {0x0F, 0x02, 0x00}, + {0x18, 0x02, 0x00}, + {0x1F, 0x02, 0x00}, + {0x29, 0x02, 0x00}, + {0x38, 0x03, 0x00}, + {0x03, 0x02, 0x24}, + {0x06, 0x02, 0x24}, + {0x0A, 0x02, 0x24}, + {0x0F, 0x02, 0x24}, + {0x18, 0x02, 0x24}, + {0x1F, 0x02, 0x24}, + {0x29, 0x02, 0x24}, + {0x38, 0x03, 0x24}, }, /* 87 */ { - {0x03, 2, 64}, - {0x06, 2, 64}, - {0x0A, 2, 64}, - {0x0F, 2, 64}, - {0x18, 2, 64}, - {0x1F, 2, 64}, - {0x29, 2, 64}, - {0x38, 3, 64}, - {0x03, 2, 91}, - {0x06, 2, 91}, - {0x0A, 2, 91}, - {0x0F, 2, 91}, - {0x18, 2, 91}, - {0x1F, 2, 91}, - {0x29, 2, 91}, - {0x38, 3, 91}, + {0x03, 0x02, 0x40}, + {0x06, 0x02, 0x40}, + {0x0A, 0x02, 0x40}, + {0x0F, 0x02, 0x40}, + {0x18, 0x02, 0x40}, + {0x1F, 0x02, 0x40}, + {0x29, 0x02, 0x40}, + {0x38, 0x03, 0x40}, + {0x03, 0x02, 0x5B}, + {0x06, 0x02, 0x5B}, + {0x0A, 0x02, 0x5B}, + {0x0F, 0x02, 0x5B}, + {0x18, 0x02, 0x5B}, + {0x1F, 0x02, 0x5B}, + {0x29, 0x02, 0x5B}, + {0x38, 0x03, 0x5B}, }, /* 88 */ { - {0x02, 2, 93}, - {0x09, 2, 93}, - {0x17, 2, 93}, - {0x28, 3, 93}, - {0x02, 2, 126}, - {0x09, 2, 126}, - {0x17, 2, 126}, - {0x28, 3, 126}, - {0x01, 2, 94}, - {0x16, 3, 94}, - {0x01, 2, 125}, - {0x16, 3, 125}, - {0x00, 3, 60}, - {0x00, 3, 96}, - {0x00, 3, 123}, - {0x5F, 0, 0}, + {0x02, 0x02, 0x5D}, + {0x09, 0x02, 0x5D}, + {0x17, 0x02, 0x5D}, + {0x28, 0x03, 0x5D}, + {0x02, 0x02, 0x7E}, + {0x09, 0x02, 0x7E}, + {0x17, 0x02, 0x7E}, + {0x28, 0x03, 0x7E}, + {0x01, 0x02, 0x5E}, + {0x16, 0x03, 0x5E}, + {0x01, 0x02, 0x7D}, + {0x16, 0x03, 0x7D}, + {0x00, 0x03, 0x3C}, + {0x00, 0x03, 0x60}, + {0x00, 0x03, 0x7B}, + {0x5F, 0x00, 0x00}, }, /* 89 */ { - {0x03, 2, 93}, - {0x06, 2, 93}, - {0x0A, 2, 93}, - {0x0F, 2, 93}, - {0x18, 2, 93}, - {0x1F, 2, 93}, - {0x29, 2, 93}, - {0x38, 3, 93}, - {0x03, 2, 126}, - {0x06, 2, 126}, - {0x0A, 2, 126}, - {0x0F, 2, 126}, - {0x18, 2, 126}, - {0x1F, 2, 126}, - {0x29, 2, 126}, - {0x38, 3, 126}, + {0x03, 0x02, 0x5D}, + {0x06, 0x02, 0x5D}, + {0x0A, 0x02, 0x5D}, + {0x0F, 0x02, 0x5D}, + {0x18, 0x02, 0x5D}, + {0x1F, 0x02, 0x5D}, + {0x29, 0x02, 0x5D}, + {0x38, 0x03, 0x5D}, + {0x03, 0x02, 0x7E}, + {0x06, 0x02, 0x7E}, + {0x0A, 0x02, 0x7E}, + {0x0F, 0x02, 0x7E}, + {0x18, 0x02, 0x7E}, + {0x1F, 0x02, 0x7E}, + {0x29, 0x02, 0x7E}, + {0x38, 0x03, 0x7E}, }, /* 90 */ { - {0x02, 2, 94}, - {0x09, 2, 94}, - {0x17, 2, 94}, - {0x28, 3, 94}, - {0x02, 2, 125}, - {0x09, 2, 125}, - {0x17, 2, 125}, - {0x28, 3, 125}, - {0x01, 2, 60}, - {0x16, 3, 60}, - {0x01, 2, 96}, - {0x16, 3, 96}, - {0x01, 2, 123}, - {0x16, 3, 123}, - {0x60, 0, 0}, - {0x6E, 0, 0}, + {0x02, 0x02, 0x5E}, + {0x09, 0x02, 0x5E}, + {0x17, 0x02, 0x5E}, + {0x28, 0x03, 0x5E}, + {0x02, 0x02, 0x7D}, + {0x09, 0x02, 0x7D}, + {0x17, 0x02, 0x7D}, + {0x28, 0x03, 0x7D}, + {0x01, 0x02, 0x3C}, + {0x16, 0x03, 0x3C}, + {0x01, 0x02, 0x60}, + {0x16, 0x03, 0x60}, + {0x01, 0x02, 0x7B}, + {0x16, 0x03, 0x7B}, + {0x60, 0x00, 0x00}, + {0x6E, 0x00, 0x00}, }, /* 91 */ { - {0x03, 2, 94}, - {0x06, 2, 94}, - {0x0A, 2, 94}, - {0x0F, 2, 94}, - {0x18, 2, 94}, - {0x1F, 2, 94}, - {0x29, 2, 94}, - {0x38, 3, 94}, - {0x03, 2, 125}, - {0x06, 2, 125}, - {0x0A, 2, 125}, - {0x0F, 2, 125}, - {0x18, 2, 125}, - {0x1F, 2, 125}, - {0x29, 2, 125}, - {0x38, 3, 125}, + {0x03, 0x02, 0x5E}, + {0x06, 0x02, 0x5E}, + {0x0A, 0x02, 0x5E}, + {0x0F, 0x02, 0x5E}, + {0x18, 0x02, 0x5E}, + {0x1F, 0x02, 0x5E}, + {0x29, 0x02, 0x5E}, + {0x38, 0x03, 0x5E}, + {0x03, 0x02, 0x7D}, + {0x06, 0x02, 0x7D}, + {0x0A, 0x02, 0x7D}, + {0x0F, 0x02, 0x7D}, + {0x18, 0x02, 0x7D}, + {0x1F, 0x02, 0x7D}, + {0x29, 0x02, 0x7D}, + {0x38, 0x03, 0x7D}, }, /* 92 */ { - {0x02, 2, 60}, - {0x09, 2, 60}, - {0x17, 2, 60}, - {0x28, 3, 60}, - {0x02, 2, 96}, - {0x09, 2, 96}, - {0x17, 2, 96}, - {0x28, 3, 96}, - {0x02, 2, 123}, - {0x09, 2, 123}, - {0x17, 2, 123}, - {0x28, 3, 123}, - {0x61, 0, 0}, - {0x65, 0, 0}, - {0x6F, 0, 0}, - {0x85, 0, 0}, + {0x02, 0x02, 0x3C}, + {0x09, 0x02, 0x3C}, + {0x17, 0x02, 0x3C}, + {0x28, 0x03, 0x3C}, + {0x02, 0x02, 0x60}, + {0x09, 0x02, 0x60}, + {0x17, 0x02, 0x60}, + {0x28, 0x03, 0x60}, + {0x02, 0x02, 0x7B}, + {0x09, 0x02, 0x7B}, + {0x17, 0x02, 0x7B}, + {0x28, 0x03, 0x7B}, + {0x61, 0x00, 0x00}, + {0x65, 0x00, 0x00}, + {0x6F, 0x00, 0x00}, + {0x85, 0x00, 0x00}, }, /* 93 */ { - {0x03, 2, 60}, - {0x06, 2, 60}, - {0x0A, 2, 60}, - {0x0F, 2, 60}, - {0x18, 2, 60}, - {0x1F, 2, 60}, - {0x29, 2, 60}, - {0x38, 3, 60}, - {0x03, 2, 96}, - {0x06, 2, 96}, - {0x0A, 2, 96}, - {0x0F, 2, 96}, - {0x18, 2, 96}, - {0x1F, 2, 96}, - {0x29, 2, 96}, - {0x38, 3, 96}, + {0x03, 0x02, 0x3C}, + {0x06, 0x02, 0x3C}, + {0x0A, 0x02, 0x3C}, + {0x0F, 0x02, 0x3C}, + {0x18, 0x02, 0x3C}, + {0x1F, 0x02, 0x3C}, + {0x29, 0x02, 0x3C}, + {0x38, 0x03, 0x3C}, + {0x03, 0x02, 0x60}, + {0x06, 0x02, 0x60}, + {0x0A, 0x02, 0x60}, + {0x0F, 0x02, 0x60}, + {0x18, 0x02, 0x60}, + {0x1F, 0x02, 0x60}, + {0x29, 0x02, 0x60}, + {0x38, 0x03, 0x60}, }, /* 94 */ { - {0x03, 2, 123}, - {0x06, 2, 123}, - {0x0A, 2, 123}, - {0x0F, 2, 123}, - {0x18, 2, 123}, - {0x1F, 2, 123}, - {0x29, 2, 123}, - {0x38, 3, 123}, - {0x62, 0, 0}, - {0x63, 0, 0}, - {0x66, 0, 0}, - {0x69, 0, 0}, - {0x70, 0, 0}, - {0x77, 0, 0}, - {0x86, 0, 0}, - {0x99, 0, 0}, + {0x03, 0x02, 0x7B}, + {0x06, 0x02, 0x7B}, + {0x0A, 0x02, 0x7B}, + {0x0F, 0x02, 0x7B}, + {0x18, 0x02, 0x7B}, + {0x1F, 0x02, 0x7B}, + {0x29, 0x02, 0x7B}, + {0x38, 0x03, 0x7B}, + {0x62, 0x00, 0x00}, + {0x63, 0x00, 0x00}, + {0x66, 0x00, 0x00}, + {0x69, 0x00, 0x00}, + {0x70, 0x00, 0x00}, + {0x77, 0x00, 0x00}, + {0x86, 0x00, 0x00}, + {0x99, 0x00, 0x00}, }, /* 95 */ { - {0x00, 3, 92}, - {0x00, 3, 195}, - {0x00, 3, 208}, - {0x64, 0, 0}, - {0x67, 0, 0}, - {0x68, 0, 0}, - {0x6A, 0, 0}, - {0x6B, 0, 0}, - {0x71, 0, 0}, - {0x74, 0, 0}, - {0x78, 0, 0}, - {0x7E, 0, 0}, - {0x87, 0, 0}, - {0x8E, 0, 0}, - {0x9A, 0, 0}, - {0xA9, 0, 0}, + {0x00, 0x03, 0x5C}, + {0x00, 0x03, 0xC3}, + {0x00, 0x03, 0xD0}, + {0x64, 0x00, 0x00}, + {0x67, 0x00, 0x00}, + {0x68, 0x00, 0x00}, + {0x6A, 0x00, 0x00}, + {0x6B, 0x00, 0x00}, + {0x71, 0x00, 0x00}, + {0x74, 0x00, 0x00}, + {0x78, 0x00, 0x00}, + {0x7E, 0x00, 0x00}, + {0x87, 0x00, 0x00}, + {0x8E, 0x00, 0x00}, + {0x9A, 0x00, 0x00}, + {0xA9, 0x00, 0x00}, }, /* 96 */ { - {0x01, 2, 92}, - {0x16, 3, 92}, - {0x01, 2, 195}, - {0x16, 3, 195}, - {0x01, 2, 208}, - {0x16, 3, 208}, - {0x00, 3, 128}, - {0x00, 3, 130}, - {0x00, 3, 131}, - {0x00, 3, 162}, - {0x00, 3, 184}, - {0x00, 3, 194}, - {0x00, 3, 224}, - {0x00, 3, 226}, - {0x6C, 0, 0}, - {0x6D, 0, 0}, + {0x01, 0x02, 0x5C}, + {0x16, 0x03, 0x5C}, + {0x01, 0x02, 0xC3}, + {0x16, 0x03, 0xC3}, + {0x01, 0x02, 0xD0}, + {0x16, 0x03, 0xD0}, + {0x00, 0x03, 0x80}, + {0x00, 0x03, 0x82}, + {0x00, 0x03, 0x83}, + {0x00, 0x03, 0xA2}, + {0x00, 0x03, 0xB8}, + {0x00, 0x03, 0xC2}, + {0x00, 0x03, 0xE0}, + {0x00, 0x03, 0xE2}, + {0x6C, 0x00, 0x00}, + {0x6D, 0x00, 0x00}, }, /* 97 */ { - {0x02, 2, 92}, - {0x09, 2, 92}, - {0x17, 2, 92}, - {0x28, 3, 92}, - {0x02, 2, 195}, - {0x09, 2, 195}, - {0x17, 2, 195}, - {0x28, 3, 195}, - {0x02, 2, 208}, - {0x09, 2, 208}, - {0x17, 2, 208}, - {0x28, 3, 208}, - {0x01, 2, 128}, - {0x16, 3, 128}, - {0x01, 2, 130}, - {0x16, 3, 130}, + {0x02, 0x02, 0x5C}, + {0x09, 0x02, 0x5C}, + {0x17, 0x02, 0x5C}, + {0x28, 0x03, 0x5C}, + {0x02, 0x02, 0xC3}, + {0x09, 0x02, 0xC3}, + {0x17, 0x02, 0xC3}, + {0x28, 0x03, 0xC3}, + {0x02, 0x02, 0xD0}, + {0x09, 0x02, 0xD0}, + {0x17, 0x02, 0xD0}, + {0x28, 0x03, 0xD0}, + {0x01, 0x02, 0x80}, + {0x16, 0x03, 0x80}, + {0x01, 0x02, 0x82}, + {0x16, 0x03, 0x82}, }, /* 98 */ { - {0x03, 2, 92}, - {0x06, 2, 92}, - {0x0A, 2, 92}, - {0x0F, 2, 92}, - {0x18, 2, 92}, - {0x1F, 2, 92}, - {0x29, 2, 92}, - {0x38, 3, 92}, - {0x03, 2, 195}, - {0x06, 2, 195}, - {0x0A, 2, 195}, - {0x0F, 2, 195}, - {0x18, 2, 195}, - {0x1F, 2, 195}, - {0x29, 2, 195}, - {0x38, 3, 195}, + {0x03, 0x02, 0x5C}, + {0x06, 0x02, 0x5C}, + {0x0A, 0x02, 0x5C}, + {0x0F, 0x02, 0x5C}, + {0x18, 0x02, 0x5C}, + {0x1F, 0x02, 0x5C}, + {0x29, 0x02, 0x5C}, + {0x38, 0x03, 0x5C}, + {0x03, 0x02, 0xC3}, + {0x06, 0x02, 0xC3}, + {0x0A, 0x02, 0xC3}, + {0x0F, 0x02, 0xC3}, + {0x18, 0x02, 0xC3}, + {0x1F, 0x02, 0xC3}, + {0x29, 0x02, 0xC3}, + {0x38, 0x03, 0xC3}, }, /* 99 */ { - {0x03, 2, 208}, - {0x06, 2, 208}, - {0x0A, 2, 208}, - {0x0F, 2, 208}, - {0x18, 2, 208}, - {0x1F, 2, 208}, - {0x29, 2, 208}, - {0x38, 3, 208}, - {0x02, 2, 128}, - {0x09, 2, 128}, - {0x17, 2, 128}, - {0x28, 3, 128}, - {0x02, 2, 130}, - {0x09, 2, 130}, - {0x17, 2, 130}, - {0x28, 3, 130}, + {0x03, 0x02, 0xD0}, + {0x06, 0x02, 0xD0}, + {0x0A, 0x02, 0xD0}, + {0x0F, 0x02, 0xD0}, + {0x18, 0x02, 0xD0}, + {0x1F, 0x02, 0xD0}, + {0x29, 0x02, 0xD0}, + {0x38, 0x03, 0xD0}, + {0x02, 0x02, 0x80}, + {0x09, 0x02, 0x80}, + {0x17, 0x02, 0x80}, + {0x28, 0x03, 0x80}, + {0x02, 0x02, 0x82}, + {0x09, 0x02, 0x82}, + {0x17, 0x02, 0x82}, + {0x28, 0x03, 0x82}, }, /* 100 */ { - {0x03, 2, 128}, - {0x06, 2, 128}, - {0x0A, 2, 128}, - {0x0F, 2, 128}, - {0x18, 2, 128}, - {0x1F, 2, 128}, - {0x29, 2, 128}, - {0x38, 3, 128}, - {0x03, 2, 130}, - {0x06, 2, 130}, - {0x0A, 2, 130}, - {0x0F, 2, 130}, - {0x18, 2, 130}, - {0x1F, 2, 130}, - {0x29, 2, 130}, - {0x38, 3, 130}, + {0x03, 0x02, 0x80}, + {0x06, 0x02, 0x80}, + {0x0A, 0x02, 0x80}, + {0x0F, 0x02, 0x80}, + {0x18, 0x02, 0x80}, + {0x1F, 0x02, 0x80}, + {0x29, 0x02, 0x80}, + {0x38, 0x03, 0x80}, + {0x03, 0x02, 0x82}, + {0x06, 0x02, 0x82}, + {0x0A, 0x02, 0x82}, + {0x0F, 0x02, 0x82}, + {0x18, 0x02, 0x82}, + {0x1F, 0x02, 0x82}, + {0x29, 0x02, 0x82}, + {0x38, 0x03, 0x82}, }, /* 101 */ { - {0x01, 2, 131}, - {0x16, 3, 131}, - {0x01, 2, 162}, - {0x16, 3, 162}, - {0x01, 2, 184}, - {0x16, 3, 184}, - {0x01, 2, 194}, - {0x16, 3, 194}, - {0x01, 2, 224}, - {0x16, 3, 224}, - {0x01, 2, 226}, - {0x16, 3, 226}, - {0x00, 3, 153}, - {0x00, 3, 161}, - {0x00, 3, 167}, - {0x00, 3, 172}, + {0x01, 0x02, 0x83}, + {0x16, 0x03, 0x83}, + {0x01, 0x02, 0xA2}, + {0x16, 0x03, 0xA2}, + {0x01, 0x02, 0xB8}, + {0x16, 0x03, 0xB8}, + {0x01, 0x02, 0xC2}, + {0x16, 0x03, 0xC2}, + {0x01, 0x02, 0xE0}, + {0x16, 0x03, 0xE0}, + {0x01, 0x02, 0xE2}, + {0x16, 0x03, 0xE2}, + {0x00, 0x03, 0x99}, + {0x00, 0x03, 0xA1}, + {0x00, 0x03, 0xA7}, + {0x00, 0x03, 0xAC}, }, /* 102 */ { - {0x02, 2, 131}, - {0x09, 2, 131}, - {0x17, 2, 131}, - {0x28, 3, 131}, - {0x02, 2, 162}, - {0x09, 2, 162}, - {0x17, 2, 162}, - {0x28, 3, 162}, - {0x02, 2, 184}, - {0x09, 2, 184}, - {0x17, 2, 184}, - {0x28, 3, 184}, - {0x02, 2, 194}, - {0x09, 2, 194}, - {0x17, 2, 194}, - {0x28, 3, 194}, + {0x02, 0x02, 0x83}, + {0x09, 0x02, 0x83}, + {0x17, 0x02, 0x83}, + {0x28, 0x03, 0x83}, + {0x02, 0x02, 0xA2}, + {0x09, 0x02, 0xA2}, + {0x17, 0x02, 0xA2}, + {0x28, 0x03, 0xA2}, + {0x02, 0x02, 0xB8}, + {0x09, 0x02, 0xB8}, + {0x17, 0x02, 0xB8}, + {0x28, 0x03, 0xB8}, + {0x02, 0x02, 0xC2}, + {0x09, 0x02, 0xC2}, + {0x17, 0x02, 0xC2}, + {0x28, 0x03, 0xC2}, }, /* 103 */ { - {0x03, 2, 131}, - {0x06, 2, 131}, - {0x0A, 2, 131}, - {0x0F, 2, 131}, - {0x18, 2, 131}, - {0x1F, 2, 131}, - {0x29, 2, 131}, - {0x38, 3, 131}, - {0x03, 2, 162}, - {0x06, 2, 162}, - {0x0A, 2, 162}, - {0x0F, 2, 162}, - {0x18, 2, 162}, - {0x1F, 2, 162}, - {0x29, 2, 162}, - {0x38, 3, 162}, + {0x03, 0x02, 0x83}, + {0x06, 0x02, 0x83}, + {0x0A, 0x02, 0x83}, + {0x0F, 0x02, 0x83}, + {0x18, 0x02, 0x83}, + {0x1F, 0x02, 0x83}, + {0x29, 0x02, 0x83}, + {0x38, 0x03, 0x83}, + {0x03, 0x02, 0xA2}, + {0x06, 0x02, 0xA2}, + {0x0A, 0x02, 0xA2}, + {0x0F, 0x02, 0xA2}, + {0x18, 0x02, 0xA2}, + {0x1F, 0x02, 0xA2}, + {0x29, 0x02, 0xA2}, + {0x38, 0x03, 0xA2}, }, /* 104 */ { - {0x03, 2, 184}, - {0x06, 2, 184}, - {0x0A, 2, 184}, - {0x0F, 2, 184}, - {0x18, 2, 184}, - {0x1F, 2, 184}, - {0x29, 2, 184}, - {0x38, 3, 184}, - {0x03, 2, 194}, - {0x06, 2, 194}, - {0x0A, 2, 194}, - {0x0F, 2, 194}, - {0x18, 2, 194}, - {0x1F, 2, 194}, - {0x29, 2, 194}, - {0x38, 3, 194}, + {0x03, 0x02, 0xB8}, + {0x06, 0x02, 0xB8}, + {0x0A, 0x02, 0xB8}, + {0x0F, 0x02, 0xB8}, + {0x18, 0x02, 0xB8}, + {0x1F, 0x02, 0xB8}, + {0x29, 0x02, 0xB8}, + {0x38, 0x03, 0xB8}, + {0x03, 0x02, 0xC2}, + {0x06, 0x02, 0xC2}, + {0x0A, 0x02, 0xC2}, + {0x0F, 0x02, 0xC2}, + {0x18, 0x02, 0xC2}, + {0x1F, 0x02, 0xC2}, + {0x29, 0x02, 0xC2}, + {0x38, 0x03, 0xC2}, }, /* 105 */ { - {0x02, 2, 224}, - {0x09, 2, 224}, - {0x17, 2, 224}, - {0x28, 3, 224}, - {0x02, 2, 226}, - {0x09, 2, 226}, - {0x17, 2, 226}, - {0x28, 3, 226}, - {0x01, 2, 153}, - {0x16, 3, 153}, - {0x01, 2, 161}, - {0x16, 3, 161}, - {0x01, 2, 167}, - {0x16, 3, 167}, - {0x01, 2, 172}, - {0x16, 3, 172}, + {0x02, 0x02, 0xE0}, + {0x09, 0x02, 0xE0}, + {0x17, 0x02, 0xE0}, + {0x28, 0x03, 0xE0}, + {0x02, 0x02, 0xE2}, + {0x09, 0x02, 0xE2}, + {0x17, 0x02, 0xE2}, + {0x28, 0x03, 0xE2}, + {0x01, 0x02, 0x99}, + {0x16, 0x03, 0x99}, + {0x01, 0x02, 0xA1}, + {0x16, 0x03, 0xA1}, + {0x01, 0x02, 0xA7}, + {0x16, 0x03, 0xA7}, + {0x01, 0x02, 0xAC}, + {0x16, 0x03, 0xAC}, }, /* 106 */ { - {0x03, 2, 224}, - {0x06, 2, 224}, - {0x0A, 2, 224}, - {0x0F, 2, 224}, - {0x18, 2, 224}, - {0x1F, 2, 224}, - {0x29, 2, 224}, - {0x38, 3, 224}, - {0x03, 2, 226}, - {0x06, 2, 226}, - {0x0A, 2, 226}, - {0x0F, 2, 226}, - {0x18, 2, 226}, - {0x1F, 2, 226}, - {0x29, 2, 226}, - {0x38, 3, 226}, + {0x03, 0x02, 0xE0}, + {0x06, 0x02, 0xE0}, + {0x0A, 0x02, 0xE0}, + {0x0F, 0x02, 0xE0}, + {0x18, 0x02, 0xE0}, + {0x1F, 0x02, 0xE0}, + {0x29, 0x02, 0xE0}, + {0x38, 0x03, 0xE0}, + {0x03, 0x02, 0xE2}, + {0x06, 0x02, 0xE2}, + {0x0A, 0x02, 0xE2}, + {0x0F, 0x02, 0xE2}, + {0x18, 0x02, 0xE2}, + {0x1F, 0x02, 0xE2}, + {0x29, 0x02, 0xE2}, + {0x38, 0x03, 0xE2}, }, /* 107 */ { - {0x02, 2, 153}, - {0x09, 2, 153}, - {0x17, 2, 153}, - {0x28, 3, 153}, - {0x02, 2, 161}, - {0x09, 2, 161}, - {0x17, 2, 161}, - {0x28, 3, 161}, - {0x02, 2, 167}, - {0x09, 2, 167}, - {0x17, 2, 167}, - {0x28, 3, 167}, - {0x02, 2, 172}, - {0x09, 2, 172}, - {0x17, 2, 172}, - {0x28, 3, 172}, + {0x02, 0x02, 0x99}, + {0x09, 0x02, 0x99}, + {0x17, 0x02, 0x99}, + {0x28, 0x03, 0x99}, + {0x02, 0x02, 0xA1}, + {0x09, 0x02, 0xA1}, + {0x17, 0x02, 0xA1}, + {0x28, 0x03, 0xA1}, + {0x02, 0x02, 0xA7}, + {0x09, 0x02, 0xA7}, + {0x17, 0x02, 0xA7}, + {0x28, 0x03, 0xA7}, + {0x02, 0x02, 0xAC}, + {0x09, 0x02, 0xAC}, + {0x17, 0x02, 0xAC}, + {0x28, 0x03, 0xAC}, }, /* 108 */ { - {0x03, 2, 153}, - {0x06, 2, 153}, - {0x0A, 2, 153}, - {0x0F, 2, 153}, - {0x18, 2, 153}, - {0x1F, 2, 153}, - {0x29, 2, 153}, - {0x38, 3, 153}, - {0x03, 2, 161}, - {0x06, 2, 161}, - {0x0A, 2, 161}, - {0x0F, 2, 161}, - {0x18, 2, 161}, - {0x1F, 2, 161}, - {0x29, 2, 161}, - {0x38, 3, 161}, + {0x03, 0x02, 0x99}, + {0x06, 0x02, 0x99}, + {0x0A, 0x02, 0x99}, + {0x0F, 0x02, 0x99}, + {0x18, 0x02, 0x99}, + {0x1F, 0x02, 0x99}, + {0x29, 0x02, 0x99}, + {0x38, 0x03, 0x99}, + {0x03, 0x02, 0xA1}, + {0x06, 0x02, 0xA1}, + {0x0A, 0x02, 0xA1}, + {0x0F, 0x02, 0xA1}, + {0x18, 0x02, 0xA1}, + {0x1F, 0x02, 0xA1}, + {0x29, 0x02, 0xA1}, + {0x38, 0x03, 0xA1}, }, /* 109 */ { - {0x03, 2, 167}, - {0x06, 2, 167}, - {0x0A, 2, 167}, - {0x0F, 2, 167}, - {0x18, 2, 167}, - {0x1F, 2, 167}, - {0x29, 2, 167}, - {0x38, 3, 167}, - {0x03, 2, 172}, - {0x06, 2, 172}, - {0x0A, 2, 172}, - {0x0F, 2, 172}, - {0x18, 2, 172}, - {0x1F, 2, 172}, - {0x29, 2, 172}, - {0x38, 3, 172}, + {0x03, 0x02, 0xA7}, + {0x06, 0x02, 0xA7}, + {0x0A, 0x02, 0xA7}, + {0x0F, 0x02, 0xA7}, + {0x18, 0x02, 0xA7}, + {0x1F, 0x02, 0xA7}, + {0x29, 0x02, 0xA7}, + {0x38, 0x03, 0xA7}, + {0x03, 0x02, 0xAC}, + {0x06, 0x02, 0xAC}, + {0x0A, 0x02, 0xAC}, + {0x0F, 0x02, 0xAC}, + {0x18, 0x02, 0xAC}, + {0x1F, 0x02, 0xAC}, + {0x29, 0x02, 0xAC}, + {0x38, 0x03, 0xAC}, }, /* 110 */ { - {0x72, 0, 0}, - {0x73, 0, 0}, - {0x75, 0, 0}, - {0x76, 0, 0}, - {0x79, 0, 0}, - {0x7B, 0, 0}, - {0x7F, 0, 0}, - {0x82, 0, 0}, - {0x88, 0, 0}, - {0x8B, 0, 0}, - {0x8F, 0, 0}, - {0x92, 0, 0}, - {0x9B, 0, 0}, - {0xA2, 0, 0}, - {0xAA, 0, 0}, - {0xB4, 0, 0}, + {0x72, 0x00, 0x00}, + {0x73, 0x00, 0x00}, + {0x75, 0x00, 0x00}, + {0x76, 0x00, 0x00}, + {0x79, 0x00, 0x00}, + {0x7B, 0x00, 0x00}, + {0x7F, 0x00, 0x00}, + {0x82, 0x00, 0x00}, + {0x88, 0x00, 0x00}, + {0x8B, 0x00, 0x00}, + {0x8F, 0x00, 0x00}, + {0x92, 0x00, 0x00}, + {0x9B, 0x00, 0x00}, + {0xA2, 0x00, 0x00}, + {0xAA, 0x00, 0x00}, + {0xB4, 0x00, 0x00}, }, /* 111 */ { - {0x00, 3, 176}, - {0x00, 3, 177}, - {0x00, 3, 179}, - {0x00, 3, 209}, - {0x00, 3, 216}, - {0x00, 3, 217}, - {0x00, 3, 227}, - {0x00, 3, 229}, - {0x00, 3, 230}, - {0x7A, 0, 0}, - {0x7C, 0, 0}, - {0x7D, 0, 0}, - {0x80, 0, 0}, - {0x81, 0, 0}, - {0x83, 0, 0}, - {0x84, 0, 0}, + {0x00, 0x03, 0xB0}, + {0x00, 0x03, 0xB1}, + {0x00, 0x03, 0xB3}, + {0x00, 0x03, 0xD1}, + {0x00, 0x03, 0xD8}, + {0x00, 0x03, 0xD9}, + {0x00, 0x03, 0xE3}, + {0x00, 0x03, 0xE5}, + {0x00, 0x03, 0xE6}, + {0x7A, 0x00, 0x00}, + {0x7C, 0x00, 0x00}, + {0x7D, 0x00, 0x00}, + {0x80, 0x00, 0x00}, + {0x81, 0x00, 0x00}, + {0x83, 0x00, 0x00}, + {0x84, 0x00, 0x00}, }, /* 112 */ { - {0x01, 2, 176}, - {0x16, 3, 176}, - {0x01, 2, 177}, - {0x16, 3, 177}, - {0x01, 2, 179}, - {0x16, 3, 179}, - {0x01, 2, 209}, - {0x16, 3, 209}, - {0x01, 2, 216}, - {0x16, 3, 216}, - {0x01, 2, 217}, - {0x16, 3, 217}, - {0x01, 2, 227}, - {0x16, 3, 227}, - {0x01, 2, 229}, - {0x16, 3, 229}, + {0x01, 0x02, 0xB0}, + {0x16, 0x03, 0xB0}, + {0x01, 0x02, 0xB1}, + {0x16, 0x03, 0xB1}, + {0x01, 0x02, 0xB3}, + {0x16, 0x03, 0xB3}, + {0x01, 0x02, 0xD1}, + {0x16, 0x03, 0xD1}, + {0x01, 0x02, 0xD8}, + {0x16, 0x03, 0xD8}, + {0x01, 0x02, 0xD9}, + {0x16, 0x03, 0xD9}, + {0x01, 0x02, 0xE3}, + {0x16, 0x03, 0xE3}, + {0x01, 0x02, 0xE5}, + {0x16, 0x03, 0xE5}, }, /* 113 */ { - {0x02, 2, 176}, - {0x09, 2, 176}, - {0x17, 2, 176}, - {0x28, 3, 176}, - {0x02, 2, 177}, - {0x09, 2, 177}, - {0x17, 2, 177}, - {0x28, 3, 177}, - {0x02, 2, 179}, - {0x09, 2, 179}, - {0x17, 2, 179}, - {0x28, 3, 179}, - {0x02, 2, 209}, - {0x09, 2, 209}, - {0x17, 2, 209}, - {0x28, 3, 209}, + {0x02, 0x02, 0xB0}, + {0x09, 0x02, 0xB0}, + {0x17, 0x02, 0xB0}, + {0x28, 0x03, 0xB0}, + {0x02, 0x02, 0xB1}, + {0x09, 0x02, 0xB1}, + {0x17, 0x02, 0xB1}, + {0x28, 0x03, 0xB1}, + {0x02, 0x02, 0xB3}, + {0x09, 0x02, 0xB3}, + {0x17, 0x02, 0xB3}, + {0x28, 0x03, 0xB3}, + {0x02, 0x02, 0xD1}, + {0x09, 0x02, 0xD1}, + {0x17, 0x02, 0xD1}, + {0x28, 0x03, 0xD1}, }, /* 114 */ { - {0x03, 2, 176}, - {0x06, 2, 176}, - {0x0A, 2, 176}, - {0x0F, 2, 176}, - {0x18, 2, 176}, - {0x1F, 2, 176}, - {0x29, 2, 176}, - {0x38, 3, 176}, - {0x03, 2, 177}, - {0x06, 2, 177}, - {0x0A, 2, 177}, - {0x0F, 2, 177}, - {0x18, 2, 177}, - {0x1F, 2, 177}, - {0x29, 2, 177}, - {0x38, 3, 177}, + {0x03, 0x02, 0xB0}, + {0x06, 0x02, 0xB0}, + {0x0A, 0x02, 0xB0}, + {0x0F, 0x02, 0xB0}, + {0x18, 0x02, 0xB0}, + {0x1F, 0x02, 0xB0}, + {0x29, 0x02, 0xB0}, + {0x38, 0x03, 0xB0}, + {0x03, 0x02, 0xB1}, + {0x06, 0x02, 0xB1}, + {0x0A, 0x02, 0xB1}, + {0x0F, 0x02, 0xB1}, + {0x18, 0x02, 0xB1}, + {0x1F, 0x02, 0xB1}, + {0x29, 0x02, 0xB1}, + {0x38, 0x03, 0xB1}, }, /* 115 */ { - {0x03, 2, 179}, - {0x06, 2, 179}, - {0x0A, 2, 179}, - {0x0F, 2, 179}, - {0x18, 2, 179}, - {0x1F, 2, 179}, - {0x29, 2, 179}, - {0x38, 3, 179}, - {0x03, 2, 209}, - {0x06, 2, 209}, - {0x0A, 2, 209}, - {0x0F, 2, 209}, - {0x18, 2, 209}, - {0x1F, 2, 209}, - {0x29, 2, 209}, - {0x38, 3, 209}, + {0x03, 0x02, 0xB3}, + {0x06, 0x02, 0xB3}, + {0x0A, 0x02, 0xB3}, + {0x0F, 0x02, 0xB3}, + {0x18, 0x02, 0xB3}, + {0x1F, 0x02, 0xB3}, + {0x29, 0x02, 0xB3}, + {0x38, 0x03, 0xB3}, + {0x03, 0x02, 0xD1}, + {0x06, 0x02, 0xD1}, + {0x0A, 0x02, 0xD1}, + {0x0F, 0x02, 0xD1}, + {0x18, 0x02, 0xD1}, + {0x1F, 0x02, 0xD1}, + {0x29, 0x02, 0xD1}, + {0x38, 0x03, 0xD1}, }, /* 116 */ { - {0x02, 2, 216}, - {0x09, 2, 216}, - {0x17, 2, 216}, - {0x28, 3, 216}, - {0x02, 2, 217}, - {0x09, 2, 217}, - {0x17, 2, 217}, - {0x28, 3, 217}, - {0x02, 2, 227}, - {0x09, 2, 227}, - {0x17, 2, 227}, - {0x28, 3, 227}, - {0x02, 2, 229}, - {0x09, 2, 229}, - {0x17, 2, 229}, - {0x28, 3, 229}, + {0x02, 0x02, 0xD8}, + {0x09, 0x02, 0xD8}, + {0x17, 0x02, 0xD8}, + {0x28, 0x03, 0xD8}, + {0x02, 0x02, 0xD9}, + {0x09, 0x02, 0xD9}, + {0x17, 0x02, 0xD9}, + {0x28, 0x03, 0xD9}, + {0x02, 0x02, 0xE3}, + {0x09, 0x02, 0xE3}, + {0x17, 0x02, 0xE3}, + {0x28, 0x03, 0xE3}, + {0x02, 0x02, 0xE5}, + {0x09, 0x02, 0xE5}, + {0x17, 0x02, 0xE5}, + {0x28, 0x03, 0xE5}, }, /* 117 */ { - {0x03, 2, 216}, - {0x06, 2, 216}, - {0x0A, 2, 216}, - {0x0F, 2, 216}, - {0x18, 2, 216}, - {0x1F, 2, 216}, - {0x29, 2, 216}, - {0x38, 3, 216}, - {0x03, 2, 217}, - {0x06, 2, 217}, - {0x0A, 2, 217}, - {0x0F, 2, 217}, - {0x18, 2, 217}, - {0x1F, 2, 217}, - {0x29, 2, 217}, - {0x38, 3, 217}, + {0x03, 0x02, 0xD8}, + {0x06, 0x02, 0xD8}, + {0x0A, 0x02, 0xD8}, + {0x0F, 0x02, 0xD8}, + {0x18, 0x02, 0xD8}, + {0x1F, 0x02, 0xD8}, + {0x29, 0x02, 0xD8}, + {0x38, 0x03, 0xD8}, + {0x03, 0x02, 0xD9}, + {0x06, 0x02, 0xD9}, + {0x0A, 0x02, 0xD9}, + {0x0F, 0x02, 0xD9}, + {0x18, 0x02, 0xD9}, + {0x1F, 0x02, 0xD9}, + {0x29, 0x02, 0xD9}, + {0x38, 0x03, 0xD9}, }, /* 118 */ { - {0x03, 2, 227}, - {0x06, 2, 227}, - {0x0A, 2, 227}, - {0x0F, 2, 227}, - {0x18, 2, 227}, - {0x1F, 2, 227}, - {0x29, 2, 227}, - {0x38, 3, 227}, - {0x03, 2, 229}, - {0x06, 2, 229}, - {0x0A, 2, 229}, - {0x0F, 2, 229}, - {0x18, 2, 229}, - {0x1F, 2, 229}, - {0x29, 2, 229}, - {0x38, 3, 229}, + {0x03, 0x02, 0xE3}, + {0x06, 0x02, 0xE3}, + {0x0A, 0x02, 0xE3}, + {0x0F, 0x02, 0xE3}, + {0x18, 0x02, 0xE3}, + {0x1F, 0x02, 0xE3}, + {0x29, 0x02, 0xE3}, + {0x38, 0x03, 0xE3}, + {0x03, 0x02, 0xE5}, + {0x06, 0x02, 0xE5}, + {0x0A, 0x02, 0xE5}, + {0x0F, 0x02, 0xE5}, + {0x18, 0x02, 0xE5}, + {0x1F, 0x02, 0xE5}, + {0x29, 0x02, 0xE5}, + {0x38, 0x03, 0xE5}, }, /* 119 */ { - {0x01, 2, 230}, - {0x16, 3, 230}, - {0x00, 3, 129}, - {0x00, 3, 132}, - {0x00, 3, 133}, - {0x00, 3, 134}, - {0x00, 3, 136}, - {0x00, 3, 146}, - {0x00, 3, 154}, - {0x00, 3, 156}, - {0x00, 3, 160}, - {0x00, 3, 163}, - {0x00, 3, 164}, - {0x00, 3, 169}, - {0x00, 3, 170}, - {0x00, 3, 173}, + {0x01, 0x02, 0xE6}, + {0x16, 0x03, 0xE6}, + {0x00, 0x03, 0x81}, + {0x00, 0x03, 0x84}, + {0x00, 0x03, 0x85}, + {0x00, 0x03, 0x86}, + {0x00, 0x03, 0x88}, + {0x00, 0x03, 0x92}, + {0x00, 0x03, 0x9A}, + {0x00, 0x03, 0x9C}, + {0x00, 0x03, 0xA0}, + {0x00, 0x03, 0xA3}, + {0x00, 0x03, 0xA4}, + {0x00, 0x03, 0xA9}, + {0x00, 0x03, 0xAA}, + {0x00, 0x03, 0xAD}, }, /* 120 */ { - {0x02, 2, 230}, - {0x09, 2, 230}, - {0x17, 2, 230}, - {0x28, 3, 230}, - {0x01, 2, 129}, - {0x16, 3, 129}, - {0x01, 2, 132}, - {0x16, 3, 132}, - {0x01, 2, 133}, - {0x16, 3, 133}, - {0x01, 2, 134}, - {0x16, 3, 134}, - {0x01, 2, 136}, - {0x16, 3, 136}, - {0x01, 2, 146}, - {0x16, 3, 146}, + {0x02, 0x02, 0xE6}, + {0x09, 0x02, 0xE6}, + {0x17, 0x02, 0xE6}, + {0x28, 0x03, 0xE6}, + {0x01, 0x02, 0x81}, + {0x16, 0x03, 0x81}, + {0x01, 0x02, 0x84}, + {0x16, 0x03, 0x84}, + {0x01, 0x02, 0x85}, + {0x16, 0x03, 0x85}, + {0x01, 0x02, 0x86}, + {0x16, 0x03, 0x86}, + {0x01, 0x02, 0x88}, + {0x16, 0x03, 0x88}, + {0x01, 0x02, 0x92}, + {0x16, 0x03, 0x92}, }, /* 121 */ { - {0x03, 2, 230}, - {0x06, 2, 230}, - {0x0A, 2, 230}, - {0x0F, 2, 230}, - {0x18, 2, 230}, - {0x1F, 2, 230}, - {0x29, 2, 230}, - {0x38, 3, 230}, - {0x02, 2, 129}, - {0x09, 2, 129}, - {0x17, 2, 129}, - {0x28, 3, 129}, - {0x02, 2, 132}, - {0x09, 2, 132}, - {0x17, 2, 132}, - {0x28, 3, 132}, + {0x03, 0x02, 0xE6}, + {0x06, 0x02, 0xE6}, + {0x0A, 0x02, 0xE6}, + {0x0F, 0x02, 0xE6}, + {0x18, 0x02, 0xE6}, + {0x1F, 0x02, 0xE6}, + {0x29, 0x02, 0xE6}, + {0x38, 0x03, 0xE6}, + {0x02, 0x02, 0x81}, + {0x09, 0x02, 0x81}, + {0x17, 0x02, 0x81}, + {0x28, 0x03, 0x81}, + {0x02, 0x02, 0x84}, + {0x09, 0x02, 0x84}, + {0x17, 0x02, 0x84}, + {0x28, 0x03, 0x84}, }, /* 122 */ { - {0x03, 2, 129}, - {0x06, 2, 129}, - {0x0A, 2, 129}, - {0x0F, 2, 129}, - {0x18, 2, 129}, - {0x1F, 2, 129}, - {0x29, 2, 129}, - {0x38, 3, 129}, - {0x03, 2, 132}, - {0x06, 2, 132}, - {0x0A, 2, 132}, - {0x0F, 2, 132}, - {0x18, 2, 132}, - {0x1F, 2, 132}, - {0x29, 2, 132}, - {0x38, 3, 132}, + {0x03, 0x02, 0x81}, + {0x06, 0x02, 0x81}, + {0x0A, 0x02, 0x81}, + {0x0F, 0x02, 0x81}, + {0x18, 0x02, 0x81}, + {0x1F, 0x02, 0x81}, + {0x29, 0x02, 0x81}, + {0x38, 0x03, 0x81}, + {0x03, 0x02, 0x84}, + {0x06, 0x02, 0x84}, + {0x0A, 0x02, 0x84}, + {0x0F, 0x02, 0x84}, + {0x18, 0x02, 0x84}, + {0x1F, 0x02, 0x84}, + {0x29, 0x02, 0x84}, + {0x38, 0x03, 0x84}, }, /* 123 */ { - {0x02, 2, 133}, - {0x09, 2, 133}, - {0x17, 2, 133}, - {0x28, 3, 133}, - {0x02, 2, 134}, - {0x09, 2, 134}, - {0x17, 2, 134}, - {0x28, 3, 134}, - {0x02, 2, 136}, - {0x09, 2, 136}, - {0x17, 2, 136}, - {0x28, 3, 136}, - {0x02, 2, 146}, - {0x09, 2, 146}, - {0x17, 2, 146}, - {0x28, 3, 146}, + {0x02, 0x02, 0x85}, + {0x09, 0x02, 0x85}, + {0x17, 0x02, 0x85}, + {0x28, 0x03, 0x85}, + {0x02, 0x02, 0x86}, + {0x09, 0x02, 0x86}, + {0x17, 0x02, 0x86}, + {0x28, 0x03, 0x86}, + {0x02, 0x02, 0x88}, + {0x09, 0x02, 0x88}, + {0x17, 0x02, 0x88}, + {0x28, 0x03, 0x88}, + {0x02, 0x02, 0x92}, + {0x09, 0x02, 0x92}, + {0x17, 0x02, 0x92}, + {0x28, 0x03, 0x92}, }, /* 124 */ { - {0x03, 2, 133}, - {0x06, 2, 133}, - {0x0A, 2, 133}, - {0x0F, 2, 133}, - {0x18, 2, 133}, - {0x1F, 2, 133}, - {0x29, 2, 133}, - {0x38, 3, 133}, - {0x03, 2, 134}, - {0x06, 2, 134}, - {0x0A, 2, 134}, - {0x0F, 2, 134}, - {0x18, 2, 134}, - {0x1F, 2, 134}, - {0x29, 2, 134}, - {0x38, 3, 134}, + {0x03, 0x02, 0x85}, + {0x06, 0x02, 0x85}, + {0x0A, 0x02, 0x85}, + {0x0F, 0x02, 0x85}, + {0x18, 0x02, 0x85}, + {0x1F, 0x02, 0x85}, + {0x29, 0x02, 0x85}, + {0x38, 0x03, 0x85}, + {0x03, 0x02, 0x86}, + {0x06, 0x02, 0x86}, + {0x0A, 0x02, 0x86}, + {0x0F, 0x02, 0x86}, + {0x18, 0x02, 0x86}, + {0x1F, 0x02, 0x86}, + {0x29, 0x02, 0x86}, + {0x38, 0x03, 0x86}, }, /* 125 */ { - {0x03, 2, 136}, - {0x06, 2, 136}, - {0x0A, 2, 136}, - {0x0F, 2, 136}, - {0x18, 2, 136}, - {0x1F, 2, 136}, - {0x29, 2, 136}, - {0x38, 3, 136}, - {0x03, 2, 146}, - {0x06, 2, 146}, - {0x0A, 2, 146}, - {0x0F, 2, 146}, - {0x18, 2, 146}, - {0x1F, 2, 146}, - {0x29, 2, 146}, - {0x38, 3, 146}, + {0x03, 0x02, 0x88}, + {0x06, 0x02, 0x88}, + {0x0A, 0x02, 0x88}, + {0x0F, 0x02, 0x88}, + {0x18, 0x02, 0x88}, + {0x1F, 0x02, 0x88}, + {0x29, 0x02, 0x88}, + {0x38, 0x03, 0x88}, + {0x03, 0x02, 0x92}, + {0x06, 0x02, 0x92}, + {0x0A, 0x02, 0x92}, + {0x0F, 0x02, 0x92}, + {0x18, 0x02, 0x92}, + {0x1F, 0x02, 0x92}, + {0x29, 0x02, 0x92}, + {0x38, 0x03, 0x92}, }, /* 126 */ { - {0x01, 2, 154}, - {0x16, 3, 154}, - {0x01, 2, 156}, - {0x16, 3, 156}, - {0x01, 2, 160}, - {0x16, 3, 160}, - {0x01, 2, 163}, - {0x16, 3, 163}, - {0x01, 2, 164}, - {0x16, 3, 164}, - {0x01, 2, 169}, - {0x16, 3, 169}, - {0x01, 2, 170}, - {0x16, 3, 170}, - {0x01, 2, 173}, - {0x16, 3, 173}, + {0x01, 0x02, 0x9A}, + {0x16, 0x03, 0x9A}, + {0x01, 0x02, 0x9C}, + {0x16, 0x03, 0x9C}, + {0x01, 0x02, 0xA0}, + {0x16, 0x03, 0xA0}, + {0x01, 0x02, 0xA3}, + {0x16, 0x03, 0xA3}, + {0x01, 0x02, 0xA4}, + {0x16, 0x03, 0xA4}, + {0x01, 0x02, 0xA9}, + {0x16, 0x03, 0xA9}, + {0x01, 0x02, 0xAA}, + {0x16, 0x03, 0xAA}, + {0x01, 0x02, 0xAD}, + {0x16, 0x03, 0xAD}, }, /* 127 */ { - {0x02, 2, 154}, - {0x09, 2, 154}, - {0x17, 2, 154}, - {0x28, 3, 154}, - {0x02, 2, 156}, - {0x09, 2, 156}, - {0x17, 2, 156}, - {0x28, 3, 156}, - {0x02, 2, 160}, - {0x09, 2, 160}, - {0x17, 2, 160}, - {0x28, 3, 160}, - {0x02, 2, 163}, - {0x09, 2, 163}, - {0x17, 2, 163}, - {0x28, 3, 163}, + {0x02, 0x02, 0x9A}, + {0x09, 0x02, 0x9A}, + {0x17, 0x02, 0x9A}, + {0x28, 0x03, 0x9A}, + {0x02, 0x02, 0x9C}, + {0x09, 0x02, 0x9C}, + {0x17, 0x02, 0x9C}, + {0x28, 0x03, 0x9C}, + {0x02, 0x02, 0xA0}, + {0x09, 0x02, 0xA0}, + {0x17, 0x02, 0xA0}, + {0x28, 0x03, 0xA0}, + {0x02, 0x02, 0xA3}, + {0x09, 0x02, 0xA3}, + {0x17, 0x02, 0xA3}, + {0x28, 0x03, 0xA3}, }, /* 128 */ { - {0x03, 2, 154}, - {0x06, 2, 154}, - {0x0A, 2, 154}, - {0x0F, 2, 154}, - {0x18, 2, 154}, - {0x1F, 2, 154}, - {0x29, 2, 154}, - {0x38, 3, 154}, - {0x03, 2, 156}, - {0x06, 2, 156}, - {0x0A, 2, 156}, - {0x0F, 2, 156}, - {0x18, 2, 156}, - {0x1F, 2, 156}, - {0x29, 2, 156}, - {0x38, 3, 156}, + {0x03, 0x02, 0x9A}, + {0x06, 0x02, 0x9A}, + {0x0A, 0x02, 0x9A}, + {0x0F, 0x02, 0x9A}, + {0x18, 0x02, 0x9A}, + {0x1F, 0x02, 0x9A}, + {0x29, 0x02, 0x9A}, + {0x38, 0x03, 0x9A}, + {0x03, 0x02, 0x9C}, + {0x06, 0x02, 0x9C}, + {0x0A, 0x02, 0x9C}, + {0x0F, 0x02, 0x9C}, + {0x18, 0x02, 0x9C}, + {0x1F, 0x02, 0x9C}, + {0x29, 0x02, 0x9C}, + {0x38, 0x03, 0x9C}, }, /* 129 */ { - {0x03, 2, 160}, - {0x06, 2, 160}, - {0x0A, 2, 160}, - {0x0F, 2, 160}, - {0x18, 2, 160}, - {0x1F, 2, 160}, - {0x29, 2, 160}, - {0x38, 3, 160}, - {0x03, 2, 163}, - {0x06, 2, 163}, - {0x0A, 2, 163}, - {0x0F, 2, 163}, - {0x18, 2, 163}, - {0x1F, 2, 163}, - {0x29, 2, 163}, - {0x38, 3, 163}, + {0x03, 0x02, 0xA0}, + {0x06, 0x02, 0xA0}, + {0x0A, 0x02, 0xA0}, + {0x0F, 0x02, 0xA0}, + {0x18, 0x02, 0xA0}, + {0x1F, 0x02, 0xA0}, + {0x29, 0x02, 0xA0}, + {0x38, 0x03, 0xA0}, + {0x03, 0x02, 0xA3}, + {0x06, 0x02, 0xA3}, + {0x0A, 0x02, 0xA3}, + {0x0F, 0x02, 0xA3}, + {0x18, 0x02, 0xA3}, + {0x1F, 0x02, 0xA3}, + {0x29, 0x02, 0xA3}, + {0x38, 0x03, 0xA3}, }, /* 130 */ { - {0x02, 2, 164}, - {0x09, 2, 164}, - {0x17, 2, 164}, - {0x28, 3, 164}, - {0x02, 2, 169}, - {0x09, 2, 169}, - {0x17, 2, 169}, - {0x28, 3, 169}, - {0x02, 2, 170}, - {0x09, 2, 170}, - {0x17, 2, 170}, - {0x28, 3, 170}, - {0x02, 2, 173}, - {0x09, 2, 173}, - {0x17, 2, 173}, - {0x28, 3, 173}, + {0x02, 0x02, 0xA4}, + {0x09, 0x02, 0xA4}, + {0x17, 0x02, 0xA4}, + {0x28, 0x03, 0xA4}, + {0x02, 0x02, 0xA9}, + {0x09, 0x02, 0xA9}, + {0x17, 0x02, 0xA9}, + {0x28, 0x03, 0xA9}, + {0x02, 0x02, 0xAA}, + {0x09, 0x02, 0xAA}, + {0x17, 0x02, 0xAA}, + {0x28, 0x03, 0xAA}, + {0x02, 0x02, 0xAD}, + {0x09, 0x02, 0xAD}, + {0x17, 0x02, 0xAD}, + {0x28, 0x03, 0xAD}, }, /* 131 */ { - {0x03, 2, 164}, - {0x06, 2, 164}, - {0x0A, 2, 164}, - {0x0F, 2, 164}, - {0x18, 2, 164}, - {0x1F, 2, 164}, - {0x29, 2, 164}, - {0x38, 3, 164}, - {0x03, 2, 169}, - {0x06, 2, 169}, - {0x0A, 2, 169}, - {0x0F, 2, 169}, - {0x18, 2, 169}, - {0x1F, 2, 169}, - {0x29, 2, 169}, - {0x38, 3, 169}, + {0x03, 0x02, 0xA4}, + {0x06, 0x02, 0xA4}, + {0x0A, 0x02, 0xA4}, + {0x0F, 0x02, 0xA4}, + {0x18, 0x02, 0xA4}, + {0x1F, 0x02, 0xA4}, + {0x29, 0x02, 0xA4}, + {0x38, 0x03, 0xA4}, + {0x03, 0x02, 0xA9}, + {0x06, 0x02, 0xA9}, + {0x0A, 0x02, 0xA9}, + {0x0F, 0x02, 0xA9}, + {0x18, 0x02, 0xA9}, + {0x1F, 0x02, 0xA9}, + {0x29, 0x02, 0xA9}, + {0x38, 0x03, 0xA9}, }, /* 132 */ { - {0x03, 2, 170}, - {0x06, 2, 170}, - {0x0A, 2, 170}, - {0x0F, 2, 170}, - {0x18, 2, 170}, - {0x1F, 2, 170}, - {0x29, 2, 170}, - {0x38, 3, 170}, - {0x03, 2, 173}, - {0x06, 2, 173}, - {0x0A, 2, 173}, - {0x0F, 2, 173}, - {0x18, 2, 173}, - {0x1F, 2, 173}, - {0x29, 2, 173}, - {0x38, 3, 173}, + {0x03, 0x02, 0xAA}, + {0x06, 0x02, 0xAA}, + {0x0A, 0x02, 0xAA}, + {0x0F, 0x02, 0xAA}, + {0x18, 0x02, 0xAA}, + {0x1F, 0x02, 0xAA}, + {0x29, 0x02, 0xAA}, + {0x38, 0x03, 0xAA}, + {0x03, 0x02, 0xAD}, + {0x06, 0x02, 0xAD}, + {0x0A, 0x02, 0xAD}, + {0x0F, 0x02, 0xAD}, + {0x18, 0x02, 0xAD}, + {0x1F, 0x02, 0xAD}, + {0x29, 0x02, 0xAD}, + {0x38, 0x03, 0xAD}, }, /* 133 */ { - {0x89, 0, 0}, - {0x8A, 0, 0}, - {0x8C, 0, 0}, - {0x8D, 0, 0}, - {0x90, 0, 0}, - {0x91, 0, 0}, - {0x93, 0, 0}, - {0x96, 0, 0}, - {0x9C, 0, 0}, - {0x9F, 0, 0}, - {0xA3, 0, 0}, - {0xA6, 0, 0}, - {0xAB, 0, 0}, - {0xAE, 0, 0}, - {0xB5, 0, 0}, - {0xBE, 0, 0}, + {0x89, 0x00, 0x00}, + {0x8A, 0x00, 0x00}, + {0x8C, 0x00, 0x00}, + {0x8D, 0x00, 0x00}, + {0x90, 0x00, 0x00}, + {0x91, 0x00, 0x00}, + {0x93, 0x00, 0x00}, + {0x96, 0x00, 0x00}, + {0x9C, 0x00, 0x00}, + {0x9F, 0x00, 0x00}, + {0xA3, 0x00, 0x00}, + {0xA6, 0x00, 0x00}, + {0xAB, 0x00, 0x00}, + {0xAE, 0x00, 0x00}, + {0xB5, 0x00, 0x00}, + {0xBE, 0x00, 0x00}, }, /* 134 */ { - {0x00, 3, 178}, - {0x00, 3, 181}, - {0x00, 3, 185}, - {0x00, 3, 186}, - {0x00, 3, 187}, - {0x00, 3, 189}, - {0x00, 3, 190}, - {0x00, 3, 196}, - {0x00, 3, 198}, - {0x00, 3, 228}, - {0x00, 3, 232}, - {0x00, 3, 233}, - {0x94, 0, 0}, - {0x95, 0, 0}, - {0x97, 0, 0}, - {0x98, 0, 0}, + {0x00, 0x03, 0xB2}, + {0x00, 0x03, 0xB5}, + {0x00, 0x03, 0xB9}, + {0x00, 0x03, 0xBA}, + {0x00, 0x03, 0xBB}, + {0x00, 0x03, 0xBD}, + {0x00, 0x03, 0xBE}, + {0x00, 0x03, 0xC4}, + {0x00, 0x03, 0xC6}, + {0x00, 0x03, 0xE4}, + {0x00, 0x03, 0xE8}, + {0x00, 0x03, 0xE9}, + {0x94, 0x00, 0x00}, + {0x95, 0x00, 0x00}, + {0x97, 0x00, 0x00}, + {0x98, 0x00, 0x00}, }, /* 135 */ { - {0x01, 2, 178}, - {0x16, 3, 178}, - {0x01, 2, 181}, - {0x16, 3, 181}, - {0x01, 2, 185}, - {0x16, 3, 185}, - {0x01, 2, 186}, - {0x16, 3, 186}, - {0x01, 2, 187}, - {0x16, 3, 187}, - {0x01, 2, 189}, - {0x16, 3, 189}, - {0x01, 2, 190}, - {0x16, 3, 190}, - {0x01, 2, 196}, - {0x16, 3, 196}, + {0x01, 0x02, 0xB2}, + {0x16, 0x03, 0xB2}, + {0x01, 0x02, 0xB5}, + {0x16, 0x03, 0xB5}, + {0x01, 0x02, 0xB9}, + {0x16, 0x03, 0xB9}, + {0x01, 0x02, 0xBA}, + {0x16, 0x03, 0xBA}, + {0x01, 0x02, 0xBB}, + {0x16, 0x03, 0xBB}, + {0x01, 0x02, 0xBD}, + {0x16, 0x03, 0xBD}, + {0x01, 0x02, 0xBE}, + {0x16, 0x03, 0xBE}, + {0x01, 0x02, 0xC4}, + {0x16, 0x03, 0xC4}, }, /* 136 */ { - {0x02, 2, 178}, - {0x09, 2, 178}, - {0x17, 2, 178}, - {0x28, 3, 178}, - {0x02, 2, 181}, - {0x09, 2, 181}, - {0x17, 2, 181}, - {0x28, 3, 181}, - {0x02, 2, 185}, - {0x09, 2, 185}, - {0x17, 2, 185}, - {0x28, 3, 185}, - {0x02, 2, 186}, - {0x09, 2, 186}, - {0x17, 2, 186}, - {0x28, 3, 186}, + {0x02, 0x02, 0xB2}, + {0x09, 0x02, 0xB2}, + {0x17, 0x02, 0xB2}, + {0x28, 0x03, 0xB2}, + {0x02, 0x02, 0xB5}, + {0x09, 0x02, 0xB5}, + {0x17, 0x02, 0xB5}, + {0x28, 0x03, 0xB5}, + {0x02, 0x02, 0xB9}, + {0x09, 0x02, 0xB9}, + {0x17, 0x02, 0xB9}, + {0x28, 0x03, 0xB9}, + {0x02, 0x02, 0xBA}, + {0x09, 0x02, 0xBA}, + {0x17, 0x02, 0xBA}, + {0x28, 0x03, 0xBA}, }, /* 137 */ { - {0x03, 2, 178}, - {0x06, 2, 178}, - {0x0A, 2, 178}, - {0x0F, 2, 178}, - {0x18, 2, 178}, - {0x1F, 2, 178}, - {0x29, 2, 178}, - {0x38, 3, 178}, - {0x03, 2, 181}, - {0x06, 2, 181}, - {0x0A, 2, 181}, - {0x0F, 2, 181}, - {0x18, 2, 181}, - {0x1F, 2, 181}, - {0x29, 2, 181}, - {0x38, 3, 181}, + {0x03, 0x02, 0xB2}, + {0x06, 0x02, 0xB2}, + {0x0A, 0x02, 0xB2}, + {0x0F, 0x02, 0xB2}, + {0x18, 0x02, 0xB2}, + {0x1F, 0x02, 0xB2}, + {0x29, 0x02, 0xB2}, + {0x38, 0x03, 0xB2}, + {0x03, 0x02, 0xB5}, + {0x06, 0x02, 0xB5}, + {0x0A, 0x02, 0xB5}, + {0x0F, 0x02, 0xB5}, + {0x18, 0x02, 0xB5}, + {0x1F, 0x02, 0xB5}, + {0x29, 0x02, 0xB5}, + {0x38, 0x03, 0xB5}, }, /* 138 */ { - {0x03, 2, 185}, - {0x06, 2, 185}, - {0x0A, 2, 185}, - {0x0F, 2, 185}, - {0x18, 2, 185}, - {0x1F, 2, 185}, - {0x29, 2, 185}, - {0x38, 3, 185}, - {0x03, 2, 186}, - {0x06, 2, 186}, - {0x0A, 2, 186}, - {0x0F, 2, 186}, - {0x18, 2, 186}, - {0x1F, 2, 186}, - {0x29, 2, 186}, - {0x38, 3, 186}, + {0x03, 0x02, 0xB9}, + {0x06, 0x02, 0xB9}, + {0x0A, 0x02, 0xB9}, + {0x0F, 0x02, 0xB9}, + {0x18, 0x02, 0xB9}, + {0x1F, 0x02, 0xB9}, + {0x29, 0x02, 0xB9}, + {0x38, 0x03, 0xB9}, + {0x03, 0x02, 0xBA}, + {0x06, 0x02, 0xBA}, + {0x0A, 0x02, 0xBA}, + {0x0F, 0x02, 0xBA}, + {0x18, 0x02, 0xBA}, + {0x1F, 0x02, 0xBA}, + {0x29, 0x02, 0xBA}, + {0x38, 0x03, 0xBA}, }, /* 139 */ { - {0x02, 2, 187}, - {0x09, 2, 187}, - {0x17, 2, 187}, - {0x28, 3, 187}, - {0x02, 2, 189}, - {0x09, 2, 189}, - {0x17, 2, 189}, - {0x28, 3, 189}, - {0x02, 2, 190}, - {0x09, 2, 190}, - {0x17, 2, 190}, - {0x28, 3, 190}, - {0x02, 2, 196}, - {0x09, 2, 196}, - {0x17, 2, 196}, - {0x28, 3, 196}, + {0x02, 0x02, 0xBB}, + {0x09, 0x02, 0xBB}, + {0x17, 0x02, 0xBB}, + {0x28, 0x03, 0xBB}, + {0x02, 0x02, 0xBD}, + {0x09, 0x02, 0xBD}, + {0x17, 0x02, 0xBD}, + {0x28, 0x03, 0xBD}, + {0x02, 0x02, 0xBE}, + {0x09, 0x02, 0xBE}, + {0x17, 0x02, 0xBE}, + {0x28, 0x03, 0xBE}, + {0x02, 0x02, 0xC4}, + {0x09, 0x02, 0xC4}, + {0x17, 0x02, 0xC4}, + {0x28, 0x03, 0xC4}, }, /* 140 */ { - {0x03, 2, 187}, - {0x06, 2, 187}, - {0x0A, 2, 187}, - {0x0F, 2, 187}, - {0x18, 2, 187}, - {0x1F, 2, 187}, - {0x29, 2, 187}, - {0x38, 3, 187}, - {0x03, 2, 189}, - {0x06, 2, 189}, - {0x0A, 2, 189}, - {0x0F, 2, 189}, - {0x18, 2, 189}, - {0x1F, 2, 189}, - {0x29, 2, 189}, - {0x38, 3, 189}, + {0x03, 0x02, 0xBB}, + {0x06, 0x02, 0xBB}, + {0x0A, 0x02, 0xBB}, + {0x0F, 0x02, 0xBB}, + {0x18, 0x02, 0xBB}, + {0x1F, 0x02, 0xBB}, + {0x29, 0x02, 0xBB}, + {0x38, 0x03, 0xBB}, + {0x03, 0x02, 0xBD}, + {0x06, 0x02, 0xBD}, + {0x0A, 0x02, 0xBD}, + {0x0F, 0x02, 0xBD}, + {0x18, 0x02, 0xBD}, + {0x1F, 0x02, 0xBD}, + {0x29, 0x02, 0xBD}, + {0x38, 0x03, 0xBD}, }, /* 141 */ { - {0x03, 2, 190}, - {0x06, 2, 190}, - {0x0A, 2, 190}, - {0x0F, 2, 190}, - {0x18, 2, 190}, - {0x1F, 2, 190}, - {0x29, 2, 190}, - {0x38, 3, 190}, - {0x03, 2, 196}, - {0x06, 2, 196}, - {0x0A, 2, 196}, - {0x0F, 2, 196}, - {0x18, 2, 196}, - {0x1F, 2, 196}, - {0x29, 2, 196}, - {0x38, 3, 196}, + {0x03, 0x02, 0xBE}, + {0x06, 0x02, 0xBE}, + {0x0A, 0x02, 0xBE}, + {0x0F, 0x02, 0xBE}, + {0x18, 0x02, 0xBE}, + {0x1F, 0x02, 0xBE}, + {0x29, 0x02, 0xBE}, + {0x38, 0x03, 0xBE}, + {0x03, 0x02, 0xC4}, + {0x06, 0x02, 0xC4}, + {0x0A, 0x02, 0xC4}, + {0x0F, 0x02, 0xC4}, + {0x18, 0x02, 0xC4}, + {0x1F, 0x02, 0xC4}, + {0x29, 0x02, 0xC4}, + {0x38, 0x03, 0xC4}, }, /* 142 */ { - {0x01, 2, 198}, - {0x16, 3, 198}, - {0x01, 2, 228}, - {0x16, 3, 228}, - {0x01, 2, 232}, - {0x16, 3, 232}, - {0x01, 2, 233}, - {0x16, 3, 233}, - {0x00, 3, 1}, - {0x00, 3, 135}, - {0x00, 3, 137}, - {0x00, 3, 138}, - {0x00, 3, 139}, - {0x00, 3, 140}, - {0x00, 3, 141}, - {0x00, 3, 143}, + {0x01, 0x02, 0xC6}, + {0x16, 0x03, 0xC6}, + {0x01, 0x02, 0xE4}, + {0x16, 0x03, 0xE4}, + {0x01, 0x02, 0xE8}, + {0x16, 0x03, 0xE8}, + {0x01, 0x02, 0xE9}, + {0x16, 0x03, 0xE9}, + {0x00, 0x03, 0x01}, + {0x00, 0x03, 0x87}, + {0x00, 0x03, 0x89}, + {0x00, 0x03, 0x8A}, + {0x00, 0x03, 0x8B}, + {0x00, 0x03, 0x8C}, + {0x00, 0x03, 0x8D}, + {0x00, 0x03, 0x8F}, }, /* 143 */ { - {0x02, 2, 198}, - {0x09, 2, 198}, - {0x17, 2, 198}, - {0x28, 3, 198}, - {0x02, 2, 228}, - {0x09, 2, 228}, - {0x17, 2, 228}, - {0x28, 3, 228}, - {0x02, 2, 232}, - {0x09, 2, 232}, - {0x17, 2, 232}, - {0x28, 3, 232}, - {0x02, 2, 233}, - {0x09, 2, 233}, - {0x17, 2, 233}, - {0x28, 3, 233}, + {0x02, 0x02, 0xC6}, + {0x09, 0x02, 0xC6}, + {0x17, 0x02, 0xC6}, + {0x28, 0x03, 0xC6}, + {0x02, 0x02, 0xE4}, + {0x09, 0x02, 0xE4}, + {0x17, 0x02, 0xE4}, + {0x28, 0x03, 0xE4}, + {0x02, 0x02, 0xE8}, + {0x09, 0x02, 0xE8}, + {0x17, 0x02, 0xE8}, + {0x28, 0x03, 0xE8}, + {0x02, 0x02, 0xE9}, + {0x09, 0x02, 0xE9}, + {0x17, 0x02, 0xE9}, + {0x28, 0x03, 0xE9}, }, /* 144 */ { - {0x03, 2, 198}, - {0x06, 2, 198}, - {0x0A, 2, 198}, - {0x0F, 2, 198}, - {0x18, 2, 198}, - {0x1F, 2, 198}, - {0x29, 2, 198}, - {0x38, 3, 198}, - {0x03, 2, 228}, - {0x06, 2, 228}, - {0x0A, 2, 228}, - {0x0F, 2, 228}, - {0x18, 2, 228}, - {0x1F, 2, 228}, - {0x29, 2, 228}, - {0x38, 3, 228}, + {0x03, 0x02, 0xC6}, + {0x06, 0x02, 0xC6}, + {0x0A, 0x02, 0xC6}, + {0x0F, 0x02, 0xC6}, + {0x18, 0x02, 0xC6}, + {0x1F, 0x02, 0xC6}, + {0x29, 0x02, 0xC6}, + {0x38, 0x03, 0xC6}, + {0x03, 0x02, 0xE4}, + {0x06, 0x02, 0xE4}, + {0x0A, 0x02, 0xE4}, + {0x0F, 0x02, 0xE4}, + {0x18, 0x02, 0xE4}, + {0x1F, 0x02, 0xE4}, + {0x29, 0x02, 0xE4}, + {0x38, 0x03, 0xE4}, }, /* 145 */ { - {0x03, 2, 232}, - {0x06, 2, 232}, - {0x0A, 2, 232}, - {0x0F, 2, 232}, - {0x18, 2, 232}, - {0x1F, 2, 232}, - {0x29, 2, 232}, - {0x38, 3, 232}, - {0x03, 2, 233}, - {0x06, 2, 233}, - {0x0A, 2, 233}, - {0x0F, 2, 233}, - {0x18, 2, 233}, - {0x1F, 2, 233}, - {0x29, 2, 233}, - {0x38, 3, 233}, + {0x03, 0x02, 0xE8}, + {0x06, 0x02, 0xE8}, + {0x0A, 0x02, 0xE8}, + {0x0F, 0x02, 0xE8}, + {0x18, 0x02, 0xE8}, + {0x1F, 0x02, 0xE8}, + {0x29, 0x02, 0xE8}, + {0x38, 0x03, 0xE8}, + {0x03, 0x02, 0xE9}, + {0x06, 0x02, 0xE9}, + {0x0A, 0x02, 0xE9}, + {0x0F, 0x02, 0xE9}, + {0x18, 0x02, 0xE9}, + {0x1F, 0x02, 0xE9}, + {0x29, 0x02, 0xE9}, + {0x38, 0x03, 0xE9}, }, /* 146 */ { - {0x01, 2, 1}, - {0x16, 3, 1}, - {0x01, 2, 135}, - {0x16, 3, 135}, - {0x01, 2, 137}, - {0x16, 3, 137}, - {0x01, 2, 138}, - {0x16, 3, 138}, - {0x01, 2, 139}, - {0x16, 3, 139}, - {0x01, 2, 140}, - {0x16, 3, 140}, - {0x01, 2, 141}, - {0x16, 3, 141}, - {0x01, 2, 143}, - {0x16, 3, 143}, + {0x01, 0x02, 0x01}, + {0x16, 0x03, 0x01}, + {0x01, 0x02, 0x87}, + {0x16, 0x03, 0x87}, + {0x01, 0x02, 0x89}, + {0x16, 0x03, 0x89}, + {0x01, 0x02, 0x8A}, + {0x16, 0x03, 0x8A}, + {0x01, 0x02, 0x8B}, + {0x16, 0x03, 0x8B}, + {0x01, 0x02, 0x8C}, + {0x16, 0x03, 0x8C}, + {0x01, 0x02, 0x8D}, + {0x16, 0x03, 0x8D}, + {0x01, 0x02, 0x8F}, + {0x16, 0x03, 0x8F}, }, /* 147 */ { - {0x02, 2, 1}, - {0x09, 2, 1}, - {0x17, 2, 1}, - {0x28, 3, 1}, - {0x02, 2, 135}, - {0x09, 2, 135}, - {0x17, 2, 135}, - {0x28, 3, 135}, - {0x02, 2, 137}, - {0x09, 2, 137}, - {0x17, 2, 137}, - {0x28, 3, 137}, - {0x02, 2, 138}, - {0x09, 2, 138}, - {0x17, 2, 138}, - {0x28, 3, 138}, + {0x02, 0x02, 0x01}, + {0x09, 0x02, 0x01}, + {0x17, 0x02, 0x01}, + {0x28, 0x03, 0x01}, + {0x02, 0x02, 0x87}, + {0x09, 0x02, 0x87}, + {0x17, 0x02, 0x87}, + {0x28, 0x03, 0x87}, + {0x02, 0x02, 0x89}, + {0x09, 0x02, 0x89}, + {0x17, 0x02, 0x89}, + {0x28, 0x03, 0x89}, + {0x02, 0x02, 0x8A}, + {0x09, 0x02, 0x8A}, + {0x17, 0x02, 0x8A}, + {0x28, 0x03, 0x8A}, }, /* 148 */ { - {0x03, 2, 1}, - {0x06, 2, 1}, - {0x0A, 2, 1}, - {0x0F, 2, 1}, - {0x18, 2, 1}, - {0x1F, 2, 1}, - {0x29, 2, 1}, - {0x38, 3, 1}, - {0x03, 2, 135}, - {0x06, 2, 135}, - {0x0A, 2, 135}, - {0x0F, 2, 135}, - {0x18, 2, 135}, - {0x1F, 2, 135}, - {0x29, 2, 135}, - {0x38, 3, 135}, + {0x03, 0x02, 0x01}, + {0x06, 0x02, 0x01}, + {0x0A, 0x02, 0x01}, + {0x0F, 0x02, 0x01}, + {0x18, 0x02, 0x01}, + {0x1F, 0x02, 0x01}, + {0x29, 0x02, 0x01}, + {0x38, 0x03, 0x01}, + {0x03, 0x02, 0x87}, + {0x06, 0x02, 0x87}, + {0x0A, 0x02, 0x87}, + {0x0F, 0x02, 0x87}, + {0x18, 0x02, 0x87}, + {0x1F, 0x02, 0x87}, + {0x29, 0x02, 0x87}, + {0x38, 0x03, 0x87}, }, /* 149 */ { - {0x03, 2, 137}, - {0x06, 2, 137}, - {0x0A, 2, 137}, - {0x0F, 2, 137}, - {0x18, 2, 137}, - {0x1F, 2, 137}, - {0x29, 2, 137}, - {0x38, 3, 137}, - {0x03, 2, 138}, - {0x06, 2, 138}, - {0x0A, 2, 138}, - {0x0F, 2, 138}, - {0x18, 2, 138}, - {0x1F, 2, 138}, - {0x29, 2, 138}, - {0x38, 3, 138}, + {0x03, 0x02, 0x89}, + {0x06, 0x02, 0x89}, + {0x0A, 0x02, 0x89}, + {0x0F, 0x02, 0x89}, + {0x18, 0x02, 0x89}, + {0x1F, 0x02, 0x89}, + {0x29, 0x02, 0x89}, + {0x38, 0x03, 0x89}, + {0x03, 0x02, 0x8A}, + {0x06, 0x02, 0x8A}, + {0x0A, 0x02, 0x8A}, + {0x0F, 0x02, 0x8A}, + {0x18, 0x02, 0x8A}, + {0x1F, 0x02, 0x8A}, + {0x29, 0x02, 0x8A}, + {0x38, 0x03, 0x8A}, }, /* 150 */ { - {0x02, 2, 139}, - {0x09, 2, 139}, - {0x17, 2, 139}, - {0x28, 3, 139}, - {0x02, 2, 140}, - {0x09, 2, 140}, - {0x17, 2, 140}, - {0x28, 3, 140}, - {0x02, 2, 141}, - {0x09, 2, 141}, - {0x17, 2, 141}, - {0x28, 3, 141}, - {0x02, 2, 143}, - {0x09, 2, 143}, - {0x17, 2, 143}, - {0x28, 3, 143}, + {0x02, 0x02, 0x8B}, + {0x09, 0x02, 0x8B}, + {0x17, 0x02, 0x8B}, + {0x28, 0x03, 0x8B}, + {0x02, 0x02, 0x8C}, + {0x09, 0x02, 0x8C}, + {0x17, 0x02, 0x8C}, + {0x28, 0x03, 0x8C}, + {0x02, 0x02, 0x8D}, + {0x09, 0x02, 0x8D}, + {0x17, 0x02, 0x8D}, + {0x28, 0x03, 0x8D}, + {0x02, 0x02, 0x8F}, + {0x09, 0x02, 0x8F}, + {0x17, 0x02, 0x8F}, + {0x28, 0x03, 0x8F}, }, /* 151 */ { - {0x03, 2, 139}, - {0x06, 2, 139}, - {0x0A, 2, 139}, - {0x0F, 2, 139}, - {0x18, 2, 139}, - {0x1F, 2, 139}, - {0x29, 2, 139}, - {0x38, 3, 139}, - {0x03, 2, 140}, - {0x06, 2, 140}, - {0x0A, 2, 140}, - {0x0F, 2, 140}, - {0x18, 2, 140}, - {0x1F, 2, 140}, - {0x29, 2, 140}, - {0x38, 3, 140}, + {0x03, 0x02, 0x8B}, + {0x06, 0x02, 0x8B}, + {0x0A, 0x02, 0x8B}, + {0x0F, 0x02, 0x8B}, + {0x18, 0x02, 0x8B}, + {0x1F, 0x02, 0x8B}, + {0x29, 0x02, 0x8B}, + {0x38, 0x03, 0x8B}, + {0x03, 0x02, 0x8C}, + {0x06, 0x02, 0x8C}, + {0x0A, 0x02, 0x8C}, + {0x0F, 0x02, 0x8C}, + {0x18, 0x02, 0x8C}, + {0x1F, 0x02, 0x8C}, + {0x29, 0x02, 0x8C}, + {0x38, 0x03, 0x8C}, }, /* 152 */ { - {0x03, 2, 141}, - {0x06, 2, 141}, - {0x0A, 2, 141}, - {0x0F, 2, 141}, - {0x18, 2, 141}, - {0x1F, 2, 141}, - {0x29, 2, 141}, - {0x38, 3, 141}, - {0x03, 2, 143}, - {0x06, 2, 143}, - {0x0A, 2, 143}, - {0x0F, 2, 143}, - {0x18, 2, 143}, - {0x1F, 2, 143}, - {0x29, 2, 143}, - {0x38, 3, 143}, + {0x03, 0x02, 0x8D}, + {0x06, 0x02, 0x8D}, + {0x0A, 0x02, 0x8D}, + {0x0F, 0x02, 0x8D}, + {0x18, 0x02, 0x8D}, + {0x1F, 0x02, 0x8D}, + {0x29, 0x02, 0x8D}, + {0x38, 0x03, 0x8D}, + {0x03, 0x02, 0x8F}, + {0x06, 0x02, 0x8F}, + {0x0A, 0x02, 0x8F}, + {0x0F, 0x02, 0x8F}, + {0x18, 0x02, 0x8F}, + {0x1F, 0x02, 0x8F}, + {0x29, 0x02, 0x8F}, + {0x38, 0x03, 0x8F}, }, /* 153 */ { - {0x9D, 0, 0}, - {0x9E, 0, 0}, - {0xA0, 0, 0}, - {0xA1, 0, 0}, - {0xA4, 0, 0}, - {0xA5, 0, 0}, - {0xA7, 0, 0}, - {0xA8, 0, 0}, - {0xAC, 0, 0}, - {0xAD, 0, 0}, - {0xAF, 0, 0}, - {0xB1, 0, 0}, - {0xB6, 0, 0}, - {0xB9, 0, 0}, - {0xBF, 0, 0}, - {0xCF, 0, 0}, + {0x9D, 0x00, 0x00}, + {0x9E, 0x00, 0x00}, + {0xA0, 0x00, 0x00}, + {0xA1, 0x00, 0x00}, + {0xA4, 0x00, 0x00}, + {0xA5, 0x00, 0x00}, + {0xA7, 0x00, 0x00}, + {0xA8, 0x00, 0x00}, + {0xAC, 0x00, 0x00}, + {0xAD, 0x00, 0x00}, + {0xAF, 0x00, 0x00}, + {0xB1, 0x00, 0x00}, + {0xB6, 0x00, 0x00}, + {0xB9, 0x00, 0x00}, + {0xBF, 0x00, 0x00}, + {0xCF, 0x00, 0x00}, }, /* 154 */ { - {0x00, 3, 147}, - {0x00, 3, 149}, - {0x00, 3, 150}, - {0x00, 3, 151}, - {0x00, 3, 152}, - {0x00, 3, 155}, - {0x00, 3, 157}, - {0x00, 3, 158}, - {0x00, 3, 165}, - {0x00, 3, 166}, - {0x00, 3, 168}, - {0x00, 3, 174}, - {0x00, 3, 175}, - {0x00, 3, 180}, - {0x00, 3, 182}, - {0x00, 3, 183}, + {0x00, 0x03, 0x93}, + {0x00, 0x03, 0x95}, + {0x00, 0x03, 0x96}, + {0x00, 0x03, 0x97}, + {0x00, 0x03, 0x98}, + {0x00, 0x03, 0x9B}, + {0x00, 0x03, 0x9D}, + {0x00, 0x03, 0x9E}, + {0x00, 0x03, 0xA5}, + {0x00, 0x03, 0xA6}, + {0x00, 0x03, 0xA8}, + {0x00, 0x03, 0xAE}, + {0x00, 0x03, 0xAF}, + {0x00, 0x03, 0xB4}, + {0x00, 0x03, 0xB6}, + {0x00, 0x03, 0xB7}, }, /* 155 */ { - {0x01, 2, 147}, - {0x16, 3, 147}, - {0x01, 2, 149}, - {0x16, 3, 149}, - {0x01, 2, 150}, - {0x16, 3, 150}, - {0x01, 2, 151}, - {0x16, 3, 151}, - {0x01, 2, 152}, - {0x16, 3, 152}, - {0x01, 2, 155}, - {0x16, 3, 155}, - {0x01, 2, 157}, - {0x16, 3, 157}, - {0x01, 2, 158}, - {0x16, 3, 158}, + {0x01, 0x02, 0x93}, + {0x16, 0x03, 0x93}, + {0x01, 0x02, 0x95}, + {0x16, 0x03, 0x95}, + {0x01, 0x02, 0x96}, + {0x16, 0x03, 0x96}, + {0x01, 0x02, 0x97}, + {0x16, 0x03, 0x97}, + {0x01, 0x02, 0x98}, + {0x16, 0x03, 0x98}, + {0x01, 0x02, 0x9B}, + {0x16, 0x03, 0x9B}, + {0x01, 0x02, 0x9D}, + {0x16, 0x03, 0x9D}, + {0x01, 0x02, 0x9E}, + {0x16, 0x03, 0x9E}, }, /* 156 */ { - {0x02, 2, 147}, - {0x09, 2, 147}, - {0x17, 2, 147}, - {0x28, 3, 147}, - {0x02, 2, 149}, - {0x09, 2, 149}, - {0x17, 2, 149}, - {0x28, 3, 149}, - {0x02, 2, 150}, - {0x09, 2, 150}, - {0x17, 2, 150}, - {0x28, 3, 150}, - {0x02, 2, 151}, - {0x09, 2, 151}, - {0x17, 2, 151}, - {0x28, 3, 151}, + {0x02, 0x02, 0x93}, + {0x09, 0x02, 0x93}, + {0x17, 0x02, 0x93}, + {0x28, 0x03, 0x93}, + {0x02, 0x02, 0x95}, + {0x09, 0x02, 0x95}, + {0x17, 0x02, 0x95}, + {0x28, 0x03, 0x95}, + {0x02, 0x02, 0x96}, + {0x09, 0x02, 0x96}, + {0x17, 0x02, 0x96}, + {0x28, 0x03, 0x96}, + {0x02, 0x02, 0x97}, + {0x09, 0x02, 0x97}, + {0x17, 0x02, 0x97}, + {0x28, 0x03, 0x97}, }, /* 157 */ { - {0x03, 2, 147}, - {0x06, 2, 147}, - {0x0A, 2, 147}, - {0x0F, 2, 147}, - {0x18, 2, 147}, - {0x1F, 2, 147}, - {0x29, 2, 147}, - {0x38, 3, 147}, - {0x03, 2, 149}, - {0x06, 2, 149}, - {0x0A, 2, 149}, - {0x0F, 2, 149}, - {0x18, 2, 149}, - {0x1F, 2, 149}, - {0x29, 2, 149}, - {0x38, 3, 149}, + {0x03, 0x02, 0x93}, + {0x06, 0x02, 0x93}, + {0x0A, 0x02, 0x93}, + {0x0F, 0x02, 0x93}, + {0x18, 0x02, 0x93}, + {0x1F, 0x02, 0x93}, + {0x29, 0x02, 0x93}, + {0x38, 0x03, 0x93}, + {0x03, 0x02, 0x95}, + {0x06, 0x02, 0x95}, + {0x0A, 0x02, 0x95}, + {0x0F, 0x02, 0x95}, + {0x18, 0x02, 0x95}, + {0x1F, 0x02, 0x95}, + {0x29, 0x02, 0x95}, + {0x38, 0x03, 0x95}, }, /* 158 */ { - {0x03, 2, 150}, - {0x06, 2, 150}, - {0x0A, 2, 150}, - {0x0F, 2, 150}, - {0x18, 2, 150}, - {0x1F, 2, 150}, - {0x29, 2, 150}, - {0x38, 3, 150}, - {0x03, 2, 151}, - {0x06, 2, 151}, - {0x0A, 2, 151}, - {0x0F, 2, 151}, - {0x18, 2, 151}, - {0x1F, 2, 151}, - {0x29, 2, 151}, - {0x38, 3, 151}, + {0x03, 0x02, 0x96}, + {0x06, 0x02, 0x96}, + {0x0A, 0x02, 0x96}, + {0x0F, 0x02, 0x96}, + {0x18, 0x02, 0x96}, + {0x1F, 0x02, 0x96}, + {0x29, 0x02, 0x96}, + {0x38, 0x03, 0x96}, + {0x03, 0x02, 0x97}, + {0x06, 0x02, 0x97}, + {0x0A, 0x02, 0x97}, + {0x0F, 0x02, 0x97}, + {0x18, 0x02, 0x97}, + {0x1F, 0x02, 0x97}, + {0x29, 0x02, 0x97}, + {0x38, 0x03, 0x97}, }, /* 159 */ { - {0x02, 2, 152}, - {0x09, 2, 152}, - {0x17, 2, 152}, - {0x28, 3, 152}, - {0x02, 2, 155}, - {0x09, 2, 155}, - {0x17, 2, 155}, - {0x28, 3, 155}, - {0x02, 2, 157}, - {0x09, 2, 157}, - {0x17, 2, 157}, - {0x28, 3, 157}, - {0x02, 2, 158}, - {0x09, 2, 158}, - {0x17, 2, 158}, - {0x28, 3, 158}, + {0x02, 0x02, 0x98}, + {0x09, 0x02, 0x98}, + {0x17, 0x02, 0x98}, + {0x28, 0x03, 0x98}, + {0x02, 0x02, 0x9B}, + {0x09, 0x02, 0x9B}, + {0x17, 0x02, 0x9B}, + {0x28, 0x03, 0x9B}, + {0x02, 0x02, 0x9D}, + {0x09, 0x02, 0x9D}, + {0x17, 0x02, 0x9D}, + {0x28, 0x03, 0x9D}, + {0x02, 0x02, 0x9E}, + {0x09, 0x02, 0x9E}, + {0x17, 0x02, 0x9E}, + {0x28, 0x03, 0x9E}, }, /* 160 */ { - {0x03, 2, 152}, - {0x06, 2, 152}, - {0x0A, 2, 152}, - {0x0F, 2, 152}, - {0x18, 2, 152}, - {0x1F, 2, 152}, - {0x29, 2, 152}, - {0x38, 3, 152}, - {0x03, 2, 155}, - {0x06, 2, 155}, - {0x0A, 2, 155}, - {0x0F, 2, 155}, - {0x18, 2, 155}, - {0x1F, 2, 155}, - {0x29, 2, 155}, - {0x38, 3, 155}, + {0x03, 0x02, 0x98}, + {0x06, 0x02, 0x98}, + {0x0A, 0x02, 0x98}, + {0x0F, 0x02, 0x98}, + {0x18, 0x02, 0x98}, + {0x1F, 0x02, 0x98}, + {0x29, 0x02, 0x98}, + {0x38, 0x03, 0x98}, + {0x03, 0x02, 0x9B}, + {0x06, 0x02, 0x9B}, + {0x0A, 0x02, 0x9B}, + {0x0F, 0x02, 0x9B}, + {0x18, 0x02, 0x9B}, + {0x1F, 0x02, 0x9B}, + {0x29, 0x02, 0x9B}, + {0x38, 0x03, 0x9B}, }, /* 161 */ { - {0x03, 2, 157}, - {0x06, 2, 157}, - {0x0A, 2, 157}, - {0x0F, 2, 157}, - {0x18, 2, 157}, - {0x1F, 2, 157}, - {0x29, 2, 157}, - {0x38, 3, 157}, - {0x03, 2, 158}, - {0x06, 2, 158}, - {0x0A, 2, 158}, - {0x0F, 2, 158}, - {0x18, 2, 158}, - {0x1F, 2, 158}, - {0x29, 2, 158}, - {0x38, 3, 158}, + {0x03, 0x02, 0x9D}, + {0x06, 0x02, 0x9D}, + {0x0A, 0x02, 0x9D}, + {0x0F, 0x02, 0x9D}, + {0x18, 0x02, 0x9D}, + {0x1F, 0x02, 0x9D}, + {0x29, 0x02, 0x9D}, + {0x38, 0x03, 0x9D}, + {0x03, 0x02, 0x9E}, + {0x06, 0x02, 0x9E}, + {0x0A, 0x02, 0x9E}, + {0x0F, 0x02, 0x9E}, + {0x18, 0x02, 0x9E}, + {0x1F, 0x02, 0x9E}, + {0x29, 0x02, 0x9E}, + {0x38, 0x03, 0x9E}, }, /* 162 */ { - {0x01, 2, 165}, - {0x16, 3, 165}, - {0x01, 2, 166}, - {0x16, 3, 166}, - {0x01, 2, 168}, - {0x16, 3, 168}, - {0x01, 2, 174}, - {0x16, 3, 174}, - {0x01, 2, 175}, - {0x16, 3, 175}, - {0x01, 2, 180}, - {0x16, 3, 180}, - {0x01, 2, 182}, - {0x16, 3, 182}, - {0x01, 2, 183}, - {0x16, 3, 183}, + {0x01, 0x02, 0xA5}, + {0x16, 0x03, 0xA5}, + {0x01, 0x02, 0xA6}, + {0x16, 0x03, 0xA6}, + {0x01, 0x02, 0xA8}, + {0x16, 0x03, 0xA8}, + {0x01, 0x02, 0xAE}, + {0x16, 0x03, 0xAE}, + {0x01, 0x02, 0xAF}, + {0x16, 0x03, 0xAF}, + {0x01, 0x02, 0xB4}, + {0x16, 0x03, 0xB4}, + {0x01, 0x02, 0xB6}, + {0x16, 0x03, 0xB6}, + {0x01, 0x02, 0xB7}, + {0x16, 0x03, 0xB7}, }, /* 163 */ { - {0x02, 2, 165}, - {0x09, 2, 165}, - {0x17, 2, 165}, - {0x28, 3, 165}, - {0x02, 2, 166}, - {0x09, 2, 166}, - {0x17, 2, 166}, - {0x28, 3, 166}, - {0x02, 2, 168}, - {0x09, 2, 168}, - {0x17, 2, 168}, - {0x28, 3, 168}, - {0x02, 2, 174}, - {0x09, 2, 174}, - {0x17, 2, 174}, - {0x28, 3, 174}, + {0x02, 0x02, 0xA5}, + {0x09, 0x02, 0xA5}, + {0x17, 0x02, 0xA5}, + {0x28, 0x03, 0xA5}, + {0x02, 0x02, 0xA6}, + {0x09, 0x02, 0xA6}, + {0x17, 0x02, 0xA6}, + {0x28, 0x03, 0xA6}, + {0x02, 0x02, 0xA8}, + {0x09, 0x02, 0xA8}, + {0x17, 0x02, 0xA8}, + {0x28, 0x03, 0xA8}, + {0x02, 0x02, 0xAE}, + {0x09, 0x02, 0xAE}, + {0x17, 0x02, 0xAE}, + {0x28, 0x03, 0xAE}, }, /* 164 */ { - {0x03, 2, 165}, - {0x06, 2, 165}, - {0x0A, 2, 165}, - {0x0F, 2, 165}, - {0x18, 2, 165}, - {0x1F, 2, 165}, - {0x29, 2, 165}, - {0x38, 3, 165}, - {0x03, 2, 166}, - {0x06, 2, 166}, - {0x0A, 2, 166}, - {0x0F, 2, 166}, - {0x18, 2, 166}, - {0x1F, 2, 166}, - {0x29, 2, 166}, - {0x38, 3, 166}, + {0x03, 0x02, 0xA5}, + {0x06, 0x02, 0xA5}, + {0x0A, 0x02, 0xA5}, + {0x0F, 0x02, 0xA5}, + {0x18, 0x02, 0xA5}, + {0x1F, 0x02, 0xA5}, + {0x29, 0x02, 0xA5}, + {0x38, 0x03, 0xA5}, + {0x03, 0x02, 0xA6}, + {0x06, 0x02, 0xA6}, + {0x0A, 0x02, 0xA6}, + {0x0F, 0x02, 0xA6}, + {0x18, 0x02, 0xA6}, + {0x1F, 0x02, 0xA6}, + {0x29, 0x02, 0xA6}, + {0x38, 0x03, 0xA6}, }, /* 165 */ { - {0x03, 2, 168}, - {0x06, 2, 168}, - {0x0A, 2, 168}, - {0x0F, 2, 168}, - {0x18, 2, 168}, - {0x1F, 2, 168}, - {0x29, 2, 168}, - {0x38, 3, 168}, - {0x03, 2, 174}, - {0x06, 2, 174}, - {0x0A, 2, 174}, - {0x0F, 2, 174}, - {0x18, 2, 174}, - {0x1F, 2, 174}, - {0x29, 2, 174}, - {0x38, 3, 174}, + {0x03, 0x02, 0xA8}, + {0x06, 0x02, 0xA8}, + {0x0A, 0x02, 0xA8}, + {0x0F, 0x02, 0xA8}, + {0x18, 0x02, 0xA8}, + {0x1F, 0x02, 0xA8}, + {0x29, 0x02, 0xA8}, + {0x38, 0x03, 0xA8}, + {0x03, 0x02, 0xAE}, + {0x06, 0x02, 0xAE}, + {0x0A, 0x02, 0xAE}, + {0x0F, 0x02, 0xAE}, + {0x18, 0x02, 0xAE}, + {0x1F, 0x02, 0xAE}, + {0x29, 0x02, 0xAE}, + {0x38, 0x03, 0xAE}, }, /* 166 */ { - {0x02, 2, 175}, - {0x09, 2, 175}, - {0x17, 2, 175}, - {0x28, 3, 175}, - {0x02, 2, 180}, - {0x09, 2, 180}, - {0x17, 2, 180}, - {0x28, 3, 180}, - {0x02, 2, 182}, - {0x09, 2, 182}, - {0x17, 2, 182}, - {0x28, 3, 182}, - {0x02, 2, 183}, - {0x09, 2, 183}, - {0x17, 2, 183}, - {0x28, 3, 183}, + {0x02, 0x02, 0xAF}, + {0x09, 0x02, 0xAF}, + {0x17, 0x02, 0xAF}, + {0x28, 0x03, 0xAF}, + {0x02, 0x02, 0xB4}, + {0x09, 0x02, 0xB4}, + {0x17, 0x02, 0xB4}, + {0x28, 0x03, 0xB4}, + {0x02, 0x02, 0xB6}, + {0x09, 0x02, 0xB6}, + {0x17, 0x02, 0xB6}, + {0x28, 0x03, 0xB6}, + {0x02, 0x02, 0xB7}, + {0x09, 0x02, 0xB7}, + {0x17, 0x02, 0xB7}, + {0x28, 0x03, 0xB7}, }, /* 167 */ { - {0x03, 2, 175}, - {0x06, 2, 175}, - {0x0A, 2, 175}, - {0x0F, 2, 175}, - {0x18, 2, 175}, - {0x1F, 2, 175}, - {0x29, 2, 175}, - {0x38, 3, 175}, - {0x03, 2, 180}, - {0x06, 2, 180}, - {0x0A, 2, 180}, - {0x0F, 2, 180}, - {0x18, 2, 180}, - {0x1F, 2, 180}, - {0x29, 2, 180}, - {0x38, 3, 180}, + {0x03, 0x02, 0xAF}, + {0x06, 0x02, 0xAF}, + {0x0A, 0x02, 0xAF}, + {0x0F, 0x02, 0xAF}, + {0x18, 0x02, 0xAF}, + {0x1F, 0x02, 0xAF}, + {0x29, 0x02, 0xAF}, + {0x38, 0x03, 0xAF}, + {0x03, 0x02, 0xB4}, + {0x06, 0x02, 0xB4}, + {0x0A, 0x02, 0xB4}, + {0x0F, 0x02, 0xB4}, + {0x18, 0x02, 0xB4}, + {0x1F, 0x02, 0xB4}, + {0x29, 0x02, 0xB4}, + {0x38, 0x03, 0xB4}, }, /* 168 */ { - {0x03, 2, 182}, - {0x06, 2, 182}, - {0x0A, 2, 182}, - {0x0F, 2, 182}, - {0x18, 2, 182}, - {0x1F, 2, 182}, - {0x29, 2, 182}, - {0x38, 3, 182}, - {0x03, 2, 183}, - {0x06, 2, 183}, - {0x0A, 2, 183}, - {0x0F, 2, 183}, - {0x18, 2, 183}, - {0x1F, 2, 183}, - {0x29, 2, 183}, - {0x38, 3, 183}, + {0x03, 0x02, 0xB6}, + {0x06, 0x02, 0xB6}, + {0x0A, 0x02, 0xB6}, + {0x0F, 0x02, 0xB6}, + {0x18, 0x02, 0xB6}, + {0x1F, 0x02, 0xB6}, + {0x29, 0x02, 0xB6}, + {0x38, 0x03, 0xB6}, + {0x03, 0x02, 0xB7}, + {0x06, 0x02, 0xB7}, + {0x0A, 0x02, 0xB7}, + {0x0F, 0x02, 0xB7}, + {0x18, 0x02, 0xB7}, + {0x1F, 0x02, 0xB7}, + {0x29, 0x02, 0xB7}, + {0x38, 0x03, 0xB7}, }, /* 169 */ { - {0x00, 3, 188}, - {0x00, 3, 191}, - {0x00, 3, 197}, - {0x00, 3, 231}, - {0x00, 3, 239}, - {0xB0, 0, 0}, - {0xB2, 0, 0}, - {0xB3, 0, 0}, - {0xB7, 0, 0}, - {0xB8, 0, 0}, - {0xBA, 0, 0}, - {0xBB, 0, 0}, - {0xC0, 0, 0}, - {0xC7, 0, 0}, - {0xD0, 0, 0}, - {0xDF, 0, 0}, + {0x00, 0x03, 0xBC}, + {0x00, 0x03, 0xBF}, + {0x00, 0x03, 0xC5}, + {0x00, 0x03, 0xE7}, + {0x00, 0x03, 0xEF}, + {0xB0, 0x00, 0x00}, + {0xB2, 0x00, 0x00}, + {0xB3, 0x00, 0x00}, + {0xB7, 0x00, 0x00}, + {0xB8, 0x00, 0x00}, + {0xBA, 0x00, 0x00}, + {0xBB, 0x00, 0x00}, + {0xC0, 0x00, 0x00}, + {0xC7, 0x00, 0x00}, + {0xD0, 0x00, 0x00}, + {0xDF, 0x00, 0x00}, }, /* 170 */ { - {0x01, 2, 188}, - {0x16, 3, 188}, - {0x01, 2, 191}, - {0x16, 3, 191}, - {0x01, 2, 197}, - {0x16, 3, 197}, - {0x01, 2, 231}, - {0x16, 3, 231}, - {0x01, 2, 239}, - {0x16, 3, 239}, - {0x00, 3, 9}, - {0x00, 3, 142}, - {0x00, 3, 144}, - {0x00, 3, 145}, - {0x00, 3, 148}, - {0x00, 3, 159}, + {0x01, 0x02, 0xBC}, + {0x16, 0x03, 0xBC}, + {0x01, 0x02, 0xBF}, + {0x16, 0x03, 0xBF}, + {0x01, 0x02, 0xC5}, + {0x16, 0x03, 0xC5}, + {0x01, 0x02, 0xE7}, + {0x16, 0x03, 0xE7}, + {0x01, 0x02, 0xEF}, + {0x16, 0x03, 0xEF}, + {0x00, 0x03, 0x09}, + {0x00, 0x03, 0x8E}, + {0x00, 0x03, 0x90}, + {0x00, 0x03, 0x91}, + {0x00, 0x03, 0x94}, + {0x00, 0x03, 0x9F}, }, /* 171 */ { - {0x02, 2, 188}, - {0x09, 2, 188}, - {0x17, 2, 188}, - {0x28, 3, 188}, - {0x02, 2, 191}, - {0x09, 2, 191}, - {0x17, 2, 191}, - {0x28, 3, 191}, - {0x02, 2, 197}, - {0x09, 2, 197}, - {0x17, 2, 197}, - {0x28, 3, 197}, - {0x02, 2, 231}, - {0x09, 2, 231}, - {0x17, 2, 231}, - {0x28, 3, 231}, + {0x02, 0x02, 0xBC}, + {0x09, 0x02, 0xBC}, + {0x17, 0x02, 0xBC}, + {0x28, 0x03, 0xBC}, + {0x02, 0x02, 0xBF}, + {0x09, 0x02, 0xBF}, + {0x17, 0x02, 0xBF}, + {0x28, 0x03, 0xBF}, + {0x02, 0x02, 0xC5}, + {0x09, 0x02, 0xC5}, + {0x17, 0x02, 0xC5}, + {0x28, 0x03, 0xC5}, + {0x02, 0x02, 0xE7}, + {0x09, 0x02, 0xE7}, + {0x17, 0x02, 0xE7}, + {0x28, 0x03, 0xE7}, }, /* 172 */ { - {0x03, 2, 188}, - {0x06, 2, 188}, - {0x0A, 2, 188}, - {0x0F, 2, 188}, - {0x18, 2, 188}, - {0x1F, 2, 188}, - {0x29, 2, 188}, - {0x38, 3, 188}, - {0x03, 2, 191}, - {0x06, 2, 191}, - {0x0A, 2, 191}, - {0x0F, 2, 191}, - {0x18, 2, 191}, - {0x1F, 2, 191}, - {0x29, 2, 191}, - {0x38, 3, 191}, + {0x03, 0x02, 0xBC}, + {0x06, 0x02, 0xBC}, + {0x0A, 0x02, 0xBC}, + {0x0F, 0x02, 0xBC}, + {0x18, 0x02, 0xBC}, + {0x1F, 0x02, 0xBC}, + {0x29, 0x02, 0xBC}, + {0x38, 0x03, 0xBC}, + {0x03, 0x02, 0xBF}, + {0x06, 0x02, 0xBF}, + {0x0A, 0x02, 0xBF}, + {0x0F, 0x02, 0xBF}, + {0x18, 0x02, 0xBF}, + {0x1F, 0x02, 0xBF}, + {0x29, 0x02, 0xBF}, + {0x38, 0x03, 0xBF}, }, /* 173 */ { - {0x03, 2, 197}, - {0x06, 2, 197}, - {0x0A, 2, 197}, - {0x0F, 2, 197}, - {0x18, 2, 197}, - {0x1F, 2, 197}, - {0x29, 2, 197}, - {0x38, 3, 197}, - {0x03, 2, 231}, - {0x06, 2, 231}, - {0x0A, 2, 231}, - {0x0F, 2, 231}, - {0x18, 2, 231}, - {0x1F, 2, 231}, - {0x29, 2, 231}, - {0x38, 3, 231}, + {0x03, 0x02, 0xC5}, + {0x06, 0x02, 0xC5}, + {0x0A, 0x02, 0xC5}, + {0x0F, 0x02, 0xC5}, + {0x18, 0x02, 0xC5}, + {0x1F, 0x02, 0xC5}, + {0x29, 0x02, 0xC5}, + {0x38, 0x03, 0xC5}, + {0x03, 0x02, 0xE7}, + {0x06, 0x02, 0xE7}, + {0x0A, 0x02, 0xE7}, + {0x0F, 0x02, 0xE7}, + {0x18, 0x02, 0xE7}, + {0x1F, 0x02, 0xE7}, + {0x29, 0x02, 0xE7}, + {0x38, 0x03, 0xE7}, }, /* 174 */ { - {0x02, 2, 239}, - {0x09, 2, 239}, - {0x17, 2, 239}, - {0x28, 3, 239}, - {0x01, 2, 9}, - {0x16, 3, 9}, - {0x01, 2, 142}, - {0x16, 3, 142}, - {0x01, 2, 144}, - {0x16, 3, 144}, - {0x01, 2, 145}, - {0x16, 3, 145}, - {0x01, 2, 148}, - {0x16, 3, 148}, - {0x01, 2, 159}, - {0x16, 3, 159}, + {0x02, 0x02, 0xEF}, + {0x09, 0x02, 0xEF}, + {0x17, 0x02, 0xEF}, + {0x28, 0x03, 0xEF}, + {0x01, 0x02, 0x09}, + {0x16, 0x03, 0x09}, + {0x01, 0x02, 0x8E}, + {0x16, 0x03, 0x8E}, + {0x01, 0x02, 0x90}, + {0x16, 0x03, 0x90}, + {0x01, 0x02, 0x91}, + {0x16, 0x03, 0x91}, + {0x01, 0x02, 0x94}, + {0x16, 0x03, 0x94}, + {0x01, 0x02, 0x9F}, + {0x16, 0x03, 0x9F}, }, /* 175 */ { - {0x03, 2, 239}, - {0x06, 2, 239}, - {0x0A, 2, 239}, - {0x0F, 2, 239}, - {0x18, 2, 239}, - {0x1F, 2, 239}, - {0x29, 2, 239}, - {0x38, 3, 239}, - {0x02, 2, 9}, - {0x09, 2, 9}, - {0x17, 2, 9}, - {0x28, 3, 9}, - {0x02, 2, 142}, - {0x09, 2, 142}, - {0x17, 2, 142}, - {0x28, 3, 142}, + {0x03, 0x02, 0xEF}, + {0x06, 0x02, 0xEF}, + {0x0A, 0x02, 0xEF}, + {0x0F, 0x02, 0xEF}, + {0x18, 0x02, 0xEF}, + {0x1F, 0x02, 0xEF}, + {0x29, 0x02, 0xEF}, + {0x38, 0x03, 0xEF}, + {0x02, 0x02, 0x09}, + {0x09, 0x02, 0x09}, + {0x17, 0x02, 0x09}, + {0x28, 0x03, 0x09}, + {0x02, 0x02, 0x8E}, + {0x09, 0x02, 0x8E}, + {0x17, 0x02, 0x8E}, + {0x28, 0x03, 0x8E}, }, /* 176 */ { - {0x03, 2, 9}, - {0x06, 2, 9}, - {0x0A, 2, 9}, - {0x0F, 2, 9}, - {0x18, 2, 9}, - {0x1F, 2, 9}, - {0x29, 2, 9}, - {0x38, 3, 9}, - {0x03, 2, 142}, - {0x06, 2, 142}, - {0x0A, 2, 142}, - {0x0F, 2, 142}, - {0x18, 2, 142}, - {0x1F, 2, 142}, - {0x29, 2, 142}, - {0x38, 3, 142}, + {0x03, 0x02, 0x09}, + {0x06, 0x02, 0x09}, + {0x0A, 0x02, 0x09}, + {0x0F, 0x02, 0x09}, + {0x18, 0x02, 0x09}, + {0x1F, 0x02, 0x09}, + {0x29, 0x02, 0x09}, + {0x38, 0x03, 0x09}, + {0x03, 0x02, 0x8E}, + {0x06, 0x02, 0x8E}, + {0x0A, 0x02, 0x8E}, + {0x0F, 0x02, 0x8E}, + {0x18, 0x02, 0x8E}, + {0x1F, 0x02, 0x8E}, + {0x29, 0x02, 0x8E}, + {0x38, 0x03, 0x8E}, }, /* 177 */ { - {0x02, 2, 144}, - {0x09, 2, 144}, - {0x17, 2, 144}, - {0x28, 3, 144}, - {0x02, 2, 145}, - {0x09, 2, 145}, - {0x17, 2, 145}, - {0x28, 3, 145}, - {0x02, 2, 148}, - {0x09, 2, 148}, - {0x17, 2, 148}, - {0x28, 3, 148}, - {0x02, 2, 159}, - {0x09, 2, 159}, - {0x17, 2, 159}, - {0x28, 3, 159}, + {0x02, 0x02, 0x90}, + {0x09, 0x02, 0x90}, + {0x17, 0x02, 0x90}, + {0x28, 0x03, 0x90}, + {0x02, 0x02, 0x91}, + {0x09, 0x02, 0x91}, + {0x17, 0x02, 0x91}, + {0x28, 0x03, 0x91}, + {0x02, 0x02, 0x94}, + {0x09, 0x02, 0x94}, + {0x17, 0x02, 0x94}, + {0x28, 0x03, 0x94}, + {0x02, 0x02, 0x9F}, + {0x09, 0x02, 0x9F}, + {0x17, 0x02, 0x9F}, + {0x28, 0x03, 0x9F}, }, /* 178 */ { - {0x03, 2, 144}, - {0x06, 2, 144}, - {0x0A, 2, 144}, - {0x0F, 2, 144}, - {0x18, 2, 144}, - {0x1F, 2, 144}, - {0x29, 2, 144}, - {0x38, 3, 144}, - {0x03, 2, 145}, - {0x06, 2, 145}, - {0x0A, 2, 145}, - {0x0F, 2, 145}, - {0x18, 2, 145}, - {0x1F, 2, 145}, - {0x29, 2, 145}, - {0x38, 3, 145}, + {0x03, 0x02, 0x90}, + {0x06, 0x02, 0x90}, + {0x0A, 0x02, 0x90}, + {0x0F, 0x02, 0x90}, + {0x18, 0x02, 0x90}, + {0x1F, 0x02, 0x90}, + {0x29, 0x02, 0x90}, + {0x38, 0x03, 0x90}, + {0x03, 0x02, 0x91}, + {0x06, 0x02, 0x91}, + {0x0A, 0x02, 0x91}, + {0x0F, 0x02, 0x91}, + {0x18, 0x02, 0x91}, + {0x1F, 0x02, 0x91}, + {0x29, 0x02, 0x91}, + {0x38, 0x03, 0x91}, }, /* 179 */ { - {0x03, 2, 148}, - {0x06, 2, 148}, - {0x0A, 2, 148}, - {0x0F, 2, 148}, - {0x18, 2, 148}, - {0x1F, 2, 148}, - {0x29, 2, 148}, - {0x38, 3, 148}, - {0x03, 2, 159}, - {0x06, 2, 159}, - {0x0A, 2, 159}, - {0x0F, 2, 159}, - {0x18, 2, 159}, - {0x1F, 2, 159}, - {0x29, 2, 159}, - {0x38, 3, 159}, + {0x03, 0x02, 0x94}, + {0x06, 0x02, 0x94}, + {0x0A, 0x02, 0x94}, + {0x0F, 0x02, 0x94}, + {0x18, 0x02, 0x94}, + {0x1F, 0x02, 0x94}, + {0x29, 0x02, 0x94}, + {0x38, 0x03, 0x94}, + {0x03, 0x02, 0x9F}, + {0x06, 0x02, 0x9F}, + {0x0A, 0x02, 0x9F}, + {0x0F, 0x02, 0x9F}, + {0x18, 0x02, 0x9F}, + {0x1F, 0x02, 0x9F}, + {0x29, 0x02, 0x9F}, + {0x38, 0x03, 0x9F}, }, /* 180 */ { - {0x00, 3, 171}, - {0x00, 3, 206}, - {0x00, 3, 215}, - {0x00, 3, 225}, - {0x00, 3, 236}, - {0x00, 3, 237}, - {0xBC, 0, 0}, - {0xBD, 0, 0}, - {0xC1, 0, 0}, - {0xC4, 0, 0}, - {0xC8, 0, 0}, - {0xCB, 0, 0}, - {0xD1, 0, 0}, - {0xD8, 0, 0}, - {0xE0, 0, 0}, - {0xEE, 0, 0}, + {0x00, 0x03, 0xAB}, + {0x00, 0x03, 0xCE}, + {0x00, 0x03, 0xD7}, + {0x00, 0x03, 0xE1}, + {0x00, 0x03, 0xEC}, + {0x00, 0x03, 0xED}, + {0xBC, 0x00, 0x00}, + {0xBD, 0x00, 0x00}, + {0xC1, 0x00, 0x00}, + {0xC4, 0x00, 0x00}, + {0xC8, 0x00, 0x00}, + {0xCB, 0x00, 0x00}, + {0xD1, 0x00, 0x00}, + {0xD8, 0x00, 0x00}, + {0xE0, 0x00, 0x00}, + {0xEE, 0x00, 0x00}, }, /* 181 */ { - {0x01, 2, 171}, - {0x16, 3, 171}, - {0x01, 2, 206}, - {0x16, 3, 206}, - {0x01, 2, 215}, - {0x16, 3, 215}, - {0x01, 2, 225}, - {0x16, 3, 225}, - {0x01, 2, 236}, - {0x16, 3, 236}, - {0x01, 2, 237}, - {0x16, 3, 237}, - {0x00, 3, 199}, - {0x00, 3, 207}, - {0x00, 3, 234}, - {0x00, 3, 235}, + {0x01, 0x02, 0xAB}, + {0x16, 0x03, 0xAB}, + {0x01, 0x02, 0xCE}, + {0x16, 0x03, 0xCE}, + {0x01, 0x02, 0xD7}, + {0x16, 0x03, 0xD7}, + {0x01, 0x02, 0xE1}, + {0x16, 0x03, 0xE1}, + {0x01, 0x02, 0xEC}, + {0x16, 0x03, 0xEC}, + {0x01, 0x02, 0xED}, + {0x16, 0x03, 0xED}, + {0x00, 0x03, 0xC7}, + {0x00, 0x03, 0xCF}, + {0x00, 0x03, 0xEA}, + {0x00, 0x03, 0xEB}, }, /* 182 */ { - {0x02, 2, 171}, - {0x09, 2, 171}, - {0x17, 2, 171}, - {0x28, 3, 171}, - {0x02, 2, 206}, - {0x09, 2, 206}, - {0x17, 2, 206}, - {0x28, 3, 206}, - {0x02, 2, 215}, - {0x09, 2, 215}, - {0x17, 2, 215}, - {0x28, 3, 215}, - {0x02, 2, 225}, - {0x09, 2, 225}, - {0x17, 2, 225}, - {0x28, 3, 225}, + {0x02, 0x02, 0xAB}, + {0x09, 0x02, 0xAB}, + {0x17, 0x02, 0xAB}, + {0x28, 0x03, 0xAB}, + {0x02, 0x02, 0xCE}, + {0x09, 0x02, 0xCE}, + {0x17, 0x02, 0xCE}, + {0x28, 0x03, 0xCE}, + {0x02, 0x02, 0xD7}, + {0x09, 0x02, 0xD7}, + {0x17, 0x02, 0xD7}, + {0x28, 0x03, 0xD7}, + {0x02, 0x02, 0xE1}, + {0x09, 0x02, 0xE1}, + {0x17, 0x02, 0xE1}, + {0x28, 0x03, 0xE1}, }, /* 183 */ { - {0x03, 2, 171}, - {0x06, 2, 171}, - {0x0A, 2, 171}, - {0x0F, 2, 171}, - {0x18, 2, 171}, - {0x1F, 2, 171}, - {0x29, 2, 171}, - {0x38, 3, 171}, - {0x03, 2, 206}, - {0x06, 2, 206}, - {0x0A, 2, 206}, - {0x0F, 2, 206}, - {0x18, 2, 206}, - {0x1F, 2, 206}, - {0x29, 2, 206}, - {0x38, 3, 206}, + {0x03, 0x02, 0xAB}, + {0x06, 0x02, 0xAB}, + {0x0A, 0x02, 0xAB}, + {0x0F, 0x02, 0xAB}, + {0x18, 0x02, 0xAB}, + {0x1F, 0x02, 0xAB}, + {0x29, 0x02, 0xAB}, + {0x38, 0x03, 0xAB}, + {0x03, 0x02, 0xCE}, + {0x06, 0x02, 0xCE}, + {0x0A, 0x02, 0xCE}, + {0x0F, 0x02, 0xCE}, + {0x18, 0x02, 0xCE}, + {0x1F, 0x02, 0xCE}, + {0x29, 0x02, 0xCE}, + {0x38, 0x03, 0xCE}, }, /* 184 */ { - {0x03, 2, 215}, - {0x06, 2, 215}, - {0x0A, 2, 215}, - {0x0F, 2, 215}, - {0x18, 2, 215}, - {0x1F, 2, 215}, - {0x29, 2, 215}, - {0x38, 3, 215}, - {0x03, 2, 225}, - {0x06, 2, 225}, - {0x0A, 2, 225}, - {0x0F, 2, 225}, - {0x18, 2, 225}, - {0x1F, 2, 225}, - {0x29, 2, 225}, - {0x38, 3, 225}, + {0x03, 0x02, 0xD7}, + {0x06, 0x02, 0xD7}, + {0x0A, 0x02, 0xD7}, + {0x0F, 0x02, 0xD7}, + {0x18, 0x02, 0xD7}, + {0x1F, 0x02, 0xD7}, + {0x29, 0x02, 0xD7}, + {0x38, 0x03, 0xD7}, + {0x03, 0x02, 0xE1}, + {0x06, 0x02, 0xE1}, + {0x0A, 0x02, 0xE1}, + {0x0F, 0x02, 0xE1}, + {0x18, 0x02, 0xE1}, + {0x1F, 0x02, 0xE1}, + {0x29, 0x02, 0xE1}, + {0x38, 0x03, 0xE1}, }, /* 185 */ { - {0x02, 2, 236}, - {0x09, 2, 236}, - {0x17, 2, 236}, - {0x28, 3, 236}, - {0x02, 2, 237}, - {0x09, 2, 237}, - {0x17, 2, 237}, - {0x28, 3, 237}, - {0x01, 2, 199}, - {0x16, 3, 199}, - {0x01, 2, 207}, - {0x16, 3, 207}, - {0x01, 2, 234}, - {0x16, 3, 234}, - {0x01, 2, 235}, - {0x16, 3, 235}, + {0x02, 0x02, 0xEC}, + {0x09, 0x02, 0xEC}, + {0x17, 0x02, 0xEC}, + {0x28, 0x03, 0xEC}, + {0x02, 0x02, 0xED}, + {0x09, 0x02, 0xED}, + {0x17, 0x02, 0xED}, + {0x28, 0x03, 0xED}, + {0x01, 0x02, 0xC7}, + {0x16, 0x03, 0xC7}, + {0x01, 0x02, 0xCF}, + {0x16, 0x03, 0xCF}, + {0x01, 0x02, 0xEA}, + {0x16, 0x03, 0xEA}, + {0x01, 0x02, 0xEB}, + {0x16, 0x03, 0xEB}, }, /* 186 */ { - {0x03, 2, 236}, - {0x06, 2, 236}, - {0x0A, 2, 236}, - {0x0F, 2, 236}, - {0x18, 2, 236}, - {0x1F, 2, 236}, - {0x29, 2, 236}, - {0x38, 3, 236}, - {0x03, 2, 237}, - {0x06, 2, 237}, - {0x0A, 2, 237}, - {0x0F, 2, 237}, - {0x18, 2, 237}, - {0x1F, 2, 237}, - {0x29, 2, 237}, - {0x38, 3, 237}, + {0x03, 0x02, 0xEC}, + {0x06, 0x02, 0xEC}, + {0x0A, 0x02, 0xEC}, + {0x0F, 0x02, 0xEC}, + {0x18, 0x02, 0xEC}, + {0x1F, 0x02, 0xEC}, + {0x29, 0x02, 0xEC}, + {0x38, 0x03, 0xEC}, + {0x03, 0x02, 0xED}, + {0x06, 0x02, 0xED}, + {0x0A, 0x02, 0xED}, + {0x0F, 0x02, 0xED}, + {0x18, 0x02, 0xED}, + {0x1F, 0x02, 0xED}, + {0x29, 0x02, 0xED}, + {0x38, 0x03, 0xED}, }, /* 187 */ { - {0x02, 2, 199}, - {0x09, 2, 199}, - {0x17, 2, 199}, - {0x28, 3, 199}, - {0x02, 2, 207}, - {0x09, 2, 207}, - {0x17, 2, 207}, - {0x28, 3, 207}, - {0x02, 2, 234}, - {0x09, 2, 234}, - {0x17, 2, 234}, - {0x28, 3, 234}, - {0x02, 2, 235}, - {0x09, 2, 235}, - {0x17, 2, 235}, - {0x28, 3, 235}, + {0x02, 0x02, 0xC7}, + {0x09, 0x02, 0xC7}, + {0x17, 0x02, 0xC7}, + {0x28, 0x03, 0xC7}, + {0x02, 0x02, 0xCF}, + {0x09, 0x02, 0xCF}, + {0x17, 0x02, 0xCF}, + {0x28, 0x03, 0xCF}, + {0x02, 0x02, 0xEA}, + {0x09, 0x02, 0xEA}, + {0x17, 0x02, 0xEA}, + {0x28, 0x03, 0xEA}, + {0x02, 0x02, 0xEB}, + {0x09, 0x02, 0xEB}, + {0x17, 0x02, 0xEB}, + {0x28, 0x03, 0xEB}, }, /* 188 */ { - {0x03, 2, 199}, - {0x06, 2, 199}, - {0x0A, 2, 199}, - {0x0F, 2, 199}, - {0x18, 2, 199}, - {0x1F, 2, 199}, - {0x29, 2, 199}, - {0x38, 3, 199}, - {0x03, 2, 207}, - {0x06, 2, 207}, - {0x0A, 2, 207}, - {0x0F, 2, 207}, - {0x18, 2, 207}, - {0x1F, 2, 207}, - {0x29, 2, 207}, - {0x38, 3, 207}, + {0x03, 0x02, 0xC7}, + {0x06, 0x02, 0xC7}, + {0x0A, 0x02, 0xC7}, + {0x0F, 0x02, 0xC7}, + {0x18, 0x02, 0xC7}, + {0x1F, 0x02, 0xC7}, + {0x29, 0x02, 0xC7}, + {0x38, 0x03, 0xC7}, + {0x03, 0x02, 0xCF}, + {0x06, 0x02, 0xCF}, + {0x0A, 0x02, 0xCF}, + {0x0F, 0x02, 0xCF}, + {0x18, 0x02, 0xCF}, + {0x1F, 0x02, 0xCF}, + {0x29, 0x02, 0xCF}, + {0x38, 0x03, 0xCF}, }, /* 189 */ { - {0x03, 2, 234}, - {0x06, 2, 234}, - {0x0A, 2, 234}, - {0x0F, 2, 234}, - {0x18, 2, 234}, - {0x1F, 2, 234}, - {0x29, 2, 234}, - {0x38, 3, 234}, - {0x03, 2, 235}, - {0x06, 2, 235}, - {0x0A, 2, 235}, - {0x0F, 2, 235}, - {0x18, 2, 235}, - {0x1F, 2, 235}, - {0x29, 2, 235}, - {0x38, 3, 235}, + {0x03, 0x02, 0xEA}, + {0x06, 0x02, 0xEA}, + {0x0A, 0x02, 0xEA}, + {0x0F, 0x02, 0xEA}, + {0x18, 0x02, 0xEA}, + {0x1F, 0x02, 0xEA}, + {0x29, 0x02, 0xEA}, + {0x38, 0x03, 0xEA}, + {0x03, 0x02, 0xEB}, + {0x06, 0x02, 0xEB}, + {0x0A, 0x02, 0xEB}, + {0x0F, 0x02, 0xEB}, + {0x18, 0x02, 0xEB}, + {0x1F, 0x02, 0xEB}, + {0x29, 0x02, 0xEB}, + {0x38, 0x03, 0xEB}, }, /* 190 */ { - {0xC2, 0, 0}, - {0xC3, 0, 0}, - {0xC5, 0, 0}, - {0xC6, 0, 0}, - {0xC9, 0, 0}, - {0xCA, 0, 0}, - {0xCC, 0, 0}, - {0xCD, 0, 0}, - {0xD2, 0, 0}, - {0xD5, 0, 0}, - {0xD9, 0, 0}, - {0xDC, 0, 0}, - {0xE1, 0, 0}, - {0xE7, 0, 0}, - {0xEF, 0, 0}, - {0xF6, 0, 0}, + {0xC2, 0x00, 0x00}, + {0xC3, 0x00, 0x00}, + {0xC5, 0x00, 0x00}, + {0xC6, 0x00, 0x00}, + {0xC9, 0x00, 0x00}, + {0xCA, 0x00, 0x00}, + {0xCC, 0x00, 0x00}, + {0xCD, 0x00, 0x00}, + {0xD2, 0x00, 0x00}, + {0xD5, 0x00, 0x00}, + {0xD9, 0x00, 0x00}, + {0xDC, 0x00, 0x00}, + {0xE1, 0x00, 0x00}, + {0xE7, 0x00, 0x00}, + {0xEF, 0x00, 0x00}, + {0xF6, 0x00, 0x00}, }, /* 191 */ { - {0x00, 3, 192}, - {0x00, 3, 193}, - {0x00, 3, 200}, - {0x00, 3, 201}, - {0x00, 3, 202}, - {0x00, 3, 205}, - {0x00, 3, 210}, - {0x00, 3, 213}, - {0x00, 3, 218}, - {0x00, 3, 219}, - {0x00, 3, 238}, - {0x00, 3, 240}, - {0x00, 3, 242}, - {0x00, 3, 243}, - {0x00, 3, 255}, - {0xCE, 0, 0}, + {0x00, 0x03, 0xC0}, + {0x00, 0x03, 0xC1}, + {0x00, 0x03, 0xC8}, + {0x00, 0x03, 0xC9}, + {0x00, 0x03, 0xCA}, + {0x00, 0x03, 0xCD}, + {0x00, 0x03, 0xD2}, + {0x00, 0x03, 0xD5}, + {0x00, 0x03, 0xDA}, + {0x00, 0x03, 0xDB}, + {0x00, 0x03, 0xEE}, + {0x00, 0x03, 0xF0}, + {0x00, 0x03, 0xF2}, + {0x00, 0x03, 0xF3}, + {0x00, 0x03, 0xFF}, + {0xCE, 0x00, 0x00}, }, /* 192 */ { - {0x01, 2, 192}, - {0x16, 3, 192}, - {0x01, 2, 193}, - {0x16, 3, 193}, - {0x01, 2, 200}, - {0x16, 3, 200}, - {0x01, 2, 201}, - {0x16, 3, 201}, - {0x01, 2, 202}, - {0x16, 3, 202}, - {0x01, 2, 205}, - {0x16, 3, 205}, - {0x01, 2, 210}, - {0x16, 3, 210}, - {0x01, 2, 213}, - {0x16, 3, 213}, + {0x01, 0x02, 0xC0}, + {0x16, 0x03, 0xC0}, + {0x01, 0x02, 0xC1}, + {0x16, 0x03, 0xC1}, + {0x01, 0x02, 0xC8}, + {0x16, 0x03, 0xC8}, + {0x01, 0x02, 0xC9}, + {0x16, 0x03, 0xC9}, + {0x01, 0x02, 0xCA}, + {0x16, 0x03, 0xCA}, + {0x01, 0x02, 0xCD}, + {0x16, 0x03, 0xCD}, + {0x01, 0x02, 0xD2}, + {0x16, 0x03, 0xD2}, + {0x01, 0x02, 0xD5}, + {0x16, 0x03, 0xD5}, }, /* 193 */ { - {0x02, 2, 192}, - {0x09, 2, 192}, - {0x17, 2, 192}, - {0x28, 3, 192}, - {0x02, 2, 193}, - {0x09, 2, 193}, - {0x17, 2, 193}, - {0x28, 3, 193}, - {0x02, 2, 200}, - {0x09, 2, 200}, - {0x17, 2, 200}, - {0x28, 3, 200}, - {0x02, 2, 201}, - {0x09, 2, 201}, - {0x17, 2, 201}, - {0x28, 3, 201}, + {0x02, 0x02, 0xC0}, + {0x09, 0x02, 0xC0}, + {0x17, 0x02, 0xC0}, + {0x28, 0x03, 0xC0}, + {0x02, 0x02, 0xC1}, + {0x09, 0x02, 0xC1}, + {0x17, 0x02, 0xC1}, + {0x28, 0x03, 0xC1}, + {0x02, 0x02, 0xC8}, + {0x09, 0x02, 0xC8}, + {0x17, 0x02, 0xC8}, + {0x28, 0x03, 0xC8}, + {0x02, 0x02, 0xC9}, + {0x09, 0x02, 0xC9}, + {0x17, 0x02, 0xC9}, + {0x28, 0x03, 0xC9}, }, /* 194 */ { - {0x03, 2, 192}, - {0x06, 2, 192}, - {0x0A, 2, 192}, - {0x0F, 2, 192}, - {0x18, 2, 192}, - {0x1F, 2, 192}, - {0x29, 2, 192}, - {0x38, 3, 192}, - {0x03, 2, 193}, - {0x06, 2, 193}, - {0x0A, 2, 193}, - {0x0F, 2, 193}, - {0x18, 2, 193}, - {0x1F, 2, 193}, - {0x29, 2, 193}, - {0x38, 3, 193}, + {0x03, 0x02, 0xC0}, + {0x06, 0x02, 0xC0}, + {0x0A, 0x02, 0xC0}, + {0x0F, 0x02, 0xC0}, + {0x18, 0x02, 0xC0}, + {0x1F, 0x02, 0xC0}, + {0x29, 0x02, 0xC0}, + {0x38, 0x03, 0xC0}, + {0x03, 0x02, 0xC1}, + {0x06, 0x02, 0xC1}, + {0x0A, 0x02, 0xC1}, + {0x0F, 0x02, 0xC1}, + {0x18, 0x02, 0xC1}, + {0x1F, 0x02, 0xC1}, + {0x29, 0x02, 0xC1}, + {0x38, 0x03, 0xC1}, }, /* 195 */ { - {0x03, 2, 200}, - {0x06, 2, 200}, - {0x0A, 2, 200}, - {0x0F, 2, 200}, - {0x18, 2, 200}, - {0x1F, 2, 200}, - {0x29, 2, 200}, - {0x38, 3, 200}, - {0x03, 2, 201}, - {0x06, 2, 201}, - {0x0A, 2, 201}, - {0x0F, 2, 201}, - {0x18, 2, 201}, - {0x1F, 2, 201}, - {0x29, 2, 201}, - {0x38, 3, 201}, + {0x03, 0x02, 0xC8}, + {0x06, 0x02, 0xC8}, + {0x0A, 0x02, 0xC8}, + {0x0F, 0x02, 0xC8}, + {0x18, 0x02, 0xC8}, + {0x1F, 0x02, 0xC8}, + {0x29, 0x02, 0xC8}, + {0x38, 0x03, 0xC8}, + {0x03, 0x02, 0xC9}, + {0x06, 0x02, 0xC9}, + {0x0A, 0x02, 0xC9}, + {0x0F, 0x02, 0xC9}, + {0x18, 0x02, 0xC9}, + {0x1F, 0x02, 0xC9}, + {0x29, 0x02, 0xC9}, + {0x38, 0x03, 0xC9}, }, /* 196 */ { - {0x02, 2, 202}, - {0x09, 2, 202}, - {0x17, 2, 202}, - {0x28, 3, 202}, - {0x02, 2, 205}, - {0x09, 2, 205}, - {0x17, 2, 205}, - {0x28, 3, 205}, - {0x02, 2, 210}, - {0x09, 2, 210}, - {0x17, 2, 210}, - {0x28, 3, 210}, - {0x02, 2, 213}, - {0x09, 2, 213}, - {0x17, 2, 213}, - {0x28, 3, 213}, + {0x02, 0x02, 0xCA}, + {0x09, 0x02, 0xCA}, + {0x17, 0x02, 0xCA}, + {0x28, 0x03, 0xCA}, + {0x02, 0x02, 0xCD}, + {0x09, 0x02, 0xCD}, + {0x17, 0x02, 0xCD}, + {0x28, 0x03, 0xCD}, + {0x02, 0x02, 0xD2}, + {0x09, 0x02, 0xD2}, + {0x17, 0x02, 0xD2}, + {0x28, 0x03, 0xD2}, + {0x02, 0x02, 0xD5}, + {0x09, 0x02, 0xD5}, + {0x17, 0x02, 0xD5}, + {0x28, 0x03, 0xD5}, }, /* 197 */ { - {0x03, 2, 202}, - {0x06, 2, 202}, - {0x0A, 2, 202}, - {0x0F, 2, 202}, - {0x18, 2, 202}, - {0x1F, 2, 202}, - {0x29, 2, 202}, - {0x38, 3, 202}, - {0x03, 2, 205}, - {0x06, 2, 205}, - {0x0A, 2, 205}, - {0x0F, 2, 205}, - {0x18, 2, 205}, - {0x1F, 2, 205}, - {0x29, 2, 205}, - {0x38, 3, 205}, + {0x03, 0x02, 0xCA}, + {0x06, 0x02, 0xCA}, + {0x0A, 0x02, 0xCA}, + {0x0F, 0x02, 0xCA}, + {0x18, 0x02, 0xCA}, + {0x1F, 0x02, 0xCA}, + {0x29, 0x02, 0xCA}, + {0x38, 0x03, 0xCA}, + {0x03, 0x02, 0xCD}, + {0x06, 0x02, 0xCD}, + {0x0A, 0x02, 0xCD}, + {0x0F, 0x02, 0xCD}, + {0x18, 0x02, 0xCD}, + {0x1F, 0x02, 0xCD}, + {0x29, 0x02, 0xCD}, + {0x38, 0x03, 0xCD}, }, /* 198 */ { - {0x03, 2, 210}, - {0x06, 2, 210}, - {0x0A, 2, 210}, - {0x0F, 2, 210}, - {0x18, 2, 210}, - {0x1F, 2, 210}, - {0x29, 2, 210}, - {0x38, 3, 210}, - {0x03, 2, 213}, - {0x06, 2, 213}, - {0x0A, 2, 213}, - {0x0F, 2, 213}, - {0x18, 2, 213}, - {0x1F, 2, 213}, - {0x29, 2, 213}, - {0x38, 3, 213}, + {0x03, 0x02, 0xD2}, + {0x06, 0x02, 0xD2}, + {0x0A, 0x02, 0xD2}, + {0x0F, 0x02, 0xD2}, + {0x18, 0x02, 0xD2}, + {0x1F, 0x02, 0xD2}, + {0x29, 0x02, 0xD2}, + {0x38, 0x03, 0xD2}, + {0x03, 0x02, 0xD5}, + {0x06, 0x02, 0xD5}, + {0x0A, 0x02, 0xD5}, + {0x0F, 0x02, 0xD5}, + {0x18, 0x02, 0xD5}, + {0x1F, 0x02, 0xD5}, + {0x29, 0x02, 0xD5}, + {0x38, 0x03, 0xD5}, }, /* 199 */ { - {0x01, 2, 218}, - {0x16, 3, 218}, - {0x01, 2, 219}, - {0x16, 3, 219}, - {0x01, 2, 238}, - {0x16, 3, 238}, - {0x01, 2, 240}, - {0x16, 3, 240}, - {0x01, 2, 242}, - {0x16, 3, 242}, - {0x01, 2, 243}, - {0x16, 3, 243}, - {0x01, 2, 255}, - {0x16, 3, 255}, - {0x00, 3, 203}, - {0x00, 3, 204}, + {0x01, 0x02, 0xDA}, + {0x16, 0x03, 0xDA}, + {0x01, 0x02, 0xDB}, + {0x16, 0x03, 0xDB}, + {0x01, 0x02, 0xEE}, + {0x16, 0x03, 0xEE}, + {0x01, 0x02, 0xF0}, + {0x16, 0x03, 0xF0}, + {0x01, 0x02, 0xF2}, + {0x16, 0x03, 0xF2}, + {0x01, 0x02, 0xF3}, + {0x16, 0x03, 0xF3}, + {0x01, 0x02, 0xFF}, + {0x16, 0x03, 0xFF}, + {0x00, 0x03, 0xCB}, + {0x00, 0x03, 0xCC}, }, /* 200 */ { - {0x02, 2, 218}, - {0x09, 2, 218}, - {0x17, 2, 218}, - {0x28, 3, 218}, - {0x02, 2, 219}, - {0x09, 2, 219}, - {0x17, 2, 219}, - {0x28, 3, 219}, - {0x02, 2, 238}, - {0x09, 2, 238}, - {0x17, 2, 238}, - {0x28, 3, 238}, - {0x02, 2, 240}, - {0x09, 2, 240}, - {0x17, 2, 240}, - {0x28, 3, 240}, + {0x02, 0x02, 0xDA}, + {0x09, 0x02, 0xDA}, + {0x17, 0x02, 0xDA}, + {0x28, 0x03, 0xDA}, + {0x02, 0x02, 0xDB}, + {0x09, 0x02, 0xDB}, + {0x17, 0x02, 0xDB}, + {0x28, 0x03, 0xDB}, + {0x02, 0x02, 0xEE}, + {0x09, 0x02, 0xEE}, + {0x17, 0x02, 0xEE}, + {0x28, 0x03, 0xEE}, + {0x02, 0x02, 0xF0}, + {0x09, 0x02, 0xF0}, + {0x17, 0x02, 0xF0}, + {0x28, 0x03, 0xF0}, }, /* 201 */ { - {0x03, 2, 218}, - {0x06, 2, 218}, - {0x0A, 2, 218}, - {0x0F, 2, 218}, - {0x18, 2, 218}, - {0x1F, 2, 218}, - {0x29, 2, 218}, - {0x38, 3, 218}, - {0x03, 2, 219}, - {0x06, 2, 219}, - {0x0A, 2, 219}, - {0x0F, 2, 219}, - {0x18, 2, 219}, - {0x1F, 2, 219}, - {0x29, 2, 219}, - {0x38, 3, 219}, + {0x03, 0x02, 0xDA}, + {0x06, 0x02, 0xDA}, + {0x0A, 0x02, 0xDA}, + {0x0F, 0x02, 0xDA}, + {0x18, 0x02, 0xDA}, + {0x1F, 0x02, 0xDA}, + {0x29, 0x02, 0xDA}, + {0x38, 0x03, 0xDA}, + {0x03, 0x02, 0xDB}, + {0x06, 0x02, 0xDB}, + {0x0A, 0x02, 0xDB}, + {0x0F, 0x02, 0xDB}, + {0x18, 0x02, 0xDB}, + {0x1F, 0x02, 0xDB}, + {0x29, 0x02, 0xDB}, + {0x38, 0x03, 0xDB}, }, /* 202 */ { - {0x03, 2, 238}, - {0x06, 2, 238}, - {0x0A, 2, 238}, - {0x0F, 2, 238}, - {0x18, 2, 238}, - {0x1F, 2, 238}, - {0x29, 2, 238}, - {0x38, 3, 238}, - {0x03, 2, 240}, - {0x06, 2, 240}, - {0x0A, 2, 240}, - {0x0F, 2, 240}, - {0x18, 2, 240}, - {0x1F, 2, 240}, - {0x29, 2, 240}, - {0x38, 3, 240}, + {0x03, 0x02, 0xEE}, + {0x06, 0x02, 0xEE}, + {0x0A, 0x02, 0xEE}, + {0x0F, 0x02, 0xEE}, + {0x18, 0x02, 0xEE}, + {0x1F, 0x02, 0xEE}, + {0x29, 0x02, 0xEE}, + {0x38, 0x03, 0xEE}, + {0x03, 0x02, 0xF0}, + {0x06, 0x02, 0xF0}, + {0x0A, 0x02, 0xF0}, + {0x0F, 0x02, 0xF0}, + {0x18, 0x02, 0xF0}, + {0x1F, 0x02, 0xF0}, + {0x29, 0x02, 0xF0}, + {0x38, 0x03, 0xF0}, }, /* 203 */ { - {0x02, 2, 242}, - {0x09, 2, 242}, - {0x17, 2, 242}, - {0x28, 3, 242}, - {0x02, 2, 243}, - {0x09, 2, 243}, - {0x17, 2, 243}, - {0x28, 3, 243}, - {0x02, 2, 255}, - {0x09, 2, 255}, - {0x17, 2, 255}, - {0x28, 3, 255}, - {0x01, 2, 203}, - {0x16, 3, 203}, - {0x01, 2, 204}, - {0x16, 3, 204}, + {0x02, 0x02, 0xF2}, + {0x09, 0x02, 0xF2}, + {0x17, 0x02, 0xF2}, + {0x28, 0x03, 0xF2}, + {0x02, 0x02, 0xF3}, + {0x09, 0x02, 0xF3}, + {0x17, 0x02, 0xF3}, + {0x28, 0x03, 0xF3}, + {0x02, 0x02, 0xFF}, + {0x09, 0x02, 0xFF}, + {0x17, 0x02, 0xFF}, + {0x28, 0x03, 0xFF}, + {0x01, 0x02, 0xCB}, + {0x16, 0x03, 0xCB}, + {0x01, 0x02, 0xCC}, + {0x16, 0x03, 0xCC}, }, /* 204 */ { - {0x03, 2, 242}, - {0x06, 2, 242}, - {0x0A, 2, 242}, - {0x0F, 2, 242}, - {0x18, 2, 242}, - {0x1F, 2, 242}, - {0x29, 2, 242}, - {0x38, 3, 242}, - {0x03, 2, 243}, - {0x06, 2, 243}, - {0x0A, 2, 243}, - {0x0F, 2, 243}, - {0x18, 2, 243}, - {0x1F, 2, 243}, - {0x29, 2, 243}, - {0x38, 3, 243}, + {0x03, 0x02, 0xF2}, + {0x06, 0x02, 0xF2}, + {0x0A, 0x02, 0xF2}, + {0x0F, 0x02, 0xF2}, + {0x18, 0x02, 0xF2}, + {0x1F, 0x02, 0xF2}, + {0x29, 0x02, 0xF2}, + {0x38, 0x03, 0xF2}, + {0x03, 0x02, 0xF3}, + {0x06, 0x02, 0xF3}, + {0x0A, 0x02, 0xF3}, + {0x0F, 0x02, 0xF3}, + {0x18, 0x02, 0xF3}, + {0x1F, 0x02, 0xF3}, + {0x29, 0x02, 0xF3}, + {0x38, 0x03, 0xF3}, }, /* 205 */ { - {0x03, 2, 255}, - {0x06, 2, 255}, - {0x0A, 2, 255}, - {0x0F, 2, 255}, - {0x18, 2, 255}, - {0x1F, 2, 255}, - {0x29, 2, 255}, - {0x38, 3, 255}, - {0x02, 2, 203}, - {0x09, 2, 203}, - {0x17, 2, 203}, - {0x28, 3, 203}, - {0x02, 2, 204}, - {0x09, 2, 204}, - {0x17, 2, 204}, - {0x28, 3, 204}, + {0x03, 0x02, 0xFF}, + {0x06, 0x02, 0xFF}, + {0x0A, 0x02, 0xFF}, + {0x0F, 0x02, 0xFF}, + {0x18, 0x02, 0xFF}, + {0x1F, 0x02, 0xFF}, + {0x29, 0x02, 0xFF}, + {0x38, 0x03, 0xFF}, + {0x02, 0x02, 0xCB}, + {0x09, 0x02, 0xCB}, + {0x17, 0x02, 0xCB}, + {0x28, 0x03, 0xCB}, + {0x02, 0x02, 0xCC}, + {0x09, 0x02, 0xCC}, + {0x17, 0x02, 0xCC}, + {0x28, 0x03, 0xCC}, }, /* 206 */ { - {0x03, 2, 203}, - {0x06, 2, 203}, - {0x0A, 2, 203}, - {0x0F, 2, 203}, - {0x18, 2, 203}, - {0x1F, 2, 203}, - {0x29, 2, 203}, - {0x38, 3, 203}, - {0x03, 2, 204}, - {0x06, 2, 204}, - {0x0A, 2, 204}, - {0x0F, 2, 204}, - {0x18, 2, 204}, - {0x1F, 2, 204}, - {0x29, 2, 204}, - {0x38, 3, 204}, + {0x03, 0x02, 0xCB}, + {0x06, 0x02, 0xCB}, + {0x0A, 0x02, 0xCB}, + {0x0F, 0x02, 0xCB}, + {0x18, 0x02, 0xCB}, + {0x1F, 0x02, 0xCB}, + {0x29, 0x02, 0xCB}, + {0x38, 0x03, 0xCB}, + {0x03, 0x02, 0xCC}, + {0x06, 0x02, 0xCC}, + {0x0A, 0x02, 0xCC}, + {0x0F, 0x02, 0xCC}, + {0x18, 0x02, 0xCC}, + {0x1F, 0x02, 0xCC}, + {0x29, 0x02, 0xCC}, + {0x38, 0x03, 0xCC}, }, /* 207 */ { - {0xD3, 0, 0}, - {0xD4, 0, 0}, - {0xD6, 0, 0}, - {0xD7, 0, 0}, - {0xDA, 0, 0}, - {0xDB, 0, 0}, - {0xDD, 0, 0}, - {0xDE, 0, 0}, - {0xE2, 0, 0}, - {0xE4, 0, 0}, - {0xE8, 0, 0}, - {0xEB, 0, 0}, - {0xF0, 0, 0}, - {0xF3, 0, 0}, - {0xF7, 0, 0}, - {0xFA, 0, 0}, + {0xD3, 0x00, 0x00}, + {0xD4, 0x00, 0x00}, + {0xD6, 0x00, 0x00}, + {0xD7, 0x00, 0x00}, + {0xDA, 0x00, 0x00}, + {0xDB, 0x00, 0x00}, + {0xDD, 0x00, 0x00}, + {0xDE, 0x00, 0x00}, + {0xE2, 0x00, 0x00}, + {0xE4, 0x00, 0x00}, + {0xE8, 0x00, 0x00}, + {0xEB, 0x00, 0x00}, + {0xF0, 0x00, 0x00}, + {0xF3, 0x00, 0x00}, + {0xF7, 0x00, 0x00}, + {0xFA, 0x00, 0x00}, }, /* 208 */ { - {0x00, 3, 211}, - {0x00, 3, 212}, - {0x00, 3, 214}, - {0x00, 3, 221}, - {0x00, 3, 222}, - {0x00, 3, 223}, - {0x00, 3, 241}, - {0x00, 3, 244}, - {0x00, 3, 245}, - {0x00, 3, 246}, - {0x00, 3, 247}, - {0x00, 3, 248}, - {0x00, 3, 250}, - {0x00, 3, 251}, - {0x00, 3, 252}, - {0x00, 3, 253}, + {0x00, 0x03, 0xD3}, + {0x00, 0x03, 0xD4}, + {0x00, 0x03, 0xD6}, + {0x00, 0x03, 0xDD}, + {0x00, 0x03, 0xDE}, + {0x00, 0x03, 0xDF}, + {0x00, 0x03, 0xF1}, + {0x00, 0x03, 0xF4}, + {0x00, 0x03, 0xF5}, + {0x00, 0x03, 0xF6}, + {0x00, 0x03, 0xF7}, + {0x00, 0x03, 0xF8}, + {0x00, 0x03, 0xFA}, + {0x00, 0x03, 0xFB}, + {0x00, 0x03, 0xFC}, + {0x00, 0x03, 0xFD}, }, /* 209 */ { - {0x01, 2, 211}, - {0x16, 3, 211}, - {0x01, 2, 212}, - {0x16, 3, 212}, - {0x01, 2, 214}, - {0x16, 3, 214}, - {0x01, 2, 221}, - {0x16, 3, 221}, - {0x01, 2, 222}, - {0x16, 3, 222}, - {0x01, 2, 223}, - {0x16, 3, 223}, - {0x01, 2, 241}, - {0x16, 3, 241}, - {0x01, 2, 244}, - {0x16, 3, 244}, + {0x01, 0x02, 0xD3}, + {0x16, 0x03, 0xD3}, + {0x01, 0x02, 0xD4}, + {0x16, 0x03, 0xD4}, + {0x01, 0x02, 0xD6}, + {0x16, 0x03, 0xD6}, + {0x01, 0x02, 0xDD}, + {0x16, 0x03, 0xDD}, + {0x01, 0x02, 0xDE}, + {0x16, 0x03, 0xDE}, + {0x01, 0x02, 0xDF}, + {0x16, 0x03, 0xDF}, + {0x01, 0x02, 0xF1}, + {0x16, 0x03, 0xF1}, + {0x01, 0x02, 0xF4}, + {0x16, 0x03, 0xF4}, }, /* 210 */ { - {0x02, 2, 211}, - {0x09, 2, 211}, - {0x17, 2, 211}, - {0x28, 3, 211}, - {0x02, 2, 212}, - {0x09, 2, 212}, - {0x17, 2, 212}, - {0x28, 3, 212}, - {0x02, 2, 214}, - {0x09, 2, 214}, - {0x17, 2, 214}, - {0x28, 3, 214}, - {0x02, 2, 221}, - {0x09, 2, 221}, - {0x17, 2, 221}, - {0x28, 3, 221}, + {0x02, 0x02, 0xD3}, + {0x09, 0x02, 0xD3}, + {0x17, 0x02, 0xD3}, + {0x28, 0x03, 0xD3}, + {0x02, 0x02, 0xD4}, + {0x09, 0x02, 0xD4}, + {0x17, 0x02, 0xD4}, + {0x28, 0x03, 0xD4}, + {0x02, 0x02, 0xD6}, + {0x09, 0x02, 0xD6}, + {0x17, 0x02, 0xD6}, + {0x28, 0x03, 0xD6}, + {0x02, 0x02, 0xDD}, + {0x09, 0x02, 0xDD}, + {0x17, 0x02, 0xDD}, + {0x28, 0x03, 0xDD}, }, /* 211 */ { - {0x03, 2, 211}, - {0x06, 2, 211}, - {0x0A, 2, 211}, - {0x0F, 2, 211}, - {0x18, 2, 211}, - {0x1F, 2, 211}, - {0x29, 2, 211}, - {0x38, 3, 211}, - {0x03, 2, 212}, - {0x06, 2, 212}, - {0x0A, 2, 212}, - {0x0F, 2, 212}, - {0x18, 2, 212}, - {0x1F, 2, 212}, - {0x29, 2, 212}, - {0x38, 3, 212}, + {0x03, 0x02, 0xD3}, + {0x06, 0x02, 0xD3}, + {0x0A, 0x02, 0xD3}, + {0x0F, 0x02, 0xD3}, + {0x18, 0x02, 0xD3}, + {0x1F, 0x02, 0xD3}, + {0x29, 0x02, 0xD3}, + {0x38, 0x03, 0xD3}, + {0x03, 0x02, 0xD4}, + {0x06, 0x02, 0xD4}, + {0x0A, 0x02, 0xD4}, + {0x0F, 0x02, 0xD4}, + {0x18, 0x02, 0xD4}, + {0x1F, 0x02, 0xD4}, + {0x29, 0x02, 0xD4}, + {0x38, 0x03, 0xD4}, }, /* 212 */ { - {0x03, 2, 214}, - {0x06, 2, 214}, - {0x0A, 2, 214}, - {0x0F, 2, 214}, - {0x18, 2, 214}, - {0x1F, 2, 214}, - {0x29, 2, 214}, - {0x38, 3, 214}, - {0x03, 2, 221}, - {0x06, 2, 221}, - {0x0A, 2, 221}, - {0x0F, 2, 221}, - {0x18, 2, 221}, - {0x1F, 2, 221}, - {0x29, 2, 221}, - {0x38, 3, 221}, + {0x03, 0x02, 0xD6}, + {0x06, 0x02, 0xD6}, + {0x0A, 0x02, 0xD6}, + {0x0F, 0x02, 0xD6}, + {0x18, 0x02, 0xD6}, + {0x1F, 0x02, 0xD6}, + {0x29, 0x02, 0xD6}, + {0x38, 0x03, 0xD6}, + {0x03, 0x02, 0xDD}, + {0x06, 0x02, 0xDD}, + {0x0A, 0x02, 0xDD}, + {0x0F, 0x02, 0xDD}, + {0x18, 0x02, 0xDD}, + {0x1F, 0x02, 0xDD}, + {0x29, 0x02, 0xDD}, + {0x38, 0x03, 0xDD}, }, /* 213 */ { - {0x02, 2, 222}, - {0x09, 2, 222}, - {0x17, 2, 222}, - {0x28, 3, 222}, - {0x02, 2, 223}, - {0x09, 2, 223}, - {0x17, 2, 223}, - {0x28, 3, 223}, - {0x02, 2, 241}, - {0x09, 2, 241}, - {0x17, 2, 241}, - {0x28, 3, 241}, - {0x02, 2, 244}, - {0x09, 2, 244}, - {0x17, 2, 244}, - {0x28, 3, 244}, + {0x02, 0x02, 0xDE}, + {0x09, 0x02, 0xDE}, + {0x17, 0x02, 0xDE}, + {0x28, 0x03, 0xDE}, + {0x02, 0x02, 0xDF}, + {0x09, 0x02, 0xDF}, + {0x17, 0x02, 0xDF}, + {0x28, 0x03, 0xDF}, + {0x02, 0x02, 0xF1}, + {0x09, 0x02, 0xF1}, + {0x17, 0x02, 0xF1}, + {0x28, 0x03, 0xF1}, + {0x02, 0x02, 0xF4}, + {0x09, 0x02, 0xF4}, + {0x17, 0x02, 0xF4}, + {0x28, 0x03, 0xF4}, }, /* 214 */ { - {0x03, 2, 222}, - {0x06, 2, 222}, - {0x0A, 2, 222}, - {0x0F, 2, 222}, - {0x18, 2, 222}, - {0x1F, 2, 222}, - {0x29, 2, 222}, - {0x38, 3, 222}, - {0x03, 2, 223}, - {0x06, 2, 223}, - {0x0A, 2, 223}, - {0x0F, 2, 223}, - {0x18, 2, 223}, - {0x1F, 2, 223}, - {0x29, 2, 223}, - {0x38, 3, 223}, + {0x03, 0x02, 0xDE}, + {0x06, 0x02, 0xDE}, + {0x0A, 0x02, 0xDE}, + {0x0F, 0x02, 0xDE}, + {0x18, 0x02, 0xDE}, + {0x1F, 0x02, 0xDE}, + {0x29, 0x02, 0xDE}, + {0x38, 0x03, 0xDE}, + {0x03, 0x02, 0xDF}, + {0x06, 0x02, 0xDF}, + {0x0A, 0x02, 0xDF}, + {0x0F, 0x02, 0xDF}, + {0x18, 0x02, 0xDF}, + {0x1F, 0x02, 0xDF}, + {0x29, 0x02, 0xDF}, + {0x38, 0x03, 0xDF}, }, /* 215 */ { - {0x03, 2, 241}, - {0x06, 2, 241}, - {0x0A, 2, 241}, - {0x0F, 2, 241}, - {0x18, 2, 241}, - {0x1F, 2, 241}, - {0x29, 2, 241}, - {0x38, 3, 241}, - {0x03, 2, 244}, - {0x06, 2, 244}, - {0x0A, 2, 244}, - {0x0F, 2, 244}, - {0x18, 2, 244}, - {0x1F, 2, 244}, - {0x29, 2, 244}, - {0x38, 3, 244}, + {0x03, 0x02, 0xF1}, + {0x06, 0x02, 0xF1}, + {0x0A, 0x02, 0xF1}, + {0x0F, 0x02, 0xF1}, + {0x18, 0x02, 0xF1}, + {0x1F, 0x02, 0xF1}, + {0x29, 0x02, 0xF1}, + {0x38, 0x03, 0xF1}, + {0x03, 0x02, 0xF4}, + {0x06, 0x02, 0xF4}, + {0x0A, 0x02, 0xF4}, + {0x0F, 0x02, 0xF4}, + {0x18, 0x02, 0xF4}, + {0x1F, 0x02, 0xF4}, + {0x29, 0x02, 0xF4}, + {0x38, 0x03, 0xF4}, }, /* 216 */ { - {0x01, 2, 245}, - {0x16, 3, 245}, - {0x01, 2, 246}, - {0x16, 3, 246}, - {0x01, 2, 247}, - {0x16, 3, 247}, - {0x01, 2, 248}, - {0x16, 3, 248}, - {0x01, 2, 250}, - {0x16, 3, 250}, - {0x01, 2, 251}, - {0x16, 3, 251}, - {0x01, 2, 252}, - {0x16, 3, 252}, - {0x01, 2, 253}, - {0x16, 3, 253}, + {0x01, 0x02, 0xF5}, + {0x16, 0x03, 0xF5}, + {0x01, 0x02, 0xF6}, + {0x16, 0x03, 0xF6}, + {0x01, 0x02, 0xF7}, + {0x16, 0x03, 0xF7}, + {0x01, 0x02, 0xF8}, + {0x16, 0x03, 0xF8}, + {0x01, 0x02, 0xFA}, + {0x16, 0x03, 0xFA}, + {0x01, 0x02, 0xFB}, + {0x16, 0x03, 0xFB}, + {0x01, 0x02, 0xFC}, + {0x16, 0x03, 0xFC}, + {0x01, 0x02, 0xFD}, + {0x16, 0x03, 0xFD}, }, /* 217 */ { - {0x02, 2, 245}, - {0x09, 2, 245}, - {0x17, 2, 245}, - {0x28, 3, 245}, - {0x02, 2, 246}, - {0x09, 2, 246}, - {0x17, 2, 246}, - {0x28, 3, 246}, - {0x02, 2, 247}, - {0x09, 2, 247}, - {0x17, 2, 247}, - {0x28, 3, 247}, - {0x02, 2, 248}, - {0x09, 2, 248}, - {0x17, 2, 248}, - {0x28, 3, 248}, + {0x02, 0x02, 0xF5}, + {0x09, 0x02, 0xF5}, + {0x17, 0x02, 0xF5}, + {0x28, 0x03, 0xF5}, + {0x02, 0x02, 0xF6}, + {0x09, 0x02, 0xF6}, + {0x17, 0x02, 0xF6}, + {0x28, 0x03, 0xF6}, + {0x02, 0x02, 0xF7}, + {0x09, 0x02, 0xF7}, + {0x17, 0x02, 0xF7}, + {0x28, 0x03, 0xF7}, + {0x02, 0x02, 0xF8}, + {0x09, 0x02, 0xF8}, + {0x17, 0x02, 0xF8}, + {0x28, 0x03, 0xF8}, }, /* 218 */ { - {0x03, 2, 245}, - {0x06, 2, 245}, - {0x0A, 2, 245}, - {0x0F, 2, 245}, - {0x18, 2, 245}, - {0x1F, 2, 245}, - {0x29, 2, 245}, - {0x38, 3, 245}, - {0x03, 2, 246}, - {0x06, 2, 246}, - {0x0A, 2, 246}, - {0x0F, 2, 246}, - {0x18, 2, 246}, - {0x1F, 2, 246}, - {0x29, 2, 246}, - {0x38, 3, 246}, + {0x03, 0x02, 0xF5}, + {0x06, 0x02, 0xF5}, + {0x0A, 0x02, 0xF5}, + {0x0F, 0x02, 0xF5}, + {0x18, 0x02, 0xF5}, + {0x1F, 0x02, 0xF5}, + {0x29, 0x02, 0xF5}, + {0x38, 0x03, 0xF5}, + {0x03, 0x02, 0xF6}, + {0x06, 0x02, 0xF6}, + {0x0A, 0x02, 0xF6}, + {0x0F, 0x02, 0xF6}, + {0x18, 0x02, 0xF6}, + {0x1F, 0x02, 0xF6}, + {0x29, 0x02, 0xF6}, + {0x38, 0x03, 0xF6}, }, /* 219 */ { - {0x03, 2, 247}, - {0x06, 2, 247}, - {0x0A, 2, 247}, - {0x0F, 2, 247}, - {0x18, 2, 247}, - {0x1F, 2, 247}, - {0x29, 2, 247}, - {0x38, 3, 247}, - {0x03, 2, 248}, - {0x06, 2, 248}, - {0x0A, 2, 248}, - {0x0F, 2, 248}, - {0x18, 2, 248}, - {0x1F, 2, 248}, - {0x29, 2, 248}, - {0x38, 3, 248}, + {0x03, 0x02, 0xF7}, + {0x06, 0x02, 0xF7}, + {0x0A, 0x02, 0xF7}, + {0x0F, 0x02, 0xF7}, + {0x18, 0x02, 0xF7}, + {0x1F, 0x02, 0xF7}, + {0x29, 0x02, 0xF7}, + {0x38, 0x03, 0xF7}, + {0x03, 0x02, 0xF8}, + {0x06, 0x02, 0xF8}, + {0x0A, 0x02, 0xF8}, + {0x0F, 0x02, 0xF8}, + {0x18, 0x02, 0xF8}, + {0x1F, 0x02, 0xF8}, + {0x29, 0x02, 0xF8}, + {0x38, 0x03, 0xF8}, }, /* 220 */ { - {0x02, 2, 250}, - {0x09, 2, 250}, - {0x17, 2, 250}, - {0x28, 3, 250}, - {0x02, 2, 251}, - {0x09, 2, 251}, - {0x17, 2, 251}, - {0x28, 3, 251}, - {0x02, 2, 252}, - {0x09, 2, 252}, - {0x17, 2, 252}, - {0x28, 3, 252}, - {0x02, 2, 253}, - {0x09, 2, 253}, - {0x17, 2, 253}, - {0x28, 3, 253}, + {0x02, 0x02, 0xFA}, + {0x09, 0x02, 0xFA}, + {0x17, 0x02, 0xFA}, + {0x28, 0x03, 0xFA}, + {0x02, 0x02, 0xFB}, + {0x09, 0x02, 0xFB}, + {0x17, 0x02, 0xFB}, + {0x28, 0x03, 0xFB}, + {0x02, 0x02, 0xFC}, + {0x09, 0x02, 0xFC}, + {0x17, 0x02, 0xFC}, + {0x28, 0x03, 0xFC}, + {0x02, 0x02, 0xFD}, + {0x09, 0x02, 0xFD}, + {0x17, 0x02, 0xFD}, + {0x28, 0x03, 0xFD}, }, /* 221 */ { - {0x03, 2, 250}, - {0x06, 2, 250}, - {0x0A, 2, 250}, - {0x0F, 2, 250}, - {0x18, 2, 250}, - {0x1F, 2, 250}, - {0x29, 2, 250}, - {0x38, 3, 250}, - {0x03, 2, 251}, - {0x06, 2, 251}, - {0x0A, 2, 251}, - {0x0F, 2, 251}, - {0x18, 2, 251}, - {0x1F, 2, 251}, - {0x29, 2, 251}, - {0x38, 3, 251}, + {0x03, 0x02, 0xFA}, + {0x06, 0x02, 0xFA}, + {0x0A, 0x02, 0xFA}, + {0x0F, 0x02, 0xFA}, + {0x18, 0x02, 0xFA}, + {0x1F, 0x02, 0xFA}, + {0x29, 0x02, 0xFA}, + {0x38, 0x03, 0xFA}, + {0x03, 0x02, 0xFB}, + {0x06, 0x02, 0xFB}, + {0x0A, 0x02, 0xFB}, + {0x0F, 0x02, 0xFB}, + {0x18, 0x02, 0xFB}, + {0x1F, 0x02, 0xFB}, + {0x29, 0x02, 0xFB}, + {0x38, 0x03, 0xFB}, }, /* 222 */ { - {0x03, 2, 252}, - {0x06, 2, 252}, - {0x0A, 2, 252}, - {0x0F, 2, 252}, - {0x18, 2, 252}, - {0x1F, 2, 252}, - {0x29, 2, 252}, - {0x38, 3, 252}, - {0x03, 2, 253}, - {0x06, 2, 253}, - {0x0A, 2, 253}, - {0x0F, 2, 253}, - {0x18, 2, 253}, - {0x1F, 2, 253}, - {0x29, 2, 253}, - {0x38, 3, 253}, + {0x03, 0x02, 0xFC}, + {0x06, 0x02, 0xFC}, + {0x0A, 0x02, 0xFC}, + {0x0F, 0x02, 0xFC}, + {0x18, 0x02, 0xFC}, + {0x1F, 0x02, 0xFC}, + {0x29, 0x02, 0xFC}, + {0x38, 0x03, 0xFC}, + {0x03, 0x02, 0xFD}, + {0x06, 0x02, 0xFD}, + {0x0A, 0x02, 0xFD}, + {0x0F, 0x02, 0xFD}, + {0x18, 0x02, 0xFD}, + {0x1F, 0x02, 0xFD}, + {0x29, 0x02, 0xFD}, + {0x38, 0x03, 0xFD}, }, /* 223 */ { - {0x00, 3, 254}, - {0xE3, 0, 0}, - {0xE5, 0, 0}, - {0xE6, 0, 0}, - {0xE9, 0, 0}, - {0xEA, 0, 0}, - {0xEC, 0, 0}, - {0xED, 0, 0}, - {0xF1, 0, 0}, - {0xF2, 0, 0}, - {0xF4, 0, 0}, - {0xF5, 0, 0}, - {0xF8, 0, 0}, - {0xF9, 0, 0}, - {0xFB, 0, 0}, - {0xFC, 0, 0}, + {0x00, 0x03, 0xFE}, + {0xE3, 0x00, 0x00}, + {0xE5, 0x00, 0x00}, + {0xE6, 0x00, 0x00}, + {0xE9, 0x00, 0x00}, + {0xEA, 0x00, 0x00}, + {0xEC, 0x00, 0x00}, + {0xED, 0x00, 0x00}, + {0xF1, 0x00, 0x00}, + {0xF2, 0x00, 0x00}, + {0xF4, 0x00, 0x00}, + {0xF5, 0x00, 0x00}, + {0xF8, 0x00, 0x00}, + {0xF9, 0x00, 0x00}, + {0xFB, 0x00, 0x00}, + {0xFC, 0x00, 0x00}, }, /* 224 */ { - {0x01, 2, 254}, - {0x16, 3, 254}, - {0x00, 3, 2}, - {0x00, 3, 3}, - {0x00, 3, 4}, - {0x00, 3, 5}, - {0x00, 3, 6}, - {0x00, 3, 7}, - {0x00, 3, 8}, - {0x00, 3, 11}, - {0x00, 3, 12}, - {0x00, 3, 14}, - {0x00, 3, 15}, - {0x00, 3, 16}, - {0x00, 3, 17}, - {0x00, 3, 18}, + {0x01, 0x02, 0xFE}, + {0x16, 0x03, 0xFE}, + {0x00, 0x03, 0x02}, + {0x00, 0x03, 0x03}, + {0x00, 0x03, 0x04}, + {0x00, 0x03, 0x05}, + {0x00, 0x03, 0x06}, + {0x00, 0x03, 0x07}, + {0x00, 0x03, 0x08}, + {0x00, 0x03, 0x0B}, + {0x00, 0x03, 0x0C}, + {0x00, 0x03, 0x0E}, + {0x00, 0x03, 0x0F}, + {0x00, 0x03, 0x10}, + {0x00, 0x03, 0x11}, + {0x00, 0x03, 0x12}, }, /* 225 */ { - {0x02, 2, 254}, - {0x09, 2, 254}, - {0x17, 2, 254}, - {0x28, 3, 254}, - {0x01, 2, 2}, - {0x16, 3, 2}, - {0x01, 2, 3}, - {0x16, 3, 3}, - {0x01, 2, 4}, - {0x16, 3, 4}, - {0x01, 2, 5}, - {0x16, 3, 5}, - {0x01, 2, 6}, - {0x16, 3, 6}, - {0x01, 2, 7}, - {0x16, 3, 7}, + {0x02, 0x02, 0xFE}, + {0x09, 0x02, 0xFE}, + {0x17, 0x02, 0xFE}, + {0x28, 0x03, 0xFE}, + {0x01, 0x02, 0x02}, + {0x16, 0x03, 0x02}, + {0x01, 0x02, 0x03}, + {0x16, 0x03, 0x03}, + {0x01, 0x02, 0x04}, + {0x16, 0x03, 0x04}, + {0x01, 0x02, 0x05}, + {0x16, 0x03, 0x05}, + {0x01, 0x02, 0x06}, + {0x16, 0x03, 0x06}, + {0x01, 0x02, 0x07}, + {0x16, 0x03, 0x07}, }, /* 226 */ { - {0x03, 2, 254}, - {0x06, 2, 254}, - {0x0A, 2, 254}, - {0x0F, 2, 254}, - {0x18, 2, 254}, - {0x1F, 2, 254}, - {0x29, 2, 254}, - {0x38, 3, 254}, - {0x02, 2, 2}, - {0x09, 2, 2}, - {0x17, 2, 2}, - {0x28, 3, 2}, - {0x02, 2, 3}, - {0x09, 2, 3}, - {0x17, 2, 3}, - {0x28, 3, 3}, + {0x03, 0x02, 0xFE}, + {0x06, 0x02, 0xFE}, + {0x0A, 0x02, 0xFE}, + {0x0F, 0x02, 0xFE}, + {0x18, 0x02, 0xFE}, + {0x1F, 0x02, 0xFE}, + {0x29, 0x02, 0xFE}, + {0x38, 0x03, 0xFE}, + {0x02, 0x02, 0x02}, + {0x09, 0x02, 0x02}, + {0x17, 0x02, 0x02}, + {0x28, 0x03, 0x02}, + {0x02, 0x02, 0x03}, + {0x09, 0x02, 0x03}, + {0x17, 0x02, 0x03}, + {0x28, 0x03, 0x03}, }, /* 227 */ { - {0x03, 2, 2}, - {0x06, 2, 2}, - {0x0A, 2, 2}, - {0x0F, 2, 2}, - {0x18, 2, 2}, - {0x1F, 2, 2}, - {0x29, 2, 2}, - {0x38, 3, 2}, - {0x03, 2, 3}, - {0x06, 2, 3}, - {0x0A, 2, 3}, - {0x0F, 2, 3}, - {0x18, 2, 3}, - {0x1F, 2, 3}, - {0x29, 2, 3}, - {0x38, 3, 3}, + {0x03, 0x02, 0x02}, + {0x06, 0x02, 0x02}, + {0x0A, 0x02, 0x02}, + {0x0F, 0x02, 0x02}, + {0x18, 0x02, 0x02}, + {0x1F, 0x02, 0x02}, + {0x29, 0x02, 0x02}, + {0x38, 0x03, 0x02}, + {0x03, 0x02, 0x03}, + {0x06, 0x02, 0x03}, + {0x0A, 0x02, 0x03}, + {0x0F, 0x02, 0x03}, + {0x18, 0x02, 0x03}, + {0x1F, 0x02, 0x03}, + {0x29, 0x02, 0x03}, + {0x38, 0x03, 0x03}, }, /* 228 */ { - {0x02, 2, 4}, - {0x09, 2, 4}, - {0x17, 2, 4}, - {0x28, 3, 4}, - {0x02, 2, 5}, - {0x09, 2, 5}, - {0x17, 2, 5}, - {0x28, 3, 5}, - {0x02, 2, 6}, - {0x09, 2, 6}, - {0x17, 2, 6}, - {0x28, 3, 6}, - {0x02, 2, 7}, - {0x09, 2, 7}, - {0x17, 2, 7}, - {0x28, 3, 7}, + {0x02, 0x02, 0x04}, + {0x09, 0x02, 0x04}, + {0x17, 0x02, 0x04}, + {0x28, 0x03, 0x04}, + {0x02, 0x02, 0x05}, + {0x09, 0x02, 0x05}, + {0x17, 0x02, 0x05}, + {0x28, 0x03, 0x05}, + {0x02, 0x02, 0x06}, + {0x09, 0x02, 0x06}, + {0x17, 0x02, 0x06}, + {0x28, 0x03, 0x06}, + {0x02, 0x02, 0x07}, + {0x09, 0x02, 0x07}, + {0x17, 0x02, 0x07}, + {0x28, 0x03, 0x07}, }, /* 229 */ { - {0x03, 2, 4}, - {0x06, 2, 4}, - {0x0A, 2, 4}, - {0x0F, 2, 4}, - {0x18, 2, 4}, - {0x1F, 2, 4}, - {0x29, 2, 4}, - {0x38, 3, 4}, - {0x03, 2, 5}, - {0x06, 2, 5}, - {0x0A, 2, 5}, - {0x0F, 2, 5}, - {0x18, 2, 5}, - {0x1F, 2, 5}, - {0x29, 2, 5}, - {0x38, 3, 5}, + {0x03, 0x02, 0x04}, + {0x06, 0x02, 0x04}, + {0x0A, 0x02, 0x04}, + {0x0F, 0x02, 0x04}, + {0x18, 0x02, 0x04}, + {0x1F, 0x02, 0x04}, + {0x29, 0x02, 0x04}, + {0x38, 0x03, 0x04}, + {0x03, 0x02, 0x05}, + {0x06, 0x02, 0x05}, + {0x0A, 0x02, 0x05}, + {0x0F, 0x02, 0x05}, + {0x18, 0x02, 0x05}, + {0x1F, 0x02, 0x05}, + {0x29, 0x02, 0x05}, + {0x38, 0x03, 0x05}, }, /* 230 */ { - {0x03, 2, 6}, - {0x06, 2, 6}, - {0x0A, 2, 6}, - {0x0F, 2, 6}, - {0x18, 2, 6}, - {0x1F, 2, 6}, - {0x29, 2, 6}, - {0x38, 3, 6}, - {0x03, 2, 7}, - {0x06, 2, 7}, - {0x0A, 2, 7}, - {0x0F, 2, 7}, - {0x18, 2, 7}, - {0x1F, 2, 7}, - {0x29, 2, 7}, - {0x38, 3, 7}, + {0x03, 0x02, 0x06}, + {0x06, 0x02, 0x06}, + {0x0A, 0x02, 0x06}, + {0x0F, 0x02, 0x06}, + {0x18, 0x02, 0x06}, + {0x1F, 0x02, 0x06}, + {0x29, 0x02, 0x06}, + {0x38, 0x03, 0x06}, + {0x03, 0x02, 0x07}, + {0x06, 0x02, 0x07}, + {0x0A, 0x02, 0x07}, + {0x0F, 0x02, 0x07}, + {0x18, 0x02, 0x07}, + {0x1F, 0x02, 0x07}, + {0x29, 0x02, 0x07}, + {0x38, 0x03, 0x07}, }, /* 231 */ { - {0x01, 2, 8}, - {0x16, 3, 8}, - {0x01, 2, 11}, - {0x16, 3, 11}, - {0x01, 2, 12}, - {0x16, 3, 12}, - {0x01, 2, 14}, - {0x16, 3, 14}, - {0x01, 2, 15}, - {0x16, 3, 15}, - {0x01, 2, 16}, - {0x16, 3, 16}, - {0x01, 2, 17}, - {0x16, 3, 17}, - {0x01, 2, 18}, - {0x16, 3, 18}, + {0x01, 0x02, 0x08}, + {0x16, 0x03, 0x08}, + {0x01, 0x02, 0x0B}, + {0x16, 0x03, 0x0B}, + {0x01, 0x02, 0x0C}, + {0x16, 0x03, 0x0C}, + {0x01, 0x02, 0x0E}, + {0x16, 0x03, 0x0E}, + {0x01, 0x02, 0x0F}, + {0x16, 0x03, 0x0F}, + {0x01, 0x02, 0x10}, + {0x16, 0x03, 0x10}, + {0x01, 0x02, 0x11}, + {0x16, 0x03, 0x11}, + {0x01, 0x02, 0x12}, + {0x16, 0x03, 0x12}, }, /* 232 */ { - {0x02, 2, 8}, - {0x09, 2, 8}, - {0x17, 2, 8}, - {0x28, 3, 8}, - {0x02, 2, 11}, - {0x09, 2, 11}, - {0x17, 2, 11}, - {0x28, 3, 11}, - {0x02, 2, 12}, - {0x09, 2, 12}, - {0x17, 2, 12}, - {0x28, 3, 12}, - {0x02, 2, 14}, - {0x09, 2, 14}, - {0x17, 2, 14}, - {0x28, 3, 14}, + {0x02, 0x02, 0x08}, + {0x09, 0x02, 0x08}, + {0x17, 0x02, 0x08}, + {0x28, 0x03, 0x08}, + {0x02, 0x02, 0x0B}, + {0x09, 0x02, 0x0B}, + {0x17, 0x02, 0x0B}, + {0x28, 0x03, 0x0B}, + {0x02, 0x02, 0x0C}, + {0x09, 0x02, 0x0C}, + {0x17, 0x02, 0x0C}, + {0x28, 0x03, 0x0C}, + {0x02, 0x02, 0x0E}, + {0x09, 0x02, 0x0E}, + {0x17, 0x02, 0x0E}, + {0x28, 0x03, 0x0E}, }, /* 233 */ { - {0x03, 2, 8}, - {0x06, 2, 8}, - {0x0A, 2, 8}, - {0x0F, 2, 8}, - {0x18, 2, 8}, - {0x1F, 2, 8}, - {0x29, 2, 8}, - {0x38, 3, 8}, - {0x03, 2, 11}, - {0x06, 2, 11}, - {0x0A, 2, 11}, - {0x0F, 2, 11}, - {0x18, 2, 11}, - {0x1F, 2, 11}, - {0x29, 2, 11}, - {0x38, 3, 11}, + {0x03, 0x02, 0x08}, + {0x06, 0x02, 0x08}, + {0x0A, 0x02, 0x08}, + {0x0F, 0x02, 0x08}, + {0x18, 0x02, 0x08}, + {0x1F, 0x02, 0x08}, + {0x29, 0x02, 0x08}, + {0x38, 0x03, 0x08}, + {0x03, 0x02, 0x0B}, + {0x06, 0x02, 0x0B}, + {0x0A, 0x02, 0x0B}, + {0x0F, 0x02, 0x0B}, + {0x18, 0x02, 0x0B}, + {0x1F, 0x02, 0x0B}, + {0x29, 0x02, 0x0B}, + {0x38, 0x03, 0x0B}, }, /* 234 */ { - {0x03, 2, 12}, - {0x06, 2, 12}, - {0x0A, 2, 12}, - {0x0F, 2, 12}, - {0x18, 2, 12}, - {0x1F, 2, 12}, - {0x29, 2, 12}, - {0x38, 3, 12}, - {0x03, 2, 14}, - {0x06, 2, 14}, - {0x0A, 2, 14}, - {0x0F, 2, 14}, - {0x18, 2, 14}, - {0x1F, 2, 14}, - {0x29, 2, 14}, - {0x38, 3, 14}, + {0x03, 0x02, 0x0C}, + {0x06, 0x02, 0x0C}, + {0x0A, 0x02, 0x0C}, + {0x0F, 0x02, 0x0C}, + {0x18, 0x02, 0x0C}, + {0x1F, 0x02, 0x0C}, + {0x29, 0x02, 0x0C}, + {0x38, 0x03, 0x0C}, + {0x03, 0x02, 0x0E}, + {0x06, 0x02, 0x0E}, + {0x0A, 0x02, 0x0E}, + {0x0F, 0x02, 0x0E}, + {0x18, 0x02, 0x0E}, + {0x1F, 0x02, 0x0E}, + {0x29, 0x02, 0x0E}, + {0x38, 0x03, 0x0E}, }, /* 235 */ { - {0x02, 2, 15}, - {0x09, 2, 15}, - {0x17, 2, 15}, - {0x28, 3, 15}, - {0x02, 2, 16}, - {0x09, 2, 16}, - {0x17, 2, 16}, - {0x28, 3, 16}, - {0x02, 2, 17}, - {0x09, 2, 17}, - {0x17, 2, 17}, - {0x28, 3, 17}, - {0x02, 2, 18}, - {0x09, 2, 18}, - {0x17, 2, 18}, - {0x28, 3, 18}, + {0x02, 0x02, 0x0F}, + {0x09, 0x02, 0x0F}, + {0x17, 0x02, 0x0F}, + {0x28, 0x03, 0x0F}, + {0x02, 0x02, 0x10}, + {0x09, 0x02, 0x10}, + {0x17, 0x02, 0x10}, + {0x28, 0x03, 0x10}, + {0x02, 0x02, 0x11}, + {0x09, 0x02, 0x11}, + {0x17, 0x02, 0x11}, + {0x28, 0x03, 0x11}, + {0x02, 0x02, 0x12}, + {0x09, 0x02, 0x12}, + {0x17, 0x02, 0x12}, + {0x28, 0x03, 0x12}, }, /* 236 */ { - {0x03, 2, 15}, - {0x06, 2, 15}, - {0x0A, 2, 15}, - {0x0F, 2, 15}, - {0x18, 2, 15}, - {0x1F, 2, 15}, - {0x29, 2, 15}, - {0x38, 3, 15}, - {0x03, 2, 16}, - {0x06, 2, 16}, - {0x0A, 2, 16}, - {0x0F, 2, 16}, - {0x18, 2, 16}, - {0x1F, 2, 16}, - {0x29, 2, 16}, - {0x38, 3, 16}, + {0x03, 0x02, 0x0F}, + {0x06, 0x02, 0x0F}, + {0x0A, 0x02, 0x0F}, + {0x0F, 0x02, 0x0F}, + {0x18, 0x02, 0x0F}, + {0x1F, 0x02, 0x0F}, + {0x29, 0x02, 0x0F}, + {0x38, 0x03, 0x0F}, + {0x03, 0x02, 0x10}, + {0x06, 0x02, 0x10}, + {0x0A, 0x02, 0x10}, + {0x0F, 0x02, 0x10}, + {0x18, 0x02, 0x10}, + {0x1F, 0x02, 0x10}, + {0x29, 0x02, 0x10}, + {0x38, 0x03, 0x10}, }, /* 237 */ { - {0x03, 2, 17}, - {0x06, 2, 17}, - {0x0A, 2, 17}, - {0x0F, 2, 17}, - {0x18, 2, 17}, - {0x1F, 2, 17}, - {0x29, 2, 17}, - {0x38, 3, 17}, - {0x03, 2, 18}, - {0x06, 2, 18}, - {0x0A, 2, 18}, - {0x0F, 2, 18}, - {0x18, 2, 18}, - {0x1F, 2, 18}, - {0x29, 2, 18}, - {0x38, 3, 18}, + {0x03, 0x02, 0x11}, + {0x06, 0x02, 0x11}, + {0x0A, 0x02, 0x11}, + {0x0F, 0x02, 0x11}, + {0x18, 0x02, 0x11}, + {0x1F, 0x02, 0x11}, + {0x29, 0x02, 0x11}, + {0x38, 0x03, 0x11}, + {0x03, 0x02, 0x12}, + {0x06, 0x02, 0x12}, + {0x0A, 0x02, 0x12}, + {0x0F, 0x02, 0x12}, + {0x18, 0x02, 0x12}, + {0x1F, 0x02, 0x12}, + {0x29, 0x02, 0x12}, + {0x38, 0x03, 0x12}, }, /* 238 */ { - {0x00, 3, 19}, - {0x00, 3, 20}, - {0x00, 3, 21}, - {0x00, 3, 23}, - {0x00, 3, 24}, - {0x00, 3, 25}, - {0x00, 3, 26}, - {0x00, 3, 27}, - {0x00, 3, 28}, - {0x00, 3, 29}, - {0x00, 3, 30}, - {0x00, 3, 31}, - {0x00, 3, 127}, - {0x00, 3, 220}, - {0x00, 3, 249}, - {0xFD, 0, 0}, + {0x00, 0x03, 0x13}, + {0x00, 0x03, 0x14}, + {0x00, 0x03, 0x15}, + {0x00, 0x03, 0x17}, + {0x00, 0x03, 0x18}, + {0x00, 0x03, 0x19}, + {0x00, 0x03, 0x1A}, + {0x00, 0x03, 0x1B}, + {0x00, 0x03, 0x1C}, + {0x00, 0x03, 0x1D}, + {0x00, 0x03, 0x1E}, + {0x00, 0x03, 0x1F}, + {0x00, 0x03, 0x7F}, + {0x00, 0x03, 0xDC}, + {0x00, 0x03, 0xF9}, + {0xFD, 0x00, 0x00}, }, /* 239 */ { - {0x01, 2, 19}, - {0x16, 3, 19}, - {0x01, 2, 20}, - {0x16, 3, 20}, - {0x01, 2, 21}, - {0x16, 3, 21}, - {0x01, 2, 23}, - {0x16, 3, 23}, - {0x01, 2, 24}, - {0x16, 3, 24}, - {0x01, 2, 25}, - {0x16, 3, 25}, - {0x01, 2, 26}, - {0x16, 3, 26}, - {0x01, 2, 27}, - {0x16, 3, 27}, + {0x01, 0x02, 0x13}, + {0x16, 0x03, 0x13}, + {0x01, 0x02, 0x14}, + {0x16, 0x03, 0x14}, + {0x01, 0x02, 0x15}, + {0x16, 0x03, 0x15}, + {0x01, 0x02, 0x17}, + {0x16, 0x03, 0x17}, + {0x01, 0x02, 0x18}, + {0x16, 0x03, 0x18}, + {0x01, 0x02, 0x19}, + {0x16, 0x03, 0x19}, + {0x01, 0x02, 0x1A}, + {0x16, 0x03, 0x1A}, + {0x01, 0x02, 0x1B}, + {0x16, 0x03, 0x1B}, }, /* 240 */ { - {0x02, 2, 19}, - {0x09, 2, 19}, - {0x17, 2, 19}, - {0x28, 3, 19}, - {0x02, 2, 20}, - {0x09, 2, 20}, - {0x17, 2, 20}, - {0x28, 3, 20}, - {0x02, 2, 21}, - {0x09, 2, 21}, - {0x17, 2, 21}, - {0x28, 3, 21}, - {0x02, 2, 23}, - {0x09, 2, 23}, - {0x17, 2, 23}, - {0x28, 3, 23}, + {0x02, 0x02, 0x13}, + {0x09, 0x02, 0x13}, + {0x17, 0x02, 0x13}, + {0x28, 0x03, 0x13}, + {0x02, 0x02, 0x14}, + {0x09, 0x02, 0x14}, + {0x17, 0x02, 0x14}, + {0x28, 0x03, 0x14}, + {0x02, 0x02, 0x15}, + {0x09, 0x02, 0x15}, + {0x17, 0x02, 0x15}, + {0x28, 0x03, 0x15}, + {0x02, 0x02, 0x17}, + {0x09, 0x02, 0x17}, + {0x17, 0x02, 0x17}, + {0x28, 0x03, 0x17}, }, /* 241 */ { - {0x03, 2, 19}, - {0x06, 2, 19}, - {0x0A, 2, 19}, - {0x0F, 2, 19}, - {0x18, 2, 19}, - {0x1F, 2, 19}, - {0x29, 2, 19}, - {0x38, 3, 19}, - {0x03, 2, 20}, - {0x06, 2, 20}, - {0x0A, 2, 20}, - {0x0F, 2, 20}, - {0x18, 2, 20}, - {0x1F, 2, 20}, - {0x29, 2, 20}, - {0x38, 3, 20}, + {0x03, 0x02, 0x13}, + {0x06, 0x02, 0x13}, + {0x0A, 0x02, 0x13}, + {0x0F, 0x02, 0x13}, + {0x18, 0x02, 0x13}, + {0x1F, 0x02, 0x13}, + {0x29, 0x02, 0x13}, + {0x38, 0x03, 0x13}, + {0x03, 0x02, 0x14}, + {0x06, 0x02, 0x14}, + {0x0A, 0x02, 0x14}, + {0x0F, 0x02, 0x14}, + {0x18, 0x02, 0x14}, + {0x1F, 0x02, 0x14}, + {0x29, 0x02, 0x14}, + {0x38, 0x03, 0x14}, }, /* 242 */ { - {0x03, 2, 21}, - {0x06, 2, 21}, - {0x0A, 2, 21}, - {0x0F, 2, 21}, - {0x18, 2, 21}, - {0x1F, 2, 21}, - {0x29, 2, 21}, - {0x38, 3, 21}, - {0x03, 2, 23}, - {0x06, 2, 23}, - {0x0A, 2, 23}, - {0x0F, 2, 23}, - {0x18, 2, 23}, - {0x1F, 2, 23}, - {0x29, 2, 23}, - {0x38, 3, 23}, + {0x03, 0x02, 0x15}, + {0x06, 0x02, 0x15}, + {0x0A, 0x02, 0x15}, + {0x0F, 0x02, 0x15}, + {0x18, 0x02, 0x15}, + {0x1F, 0x02, 0x15}, + {0x29, 0x02, 0x15}, + {0x38, 0x03, 0x15}, + {0x03, 0x02, 0x17}, + {0x06, 0x02, 0x17}, + {0x0A, 0x02, 0x17}, + {0x0F, 0x02, 0x17}, + {0x18, 0x02, 0x17}, + {0x1F, 0x02, 0x17}, + {0x29, 0x02, 0x17}, + {0x38, 0x03, 0x17}, }, /* 243 */ { - {0x02, 2, 24}, - {0x09, 2, 24}, - {0x17, 2, 24}, - {0x28, 3, 24}, - {0x02, 2, 25}, - {0x09, 2, 25}, - {0x17, 2, 25}, - {0x28, 3, 25}, - {0x02, 2, 26}, - {0x09, 2, 26}, - {0x17, 2, 26}, - {0x28, 3, 26}, - {0x02, 2, 27}, - {0x09, 2, 27}, - {0x17, 2, 27}, - {0x28, 3, 27}, + {0x02, 0x02, 0x18}, + {0x09, 0x02, 0x18}, + {0x17, 0x02, 0x18}, + {0x28, 0x03, 0x18}, + {0x02, 0x02, 0x19}, + {0x09, 0x02, 0x19}, + {0x17, 0x02, 0x19}, + {0x28, 0x03, 0x19}, + {0x02, 0x02, 0x1A}, + {0x09, 0x02, 0x1A}, + {0x17, 0x02, 0x1A}, + {0x28, 0x03, 0x1A}, + {0x02, 0x02, 0x1B}, + {0x09, 0x02, 0x1B}, + {0x17, 0x02, 0x1B}, + {0x28, 0x03, 0x1B}, }, /* 244 */ { - {0x03, 2, 24}, - {0x06, 2, 24}, - {0x0A, 2, 24}, - {0x0F, 2, 24}, - {0x18, 2, 24}, - {0x1F, 2, 24}, - {0x29, 2, 24}, - {0x38, 3, 24}, - {0x03, 2, 25}, - {0x06, 2, 25}, - {0x0A, 2, 25}, - {0x0F, 2, 25}, - {0x18, 2, 25}, - {0x1F, 2, 25}, - {0x29, 2, 25}, - {0x38, 3, 25}, + {0x03, 0x02, 0x18}, + {0x06, 0x02, 0x18}, + {0x0A, 0x02, 0x18}, + {0x0F, 0x02, 0x18}, + {0x18, 0x02, 0x18}, + {0x1F, 0x02, 0x18}, + {0x29, 0x02, 0x18}, + {0x38, 0x03, 0x18}, + {0x03, 0x02, 0x19}, + {0x06, 0x02, 0x19}, + {0x0A, 0x02, 0x19}, + {0x0F, 0x02, 0x19}, + {0x18, 0x02, 0x19}, + {0x1F, 0x02, 0x19}, + {0x29, 0x02, 0x19}, + {0x38, 0x03, 0x19}, }, /* 245 */ { - {0x03, 2, 26}, - {0x06, 2, 26}, - {0x0A, 2, 26}, - {0x0F, 2, 26}, - {0x18, 2, 26}, - {0x1F, 2, 26}, - {0x29, 2, 26}, - {0x38, 3, 26}, - {0x03, 2, 27}, - {0x06, 2, 27}, - {0x0A, 2, 27}, - {0x0F, 2, 27}, - {0x18, 2, 27}, - {0x1F, 2, 27}, - {0x29, 2, 27}, - {0x38, 3, 27}, + {0x03, 0x02, 0x1A}, + {0x06, 0x02, 0x1A}, + {0x0A, 0x02, 0x1A}, + {0x0F, 0x02, 0x1A}, + {0x18, 0x02, 0x1A}, + {0x1F, 0x02, 0x1A}, + {0x29, 0x02, 0x1A}, + {0x38, 0x03, 0x1A}, + {0x03, 0x02, 0x1B}, + {0x06, 0x02, 0x1B}, + {0x0A, 0x02, 0x1B}, + {0x0F, 0x02, 0x1B}, + {0x18, 0x02, 0x1B}, + {0x1F, 0x02, 0x1B}, + {0x29, 0x02, 0x1B}, + {0x38, 0x03, 0x1B}, }, /* 246 */ { - {0x01, 2, 28}, - {0x16, 3, 28}, - {0x01, 2, 29}, - {0x16, 3, 29}, - {0x01, 2, 30}, - {0x16, 3, 30}, - {0x01, 2, 31}, - {0x16, 3, 31}, - {0x01, 2, 127}, - {0x16, 3, 127}, - {0x01, 2, 220}, - {0x16, 3, 220}, - {0x01, 2, 249}, - {0x16, 3, 249}, - {0xFE, 0, 0}, - {0xFF, 0, 0}, + {0x01, 0x02, 0x1C}, + {0x16, 0x03, 0x1C}, + {0x01, 0x02, 0x1D}, + {0x16, 0x03, 0x1D}, + {0x01, 0x02, 0x1E}, + {0x16, 0x03, 0x1E}, + {0x01, 0x02, 0x1F}, + {0x16, 0x03, 0x1F}, + {0x01, 0x02, 0x7F}, + {0x16, 0x03, 0x7F}, + {0x01, 0x02, 0xDC}, + {0x16, 0x03, 0xDC}, + {0x01, 0x02, 0xF9}, + {0x16, 0x03, 0xF9}, + {0xFE, 0x00, 0x00}, + {0xFF, 0x00, 0x00}, }, /* 247 */ { - {0x02, 2, 28}, - {0x09, 2, 28}, - {0x17, 2, 28}, - {0x28, 3, 28}, - {0x02, 2, 29}, - {0x09, 2, 29}, - {0x17, 2, 29}, - {0x28, 3, 29}, - {0x02, 2, 30}, - {0x09, 2, 30}, - {0x17, 2, 30}, - {0x28, 3, 30}, - {0x02, 2, 31}, - {0x09, 2, 31}, - {0x17, 2, 31}, - {0x28, 3, 31}, + {0x02, 0x02, 0x1C}, + {0x09, 0x02, 0x1C}, + {0x17, 0x02, 0x1C}, + {0x28, 0x03, 0x1C}, + {0x02, 0x02, 0x1D}, + {0x09, 0x02, 0x1D}, + {0x17, 0x02, 0x1D}, + {0x28, 0x03, 0x1D}, + {0x02, 0x02, 0x1E}, + {0x09, 0x02, 0x1E}, + {0x17, 0x02, 0x1E}, + {0x28, 0x03, 0x1E}, + {0x02, 0x02, 0x1F}, + {0x09, 0x02, 0x1F}, + {0x17, 0x02, 0x1F}, + {0x28, 0x03, 0x1F}, }, /* 248 */ { - {0x03, 2, 28}, - {0x06, 2, 28}, - {0x0A, 2, 28}, - {0x0F, 2, 28}, - {0x18, 2, 28}, - {0x1F, 2, 28}, - {0x29, 2, 28}, - {0x38, 3, 28}, - {0x03, 2, 29}, - {0x06, 2, 29}, - {0x0A, 2, 29}, - {0x0F, 2, 29}, - {0x18, 2, 29}, - {0x1F, 2, 29}, - {0x29, 2, 29}, - {0x38, 3, 29}, + {0x03, 0x02, 0x1C}, + {0x06, 0x02, 0x1C}, + {0x0A, 0x02, 0x1C}, + {0x0F, 0x02, 0x1C}, + {0x18, 0x02, 0x1C}, + {0x1F, 0x02, 0x1C}, + {0x29, 0x02, 0x1C}, + {0x38, 0x03, 0x1C}, + {0x03, 0x02, 0x1D}, + {0x06, 0x02, 0x1D}, + {0x0A, 0x02, 0x1D}, + {0x0F, 0x02, 0x1D}, + {0x18, 0x02, 0x1D}, + {0x1F, 0x02, 0x1D}, + {0x29, 0x02, 0x1D}, + {0x38, 0x03, 0x1D}, }, /* 249 */ { - {0x03, 2, 30}, - {0x06, 2, 30}, - {0x0A, 2, 30}, - {0x0F, 2, 30}, - {0x18, 2, 30}, - {0x1F, 2, 30}, - {0x29, 2, 30}, - {0x38, 3, 30}, - {0x03, 2, 31}, - {0x06, 2, 31}, - {0x0A, 2, 31}, - {0x0F, 2, 31}, - {0x18, 2, 31}, - {0x1F, 2, 31}, - {0x29, 2, 31}, - {0x38, 3, 31}, + {0x03, 0x02, 0x1E}, + {0x06, 0x02, 0x1E}, + {0x0A, 0x02, 0x1E}, + {0x0F, 0x02, 0x1E}, + {0x18, 0x02, 0x1E}, + {0x1F, 0x02, 0x1E}, + {0x29, 0x02, 0x1E}, + {0x38, 0x03, 0x1E}, + {0x03, 0x02, 0x1F}, + {0x06, 0x02, 0x1F}, + {0x0A, 0x02, 0x1F}, + {0x0F, 0x02, 0x1F}, + {0x18, 0x02, 0x1F}, + {0x1F, 0x02, 0x1F}, + {0x29, 0x02, 0x1F}, + {0x38, 0x03, 0x1F}, }, /* 250 */ { - {0x02, 2, 127}, - {0x09, 2, 127}, - {0x17, 2, 127}, - {0x28, 3, 127}, - {0x02, 2, 220}, - {0x09, 2, 220}, - {0x17, 2, 220}, - {0x28, 3, 220}, - {0x02, 2, 249}, - {0x09, 2, 249}, - {0x17, 2, 249}, - {0x28, 3, 249}, - {0x00, 3, 10}, - {0x00, 3, 13}, - {0x00, 3, 22}, - {0x100, 0, 0}, + {0x02, 0x02, 0x7F}, + {0x09, 0x02, 0x7F}, + {0x17, 0x02, 0x7F}, + {0x28, 0x03, 0x7F}, + {0x02, 0x02, 0xDC}, + {0x09, 0x02, 0xDC}, + {0x17, 0x02, 0xDC}, + {0x28, 0x03, 0xDC}, + {0x02, 0x02, 0xF9}, + {0x09, 0x02, 0xF9}, + {0x17, 0x02, 0xF9}, + {0x28, 0x03, 0xF9}, + {0x00, 0x03, 0x0A}, + {0x00, 0x03, 0x0D}, + {0x00, 0x03, 0x16}, + {0x100, 0x00, 0x00}, }, /* 251 */ { - {0x03, 2, 127}, - {0x06, 2, 127}, - {0x0A, 2, 127}, - {0x0F, 2, 127}, - {0x18, 2, 127}, - {0x1F, 2, 127}, - {0x29, 2, 127}, - {0x38, 3, 127}, - {0x03, 2, 220}, - {0x06, 2, 220}, - {0x0A, 2, 220}, - {0x0F, 2, 220}, - {0x18, 2, 220}, - {0x1F, 2, 220}, - {0x29, 2, 220}, - {0x38, 3, 220}, + {0x03, 0x02, 0x7F}, + {0x06, 0x02, 0x7F}, + {0x0A, 0x02, 0x7F}, + {0x0F, 0x02, 0x7F}, + {0x18, 0x02, 0x7F}, + {0x1F, 0x02, 0x7F}, + {0x29, 0x02, 0x7F}, + {0x38, 0x03, 0x7F}, + {0x03, 0x02, 0xDC}, + {0x06, 0x02, 0xDC}, + {0x0A, 0x02, 0xDC}, + {0x0F, 0x02, 0xDC}, + {0x18, 0x02, 0xDC}, + {0x1F, 0x02, 0xDC}, + {0x29, 0x02, 0xDC}, + {0x38, 0x03, 0xDC}, }, /* 252 */ { - {0x03, 2, 249}, - {0x06, 2, 249}, - {0x0A, 2, 249}, - {0x0F, 2, 249}, - {0x18, 2, 249}, - {0x1F, 2, 249}, - {0x29, 2, 249}, - {0x38, 3, 249}, - {0x01, 2, 10}, - {0x16, 3, 10}, - {0x01, 2, 13}, - {0x16, 3, 13}, - {0x01, 2, 22}, - {0x16, 3, 22}, - {0x100, 0, 0}, - {0x100, 0, 0}, + {0x03, 0x02, 0xF9}, + {0x06, 0x02, 0xF9}, + {0x0A, 0x02, 0xF9}, + {0x0F, 0x02, 0xF9}, + {0x18, 0x02, 0xF9}, + {0x1F, 0x02, 0xF9}, + {0x29, 0x02, 0xF9}, + {0x38, 0x03, 0xF9}, + {0x01, 0x02, 0x0A}, + {0x16, 0x03, 0x0A}, + {0x01, 0x02, 0x0D}, + {0x16, 0x03, 0x0D}, + {0x01, 0x02, 0x16}, + {0x16, 0x03, 0x16}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, }, /* 253 */ { - {0x02, 2, 10}, - {0x09, 2, 10}, - {0x17, 2, 10}, - {0x28, 3, 10}, - {0x02, 2, 13}, - {0x09, 2, 13}, - {0x17, 2, 13}, - {0x28, 3, 13}, - {0x02, 2, 22}, - {0x09, 2, 22}, - {0x17, 2, 22}, - {0x28, 3, 22}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, + {0x02, 0x02, 0x0A}, + {0x09, 0x02, 0x0A}, + {0x17, 0x02, 0x0A}, + {0x28, 0x03, 0x0A}, + {0x02, 0x02, 0x0D}, + {0x09, 0x02, 0x0D}, + {0x17, 0x02, 0x0D}, + {0x28, 0x03, 0x0D}, + {0x02, 0x02, 0x16}, + {0x09, 0x02, 0x16}, + {0x17, 0x02, 0x16}, + {0x28, 0x03, 0x16}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, }, /* 254 */ { - {0x03, 2, 10}, - {0x06, 2, 10}, - {0x0A, 2, 10}, - {0x0F, 2, 10}, - {0x18, 2, 10}, - {0x1F, 2, 10}, - {0x29, 2, 10}, - {0x38, 3, 10}, - {0x03, 2, 13}, - {0x06, 2, 13}, - {0x0A, 2, 13}, - {0x0F, 2, 13}, - {0x18, 2, 13}, - {0x1F, 2, 13}, - {0x29, 2, 13}, - {0x38, 3, 13}, + {0x03, 0x02, 0x0A}, + {0x06, 0x02, 0x0A}, + {0x0A, 0x02, 0x0A}, + {0x0F, 0x02, 0x0A}, + {0x18, 0x02, 0x0A}, + {0x1F, 0x02, 0x0A}, + {0x29, 0x02, 0x0A}, + {0x38, 0x03, 0x0A}, + {0x03, 0x02, 0x0D}, + {0x06, 0x02, 0x0D}, + {0x0A, 0x02, 0x0D}, + {0x0F, 0x02, 0x0D}, + {0x18, 0x02, 0x0D}, + {0x1F, 0x02, 0x0D}, + {0x29, 0x02, 0x0D}, + {0x38, 0x03, 0x0D}, }, /* 255 */ { - {0x03, 2, 22}, - {0x06, 2, 22}, - {0x0A, 2, 22}, - {0x0F, 2, 22}, - {0x18, 2, 22}, - {0x1F, 2, 22}, - {0x29, 2, 22}, - {0x38, 3, 22}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, + {0x03, 0x02, 0x16}, + {0x06, 0x02, 0x16}, + {0x0A, 0x02, 0x16}, + {0x0F, 0x02, 0x16}, + {0x18, 0x02, 0x16}, + {0x1F, 0x02, 0x16}, + {0x29, 0x02, 0x16}, + {0x38, 0x03, 0x16}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, }, /* 256 */ { - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, - {0x100, 0, 0}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, + {0x100, 0x00, 0x00}, }, }; diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_str.c b/deps/ngtcp2/nghttp3/lib/nghttp3_str.c index 4fcda6658f8b55..7564125cfdb3e8 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_str.c +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_str.c @@ -35,76 +35,76 @@ uint8_t *nghttp3_cpymem(uint8_t *dest, const uint8_t *src, size_t n) { } /* Generated by gendowncasetbl.py */ -static const uint8_t DOWNCASE_TBL[] = { - 0 /* NUL */, 1 /* SOH */, 2 /* STX */, 3 /* ETX */, - 4 /* EOT */, 5 /* ENQ */, 6 /* ACK */, 7 /* BEL */, - 8 /* BS */, 9 /* HT */, 10 /* LF */, 11 /* VT */, - 12 /* FF */, 13 /* CR */, 14 /* SO */, 15 /* SI */, - 16 /* DLE */, 17 /* DC1 */, 18 /* DC2 */, 19 /* DC3 */, - 20 /* DC4 */, 21 /* NAK */, 22 /* SYN */, 23 /* ETB */, - 24 /* CAN */, 25 /* EM */, 26 /* SUB */, 27 /* ESC */, - 28 /* FS */, 29 /* GS */, 30 /* RS */, 31 /* US */, - 32 /* SPC */, 33 /* ! */, 34 /* " */, 35 /* # */, - 36 /* $ */, 37 /* % */, 38 /* & */, 39 /* ' */, - 40 /* ( */, 41 /* ) */, 42 /* * */, 43 /* + */, - 44 /* , */, 45 /* - */, 46 /* . */, 47 /* / */, - 48 /* 0 */, 49 /* 1 */, 50 /* 2 */, 51 /* 3 */, - 52 /* 4 */, 53 /* 5 */, 54 /* 6 */, 55 /* 7 */, - 56 /* 8 */, 57 /* 9 */, 58 /* : */, 59 /* ; */, - 60 /* < */, 61 /* = */, 62 /* > */, 63 /* ? */, - 64 /* @ */, 97 /* A */, 98 /* B */, 99 /* C */, - 100 /* D */, 101 /* E */, 102 /* F */, 103 /* G */, - 104 /* H */, 105 /* I */, 106 /* J */, 107 /* K */, - 108 /* L */, 109 /* M */, 110 /* N */, 111 /* O */, - 112 /* P */, 113 /* Q */, 114 /* R */, 115 /* S */, - 116 /* T */, 117 /* U */, 118 /* V */, 119 /* W */, - 120 /* X */, 121 /* Y */, 122 /* Z */, 91 /* [ */, - 92 /* \ */, 93 /* ] */, 94 /* ^ */, 95 /* _ */, - 96 /* ` */, 97 /* a */, 98 /* b */, 99 /* c */, - 100 /* d */, 101 /* e */, 102 /* f */, 103 /* g */, - 104 /* h */, 105 /* i */, 106 /* j */, 107 /* k */, - 108 /* l */, 109 /* m */, 110 /* n */, 111 /* o */, - 112 /* p */, 113 /* q */, 114 /* r */, 115 /* s */, - 116 /* t */, 117 /* u */, 118 /* v */, 119 /* w */, - 120 /* x */, 121 /* y */, 122 /* z */, 123 /* { */, - 124 /* | */, 125 /* } */, 126 /* ~ */, 127 /* DEL */, - 128 /* 0x80 */, 129 /* 0x81 */, 130 /* 0x82 */, 131 /* 0x83 */, - 132 /* 0x84 */, 133 /* 0x85 */, 134 /* 0x86 */, 135 /* 0x87 */, - 136 /* 0x88 */, 137 /* 0x89 */, 138 /* 0x8A */, 139 /* 0x8B */, - 140 /* 0x8C */, 141 /* 0x8D */, 142 /* 0x8E */, 143 /* 0x8F */, - 144 /* 0x90 */, 145 /* 0x91 */, 146 /* 0x92 */, 147 /* 0x93 */, - 148 /* 0x94 */, 149 /* 0x95 */, 150 /* 0x96 */, 151 /* 0x97 */, - 152 /* 0x98 */, 153 /* 0x99 */, 154 /* 0x9A */, 155 /* 0x9B */, - 156 /* 0x9C */, 157 /* 0x9D */, 158 /* 0x9E */, 159 /* 0x9F */, - 160 /* 0xA0 */, 161 /* 0xA1 */, 162 /* 0xA2 */, 163 /* 0xA3 */, - 164 /* 0xA4 */, 165 /* 0xA5 */, 166 /* 0xA6 */, 167 /* 0xA7 */, - 168 /* 0xA8 */, 169 /* 0xA9 */, 170 /* 0xAA */, 171 /* 0xAB */, - 172 /* 0xAC */, 173 /* 0xAD */, 174 /* 0xAE */, 175 /* 0xAF */, - 176 /* 0xB0 */, 177 /* 0xB1 */, 178 /* 0xB2 */, 179 /* 0xB3 */, - 180 /* 0xB4 */, 181 /* 0xB5 */, 182 /* 0xB6 */, 183 /* 0xB7 */, - 184 /* 0xB8 */, 185 /* 0xB9 */, 186 /* 0xBA */, 187 /* 0xBB */, - 188 /* 0xBC */, 189 /* 0xBD */, 190 /* 0xBE */, 191 /* 0xBF */, - 192 /* 0xC0 */, 193 /* 0xC1 */, 194 /* 0xC2 */, 195 /* 0xC3 */, - 196 /* 0xC4 */, 197 /* 0xC5 */, 198 /* 0xC6 */, 199 /* 0xC7 */, - 200 /* 0xC8 */, 201 /* 0xC9 */, 202 /* 0xCA */, 203 /* 0xCB */, - 204 /* 0xCC */, 205 /* 0xCD */, 206 /* 0xCE */, 207 /* 0xCF */, - 208 /* 0xD0 */, 209 /* 0xD1 */, 210 /* 0xD2 */, 211 /* 0xD3 */, - 212 /* 0xD4 */, 213 /* 0xD5 */, 214 /* 0xD6 */, 215 /* 0xD7 */, - 216 /* 0xD8 */, 217 /* 0xD9 */, 218 /* 0xDA */, 219 /* 0xDB */, - 220 /* 0xDC */, 221 /* 0xDD */, 222 /* 0xDE */, 223 /* 0xDF */, - 224 /* 0xE0 */, 225 /* 0xE1 */, 226 /* 0xE2 */, 227 /* 0xE3 */, - 228 /* 0xE4 */, 229 /* 0xE5 */, 230 /* 0xE6 */, 231 /* 0xE7 */, - 232 /* 0xE8 */, 233 /* 0xE9 */, 234 /* 0xEA */, 235 /* 0xEB */, - 236 /* 0xEC */, 237 /* 0xED */, 238 /* 0xEE */, 239 /* 0xEF */, - 240 /* 0xF0 */, 241 /* 0xF1 */, 242 /* 0xF2 */, 243 /* 0xF3 */, - 244 /* 0xF4 */, 245 /* 0xF5 */, 246 /* 0xF6 */, 247 /* 0xF7 */, - 248 /* 0xF8 */, 249 /* 0xF9 */, 250 /* 0xFA */, 251 /* 0xFB */, - 252 /* 0xFC */, 253 /* 0xFD */, 254 /* 0xFE */, 255 /* 0xFF */, +const uint8_t nghttp3_downcase_tbl[] = { + 0x00 /* NUL */, 0x01 /* SOH */, 0x02 /* STX */, 0x03 /* ETX */, + 0x04 /* EOT */, 0x05 /* ENQ */, 0x06 /* ACK */, 0x07 /* BEL */, + 0x08 /* BS */, 0x09 /* HT */, 0x0A /* LF */, 0x0B /* VT */, + 0x0C /* FF */, 0x0D /* CR */, 0x0E /* SO */, 0x0F /* SI */, + 0x10 /* DLE */, 0x11 /* DC1 */, 0x12 /* DC2 */, 0x13 /* DC3 */, + 0x14 /* DC4 */, 0x15 /* NAK */, 0x16 /* SYN */, 0x17 /* ETB */, + 0x18 /* CAN */, 0x19 /* EM */, 0x1A /* SUB */, 0x1B /* ESC */, + 0x1C /* FS */, 0x1D /* GS */, 0x1E /* RS */, 0x1F /* US */, + 0x20 /* SPC */, 0x21 /* ! */, 0x22 /* " */, 0x23 /* # */, + 0x24 /* $ */, 0x25 /* % */, 0x26 /* & */, 0x27 /* ' */, + 0x28 /* ( */, 0x29 /* ) */, 0x2A /* * */, 0x2B /* + */, + 0x2C /* , */, 0x2D /* - */, 0x2E /* . */, 0x2F /* / */, + 0x30 /* 0 */, 0x31 /* 1 */, 0x32 /* 2 */, 0x33 /* 3 */, + 0x34 /* 4 */, 0x35 /* 5 */, 0x36 /* 6 */, 0x37 /* 7 */, + 0x38 /* 8 */, 0x39 /* 9 */, 0x3A /* : */, 0x3B /* ; */, + 0x3C /* < */, 0x3D /* = */, 0x3E /* > */, 0x3F /* ? */, + 0x40 /* @ */, 0x61 /* A */, 0x62 /* B */, 0x63 /* C */, + 0x64 /* D */, 0x65 /* E */, 0x66 /* F */, 0x67 /* G */, + 0x68 /* H */, 0x69 /* I */, 0x6A /* J */, 0x6B /* K */, + 0x6C /* L */, 0x6D /* M */, 0x6E /* N */, 0x6F /* O */, + 0x70 /* P */, 0x71 /* Q */, 0x72 /* R */, 0x73 /* S */, + 0x74 /* T */, 0x75 /* U */, 0x76 /* V */, 0x77 /* W */, + 0x78 /* X */, 0x79 /* Y */, 0x7A /* Z */, 0x5B /* [ */, + 0x5C /* \ */, 0x5D /* ] */, 0x5E /* ^ */, 0x5F /* _ */, + 0x60 /* ` */, 0x61 /* a */, 0x62 /* b */, 0x63 /* c */, + 0x64 /* d */, 0x65 /* e */, 0x66 /* f */, 0x67 /* g */, + 0x68 /* h */, 0x69 /* i */, 0x6A /* j */, 0x6B /* k */, + 0x6C /* l */, 0x6D /* m */, 0x6E /* n */, 0x6F /* o */, + 0x70 /* p */, 0x71 /* q */, 0x72 /* r */, 0x73 /* s */, + 0x74 /* t */, 0x75 /* u */, 0x76 /* v */, 0x77 /* w */, + 0x78 /* x */, 0x79 /* y */, 0x7A /* z */, 0x7B /* { */, + 0x7C /* | */, 0x7D /* } */, 0x7E /* ~ */, 0x7F /* DEL */, + 0x80 /* 0x80 */, 0x81 /* 0x81 */, 0x82 /* 0x82 */, 0x83 /* 0x83 */, + 0x84 /* 0x84 */, 0x85 /* 0x85 */, 0x86 /* 0x86 */, 0x87 /* 0x87 */, + 0x88 /* 0x88 */, 0x89 /* 0x89 */, 0x8A /* 0x8A */, 0x8B /* 0x8B */, + 0x8C /* 0x8C */, 0x8D /* 0x8D */, 0x8E /* 0x8E */, 0x8F /* 0x8F */, + 0x90 /* 0x90 */, 0x91 /* 0x91 */, 0x92 /* 0x92 */, 0x93 /* 0x93 */, + 0x94 /* 0x94 */, 0x95 /* 0x95 */, 0x96 /* 0x96 */, 0x97 /* 0x97 */, + 0x98 /* 0x98 */, 0x99 /* 0x99 */, 0x9A /* 0x9A */, 0x9B /* 0x9B */, + 0x9C /* 0x9C */, 0x9D /* 0x9D */, 0x9E /* 0x9E */, 0x9F /* 0x9F */, + 0xA0 /* 0xA0 */, 0xA1 /* 0xA1 */, 0xA2 /* 0xA2 */, 0xA3 /* 0xA3 */, + 0xA4 /* 0xA4 */, 0xA5 /* 0xA5 */, 0xA6 /* 0xA6 */, 0xA7 /* 0xA7 */, + 0xA8 /* 0xA8 */, 0xA9 /* 0xA9 */, 0xAA /* 0xAA */, 0xAB /* 0xAB */, + 0xAC /* 0xAC */, 0xAD /* 0xAD */, 0xAE /* 0xAE */, 0xAF /* 0xAF */, + 0xB0 /* 0xB0 */, 0xB1 /* 0xB1 */, 0xB2 /* 0xB2 */, 0xB3 /* 0xB3 */, + 0xB4 /* 0xB4 */, 0xB5 /* 0xB5 */, 0xB6 /* 0xB6 */, 0xB7 /* 0xB7 */, + 0xB8 /* 0xB8 */, 0xB9 /* 0xB9 */, 0xBA /* 0xBA */, 0xBB /* 0xBB */, + 0xBC /* 0xBC */, 0xBD /* 0xBD */, 0xBE /* 0xBE */, 0xBF /* 0xBF */, + 0xC0 /* 0xC0 */, 0xC1 /* 0xC1 */, 0xC2 /* 0xC2 */, 0xC3 /* 0xC3 */, + 0xC4 /* 0xC4 */, 0xC5 /* 0xC5 */, 0xC6 /* 0xC6 */, 0xC7 /* 0xC7 */, + 0xC8 /* 0xC8 */, 0xC9 /* 0xC9 */, 0xCA /* 0xCA */, 0xCB /* 0xCB */, + 0xCC /* 0xCC */, 0xCD /* 0xCD */, 0xCE /* 0xCE */, 0xCF /* 0xCF */, + 0xD0 /* 0xD0 */, 0xD1 /* 0xD1 */, 0xD2 /* 0xD2 */, 0xD3 /* 0xD3 */, + 0xD4 /* 0xD4 */, 0xD5 /* 0xD5 */, 0xD6 /* 0xD6 */, 0xD7 /* 0xD7 */, + 0xD8 /* 0xD8 */, 0xD9 /* 0xD9 */, 0xDA /* 0xDA */, 0xDB /* 0xDB */, + 0xDC /* 0xDC */, 0xDD /* 0xDD */, 0xDE /* 0xDE */, 0xDF /* 0xDF */, + 0xE0 /* 0xE0 */, 0xE1 /* 0xE1 */, 0xE2 /* 0xE2 */, 0xE3 /* 0xE3 */, + 0xE4 /* 0xE4 */, 0xE5 /* 0xE5 */, 0xE6 /* 0xE6 */, 0xE7 /* 0xE7 */, + 0xE8 /* 0xE8 */, 0xE9 /* 0xE9 */, 0xEA /* 0xEA */, 0xEB /* 0xEB */, + 0xEC /* 0xEC */, 0xED /* 0xED */, 0xEE /* 0xEE */, 0xEF /* 0xEF */, + 0xF0 /* 0xF0 */, 0xF1 /* 0xF1 */, 0xF2 /* 0xF2 */, 0xF3 /* 0xF3 */, + 0xF4 /* 0xF4 */, 0xF5 /* 0xF5 */, 0xF6 /* 0xF6 */, 0xF7 /* 0xF7 */, + 0xF8 /* 0xF8 */, 0xF9 /* 0xF9 */, 0xFA /* 0xFA */, 0xFB /* 0xFB */, + 0xFC /* 0xFC */, 0xFD /* 0xFD */, 0xFE /* 0xFE */, 0xFF /* 0xFF */, }; void nghttp3_downcase(uint8_t *s, size_t len) { size_t i; for (i = 0; i < len; ++i) { - s[i] = DOWNCASE_TBL[s[i]]; + s[i] = nghttp3_downcase_byte(s[i]); } } diff --git a/deps/ngtcp2/nghttp3/lib/nghttp3_str.h b/deps/ngtcp2/nghttp3/lib/nghttp3_str.h index 280749a3a9a3d9..ee0562f26a3b0d 100644 --- a/deps/ngtcp2/nghttp3/lib/nghttp3_str.h +++ b/deps/ngtcp2/nghttp3/lib/nghttp3_str.h @@ -37,4 +37,14 @@ uint8_t *nghttp3_cpymem(uint8_t *dest, const uint8_t *src, size_t n); void nghttp3_downcase(uint8_t *s, size_t len); +extern const uint8_t nghttp3_downcase_tbl[]; + +/* + * nghttp3_downcase_byte returns the lower case version of |c| if 'A' + * <= |c| && |c| <= 'Z'. Otherwise, it returns |c|. + */ +static inline uint8_t nghttp3_downcase_byte(uint8_t c) { + return nghttp3_downcase_tbl[c]; +} + #endif /* !defined(NGHTTP3_STR_H) */ diff --git a/deps/ngtcp2/nghttp3/lib/sfparse/sfparse.c b/deps/ngtcp2/nghttp3/lib/sfparse/sfparse.c index cbcf813e23a094..c312c04f4a8f0a 100644 --- a/deps/ngtcp2/nghttp3/lib/sfparse/sfparse.c +++ b/deps/ngtcp2/nghttp3/lib/sfparse/sfparse.c @@ -34,18 +34,18 @@ # include #endif /* __AVX2__ */ -#define SFPARSE_STATE_DICT 0x08u -#define SFPARSE_STATE_LIST 0x10u -#define SFPARSE_STATE_ITEM 0x18u +#define SFPARSE_STATE_DICT 0x08U +#define SFPARSE_STATE_LIST 0x10U +#define SFPARSE_STATE_ITEM 0x18U -#define SFPARSE_STATE_INNER_LIST 0x04u +#define SFPARSE_STATE_INNER_LIST 0x04U -#define SFPARSE_STATE_BEFORE 0x00u -#define SFPARSE_STATE_BEFORE_PARAMS 0x01u -#define SFPARSE_STATE_PARAMS 0x02u -#define SFPARSE_STATE_AFTER 0x03u +#define SFPARSE_STATE_BEFORE 0x00U +#define SFPARSE_STATE_BEFORE_PARAMS 0x01U +#define SFPARSE_STATE_PARAMS 0x02U +#define SFPARSE_STATE_AFTER 0x03U -#define SFPARSE_STATE_OP_MASK 0x03u +#define SFPARSE_STATE_OP_MASK 0x03U #define SFPARSE_SET_STATE_AFTER(NAME) \ (SFPARSE_STATE_##NAME | SFPARSE_STATE_AFTER) @@ -69,7 +69,7 @@ #define SFPARSE_STATE_ITEM_INNER_LIST_BEFORE \ SFPARSE_SET_STATE_INNER_LIST_BEFORE(ITEM) -#define SFPARSE_STATE_INITIAL 0x00u +#define SFPARSE_STATE_INITIAL 0x00U #define LCALPHAS \ ['a'] = 1, ['b'] = 1, ['c'] = 1, ['d'] = 1, ['e'] = 1, ['f'] = 1, ['g'] = 1, \ @@ -200,7 +200,7 @@ static int parser_key(sfparse_parser *sfp, sfparse_vec *dest) { #ifdef __AVX2__ if (sfp->end - sfp->pos >= 32) { - last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu); + last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1FU); sfp->pos = find_char_key(sfp->pos, last); if (sfp->pos != last) { @@ -349,7 +349,7 @@ static const uint8_t *find_char_string(const uint8_t *first, const uint8_t *last) { const __m256i bs = _mm256_set1_epi8('\\'); const __m256i dq = _mm256_set1_epi8('"'); - const __m256i del = _mm256_set1_epi8(0x7f); + const __m256i del = _mm256_set1_epi8(0x7F); const __m256i sp = _mm256_set1_epi8(' '); __m256i s, x; uint32_t m; @@ -394,7 +394,7 @@ static int parser_string(sfparse_parser *sfp, sfparse_value *dest) { #ifdef __AVX2__ for (; sfp->end - sfp->pos >= 32; ++sfp->pos) { - last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu); + last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1FU); sfp->pos = find_char_string(sfp->pos, last); if (sfp->pos == last) { @@ -541,7 +541,7 @@ static int parser_token(sfparse_parser *sfp, sfparse_value *dest) { #ifdef __AVX2__ if (sfp->end - sfp->pos >= 32) { - last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu); + last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1FU); sfp->pos = find_char_token(sfp->pos, last); if (sfp->pos != last) { @@ -622,7 +622,7 @@ static int parser_byteseq(sfparse_parser *sfp, sfparse_value *dest) { #ifdef __AVX2__ if (sfp->end - sfp->pos >= 32) { - last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1fu); + last = sfp->pos + ((sfp->end - sfp->pos) & ~0x1FU); sfp->pos = find_char_byteseq(sfp->pos, last); } #endif /* __AVX2__ */ @@ -1429,8 +1429,8 @@ void sfparse_base64decode(sfparse_vec *dest, const sfparse_vec *src) { } *o++ = (uint8_t)(n >> 16); - *o++ = (n >> 8) & 0xffu; - *o++ = n & 0xffu; + *o++ = (n >> 8) & 0xFFU; + *o++ = n & 0xFFU; } switch (left) { @@ -1467,8 +1467,8 @@ void sfparse_base64decode(sfparse_vec *dest, const sfparse_vec *src) { n = (uint32_t)(index_tbl[*p++] << 10); n += (uint32_t)(index_tbl[*p++] << 4); n += (uint32_t)(index_tbl[*p++] >> 2); - *o++ = (n >> 8) & 0xffu; - *o++ = n & 0xffu; + *o++ = (n >> 8) & 0xFFU; + *o++ = n & 0xFFU; break; } diff --git a/deps/ngtcp2/nghttp3/lib/sfparse/sfparse.h b/deps/ngtcp2/nghttp3/lib/sfparse/sfparse.h index 9341221a099438..7f36ce8a08c56b 100644 --- a/deps/ngtcp2/nghttp3/lib/sfparse/sfparse.h +++ b/deps/ngtcp2/nghttp3/lib/sfparse/sfparse.h @@ -130,7 +130,7 @@ typedef struct sfparse_vec { * * :macro:`SFPARSE_VALUE_FLAG_NONE` indicates no flag set. */ -#define SFPARSE_VALUE_FLAG_NONE 0x0u +#define SFPARSE_VALUE_FLAG_NONE 0x0U /** * @macro @@ -138,7 +138,7 @@ typedef struct sfparse_vec { * :macro:`SFPARSE_VALUE_FLAG_ESCAPED_STRING` indicates that a string * contains escaped character(s). */ -#define SFPARSE_VALUE_FLAG_ESCAPED_STRING 0x1u +#define SFPARSE_VALUE_FLAG_ESCAPED_STRING 0x1U /** * @struct From f162234f248078b2fe8c0c3fce7f0c78b51f1743 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Mon, 29 Jun 2026 23:25:00 -0700 Subject: [PATCH 062/131] stream: normalize Broadcast.from() byte inputs Route non-Broadcastable inputs through from(). This makes strings and ArrayBuffer views byte inputs instead of generic iterables. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.5 PR-URL: https://github.com/nodejs/node/pull/64082 Fixes: https://github.com/nodejs/node/issues/64081 Reviewed-By: James M Snell --- lib/internal/streams/iter/broadcast.js | 13 ++++++---- .../test-stream-iter-broadcast-from.js | 25 +++++++++++++++++++ test/parallel/test-stream-iter-validation.js | 3 +-- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/lib/internal/streams/iter/broadcast.js b/lib/internal/streams/iter/broadcast.js index b667857c478885..3592453036d303 100644 --- a/lib/internal/streams/iter/broadcast.js +++ b/lib/internal/streams/iter/broadcast.js @@ -44,6 +44,7 @@ const { } = require('internal/streams/iter/types'); const { + from, isAsyncIterable, isSyncIterable, } = require('internal/streams/iter/from'); @@ -799,7 +800,9 @@ const Broadcast = { return { __proto__: null, writer: { __proto__: null }, broadcast: bc }; } - if (!isAsyncIterable(input) && !isSyncIterable(input)) { + const source = from(input); + + if (!isAsyncIterable(source) && !isSyncIterable(source)) { throw new ERR_INVALID_ARG_TYPE( 'input', ['Broadcastable', 'AsyncIterable', 'Iterable'], input); } @@ -810,8 +813,8 @@ const Broadcast = { const pump = async () => { const w = result.writer; try { - if (isAsyncIterable(input)) { - for await (const chunks of input) { + if (isAsyncIterable(source)) { + for await (const chunks of source) { signal?.throwIfAborted(); if (ArrayIsArray(chunks)) { if (!w.writevSync(chunks)) { @@ -821,8 +824,8 @@ const Broadcast = { await w.write(chunks, signal ? { signal } : undefined); } } - } else if (isSyncIterable(input)) { - for (const chunks of input) { + } else if (isSyncIterable(source)) { + for (const chunks of source) { signal?.throwIfAborted(); if (ArrayIsArray(chunks)) { if (!w.writevSync(chunks)) { diff --git a/test/parallel/test-stream-iter-broadcast-from.js b/test/parallel/test-stream-iter-broadcast-from.js index 0203252f26229a..39d92c2aef49b3 100644 --- a/test/parallel/test-stream-iter-broadcast-from.js +++ b/test/parallel/test-stream-iter-broadcast-from.js @@ -43,6 +43,28 @@ async function testBroadcastFromStringChunks() { assert.strictEqual(data, 'foobar'); } +async function testBroadcastFromStringInput() { + const { broadcast: bc } = Broadcast.from('abc'); + const consumer = bc.push(); + const data = await text(consumer); + assert.strictEqual(data, 'abc'); +} + +async function testBroadcastFromUint8ArrayInput() { + const { broadcast: bc } = Broadcast.from(new Uint8Array([97])); + const consumer = bc.push(); + const data = await text(consumer); + assert.strictEqual(data, 'a'); +} + +async function testBroadcastFromDataViewInput() { + const view = new DataView(new Uint8Array([104, 105]).buffer); + const { broadcast: bc } = Broadcast.from(view); + const consumer = bc.push(); + const data = await text(consumer); + assert.strictEqual(data, 'hi'); +} + async function testBroadcastFromMultipleConsumers() { const source = from('shared-data'); const { broadcast: bc } = Broadcast.from(source); @@ -180,6 +202,9 @@ Promise.all([ testBroadcastFromAsyncIterable(), testBroadcastFromNonArrayChunks(), testBroadcastFromStringChunks(), + testBroadcastFromStringInput(), + testBroadcastFromUint8ArrayInput(), + testBroadcastFromDataViewInput(), testBroadcastFromMultipleConsumers(), testAbortSignal(), testAlreadyAbortedSignal(), diff --git a/test/parallel/test-stream-iter-validation.js b/test/parallel/test-stream-iter-validation.js index 19cde169d6f496..ecefaeb171ec41 100644 --- a/test/parallel/test-stream-iter-validation.js +++ b/test/parallel/test-stream-iter-validation.js @@ -157,9 +157,8 @@ assert.throws(() => broadcast({ backpressure: 'bad' }), { code: 'ERR_INVALID_ARG writer.endSync(); } -// Broadcast.from rejects non-iterable input +// Broadcast.from rejects non-streamable input assert.throws(() => Broadcast.from(42), { code: 'ERR_INVALID_ARG_TYPE' }); -assert.throws(() => Broadcast.from('bad'), { code: 'ERR_INVALID_ARG_TYPE' }); // ============================================================================= // share() / shareSync() validation From 9395d209c7c5e6b3008e2d12cf727b77b5099e69 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Tue, 30 Jun 2026 12:08:40 +0200 Subject: [PATCH 063/131] vfs: avoid recursive readdir symlink cycles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Track the active MemoryProvider recursive readdir traversal path so circular symlinks to directories stop recursing while still listing the symlink entries. Add sync, promise, and withFileTypes coverage. Fixes: https://github.com/nodejs/node/issues/64148 Signed-off-by: Matteo Collina PR-URL: https://github.com/nodejs/node/pull/64168 Reviewed-By: James M Snell Reviewed-By: Paolo Insogna Reviewed-By: Gürgün Dayıoğlu --- lib/internal/vfs/providers/memory.js | 72 +++++++++++-------- .../test-vfs-readdir-symlink-recursive.js | 55 +++++++++++++- 2 files changed, 96 insertions(+), 31 deletions(-) diff --git a/lib/internal/vfs/providers/memory.js b/lib/internal/vfs/providers/memory.js index 5fc18ccdd2b517..995b8f236200d5 100644 --- a/lib/internal/vfs/providers/memory.js +++ b/lib/internal/vfs/providers/memory.js @@ -5,6 +5,7 @@ const { ArrayPrototypePush, DateNow, SafeMap, + SafeSet, StringPrototypeReplaceAll, Symbol, } = primordials; @@ -611,44 +612,55 @@ class MemoryProvider extends VirtualProvider { */ #readdirRecursive(dirEntry, dirPath, withFileTypes) { const results = []; + const active = new SafeSet(); const walk = (entry, currentPath, relativePath) => { - this.#ensurePopulated(entry, currentPath); - - for (const { 0: name, 1: childEntry } of entry.children) { - const childRelative = relativePath ? - relativePath + '/' + name : name; + if (active.has(entry)) { + return; + } - if (withFileTypes) { - let type; - if (childEntry.isSymbolicLink()) { - type = UV_DIRENT_LINK; - } else if (childEntry.isDirectory()) { - type = UV_DIRENT_DIR; + active.add(entry); + try { + this.#ensurePopulated(entry, currentPath); + + for (const { 0: name, 1: childEntry } of entry.children) { + const childRelative = relativePath ? + relativePath + '/' + name : name; + + if (withFileTypes) { + let type; + if (childEntry.isSymbolicLink()) { + type = UV_DIRENT_LINK; + } else if (childEntry.isDirectory()) { + type = UV_DIRENT_DIR; + } else { + type = UV_DIRENT_FILE; + } + ArrayPrototypePush(results, + new Dirent(childRelative, type, dirPath)); } else { - type = UV_DIRENT_FILE; + ArrayPrototypePush(results, childRelative); } - ArrayPrototypePush(results, - new Dirent(childRelative, type, dirPath)); - } else { - ArrayPrototypePush(results, childRelative); - } - // Follow symlinks to directories for recursive traversal - let resolvedChild = childEntry; - if (childEntry.isSymbolicLink()) { - const targetPath = this.#resolveSymlinkTarget( - pathPosix.join(currentPath, name), childEntry.target, - ); - const result = this.#lookupEntry(targetPath, true, 0); - if (result.entry) { - resolvedChild = result.entry; + // Follow symlinks to directories for recursive traversal. + // Track the active traversal path to avoid symlink cycles. + let resolvedChild = childEntry; + if (childEntry.isSymbolicLink()) { + const targetPath = this.#resolveSymlinkTarget( + pathPosix.join(currentPath, name), childEntry.target, + ); + const result = this.#lookupEntry(targetPath, true, 0); + if (result.entry) { + resolvedChild = result.entry; + } + } + if (resolvedChild.isDirectory()) { + const childPath = pathPosix.join(currentPath, name); + walk(resolvedChild, childPath, childRelative); } } - if (resolvedChild.isDirectory()) { - const childPath = pathPosix.join(currentPath, name); - walk(resolvedChild, childPath, childRelative); - } + } finally { + active.delete(entry); } }; diff --git a/test/parallel/test-vfs-readdir-symlink-recursive.js b/test/parallel/test-vfs-readdir-symlink-recursive.js index 1f9661947c7444..33b52bb5d4a416 100644 --- a/test/parallel/test-vfs-readdir-symlink-recursive.js +++ b/test/parallel/test-vfs-readdir-symlink-recursive.js @@ -3,7 +3,7 @@ // Recursive readdir must follow symlinks to directories. -require('../common'); +const common = require('../common'); const assert = require('assert'); const vfs = require('node:vfs'); @@ -21,6 +21,59 @@ assert.ok( `Expected 'symdir/nested.txt' in entries: ${entries}`, ); +// Recursive readdir avoids following symlink cycles indefinitely. +{ + const v = vfs.create(); + v.mkdirSync('/dir'); + v.writeFileSync('/dir/nested.txt', 'nested'); + v.symlinkSync('/dir', '/dir/loop'); + + assert.deepStrictEqual(v.readdirSync('/', { recursive: true }).sort(), [ + 'dir', + 'dir/loop', + 'dir/nested.txt', + ]); + + const dirents = v.readdirSync('/', { recursive: true, withFileTypes: true }); + assert.strictEqual(dirents.length, 3); + assert.ok(dirents.some((dirent) => + dirent.name === 'loop' && + dirent.parentPath === '/dir' && + dirent.isSymbolicLink())); +} + +// Recursive readdir avoids cycles through multiple symlinks. +{ + const v = vfs.create(); + v.mkdirSync('/a'); + v.mkdirSync('/b'); + v.symlinkSync('/b', '/a/link_to_b'); + v.symlinkSync('/a', '/b/link_to_a'); + + assert.deepStrictEqual(v.readdirSync('/', { recursive: true }).sort(), [ + 'a', + 'a/link_to_b', + 'a/link_to_b/link_to_a', + 'b', + 'b/link_to_a', + 'b/link_to_a/link_to_b', + ]); +} + +(async () => { + const v = vfs.create(); + v.mkdirSync('/dir'); + v.writeFileSync('/dir/nested.txt', 'nested'); + v.symlinkSync('/dir', '/dir/loop'); + + const entries = await v.promises.readdir('/', { recursive: true }); + assert.deepStrictEqual(entries.sort(), [ + 'dir', + 'dir/loop', + 'dir/nested.txt', + ]); +})().then(common.mustCall()); + // Recursive readdir with withFileTypes:true returns Dirent objects whose // parentPath reflects the actual location of the entry (not the entry's // stringified relative path). From b7bf6e3a06624e08ea59dcc483cc0849cbfb1c67 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Tue, 30 Jun 2026 15:07:26 +0200 Subject: [PATCH 064/131] doc: add guide and answers to FAQs for first-time contributors Signed-off-by: Joyee Cheung PR-URL: https://github.com/nodejs/node/pull/63685 Reviewed-By: Trivikram Kamat Reviewed-By: Moshe Atlow Reviewed-By: Filip Skokan --- .github/PULL_REQUEST_TEMPLATE.md | 4 + CONTRIBUTING.md | 5 + doc/contributing/first-contributions.md | 235 ++++++++++++++++++++++++ 3 files changed, 244 insertions(+) create mode 100644 doc/contributing/first-contributions.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 936c2a06125795..3950bc702eb58b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,4 +1,8 @@ -The default curve name to use for ECDH key agreement in a tls server. The -default value is `'auto'`. See [`tls.createSecureContext()`][] for further -information. +The default named curve or TLS group list to use for key agreement in a TLS +server. The default value is `'auto'`. See [`tls.createSecureContext()`][] for +further information. ## `tls.DEFAULT_MAX_VERSION` @@ -2485,6 +2497,7 @@ added: v0.11.3 [Chrome's 'modern cryptography' setting]: https://www.chromium.org/Home/chromium-security/education/tls#TOC-Cipher-Suites [DHE]: https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange [ECDHE]: https://en.wikipedia.org/wiki/Elliptic_curve_Diffie%E2%80%93Hellman +[IANA TLS Supported Groups registry]: https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8 [Modifying the default TLS cipher suite]: #modifying-the-default-tls-cipher-suite [Mozilla's publicly trusted list of CAs]: https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins/certdata.txt [OCSP request]: https://en.wikipedia.org/wiki/OCSP_stapling diff --git a/src/crypto/crypto_common.cc b/src/crypto/crypto_common.cc index 4f117f160a9673..0db5d0eaac8fc3 100644 --- a/src/crypto/crypto_common.cc +++ b/src/crypto/crypto_common.cc @@ -215,13 +215,15 @@ MaybeLocal GetEphemeralKey(Environment* env, const SSLPointer& ssl) { Undefined(env->isolate()), // name Undefined(env->isolate()), // size }; - EVPKeyPointer key = ssl.getPeerTempKey(); + + bool found = false; if (EVPKeyPointer key = ssl.getPeerTempKey()) { int kid = key.id(); switch (kid) { case EVP_PKEY_DH: { values[0] = env->dh_string(); values[2] = Integer::New(env->isolate(), key.bits()); + found = true; break; } case EVP_PKEY_EC: @@ -237,10 +239,17 @@ MaybeLocal GetEphemeralKey(Environment* env, const SSLPointer& ssl) { values[0] = env->ecdh_string(); values[1] = OneByteString(env->isolate(), curve_name); values[2] = Integer::New(env->isolate(), key.bits()); + found = true; break; } } } + if (!found) { + if (auto name = ssl.getNegotiatedGroup()) { + values[0] = env->tls_group_string(); + values[1] = OneByteString(env->isolate(), name.value()); + } + } return scope.EscapeMaybe(NewDictionaryInstance(env->context(), tmpl, values)); } diff --git a/src/env_properties.h b/src/env_properties.h index c0ccfe417b03a7..26fab56b2649d2 100644 --- a/src/env_properties.h +++ b/src/env_properties.h @@ -363,6 +363,7 @@ V(target_string, "target") \ V(thread_id_string, "threadId") \ V(thread_name_string, "threadName") \ + V(tls_group_string, "TLSGroup") \ V(ticketkeycallback_string, "onticketkeycallback") \ V(timeout_string, "timeout") \ V(time_to_first_byte_string, "timeToFirstByte") \ diff --git a/test/parallel/test-tls-client-getephemeralkeyinfo.js b/test/parallel/test-tls-client-getephemeralkeyinfo.js index 2107d024012c4d..ea6dec7bdc4629 100644 --- a/test/parallel/test-tls-client-getephemeralkeyinfo.js +++ b/test/parallel/test-tls-client-getephemeralkeyinfo.js @@ -18,9 +18,6 @@ const tls = require('tls'); const key = fixtures.readKey('agent2-key.pem'); const cert = fixtures.readKey('agent2-cert.pem'); -// TODO(@sam-github) test works with TLS1.3, rework test to add -// 'ECDH' with 'TLS_AES_128_GCM_SHA256', - function loadDHParam(n) { return fixtures.readKey(`dh${n}.pem`); } @@ -89,3 +86,57 @@ test(256, 'ECDH', 'prime256v1', 'ECDHE-RSA-AES256-GCM-SHA384'); test(521, 'ECDH', 'secp521r1', 'ECDHE-RSA-AES256-GCM-SHA384'); test(253, 'ECDH', 'X25519', 'ECDHE-RSA-AES256-GCM-SHA384'); test(448, 'ECDH', 'X448', 'ECDHE-RSA-AES256-GCM-SHA384'); + +function testTLS13Group(size, type, name) { + const options = { + key, + cert, + ecdhCurve: name, + minVersion: 'TLSv1.3', + maxVersion: 'TLSv1.3', + }; + + const server = tls.createServer(options, common.mustCall((conn) => { + assert.strictEqual(conn.getEphemeralKeyInfo(), null); + conn.end(); + })); + + server.on('close', common.mustSucceed()); + + server.listen(0, common.mustCall(() => { + const client = tls.connect({ + port: server.address().port, + rejectUnauthorized: false, + ecdhCurve: name, + minVersion: 'TLSv1.3', + maxVersion: 'TLSv1.3', + }, common.mustCall(() => { + const ekeyinfo = client.getEphemeralKeyInfo(); + assert.strictEqual(ekeyinfo.type, type); + assert.strictEqual(ekeyinfo.size, size); + assert.strictEqual(ekeyinfo.name, name); + server.close(); + })); + client.on('secureConnect', common.mustCall()); + })); +} + +testTLS13Group(253, 'ECDH', 'X25519'); + +if (hasOpenSSL(3, 5)) { + const tls13Groups = [ + 'MLKEM512', + 'MLKEM768', + 'MLKEM1024', + 'SecP256r1MLKEM768', + 'X25519MLKEM768', + 'SecP384r1MLKEM1024', + ]; + + if (hasOpenSSL(4, 0)) { + tls13Groups.push('curveSM2'); + tls13Groups.push('curveSM2MLKEM768'); + } + + tls13Groups.forEach((name) => testTLS13Group(undefined, 'TLSGroup', name)); +} From 6e187db7d774e124368de878a5b5f3f53d72e9ef Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Wed, 1 Jul 2026 11:26:09 +0200 Subject: [PATCH 068/131] tools: update c-ares updater script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Antoine du Hamel PR-URL: https://github.com/nodejs/node/pull/64194 Reviewed-By: Richard Lau Reviewed-By: Joyee Cheung Reviewed-By: Luigi Pinca Reviewed-By: René --- tools/dep_updaters/c-ares.kbx | Bin 0 -> 4217 bytes tools/dep_updaters/update-c-ares.sh | 33 ++++++++++++++-------------- 2 files changed, 17 insertions(+), 16 deletions(-) create mode 100644 tools/dep_updaters/c-ares.kbx diff --git a/tools/dep_updaters/c-ares.kbx b/tools/dep_updaters/c-ares.kbx new file mode 100644 index 0000000000000000000000000000000000000000..720f1df36917d7ccb3c568ccc1ce3599967682f2 GIT binary patch literal 4217 zcmb7`2T)Vpw#QFGfY7B11TcV7q$5oT9WNsFqXtQ6LZ~8yE>%FJNfo3?Zz4siN>iF3 zRS+VfDT4Ig5ri9f&wJn8`R2WOYi94W_S)r~+55Nu>i_@%2Y~>vrV0`R5X@0UwDG*0 z`~PLc-eAy$7YG25p8yzO<6T?c7LjdQ(VIx8Lw$n&e#1f6Mi>D*f&ie=k0w@X9JAwy4ZxU96Ts;4yB78y9c_aKa*&=(2puj0}bPoEU zrTx{oWm0;SoR(>RSKD@aX9)-T!J9t)9X$CD1MQYV=Dx$5U%xEnF6(ax3jXDp`tpSC zm8WVnFPlyD$hP#^y7YX`kV>cIoE@@4-qn8iPSX3k4+rf-<|8I{l2ppNU1#ph58q4X z4#hRa!UN2=H&5r<`B{%?KmJ}-@=n62<6X3d1(Aw^rS_3z;-%<7NR1V7R8wxQVyxNc za9Qj#@)_t3AYW2coe7KC_oDWK(BcL zz|PeU1Ula!n7xOGtE`BKn2e;bm^h)x$Owx|$%={HkQS?jt68}?*gC@vJZxR8ZLxN6 zgv~`j$==GxN7&s~;WgnP2up!4mI5L{(hzzOIlxH_KHqOJjEI8U0D&(D1LS0v{v5i@OVTsF>YS3NW1BfTMkQ7h{O>n`^zKtv6iaTkvoh>@^&C=eEC5Hqr6US4J68MG+g|<;-|(AHEe3-c7}l@1FOb+^_y7$@h4n)-+QW zw4m_>KV3fR0ocKz?Al$ZyTdjLE?DE(oWtcg6?8N>!}V?IRhtlca#G1!Esu(%_~?i! zUI2e(K|K}ud4x#yI&WcTXPwbup#ak5K;{ud`b3LU*!x#)TL^HaVT1G7C)%|%j=v<6 zEo^ot-#>`^yQaBnPf4OXI2J)={PF_TNYE7sGl3|wKSWXfPjZ&;k)9ctgcsjWe79BO zrM6}U_Osc_6xAo$h%$1o&!EgKO*M&h&AKk6Ap)VIu0Ar#>@4!(uc`8}RW^_z zIgK#8eteZNC%(dQ>{>Euw$b|O&WlrnS6P}=ku`iaR;Sz|GHvu^Or+D5 zKxD6pHqCw)>SQet)@d$6C8cl3kkVw1uLyBDp;+3K@Fp(QYy9lKG9BJzU=WJx@e}EM z@6kLh^mty48$G<-^(bnGdOG<``l!cgFey`pjg>9ikrtYI#)!>jAm*=kG@$p9?Ad1! zc6#hO6r8yU`Dn@Go$vUXKO^o})vUn1HyKrL@-T~!NB4TRw}q?zkb`qBA3Ba@x+N@| z-PLK8$5sgw3IYJ~AO9`8Sp;7cAOhIN18nBH1+Aa;y5~`I%?`;K(!S{-Xe9hxC_Pu4 zbLJJ|JI(~d<64J|X{+b36ol}F?2el29Ny@ZOnXE<`vf;sNcTwSc$v_LJfBCf3rPm! z2_F2sNqE!WO7eNvzhoIq1;JQo@q#V^gYDiB(Hw=C$;+dH8I*(B0rrImZS&*u?J^4vXp3YmVp@}}!I>B4a ztj~6)6_`z^ul_JI6pUgY);XdKL+9@1-1O8LNo6@K@>fd6dQ)h>3<=Eby=-2&PsHD; zCyBcD31Rp4zKWOxU?%%h#q~HyTr0uaNgB#ZJvdQ2qG4m+9pIWLsJHWK$#KwYy|=JL z{Ma_g@5kdfRtn+CpCX@X%{q&TZU`E%gwe#3D>`bW2v@ljm2*qTa(oHWBH~LmyZ1f{ zw!+wFWEsbR_#k{}IYV0UtgKf+F7;RC8fJW5$9%RWMwI1f^_KfQ3)e1EmP%nB{dRl9 zW~;0SZmIg&Y^F$1%hs|P6Eoint zUhtdcceL-OYfnAu<()#u;>_gh9WkqPh3*X`n8e&C?PZ{-TKI@jxRwh zC6J<4wSLv|`%7%{<3(y0%ZZZNm}o(}ybuHkGme)jmE2YO%Fn!+C%a|Hq2c#1Js$Bh zDjIWe&vz|kgXD(vw@YeY#XLm{eAJ6O<=vi;JP&eWP|jc23&;bbrB2rps(H(wWS%Vp zUPZbOND63;mMvzht(tR!2U$@Qvn;Oz?^NU-aX;#n?-V~=aWKqjsmSQx3@%mAsAn4T zt_-M+TWN+kk#C|^Ti@gKbO$Rky_j_bS7#e$(2Za2*qM!J)tAuRO>Q%E9|iq z*1Q@5GcKpyIOTW9F?C@#S*IC}W>|4nfFxT?boqW&*O$*TgEU6jL%s?R=SHd<(Ay2A zAlY!cMHwj>y=JRB7(+wrl0?O{{BTfK7_Gk4LeH8MYP{dw04q^cYksILk*WD{uHya- ze#nYmCu|8V&-Tl#qVKewR1;4-aA+da#ma>{Y5!PnMazbK* z0`UI@IUQy&3=BN_H+5cc2n!QAz)qO+cT#@{PK2y>x7vNzjgUMJHGpP}Jm zH$u#mcCb-AKcStrw%tsU#;a5#T|Y6N!#@q!Qq};#!LHO za-IeVjIz{veOeD5%0U5UY)*)QnosX6BT#8vcO+sXEu%(EMT}Yq7aew z>uYngePa*>k$Ptq*N{82*}aa{Pcim>u1g!(v|PpVgvWurP{TbDp2IaE)iL!u5lAl(L`q&gNp8|P1)T{xzd9bU$*5hDrC}if|dR0LBTO@z|P^RI=UXGRP6r&)`C(-486 zq>*5$|C@LsFzn(F?~l&1-l92%Xs21+rkprasxvn{`Qp_uYRcPPjIYq*WIW53Pi^nF zzQtS1@YGWzBE}>~Olb^@4JIBGDzy;X(#s%?s+>Ze6_!y`pljk8@66S0Rzv#Q67w91q>Bc!WyRSAdG9%(Ecy6$By zE<@d#kNeh7@&}YpDvg5Y@23mOWI8KiJ&)oUbI#CmD$!Ect**7YTVK||>~sFAGGQcw z_N@9=uc4Wji=0co+`v*&8Ex0;^6?a?7cN27atdfdf0R(OK-)W|TxlvHZzDzeUo$~p z!jrP)cAhu)A*38hTofBagi3qBS#fSN6C{_yP7M`9aLL31x1bgVOY6EjiJDzxo_0)W zyIft name.endsWith('.tar.gz')); if(!browser_download_url || !name) throw new Error('No tarball found'); -console.log(`${tag_name} ${browser_download_url} ${name}`); +console.log(`${tag_name.replace(/^v/, '')} ${browser_download_url}`); EOF )" -IFS=' ' read -r NEW_VERSION NEW_VERSION_URL ARES_TARBALL < /dev/null || mktemp -d -t 'tmp') +ARES_TARBALL="$WORKSPACE/c-ares.tgz" cleanup () { EXIT_CODE=$? @@ -47,29 +48,29 @@ cleanup () { trap cleanup INT TERM EXIT -cd "$WORKSPACE" - echo "Fetching c-ares source archive" curl -sL -o "$ARES_TARBALL" "$NEW_VERSION_URL" -log_and_verify_sha256sum "c-ares" "$ARES_TARBALL" -gzip -dc "$ARES_TARBALL" | tar xf - -rm -- "$ARES_TARBALL" -FOLDER=$(ls -d -- */) +echo "Verifying PGP signature" +curl -sL -o "$ARES_TARBALL.asc" "$NEW_VERSION_URL.asc" +gpgv --keyring "$BASE_DIR/tools/dep_updaters/c-ares.kbx" "${ARES_TARBALL}.asc" "${ARES_TARBALL}" + +log_and_verify_sha256sum "c-ares" "$ARES_TARBALL" +tar -C "$WORKSPACE" -xzf "$ARES_TARBALL" -mv -- "$FOLDER" cares +ARES_FOLDER=$(find "$WORKSPACE" -mindepth 1 -maxdepth 1 -type d -print -quit) echo "Removing tests" -rm -rf "$WORKSPACE/cares/test" +rm -rf "$ARES_FOLDER/test" echo "Copying existing .gitignore, config, gyp and gn files" -cp -R "$DEPS_DIR/cares/config" "$WORKSPACE/cares" -cp "$DEPS_DIR/cares/.gitignore" "$WORKSPACE/cares" -cp "$DEPS_DIR/cares/cares.gyp" "$WORKSPACE/cares" -cp "$DEPS_DIR/cares/"*.gn "$DEPS_DIR/cares/"*.gni "$WORKSPACE/cares" +cp -R "$DEPS_DIR/cares/config" "$ARES_FOLDER" +cp "$DEPS_DIR/cares/.gitignore" "$ARES_FOLDER" +cp "$DEPS_DIR/cares/cares.gyp" "$ARES_FOLDER" +cp "$DEPS_DIR/cares/"*.gn "$DEPS_DIR/cares/"*.gni "$ARES_FOLDER" echo "Replacing existing c-ares" -replace_dir "$DEPS_DIR/cares" "$WORKSPACE/cares" +replace_dir "$DEPS_DIR/cares" "$ARES_FOLDER" echo "Updating cares.gyp" "$NODE" "$ROOT/tools/dep_updaters/update-c-ares.mjs" From 8e8874b216e9872ea2d64cab905931c21c22b453 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Wed, 1 Jul 2026 12:44:52 +0200 Subject: [PATCH 069/131] http: document and validate options.path when it's in absolute-form MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When `options.path` passed to `http.request()` contains an absolute URL, `http.request` has been sending it directly as the request target in the HTTP 1.1 message. If the receiving server is a proxy, the proxy server typically forwards the request to the destination specified in the request target and ignores the Host header. This means eventually the request can be forwarded to a destination that is not consistent with `options.host`, depending on how the receiving server behaves. Mimatched Host header and request target also violates RFC 9112 Section 3.2, which we have been entirely leaving to the users to verify. This patch documents this behavior and warns that the user needs to ensure the `path`, `option` and `headers` conform to the RFC. If the receiving server is known to be a proxy server because the request is routed by Node.js' built-in HTTP proxy support, we now do a best-effort check to verify that the authority in `options.path` (if absolute), Host headers and `options.host` agree at request construction time. Node.js will give up on the require target rewriting and throw an error when they don't match at request construction. Signed-off-by: Joyee Cheung PR-URL: https://github.com/nodejs/node/pull/64108 Reviewed-By: Matteo Collina Reviewed-By: Tim Perry Reviewed-By: Ulises Gascón --- doc/api/http.md | 14 ++ lib/_http_client.js | 196 +++++++++++++++--- ...-request-absolute-path-authority-match.mjs | 70 +++++++ ...p-proxy-request-authority-construction.mjs | 82 ++++++++ ...st-http-proxy-request-origin-form-path.mjs | 45 ++++ ...t-http-proxy-request-validation-errors.mjs | 119 +++++++++++ test/common/proxy-server.js | 8 +- 7 files changed, 500 insertions(+), 34 deletions(-) create mode 100644 test/client-proxy/test-http-proxy-request-absolute-path-authority-match.mjs create mode 100644 test/client-proxy/test-http-proxy-request-authority-construction.mjs create mode 100644 test/client-proxy/test-http-proxy-request-origin-form-path.mjs create mode 100644 test/client-proxy/test-http-proxy-request-validation-errors.mjs diff --git a/doc/api/http.md b/doc/api/http.md index 33231bb47c7b8c..71eb5af02c93e3 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -4076,6 +4076,18 @@ changes: E.G. `'/index.html?page=12'`. An exception is thrown when the request path contains illegal characters. Currently, only spaces are rejected but that may change in the future. **Default:** `'/'`. + The content in `path` is sent as the [request target][] in the HTTP 1.1 message. + When `path` is an absolute URL, this means the request target in the message in [absolute form][]. + If the receiving server is a proxy, the server typically forwards the request to the + destination specified in the request target, and ignores the `Host` header. + The user needs to make sure that `path`, `host` and the Host headers conform to the + requirement of the [request target][] in the HTTP specification. + When the receiving server is known to be a proxy because the request is routed through + [Built-in Proxy Support][], `http.request` will additionally perform a best-effort + check to see that the `host` option or `Host` in `headers` agrees with the authority + in `path` during the initial construction of the request. It gives up rewriting the + request target for proxying and throws an error if they don't match at request + construction time, though there won't be checks for later header mutations done by the user. * `port` {number} Port of remote server. **Default:** `defaultPort` if set, else `80`. * `protocol` {string} Protocol to use. **Default:** `'http:'`. @@ -4772,5 +4784,7 @@ const agent2 = new http.Agent({ proxyEnv: process.env }); [`writable.destroyed`]: stream.md#writabledestroyed [`writable.uncork()`]: stream.md#writableuncork [`writable.write()`]: stream.md#writablewritechunk-encoding-callback +[absolute form]: https://datatracker.ietf.org/doc/html/rfc9112#section-3.2.2 [information event]: #event-information [initial delay]: net.md#socketsetkeepaliveenable-initialdelay-interval-count +[request target]: https://datatracker.ietf.org/doc/html/rfc9112#section-3.2 diff --git a/lib/_http_client.js b/lib/_http_client.js index 73d7b84c17a8fd..e6bd38aa35ac9d 100644 --- a/lib/_http_client.js +++ b/lib/_http_client.js @@ -84,6 +84,7 @@ const { validateInteger, validateBoolean, validateOneOf, + validatePort, validateString, } = require('internal/validators'); const { getTimerDuration } = require('internal/timers'); @@ -139,15 +140,134 @@ class HTTPClientAsyncResource { } } +// The only documented shape is [k, v, k, v, ...]. Here we also accept [[k, v], [k, v], ...]. +// for backward compatibility, and reject others. Also reject if there are duplicate Host entries. +// Returns the Host header value, or undefined if absent. +function getHostFromHeaderArray(headers) { + let host; + const isPairs = headers.length > 0 && ArrayIsArray(headers[0]); + if (isPairs) { + for (let i = 0; i < headers.length; i++) { + const entry = headers[i]; + if (!ArrayIsArray(entry)) { + throw new ERR_INVALID_ARG_VALUE(`options.headers[${i}]`, typeof entry, + 'must be an array when headers is passed as an array of pairs'); + } + if (`${entry[0]}`.toLowerCase() === 'host') { + if (host !== undefined) { + throw new ERR_INVALID_ARG_VALUE('options.headers', '(redacted)', + 'must not contain duplicate Host headers'); + } + host = `${entry[1]}`; + } + } + } else { + for (let i = 0; i + 1 < headers.length; i += 2) { + if (`${headers[i]}`.toLowerCase() === 'host') { + if (host !== undefined) { + throw new ERR_INVALID_ARG_VALUE('options.headers', '(redacted)', + 'must not contain duplicate Host headers'); + } + host = `${headers[i + 1]}`; + } + } + } + return host; +} + +function authoritiesMatch(canonicalHost, hostFromHeader) { + let parsed; + try { + parsed = new URL(`http://${hostFromHeader}`); + } catch { + return false; + } + if (parsed.username || parsed.password || + parsed.pathname !== '/' || parsed.search || parsed.hash) { + return false; + } + return parsed.host === canonicalHost; +} + +// https://datatracker.ietf.org/doc/html/rfc9112#section-3.2 +// When the request target is in absolute-form, ensure it is consistent with +// the request authority: same scheme, no userinfo, and an authority +// component agree with options.host[:port]. +function validateRequestAuthority(pathOption, proxyAuthority, userHostHeader, headerArray) { + validatePort(proxyAuthority.port, 'options.port', true); + pathOption = `${pathOption}`; + const requestBase = new URL(`http://${proxyAuthority.host}`); + requestBase.port = proxyAuthority.port; + + const result = { requestBase }; + if (headerArray !== undefined) { + const host = getHostFromHeaderArray(headerArray); + // Since we don't mutate the header array to normalize the Host value, unlike + // in the case of other shapes of headers provided, we check that it is identical + // to the authority from the requestBase. + if (host !== undefined && host !== requestBase.host) { + throw new ERR_INVALID_ARG_VALUE( + 'Host in options.headers', host, + `must match the request authority (${requestBase.host})`); + } + } else if (userHostHeader !== undefined) { + if (!authoritiesMatch(requestBase.host, userHostHeader)) { + throw new ERR_INVALID_ARG_VALUE( + 'Host in options.headers', userHostHeader, + `must match the request authority (${requestBase.host})`); + } + } + + // Per RFC 9112 Section 3.2, if request target is in absolute-form its authority + // must agree with the request authority. + let requestURL; + let isAbsoluteForm = false; + try { + requestURL = new URL(pathOption); + isAbsoluteForm = true; + } catch { + if (pathOption.charCodeAt(0) !== 0x2F) { + throw new ERR_INVALID_ARG_VALUE( + 'options.path', pathOption, 'must be in absolute-form or start with /'); + } + requestURL = new URL(requestBase.origin + pathOption); + } + result.requestURL = requestURL; + if (!isAbsoluteForm) { + return result; + } + + if (requestURL.username || requestURL.password) { + requestURL.username = ''; + requestURL.password = ''; + throw new ERR_INVALID_ARG_VALUE( + 'options.path', requestURL.href, 'must not contain userinfo, use options.auth instead'); + } + + if (requestURL.protocol !== 'http:') { + throw new ERR_INVALID_ARG_VALUE( + 'options.path', requestURL.protocol, 'must use http: scheme when specified as an absolute URL'); + } + + if (requestBase.host !== requestURL.host) { + throw new ERR_INVALID_ARG_VALUE( + 'options.path', requestURL, `must match the request authority (${requestBase.host})`); + } + + return result; +} + // When proxying a HTTP request, the following needs to be done: -// https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.2 +// https://datatracker.ietf.org/doc/html/rfc9112#section-3.2.2 // 1. Rewrite the request path to absolute-form. // 2. Add proxy-connection and proxy-authorization headers appropriately. // // This function checks whether the request should be rewritten for proxying // and modifies the headers as well as req.path if necessary. // The handling of the proxy server connection is done in createConnection. -function rewriteForProxiedHttp(req, reqOptions) { +// It also validates that the Host header and absolute-form path authority match the +// request authority specified by reqOptions. +function rewriteForProxiedHttp(req, reqOptions, proxyAuthority, userHostHeader, headerArray) { if (req._header) { debug('request._header is already sent, skipping rewriteForProxiedHttp', reqOptions); return false; @@ -165,6 +285,25 @@ function rewriteForProxiedHttp(req, reqOptions) { if (!shouldUseProxy) { return false; } + + // Per RFC 9112 Section 3.2.2, we don't need to rewrite CONNECT or OPTIONS * requests. + let requestURL; + if (req.method !== 'CONNECT' && !(req.method === 'OPTIONS' && req.path === '*')) { + // Validate Host header values agree with the request authority before mutating req, + // so a rejected request doesn't leave proxy-* headers stuck on the outgoing header store. + // XXX(joyeecheung): This validates whether the request conforms to the RFC, but here + // we only do it for proxied requests for backward compatibility. For non-proxied requests, + // ensuring thst the request is well formed has been entirely left to the user. + const result = validateRequestAuthority(req.path, proxyAuthority, userHostHeader, headerArray); + if (headerArray === undefined) { + const currentHost = req.getHeader('host'); + if (currentHost !== undefined && currentHost !== result.requestBase.host) { + req.setHeader('Host', result.requestBase.host); + } + } + requestURL = result.requestURL; + } + // Add proxy headers. const { auth, href } = agent[kProxyConfig]; if (auth) { @@ -176,15 +315,10 @@ function rewriteForProxiedHttp(req, reqOptions) { req.setHeader('proxy-connection', 'close'); } - // Convert the path to absolute-form. - // https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.2 - const requestHost = req.getHeader('host') || 'localhost'; - const requestBase = `http://${requestHost}`; - const requestURL = new URL(req.path, requestBase); - if (reqOptions.port) { - requestURL.port = reqOptions.port; + if (requestURL !== undefined) { + // Convert the path to absolute-form. The authority is built from options. + req.path = requestURL.href; } - req.path = requestURL.href; debug(`updated request for HTTP proxy ${href} with ${req.path} `, req[kOutHeaders]); return true; }; @@ -360,6 +494,21 @@ function ClientRequest(input, options, cb) { } } + let hostHeaderFromOptions = host; + // For the Host header, ensure that IPv6 addresses are enclosed + // in square brackets, as defined by URI formatting + // https://tools.ietf.org/html/rfc3986#section-3.2.2 + const posColon = hostHeaderFromOptions.indexOf(':'); + if (posColon !== -1 && + hostHeaderFromOptions.includes(':', posColon + 1) && + hostHeaderFromOptions.charCodeAt(0) !== 91/* '[' */) { + hostHeaderFromOptions = `[${hostHeaderFromOptions}]`; + } + const proxyAuthority = { host: hostHeaderFromOptions, port }; + + if (port && +port !== defaultPort) { + hostHeaderFromOptions += ':' + port; + } const headersArray = ArrayIsArray(options.headers); if (!headersArray) { if (options.headers) { @@ -372,23 +521,12 @@ function ClientRequest(input, options, cb) { } } - if (host && !this.getHeader('host') && setHost) { - let hostHeader = host; - - // For the Host header, ensure that IPv6 addresses are enclosed - // in square brackets, as defined by URI formatting - // https://tools.ietf.org/html/rfc3986#section-3.2.2 - const posColon = hostHeader.indexOf(':'); - if (posColon !== -1 && - hostHeader.includes(':', posColon + 1) && - hostHeader.charCodeAt(0) !== 91/* '[' */) { - hostHeader = `[${hostHeader}]`; - } + // Save the Host header before the implicit auto-set below, so the + // proxy validator can tell user-explicit values from Node-generated ones. + const userHostHeader = this.getHeader('host'); - if (port && +port !== defaultPort) { - hostHeader += ':' + port; - } - this.setHeader('Host', hostHeader); + if (host && !this.getHeader('host') && setHost) { + this.setHeader('Host', hostHeaderFromOptions); } if (options.auth && !this.getHeader('Authorization')) { @@ -401,14 +539,14 @@ function ClientRequest(input, options, cb) { throw new ERR_HTTP_HEADERS_SENT('render'); } - rewriteForProxiedHttp(this, optsWithoutSignal); + rewriteForProxiedHttp(this, optsWithoutSignal, proxyAuthority, userHostHeader); this._storeHeader(this.method + ' ' + this.path + ' HTTP/1.1\r\n', this[kOutHeaders]); } else { - rewriteForProxiedHttp(this, optsWithoutSignal); + rewriteForProxiedHttp(this, optsWithoutSignal, proxyAuthority, userHostHeader); } } else { - rewriteForProxiedHttp(this, optsWithoutSignal); + rewriteForProxiedHttp(this, optsWithoutSignal, proxyAuthority, undefined, options.headers); this._storeHeader(this.method + ' ' + this.path + ' HTTP/1.1\r\n', options.headers); } diff --git a/test/client-proxy/test-http-proxy-request-absolute-path-authority-match.mjs b/test/client-proxy/test-http-proxy-request-absolute-path-authority-match.mjs new file mode 100644 index 00000000000000..d544f0d2c6286f --- /dev/null +++ b/test/client-proxy/test-http-proxy-request-absolute-path-authority-match.mjs @@ -0,0 +1,70 @@ +// This tests that proxied HTTP requests succeed end-to-end when the +// absolute-form request-target matches the request authority derived from options. + +import * as common from '../common/index.mjs'; +import assert from 'node:assert'; +import http from 'node:http'; +import { once } from 'events'; +import { createProxyServer } from '../common/proxy-server.js'; + +const server = http.createServer(common.mustCall((req, res) => { + res.end('Hello world'); +}, 6)); +server.on('error', common.mustNotCall()); +server.listen(0); +await once(server, 'listening'); + +const { proxy, logs } = createProxyServer(); +proxy.listen(0); +await once(proxy, 'listening'); + +const port = server.address().port; +const serverHost = `localhost:${port}`; +const requestUrl = `http://${serverHost}/test`; + +const agent = new http.Agent({ + proxyEnv: { + HTTP_PROXY: `http://localhost:${proxy.address().port}`, + }, +}); + +async function roundTrip(options) { + const req = http.request({ agent, ...options }); + req.end(); + const [res] = await once(req, 'response'); + res.setEncoding('utf8'); + let body = ''; + for await (const chunk of res) body += chunk; + assert.strictEqual(body, 'Hello world'); +} + +const baseAbsolute = { host: 'localhost', port, path: requestUrl }; + +const options = [ + // No user-supplied headers. + baseAbsolute, + // Object form with an explicit Host that matches. + { ...baseAbsolute, headers: { Host: serverHost } }, + // Flat array form. + { ...baseAbsolute, headers: ['Host', serverHost] }, + // Array-of-pairs form. + { ...baseAbsolute, headers: [['Host', serverHost]] }, + // Contains defaultPort that matches options.port. + { host: 'localhost', port, defaultPort: port, path: '/test' }, + // Stringifiable non-string path object. + { host: 'localhost', port, path: { toString() { return '/test'; } } }, +]; + +for (const opts of options) { + await roundTrip(opts); + // Check what the proxy server received. + const log = logs.pop(); + assert.strictEqual(logs.length, 0); + assert.strictEqual(log.method, 'GET'); + assert.strictEqual(log.url, requestUrl); + assert.strictEqual(log.headers.host, serverHost); +} + +server.close(); +proxy.close(); +agent.destroy(); diff --git a/test/client-proxy/test-http-proxy-request-authority-construction.mjs b/test/client-proxy/test-http-proxy-request-authority-construction.mjs new file mode 100644 index 00000000000000..873c3ee3ae104b --- /dev/null +++ b/test/client-proxy/test-http-proxy-request-authority-construction.mjs @@ -0,0 +1,82 @@ +// Verify that the request path and Host header are constructed correctly +// for proxied requests across different option combinations. + +import '../common/index.mjs'; +import assert from 'node:assert'; +import http from 'node:http'; + +function makeAgent() { + return new http.Agent({ + proxyEnv: { HTTP_PROXY: 'http://localhost:1' }, + }); +} + +function check(options, expectedPath, expectedHost) { + const agent = makeAgent(); + const req = http.request({ agent, ...options }); + req.on('error', () => {}); + assert.strictEqual(req.path, expectedPath, `path for ${JSON.stringify(options)}`); + assert.strictEqual(req.getHeader('host'), expectedHost, `Host for ${JSON.stringify(options)}`); + req.destroy(); + agent.destroy(); +} + +const cases = [ + // [options, expectedPath, expectedHost] + + // OPTIONS * and CONNECT bypass path rewriting. + [{ host: 'localhost', port: 3000, method: 'OPTIONS', path: '*' }, + '*', 'localhost:3000'], + [{ host: 'example.com', port: 443, method: 'CONNECT', path: 'example.com:443' }, + 'example.com:443', 'example.com:443'], + + // Basic cases: implicit Host, various port/defaultPort combos. + [{ host: 'localhost', port: 3000, path: '/a' }, + 'http://localhost:3000/a', 'localhost:3000'], + [{ host: 'localhost', port: 80, path: '/b' }, + 'http://localhost/b', 'localhost'], + [{ host: 'example.com', path: '/c' }, + 'http://example.com/c', 'example.com'], + [{ host: 'localhost', port: '3000', path: '/d' }, + 'http://localhost:3000/d', 'localhost:3000'], + + // defaultPort suppresses port in auto-set Host, canonicalization corrects it. + [{ host: 'localhost', port: 80, defaultPort: 8080, path: '/e' }, + 'http://localhost/e', 'localhost'], + [{ host: 'localhost', port: 3000, defaultPort: 3000, path: '/f' }, + 'http://localhost:3000/f', 'localhost:3000'], + + // User-explicit Host header: canonicalized to match request target. + [{ host: 'localhost', port: 80, defaultPort: 8080, path: '/g', headers: { Host: 'localhost:80' } }, + 'http://localhost/g', 'localhost'], + [{ host: 'localhost', port: 80, defaultPort: 8080, path: '/h', headers: { Host: 'localhost' } }, + 'http://localhost/h', 'localhost'], + [{ host: 'localhost', port: 80, path: '/i', headers: { Host: 'localhost:80' } }, + 'http://localhost/i', 'localhost'], + [{ host: 'localhost', port: 3000, defaultPort: 3000, path: '/j', headers: { Host: 'localhost:3000' } }, + 'http://localhost:3000/j', 'localhost:3000'], + [{ host: 'localhost', port: 3000, path: '/k', headers: { Host: 'LOCALHOST:3000' } }, + 'http://localhost:3000/k', 'localhost:3000'], + + // setHost=false with user-provided Host. + [{ host: 'localhost', port: 3000, setHost: false, path: '/l', headers: { Host: 'localhost:3000' } }, + 'http://localhost:3000/l', 'localhost:3000'], + + // IPv6. + [{ host: '::1', port: 3000, path: '/m' }, + 'http://[::1]:3000/m', '[::1]:3000'], + [{ host: '::1', port: 80, path: '/n' }, + 'http://[::1]/n', '[::1]'], + + // Mixed-case host option: URL normalizes to lowercase. + [{ host: 'LocalHost', port: 3000, path: '/o' }, + 'http://localhost:3000/o', 'localhost:3000'], + + // Absolute-form path matching authority. + [{ host: 'localhost', port: 3000, path: 'http://localhost:3000/p', headers: { Host: 'localhost:3000' } }, + 'http://localhost:3000/p', 'localhost:3000'], +]; + +for (const [options, expectedPath, expectedHost] of cases) { + check(options, expectedPath, expectedHost); +} diff --git a/test/client-proxy/test-http-proxy-request-origin-form-path.mjs b/test/client-proxy/test-http-proxy-request-origin-form-path.mjs new file mode 100644 index 00000000000000..011276de03895a --- /dev/null +++ b/test/client-proxy/test-http-proxy-request-origin-form-path.mjs @@ -0,0 +1,45 @@ +// This tests that origin-form paths are preserved when proxied, including +// paths starting with //. + +import * as common from '../common/index.mjs'; +import assert from 'node:assert'; +import http from 'node:http'; +import { once } from 'events'; +import { createProxyServer } from '../common/proxy-server.js'; + +const server = http.createServer(common.mustCall((req, res) => { + res.end('Hello world'); +}, 1)); +server.on('error', common.mustNotCall()); +server.listen(0); +await once(server, 'listening'); + +const { proxy, logs } = createProxyServer(); +proxy.listen(0); +await once(proxy, 'listening'); + +const port = server.address().port; +const serverHost = `localhost:${port}`; + +const agent = new http.Agent({ + proxyEnv: { + HTTP_PROXY: `http://localhost:${proxy.address().port}`, + }, +}); + +const req = http.request({ agent, host: 'localhost', port, path: '//foo/bar' }); +req.end(); +const [res] = await once(req, 'response'); +res.setEncoding('utf8'); +let body = ''; +for await (const chunk of res) body += chunk; +assert.strictEqual(body, 'Hello world'); + +assert.strictEqual(logs.length, 1); +assert.strictEqual(logs[0].method, 'GET'); +assert.strictEqual(logs[0].url, `http://${serverHost}//foo/bar`); +assert.strictEqual(logs[0].headers.host, serverHost); + +server.close(); +proxy.close(); +agent.destroy(); diff --git a/test/client-proxy/test-http-proxy-request-validation-errors.mjs b/test/client-proxy/test-http-proxy-request-validation-errors.mjs new file mode 100644 index 00000000000000..8607b60fb3875c --- /dev/null +++ b/test/client-proxy/test-http-proxy-request-validation-errors.mjs @@ -0,0 +1,119 @@ +// This tests that proxied HTTP requests fail validation before sending any data. + +import * as common from '../common/index.mjs'; +import assert from 'node:assert'; +import http from 'node:http'; +import { once } from 'events'; +import { createProxyServer } from '../common/proxy-server.js'; + +const target = http.createServer(common.mustNotCall()); +target.listen(0); +await once(target, 'listening'); +target.on('error', common.mustNotCall()); + +const { proxy, logs } = createProxyServer(); +proxy.listen(0); +await once(proxy, 'listening'); + +const agent = new http.Agent({ + proxyEnv: { + HTTP_PROXY: `http://localhost:${proxy.address().port}`, + }, +}); + +const port = target.address().port; +const base = { host: 'localhost', port, path: '/test', agent }; + +function throwsWith(message, cases) { + for (const { name, options } of cases) { + assert.throws(() => { + http.request(options, common.mustNotCall()); + }, { code: 'ERR_INVALID_ARG_VALUE', message }, name); + } +} + +// Path authority or Host header disagrees with options.host:port. +throwsWith(/must match the request authority/, [ + { name: 'absolute path with different host', + options: { ...base, path: 'http://example.test/test' } }, + { name: 'object Host header with different host', + options: { ...base, headers: { Host: 'bad.example' } } }, + { name: 'object Host header with different port', + options: { ...base, headers: { Host: 'localhost:1' } } }, + { name: 'array Host header with different host', + options: { ...base, headers: ['Host', 'bad.example'] } }, + { name: 'array-of-pairs Host header with different host', + options: { ...base, headers: [['Host', 'bad.example']] } }, + { name: 'array Host header omitting port for non-default port', + options: { ...base, headers: ['Host', 'localhost'] } }, + { name: 'absolute path omitting port for non-default port', + options: { ...base, path: 'http://localhost/test' } }, + { name: 'object Host header omitting port when defaultPort suppresses it', + options: { ...base, defaultPort: port, headers: { Host: 'localhost' } } }, +]); + +// Absolute-form path uses a non-http scheme. +throwsWith(/must use http: scheme/, [ + { name: 'absolute path with https: scheme', + options: { ...base, path: `https://localhost:${port}/test` } }, +]); + +// Absolute-form path contains userinfo. +throwsWith(/must not contain userinfo/, [ + { name: 'absolute path with userinfo', + options: { ...base, path: `http://user:pass@localhost:${port}/test` } }, +]); + +// Origin-form path must start with /. +throwsWith(/must be in absolute-form or start with \//, [ + { name: 'path without leading slash but includes @', + options: { ...base, path: '@other.example/test' } }, +]); + +// Host header value is not a bare authority (contains userinfo, path, query, or fragment). +throwsWith(/must match the request authority/, [ + { name: 'Host with userinfo', + options: { ...base, headers: { Host: `user@localhost:${port}` } } }, + { name: 'Host with path', + options: { ...base, headers: { Host: `localhost:${port}/path` } } }, + { name: 'Host with query', + options: { ...base, headers: { Host: `localhost:${port}?x` } } }, + { name: 'Host with fragment', + options: { ...base, headers: { Host: `localhost:${port}#x` } } }, +]); + +// Multiple Host headers (invalid per RFC 9110 Section 5.3). +throwsWith(/must not contain duplicate Host headers/, [ + { name: 'flat array with duplicate Host', + options: { ...base, headers: ['Host', `localhost:${port}`, 'Host', 'bad.example'] } }, + { name: 'array-of-pairs with duplicate Host', + options: { ...base, headers: [['Host', `localhost:${port}`], ['Host', 'bad.example']] } }, + { name: 'case-insensitive duplicate Host', + options: { ...base, headers: ['host', `localhost:${port}`, 'HOST', 'bad.example'] } }, +]); + +// Non-array entry in array-of-pairs form. +throwsWith(/must be an array when headers is passed as an array of pairs/, [ + { name: 'object with numeric keys smuggling a Host', + options: { ...base, headers: [['Host', `localhost:${port}`], { 0: 'Host', 1: 'bad.example' }] } }, +]); + +// Invalid port. +for (const { name, badPort } of [ + { name: 'port >= 65536', badPort: 99999 }, + { name: 'port === 65536', badPort: 65536 }, +]) { + assert.throws(() => { + http.request({ ...base, port: badPort }, common.mustNotCall()); + }, { code: 'ERR_SOCKET_BAD_PORT' }, name); +} + +assert.throws(() => { + http.request({ ...base, method: 'GET', path: '*' }, common.mustNotCall()); +}, { code: 'ERR_INVALID_ARG_VALUE', message: /must be in absolute-form or start with \// }); + +assert.deepStrictEqual(logs, []); + +target.close(); +proxy.close(); +agent.destroy(); diff --git a/test/common/proxy-server.js b/test/common/proxy-server.js index c4cd19fe610b81..a2f8bd12e6257e 100644 --- a/test/common/proxy-server.js +++ b/test/common/proxy-server.js @@ -34,13 +34,11 @@ function createProxyServer(options = {}) { } proxy.on('request', (req, res) => { logRequest(logs, req); - const { hostname, port } = new URL(`http://${req.headers.host}`); - const targetPort = port || 80; - + // Route based on the absolute-form request-target. const url = new URL(req.url); const options = { - hostname: hostname.startsWith('[') ? hostname.slice(1, -1) : hostname, - port: targetPort, + hostname: url.hostname.startsWith('[') ? url.hostname.slice(1, -1) : url.hostname, + port: url.port || 80, path: url.pathname + url.search, // Convert back to relative URL. method: req.method, headers: { From 6a80ab485c62cf76abafbef4c2992b539548d447 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Wed, 1 Jul 2026 12:45:14 +0200 Subject: [PATCH 070/131] build: add manually-dispatched stress-test workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a GitHub action workflow that can be manually dispatched to stress-run tests on a PR/branch to verify flakiness. Signed-off-by: Joyee Cheung PR-URL: https://github.com/nodejs/node/pull/64118 Reviewed-By: Filip Skokan Reviewed-By: René --- .github/workflows/stress-test.yml | 116 ++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 .github/workflows/stress-test.yml diff --git a/.github/workflows/stress-test.yml b/.github/workflows/stress-test.yml new file mode 100644 index 00000000000000..e3846cf4d387ac --- /dev/null +++ b/.github/workflows/stress-test.yml @@ -0,0 +1,116 @@ +name: Stress Test (rebase tested branch on main for cache reuse) + +on: + workflow_dispatch: + inputs: + test_path: + description: Test path or glob (e.g. test/parallel/test-debugger-break.js or "test/parallel/test-debugger-*") + required: true + type: string + os: + description: Runner to use + required: true + default: macos-15 + type: choice + options: + - macos-15 + - ubuntu-24.04 + - ubuntu-24.04-arm + repeat: + description: Number of times to repeat each test (--repeat) + required: true + default: '1000' + type: string + test_jobs: + description: Number of jobs to run in parallel (-j). + required: true + default: '1' + type: string + test_args: + description: Extra args for tools/test.py, space-separated (e.g. "-t 10 --worker") + required: false + default: '' + type: string + +env: + PYTHON_VERSION: '3.14' + XCODE_VERSION: '16.4' + CLANG_VERSION: '19' + RUSTC_VERSION: '1.82' + +permissions: + contents: read + +jobs: + stress-test: + runs-on: ${{ inputs.os }} + env: + # Linux builds with clang (matching test-linux.yml), macOS with gcc/g++. + CC: ${{ startsWith(inputs.os, 'ubuntu') && 'sccache clang-19' || 'sccache gcc' }} + CXX: ${{ startsWith(inputs.os, 'ubuntu') && 'sccache clang++-19' || 'sccache g++' }} + # Enable sccache - this is okay for a manually-dispatched workflow that is typically used to + # test lib-only or test-only deflaking changes. This should be able to pick up cache from + # test-linux.yml and test-macos.yml running on the main branch. + SCCACHE_GHA_ENABLED: 'true' + SCCACHE_IDLE_TIMEOUT: '0' + steps: + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + persist-credentials: false + path: node + - name: Install Clang ${{ env.CLANG_VERSION }} + if: runner.os == 'Linux' + uses: ./node/.github/actions/install-clang + with: + clang-version: ${{ env.CLANG_VERSION }} + - name: Set up Xcode ${{ env.XCODE_VERSION }} + if: runner.os == 'macOS' + run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app + - name: Set up Python ${{ env.PYTHON_VERSION }} + uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + with: + python-version: ${{ env.PYTHON_VERSION }} + allow-prereleases: true + - name: Install Rust ${{ env.RUSTC_VERSION }} + run: | + rustup override set "$RUSTC_VERSION" + rustup --version + - name: Set up sccache + uses: Mozilla-Actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 # v0.0.10 + with: + version: v0.16.0 + - name: Environment Information + run: npx envinfo@7.21.0 + # This is needed due to https://github.com/nodejs/build/issues/3878 + - name: Cleanup + if: runner.os == 'macOS' + run: | + echo "::group::Free space before cleanup" + df -h + echo "::endgroup::" + echo "::group::Cleaned Files" + + sudo rm -rf /Users/runner/Library/Android/sdk + + echo "::endgroup::" + echo "::group::Free space after cleanup" + df -h + echo "::endgroup::" + - name: Build + run: make -C node build-ci -j"$(getconf _NPROCESSORS_ONLN)" V=1 CONFIG_FLAGS="--error-on-warn --v8-enable-temporal-support" + - name: Stress run ${{ inputs.test_path }} x${{ inputs.repeat }} + shell: bash + env: + REPEAT: ${{ inputs.repeat }} + JOBS: ${{ inputs.test_jobs }} + TEST_ARGS: ${{ inputs.test_args }} + TEST_PATH: ${{ inputs.test_path }} + run: | + cd node + read -ra EXTRA_ARGS <<< "$TEST_ARGS" + python3 tools/test.py \ + --repeat "$REPEAT" \ + -j "$JOBS" \ + -p actions \ + "${EXTRA_ARGS[@]}" \ + "$TEST_PATH" From bb2eed863cc6d48cebc043d77a2b15d11092d7ff Mon Sep 17 00:00:00 2001 From: Stewart X Addison Date: Mon, 29 Jun 2026 09:26:45 +0100 Subject: [PATCH 071/131] doc: add sxa GPG key (ed25519) Signed-off-by: Stewart X Addison PR-URL: https://github.com/nodejs/node/pull/64193 Reviewed-By: Antoine du Hamel Reviewed-By: Richard Lau --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index f93cfa6d492b47..dc175eadf5bb6a 100644 --- a/README.md +++ b/README.md @@ -785,6 +785,8 @@ Primary GPG keys for Node.js Releasers (some Releasers sign with subkeys): `C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C` * **Ruy Adorno** <> `108F52B48DB57BB0CC439B2997B01419BD92F80A` +* **Stewart X Addison** <> + `655F3B5C1FB3FA8D1A0CA6BDE4A7D232B936D2FD` * **Ulises Gascón** <> `A363A499291CBBC940DD62E41F10027AF002F8B0` @@ -802,6 +804,7 @@ gpg --keyserver hkps://keys.openpgp.org --recv-keys 8FCCA13FEF1D0C2E91008E09770F gpg --keyserver hkps://keys.openpgp.org --recv-keys 890C08DB8579162FEE0DF9DB8BEAB4DFCF555EF4 # Rafael Gonzaga gpg --keyserver hkps://keys.openpgp.org --recv-keys C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C # Richard Lau gpg --keyserver hkps://keys.openpgp.org --recv-keys 108F52B48DB57BB0CC439B2997B01419BD92F80A # Ruy Adorno +gpg --keyserver hkps://keys.openpgp.org --recv-keys 655F3B5C1FB3FA8D1A0CA6BDE4A7D232B936D2FD # Stewart X Addison gpg --keyserver hkps://keys.openpgp.org --recv-keys A363A499291CBBC940DD62E41F10027AF002F8B0 # Ulises Gascón ``` From 518309c363b13b8bcb06140b79faba84b10ed41d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9?= Date: Wed, 1 Jul 2026 12:20:50 +0100 Subject: [PATCH 072/131] build: suppress clang errors building libffi on Windows Signed-off-by: Renegade334 PR-URL: https://github.com/nodejs/node/pull/64222 Refs: https://github.com/nodejs/node/pull/64040 Reviewed-By: Chengzhong Wu Reviewed-By: Stefan Stojanovic Reviewed-By: Richard Lau --- deps/libffi/libffi.gyp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/deps/libffi/libffi.gyp b/deps/libffi/libffi.gyp index f3122a4e2a0041..2d43dcdb733c97 100644 --- a/deps/libffi/libffi.gyp +++ b/deps/libffi/libffi.gyp @@ -204,6 +204,13 @@ }, ], 'conditions': [ + ['OS == "win" and clang == 1', { + 'msvs_settings': { + 'VCCLCompilerTool': { + 'AdditionalOptions': ['-Wno-incompatible-pointer-types'], + }, + }, + }], ['OS == "win" and (target_arch == "x64" or target_arch == "x86_64")', { 'actions': [ { From ef4915fc3a92e26c95acf91f73144cc1a1846bda Mon Sep 17 00:00:00 2001 From: Daijiro Wachi Date: Wed, 1 Jul 2026 20:49:20 +0900 Subject: [PATCH 073/131] doc: fix Fast FFI argument count in ffi.md The text said functions with more than 7 arguments fall back to the generic call path, contradicting the preceding sentence that Fast FFI calls support up to 8 arguments. The real limit is architecture- and type-dependent: the hard cap is 8 public arguments (src/ffi/fast.cc), but register pressure lowers the effective count to 7 integer/pointer arguments on AArch64 and 6 on x86-64, while floating-point arguments can use up to 8 on both. Describe this instead of the previous, inaccurate single threshold. Signed-off-by: Daijiro Wachi PR-URL: https://github.com/nodejs/node/pull/63960 Reviewed-By: Colin Ihrig Reviewed-By: Paolo Insogna --- doc/api/ffi.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/doc/api/ffi.md b/doc/api/ffi.md index 4deef4accad375..172af6bbc6edee 100644 --- a/doc/api/ffi.md +++ b/doc/api/ffi.md @@ -125,8 +125,13 @@ raw pointer `bigint` values. For pointer-like parameters, `null`, `undefined`, strings, `Buffer`, typed array, `DataView`, and `ArrayBuffer` values are converted on the JavaScript side before calling the optimized native wrapper. -Optimized Fast FFI calls support at most 8 function arguments. Functions with -more than 7 arguments use the generic FFI call path instead. +Optimized Fast FFI calls support at most 8 function arguments, but the exact +limit depends on the architecture and on the argument types, because each +argument must fit in the registers used by the platform trampoline. Integer +and pointer arguments are limited to 7 on AArch64 and to 6 on x86-64, while +floating-point arguments can use up to 8 on both. Functions that exceed these +limits, including any function with more than 8 arguments, use the generic FFI +call path instead. ## Signature objects From 06c1fbc25bab83490b066d64f2fdf801a9727481 Mon Sep 17 00:00:00 2001 From: Jamie Magee Date: Wed, 1 Jul 2026 08:43:10 -0500 Subject: [PATCH 074/131] build: enable Maglev for riscv64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit V8's Maglev compiler has supported riscv64 since V8 14.0 (with full source files in deps/v8/src/maglev/riscv/), but Node.js never wired it up: - configure.py excluded riscv64 from maglev_enabled_architectures - tools/v8_gypfiles/v8.gyp lacked GN-scraper conditions for riscv64 Maglev sources in both the v8_internal_headers and v8_base_without_compiler blocks This adds riscv64 to both, following the same pattern used for s390x in #60863 and matching V8's own BUILD.gn which already lists riscv64 alongside arm, arm64, x64, s390x, and ppc64 as Maglev-enabled architectures. Refs: https://github.com/nodejs/build/issues/4099 Signed-off-by: Jamie Magee PR-URL: https://github.com/nodejs/node/pull/62605 Reviewed-By: René Reviewed-By: Stewart X Addison Reviewed-By: Richard Lau --- configure.py | 2 +- tools/v8_gypfiles/v8.gyp | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/configure.py b/configure.py index c625ddd8789711..73a755f67e7068 100755 --- a/configure.py +++ b/configure.py @@ -55,7 +55,7 @@ valid_mips_float_abi = ('soft', 'hard') valid_intl_modes = ('none', 'small-icu', 'full-icu', 'system-icu') icu_versions = json.loads((tools_path / 'icu' / 'icu_versions.json').read_text(encoding='utf-8')) -maglev_enabled_architectures = ('x64', 'arm', 'arm64', 'ppc64', 's390x') +maglev_enabled_architectures = ('x64', 'arm', 'arm64', 'ppc64', 's390x', 'riscv64') # builtins may be removed later if they have been disabled by options shareable_builtins = {'undici/undici': 'deps/undici/undici.js', diff --git a/tools/v8_gypfiles/v8.gyp b/tools/v8_gypfiles/v8.gyp index 38732b4b34cf68..193b8aebdd28f1 100644 --- a/tools/v8_gypfiles/v8.gyp +++ b/tools/v8_gypfiles/v8.gyp @@ -671,6 +671,11 @@ ' Date: Wed, 1 Jul 2026 21:52:17 -0700 Subject: [PATCH 075/131] test: make blob desiredSize assertion robust The blob stream pull continuation runs with setImmediate(), while the test checks desiredSize from a timer. Depending on platform scheduling, the stream may or may not have queued the next 5-byte chunk yet. Accept both valid intermediate states to avoid flaky failures. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.5 PR-URL: https://github.com/nodejs/node/pull/64106 Refs: https://github.com/nodejs/reliability/issues?q=sort%3Aupdated-desc%20%22parallel%2Ftest-blob%22 Reviewed-By: Filip Skokan --- test/parallel/test-blob.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-blob.js b/test/parallel/test-blob.js index 19ca24b0319f13..9ec2a3c04079a7 100644 --- a/test/parallel/test-blob.js +++ b/test/parallel/test-blob.js @@ -354,8 +354,10 @@ assert.throws(() => new Blob({}), { assert(!done); setTimeout(common.mustCall(() => { // The blob stream is now a byte stream hence after the first read, - // it should pull in the next 'hello' which is 5 bytes hence -5. - assert.strictEqual(stream[kState].controller.desiredSize, 0); + // it may have pulled in the next 'hello' which is 5 bytes hence -5. + // The ordering of this timer and the stream's setImmediate() pull + // continuation can vary across platforms. + assert([0, -5].includes(stream[kState].controller.desiredSize)); }), 0); })().then(common.mustCall()); From 4dceefde1ede45be492e9f478ec61a12a38e4f66 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jul 2026 10:36:02 +0200 Subject: [PATCH 076/131] tools: bump undici from 6.24.1 to 6.27.0 in /tools/doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [undici](https://github.com/nodejs/undici) from 6.24.1 to 6.27.0. - [Release notes](https://github.com/nodejs/undici/releases) - [Commits](https://github.com/nodejs/undici/compare/v6.24.1...v6.27.0) --- updated-dependencies: - dependency-name: undici dependency-version: 6.27.0 dependency-type: indirect ... PR-URL: https://github.com/nodejs/node/pull/64031 Reviewed-By: René --- tools/doc/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/doc/package-lock.json b/tools/doc/package-lock.json index 9ee8c0128d17b3..6ffe30df275a68 100644 --- a/tools/doc/package-lock.json +++ b/tools/doc/package-lock.json @@ -6086,9 +6086,9 @@ } }, "node_modules/undici": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz", - "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==", + "version": "6.27.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz", + "integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==", "license": "MIT", "engines": { "node": ">=18.17" From fe0ea2bb5d5e7f4d54bb10bdf893a447f061ac82 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jul 2026 09:42:19 +0000 Subject: [PATCH 077/131] tools: bump @node-core/doc-kit Bumps the doc group with 1 update in the /tools/doc directory: [@node-core/doc-kit](https://github.com/nodejs/doc-kit). Updates `@node-core/doc-kit` from 1.3.9 to 1.4.1 - [Commits](https://github.com/nodejs/doc-kit/commits) --- updated-dependencies: - dependency-name: "@node-core/doc-kit" dependency-version: 1.3.10 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: doc ... Signed-off-by: dependabot[bot] PR-URL: https://github.com/nodejs/node/pull/64010 Reviewed-By: Luigi Pinca Reviewed-By: Antoine du Hamel --- tools/doc/package-lock.json | 3224 +++++++++-------------------------- tools/doc/package.json | 2 +- 2 files changed, 831 insertions(+), 2395 deletions(-) diff --git a/tools/doc/package-lock.json b/tools/doc/package-lock.json index 6ffe30df275a68..9b4595ee182d68 100644 --- a/tools/doc/package-lock.json +++ b/tools/doc/package-lock.json @@ -6,7 +6,7 @@ "": { "name": "doc", "dependencies": { - "@node-core/doc-kit": "1.3.9" + "@node-core/doc-kit": "1.4.1" } }, "node_modules/@actions/core": { @@ -44,18 +44,6 @@ "integrity": "sha512-nRBchcMM+QK1pdjO7/idu86rbJI5YHUKCvKs0KxnSYbVe3F51UfGxuZX4Qy/fWlp6l7gWFwIkrOzN+oUK03kfw==", "license": "MIT" }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@emnapi/core": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", @@ -134,51 +122,6 @@ "react": ">= 16 || ^19.0.0-rc" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, "node_modules/@minify-html/wasm": { "version": "0.18.1", "resolved": "https://registry.npmjs.org/@minify-html/wasm/-/wasm-0.18.1.tgz", @@ -491,13 +434,13 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", "license": "MIT", "optional": true, "dependencies": { - "@tybys/wasm-util": "^0.10.1" + "@tybys/wasm-util": "^0.10.3" }, "funding": { "type": "github", @@ -513,6 +456,7 @@ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", "license": "MIT", + "peer": true, "engines": { "node": "^14.21.3 || >=16" }, @@ -521,19 +465,19 @@ } }, "node_modules/@node-core/doc-kit": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/@node-core/doc-kit/-/doc-kit-1.3.9.tgz", - "integrity": "sha512-DVRaycj3humM/GJ4jFk5+kKrnzHEEKAqiNcUWsb/b0BCQePrqVl6sJ8L4E82HP2qTBq6EkNkwdEI5uf+w45tkA==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@node-core/doc-kit/-/doc-kit-1.4.1.tgz", + "integrity": "sha512-4S9cIGW6+3U3wWsCHRABJg5rjkTLU90Mdyb9v53ljf622A9u8sGQgSzVH9FgQHcKw5z3ofK25h12E/eDGi5SVA==", "dependencies": { "@actions/core": "^3.0.0", "@heroicons/react": "^2.2.0", "@minify-html/wasm": "^0.18.1", "@node-core/rehype-shiki": "^1.4.1", - "@node-core/ui-components": "^1.6.3", + "@node-core/ui-components": "^1.7.0", "@orama/orama": "^3.1.18", "@orama/ui": "^1.5.4", "@rollup/plugin-virtual": "^3.0.2", - "@swc/html-wasm": "^1.15.32", + "@swc/html-wasm": "^1.15.40", "acorn": "^8.16.0", "commander": "^14.0.3", "dedent": "^1.7.2", @@ -545,21 +489,22 @@ "hastscript": "^9.0.1", "lightningcss-wasm": "^1.32.0", "mdast-util-slice-markdown": "^2.0.1", - "piscina": "^5.1.4", - "preact": "^10.29.0", - "preact-render-to-string": "^6.6.7", + "piscina": "^5.2.0", + "preact": "^10.29.2", + "preact-render-to-string": "^6.7.0", "reading-time": "^1.5.0", "recma-jsx": "^1.0.1", "rehype-raw": "^7.0.0", "rehype-recma": "^1.0.0", "rehype-stringify": "^10.0.1", "remark-gfm": "^4.0.1", + "remark-mdx": "^3.1.1", "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-stringify": "^11.0.0", - "rolldown": "1.0.0-rc.17", + "rolldown": "1.0.2", "semver": "^7.8.0", - "shiki": "^4.0.2", + "shiki": "^4.1.0", "tinyglobby": "^0.2.15", "unified": "^11.0.5", "unist-builder": "^4.0.0", @@ -683,12 +628,12 @@ } }, "node_modules/@node-core/ui-components": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/@node-core/ui-components/-/ui-components-1.6.3.tgz", - "integrity": "sha512-Oy/bI4mZC6V/i8CdIX8q62r81zR6bAEARZE0jwTpv7w49SNomB2WAVb5fnFBSumyigOCgQKgR/OJtwh8XQJnkw==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@node-core/ui-components/-/ui-components-1.7.1.tgz", + "integrity": "sha512-i1un8y0yth6WdT0OXpAQeL8XIkohcZ2P8khSC0oQstWG8H7PCRqX+mdZlJAuVUKq3MaQnC2fO34Q3j7L4TenXg==", "dependencies": { "@heroicons/react": "^2.2.0", - "@orama/core": "^1.2.19", + "@orama/orama": "^3.1.18", "@orama/ui": "^1.5.4", "@radix-ui/react-avatar": "^1.1.11", "@radix-ui/react-dialog": "^1.1.15", @@ -698,15 +643,9 @@ "@radix-ui/react-separator": "^1.1.8", "@radix-ui/react-tabs": "^1.1.13", "@radix-ui/react-tooltip": "^1.2.8", - "@tailwindcss/postcss": "~4.2.1", - "@types/react": "^19.2.13", "@vcarl/remark-headings": "~0.1.0", "classnames": "~2.5.1", - "postcss-calc": "10.1.1", - "postcss-cli": "11.0.1", - "react": "^19.2.4", - "tailwindcss": "~4.1.17", - "typescript": "5.9.3" + "react": "^19.2.6" }, "engines": { "node": ">=20" @@ -717,6 +656,7 @@ "resolved": "https://registry.npmjs.org/@orama/core/-/core-1.2.19.tgz", "integrity": "sha512-AVEI0eG/a1RUQK+tBloRMppQf46Ky4kIYKEVjo0V0VfIGZHdLOE2PJR4v949kFwiTnfSJCUaxgwM74FCA1uHUA==", "license": "AGPL-3.0", + "peer": true, "dependencies": { "@orama/cuid2": "2.2.3", "@orama/oramacore-events-parser": "0.0.5" @@ -727,6 +667,7 @@ "resolved": "https://registry.npmjs.org/@orama/cuid2/-/cuid2-2.2.3.tgz", "integrity": "sha512-Lcak3chblMejdlSHgYU2lS2cdOhDpU6vkfIJH4m+YKvqQyLqs1bB8+w6NT1MG5bO12NUK2GFc34Mn2xshMIQ1g==", "license": "MIT", + "peer": true, "dependencies": { "@noble/hashes": "^1.1.5" } @@ -744,7 +685,8 @@ "version": "0.0.5", "resolved": "https://registry.npmjs.org/@orama/oramacore-events-parser/-/oramacore-events-parser-0.0.5.tgz", "integrity": "sha512-yAuSwog+HQBAXgZ60TNKEwu04y81/09mpbYBCmz1RCxnr4ObNY2JnPZI7HmALbjAhLJ8t5p+wc2JHRK93ubO4w==", - "license": "AGPL-3.0" + "license": "AGPL-3.0", + "peer": true }, "node_modules/@orama/stopwords": { "version": "3.1.18", @@ -772,33 +714,33 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.127.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", - "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", + "version": "0.132.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.132.0.tgz", + "integrity": "sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/Boshen" } }, "node_modules/@radix-ui/number": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", - "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.2.tgz", + "integrity": "sha512-ceTwaxc4I5IOi97DgCotl3pqiyRGvffcc0oOsE2dQYaJOFIDsDt4VWG6xEbg1QePv9QWausCEIppud/tJ1wNig==", "license": "MIT" }, "node_modules/@radix-ui/primitive": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", - "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.4.tgz", + "integrity": "sha512-7AdCK9PQyiljKoBDbN8OuctCbd/esdwZPQ8RtOE3SsyQtUpiPb+ND75q0jEhC1m1ecBI0MFNeLJvwIh9iKHRcQ==", "license": "MIT" }, "node_modules/@radix-ui/react-arrow": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", - "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.11.tgz", + "integrity": "sha512-Kdil9BB1rIFC/khmf4hC35bn8701AJcizTU7G7cUbEbk5XqqbjDuHW60uUfKqO5WojjZcbAW51Q7P0hRmMLw8A==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.3" + "@radix-ui/react-primitive": "2.1.7" }, "peerDependencies": { "@types/react": "*", @@ -815,13 +757,17 @@ } } }, - "node_modules/@radix-ui/react-arrow/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "node_modules/@radix-ui/react-avatar": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.2.1.tgz", + "integrity": "sha512-+8PWoLLZv3AVb5m0pvoiOca/bQGzc9vPVb+982HB2x3Un0DpYEPM3zLMl4oqRpBsocJuNqLkiv/HXTnTrlwr4g==", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.2.3" + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-is-hydrated": "0.1.1", + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -838,17 +784,16 @@ } } }, - "node_modules/@radix-ui/react-avatar": { + "node_modules/@radix-ui/react-collection": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.11.tgz", - "integrity": "sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.11.tgz", + "integrity": "sha512-djW9+zeg137KQdlPtmE8xnaD+K2rcXXMWFrSg0hsmYZ6HRbdTA7tDHFgpaW9+huWVEu0RCabL+985T4TA0BE7g==", "license": "MIT", "dependencies": { - "@radix-ui/react-context": "1.1.3", - "@radix-ui/react-primitive": "2.1.4", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-is-hydrated": "0.1.0", - "@radix-ui/react-use-layout-effect": "1.1.1" + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", @@ -865,36 +810,25 @@ } } }, - "node_modules/@radix-ui/react-collection": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", - "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.3.tgz", + "integrity": "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA==", "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3" - }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "node_modules/@radix-ui/react-context": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.4.tgz", + "integrity": "sha512-QwH4PO5urrbO+FaGd5Aglg+YJgWTyyuZ3g/6mKvsqraLkglDdckw9JafgL5McL5VEJ6EPNduPaT3ZE9BttDAqg==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -906,13 +840,26 @@ } } }, - "node_modules/@radix-ui/react-collection/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.18.tgz", + "integrity": "sha512-apa28mldjMgORmE6g/w3sCcA0Y9UAVeeDVoozN4i7kOw12mLl9RBchfzK3Nn6qxOWjrZhK1Lfy7f07kyzxtnBw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-dismissable-layer": "1.1.14", + "@radix-ui/react-focus-guards": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.11", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-portal": "1.1.13", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-controllable-state": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", @@ -929,10 +876,10 @@ } } }, - "node_modules/@radix-ui/react-compose-refs": { + "node_modules/@radix-ui/react-direction": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", - "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.2.tgz", + "integrity": "sha512-C3vFhbyi4SW3PmbAi6Awpu4OzJtd0MxGurvSsYtr7p7nM8RNB3VAF3CUmnp2j50knpkrRcB7+ycVXzgLgF6yNA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -944,41 +891,46 @@ } } }, - "node_modules/@radix-ui/react-context": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.3.tgz", - "integrity": "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==", + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.14.tgz", + "integrity": "sha512-4lUhWTWAjbDIqFrAPWJ3WqBOpO5YchVZ88X3nh6H9Lu5AFi5nCUeTPj3D8FSDmabmFeRe9ME0BDA4MwKTha5GQ==", "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-effect-event": "0.0.3" + }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-dialog": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", - "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.19", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.19.tgz", + "integrity": "sha512-HZccBkbK0LOi8nYKIp5jll/zIRW0cCOmG6WWyqsSpmXCU+ZlcBbTqIwlBvPCu886C5RVu6c/kHV7xSP8IgYNHw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-menu": "2.1.19", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -995,10 +947,10 @@ } } }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.4.tgz", + "integrity": "sha512-cot/aB/mOm0IYVYTTmQcEEK1M48lZWi8FlYe5nDPQQ8NYZUlXEFgncJ9p2Kzer3RKSrY7cTTpEMLZKNo9QoP5Q==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -1010,13 +962,15 @@ } } }, - "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.11.tgz", + "integrity": "sha512-Mn88Vg2whaRocGJNOH+DKFqYm6ySFPQaiwHNxZPyjn99B52KAEJWWY9NP83+nWdk2HM3rdov+STu9AG471Rt9w==", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.2.3" + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-callback-ref": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -1033,11 +987,14 @@ } } }, - "node_modules/@radix-ui/react-direction": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", - "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "node_modules/@radix-ui/react-id": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.2.tgz", + "integrity": "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA==", "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.2" + }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -1048,17 +1005,13 @@ } } }, - "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", - "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "node_modules/@radix-ui/react-label": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.11.tgz", + "integrity": "sha512-3PKvDDxOn62k0oV1n4QtNtD2vpu+zYjXR7ojLBPaO6SPvhy53yg0vAmgNeBQeJW5rV3dffoRG+HYfLBZuzw0CQ==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-escape-keydown": "1.1.1" + "@radix-ui/react-primitive": "2.1.7" }, "peerDependencies": { "@types/react": "*", @@ -1075,13 +1028,30 @@ } } }, - "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" + "node_modules/@radix-ui/react-menu": { + "version": "2.1.19", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.19.tgz", + "integrity": "sha512-Mht9BVd1AIsNFVQr4KG3bIK7XQn5IXF0TL/2ObsrzOdc1loaly/+kBDL5roSCYn8j8XZkvpOD0WYLz2FQtH1Eg==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collection": "1.1.11", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.14", + "@radix-ui/react-focus-guards": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.11", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-popper": "1.3.2", + "@radix-ui/react-portal": "1.1.13", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-roving-focus": "1.1.14", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-callback-ref": "1.1.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", @@ -1098,19 +1068,22 @@ } } }, - "node_modules/@radix-ui/react-dropdown-menu": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", - "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", + "node_modules/@radix-ui/react-popper": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.3.2.tgz", + "integrity": "sha512-3QXNeMkdshed1MR3LNoiCirBywRFPkD8ETJa/HlPuLwSajaQixf2ro+isoDNJlGABg9ug41XuZpINZJIle4XWg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-menu": "2.1.16", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2" + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.11", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-use-rect": "1.1.2", + "@radix-ui/react-use-size": "1.1.2", + "@radix-ui/rect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -1127,28 +1100,14 @@ } } }, - "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "node_modules/@radix-ui/react-portal": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.13.tgz", + "integrity": "sha512-z3oXfmaHLJTF1wktbjgD6cn9jiEbq3WSondB10LIuIt2m2Ym4iJlrW04/euMwENDdWDdE7z+OuY7Qyp1YpRSwA==", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.2.3" + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -1165,30 +1124,13 @@ } } }, - "node_modules/@radix-ui/react-focus-guards": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", - "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", - "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "node_modules/@radix-ui/react-presence": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.6.tgz", + "integrity": "sha512-zdTk4PlUO0E18HnZ3wYbW0KkJJxWCdiNYp6g6X1PtONFhxVkg01vliTJAmwIszU6mHiyBOoW9P0rAugl5/hULQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1" + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -1205,13 +1147,13 @@ } } }, - "node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.7.tgz", + "integrity": "sha512-bC3NiwsprbxKjuon9l7X6BUTw7FPVzEYaL92MPEY5SCd/9hUTPXVFtVwRix7778wtRsVao+zE062gL79FZleeQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.2.3" + "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", @@ -1228,31 +1170,65 @@ } } }, - "node_modules/@radix-ui/react-id": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", - "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.14.tgz", + "integrity": "sha512-8Qcnx9447tx/aCBgw6Jenfqg4Skq+vqab9mCBmuGNipIS5YXvL275wbKEu7+ICYHIlAPgCduUMJH1XOYewKF6Q==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collection": "1.1.11", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-label": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.8.tgz", - "integrity": "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.4" + "node_modules/@radix-ui/react-select": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.3.2.tgz", + "integrity": "sha512-brXD6C/V0fVK0DDbscLVw6LsXrjQ+ay8jdOBaN+tLb4vsHsAMm6Gt6eT77wHX1Eq8GPtD5rJ+RxFtfDozsb4+Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/number": "1.1.2", + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-collection": "1.1.11", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.14", + "@radix-ui/react-focus-guards": "1.1.4", + "@radix-ui/react-focus-scope": "1.1.11", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-popper": "1.3.2", + "@radix-ui/react-portal": "1.1.13", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-callback-ref": "1.1.2", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-use-layout-effect": "1.1.2", + "@radix-ui/react-use-previous": "1.1.2", + "@radix-ui/react-visually-hidden": "1.2.7", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", @@ -1269,30 +1245,13 @@ } } }, - "node_modules/@radix-ui/react-menu": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", - "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" + "node_modules/@radix-ui/react-separator": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.11.tgz", + "integrity": "sha512-jRhe86+8PF7VZ1u14eOWVOuh2BuAhALg/FT1VcMC4OHedMTRUazDnDlKTt+yxo5cRNKHMfmvZ4sSQtWDeMV4CQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.7" }, "peerDependencies": { "@types/react": "*", @@ -1309,11 +1268,14 @@ } } }, - "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "node_modules/@radix-ui/react-slot": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.0.tgz", + "integrity": "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA==", "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.3" + }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -1324,13 +1286,20 @@ } } }, - "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.16.tgz", + "integrity": "sha512-v3Ab2l7z6U7tRB4xA0IyKdq0OsqaO1o9ZjsIEoKKnSZ/l96mZz8aCTX0NCXw+YVHJXr8Km4d+Mn6/Q8YjXa+gw==", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.2.3" + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-direction": "1.1.2", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-roving-focus": "1.1.14", + "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -1347,22 +1316,24 @@ } } }, - "node_modules/@radix-ui/react-popper": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", - "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", - "license": "MIT", - "dependencies": { - "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-rect": "1.1.1", - "@radix-ui/react-use-size": "1.1.1", - "@radix-ui/rect": "1.1.1" + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.11.tgz", + "integrity": "sha512-8XZ6Py3y3W2nEzAUGCN5cfVKaUi+CVApcz1d6lrNVVf2hvYEixMRkq8k9ggPKnQUpRRuOV5avt8uvxViH2jLwA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.3", + "@radix-ui/react-context": "1.1.4", + "@radix-ui/react-dismissable-layer": "1.1.14", + "@radix-ui/react-id": "1.1.2", + "@radix-ui/react-popper": "1.3.2", + "@radix-ui/react-portal": "1.1.13", + "@radix-ui/react-presence": "1.1.6", + "@radix-ui/react-primitive": "2.1.7", + "@radix-ui/react-slot": "1.3.0", + "@radix-ui/react-use-controllable-state": "1.2.3", + "@radix-ui/react-visually-hidden": "1.2.7" }, "peerDependencies": { "@types/react": "*", @@ -1379,10 +1350,10 @@ } } }, - "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-context": { + "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.2.tgz", + "integrity": "sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -1394,130 +1365,95 @@ } } }, - "node_modules/@radix-ui/react-popper/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.3.tgz", + "integrity": "sha512-PLzC90MS+ReootmjC597dvopoelpZ8Q61HJkDXZSExitIq7PL55vHNnesAHwguHK0aPfBnpdNzQtv1uliaqQrA==", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.2.3" + "@radix-ui/react-use-effect-event": "0.0.3", + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-portal": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", - "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.3.tgz", + "integrity": "sha512-6c8ZqvPTWILEKnyVkP53EGRCcpnJiKTC21sS/6R1GF5xKyHJJWQEPfkqlcgUkdRQivd6tb23abUwe4ngWmY0JA==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-layout-effect": "1.1.1" + "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-portal/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.1.tgz", + "integrity": "sha512-qwOiz4Tjo8CNnrOLAYUMXeZwDzXgXpvK4TKQPmWLECM9XoWvA6+0Z2/7Ag3A4ivjS4ovbLJPbskkxioFyBhr8A==", "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-presence": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", - "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.2.tgz", + "integrity": "sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA==", "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-primitive": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", - "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.2.tgz", + "integrity": "sha512-IGBQPtRFdhN6MQ8dbegVmBq1LVZluya3F1jWY+puIcQC3MHctRwTDSBWCkL/3ZcnMJLTMJ++Z+ktmvg0F89iCw==", "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.4" - }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-primitive/node_modules/@radix-ui/react-slot": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", - "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.2.tgz", + "integrity": "sha512-d8a+bBY/FxikNPlgJJoaBHZX+zKVbWHYJGTLnLvveQgFSTntkGdEKv3JDtHrMS0DNYpllz2nRsTLGLKYttbpmw==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" + "@radix-ui/rect": "1.1.2" }, "peerDependencies": { "@types/react": "*", @@ -1529,42 +1465,14 @@ } } }, - "node_modules/@radix-ui/react-roving-focus": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", - "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.2.tgz", + "integrity": "sha512-giWQp+4mxjBPt4KZ0MmyuykFNWfbDxKt4x+fPkRYmgRFJSbCZFzUglvMb/Kjn38tm10YP4ufiQZDx3zna4LU6w==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@radix-ui/react-use-layout-effect": "1.1.2" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", - "license": "MIT", "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -1575,475 +1483,13 @@ } } }, - "node_modules/@radix-ui/react-roving-focus/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.7.tgz", + "integrity": "sha512-1wNZBggTDK3GRuuQ6nP4k2yi7a6l7I5qbMPbZcRsrGsGVead/f/d5FhEzUvqFs0bcrDLx7n1zKQ3JvLR6whaaw==", "license": "MIT", "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", - "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/number": "1.1.1", - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-visually-hidden": "1.2.3", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-separator": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.8.tgz", - "integrity": "sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", - "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", - "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-visually-hidden": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-callback-ref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", - "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", - "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-effect-event": "0.0.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-effect-event": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", - "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-escape-keydown": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", - "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-callback-ref": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-is-hydrated": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", - "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", - "license": "MIT", - "dependencies": { - "use-sync-external-store": "^1.5.0" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", - "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-previous": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", - "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-rect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", - "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", - "license": "MIT", - "dependencies": { - "@radix-ui/rect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-use-size": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", - "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-visually-hidden": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", - "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" + "@radix-ui/react-primitive": "2.1.7" }, "peerDependencies": { "@types/react": "*", @@ -2061,15 +1507,15 @@ } }, "node_modules/@radix-ui/rect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", - "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.2.tgz", + "integrity": "sha512-xnXE7wG13PI+cxieVssYXlQJuYVRhH9NBoxt3KNwzghDIA69GMm7d4wXRouHIYjE+KvS6U/MsMO73NdS2MH9ZA==", "license": "MIT" }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.2.tgz", + "integrity": "sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==", "cpu": [ "arm64" ], @@ -2083,9 +1529,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.2.tgz", + "integrity": "sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==", "cpu": [ "arm64" ], @@ -2099,9 +1545,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz", - "integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.2.tgz", + "integrity": "sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==", "cpu": [ "x64" ], @@ -2115,9 +1561,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz", - "integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.2.tgz", + "integrity": "sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==", "cpu": [ "x64" ], @@ -2131,9 +1577,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz", - "integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.2.tgz", + "integrity": "sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==", "cpu": [ "arm" ], @@ -2147,12 +1593,15 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.2.tgz", + "integrity": "sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2163,12 +1612,15 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz", - "integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.2.tgz", + "integrity": "sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2179,12 +1631,15 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.2.tgz", + "integrity": "sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==", "cpu": [ "ppc64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2195,12 +1650,15 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.2.tgz", + "integrity": "sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==", "cpu": [ "s390x" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2211,12 +1669,15 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz", - "integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.2.tgz", + "integrity": "sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==", "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2227,12 +1688,15 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz", - "integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.2.tgz", + "integrity": "sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2243,9 +1707,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz", - "integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.2.tgz", + "integrity": "sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==", "cpu": [ "arm64" ], @@ -2259,9 +1723,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz", - "integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.2.tgz", + "integrity": "sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==", "cpu": [ "wasm32" ], @@ -2277,9 +1741,9 @@ } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", - "integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.2.tgz", + "integrity": "sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==", "cpu": [ "arm64" ], @@ -2293,9 +1757,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz", - "integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.2.tgz", + "integrity": "sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==", "cpu": [ "x64" ], @@ -2309,9 +1773,9 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", - "integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "license": "MIT" }, "node_modules/@rollup/plugin-virtual": { @@ -2343,391 +1807,176 @@ "hast-util-to-html": "^9.0.5" } }, - "node_modules/@shikijs/langs": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.0.2.tgz", - "integrity": "sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "4.0.2" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@shikijs/langs/node_modules/@shikijs/types": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.2.tgz", - "integrity": "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==", - "license": "MIT", - "dependencies": { - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@shikijs/primitive": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.0.2.tgz", - "integrity": "sha512-M6UMPrSa3fN5ayeJwFVl9qWofl273wtK1VG8ySDZ1mQBfhCpdd8nEx7nPZ/tk7k+TYcpqBZzj/AnwxT9lO+HJw==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "4.0.2", - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@shikijs/primitive/node_modules/@shikijs/types": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.2.tgz", - "integrity": "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==", - "license": "MIT", - "dependencies": { - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@shikijs/themes": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.0.2.tgz", - "integrity": "sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "4.0.2" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@shikijs/themes/node_modules/@shikijs/types": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.2.tgz", - "integrity": "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==", + "node_modules/@shikijs/engine-javascript": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.3.0.tgz", + "integrity": "sha512-hTv/KiFf2tpiqlACPiztGGurEARWIutB8YUhcrA1pUC7VzzwKO+g5crUocrLztrZ5ro5Z4hbXg7bYclETn3gSQ==", "license": "MIT", "dependencies": { + "@shikijs/types": "4.3.0", "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4" + "oniguruma-to-es": "^4.3.6" }, "engines": { "node": ">=20" } }, - "node_modules/@shikijs/twoslash": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/twoslash/-/twoslash-3.23.0.tgz", - "integrity": "sha512-pNaLJWMA3LU7PhT8tm9OQBZ1epy0jmdgeJzntBtr1EVXLbHxGzTj3mnf9vOdcl84l96qnlJXkJ/NGXZYBpXl5g==", - "license": "MIT", - "dependencies": { - "@shikijs/core": "3.23.0", - "@shikijs/types": "3.23.0", - "twoslash": "^0.3.6" - }, - "peerDependencies": { - "typescript": ">=5.5.0" - } - }, - "node_modules/@shikijs/types": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.23.0.tgz", - "integrity": "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==", + "node_modules/@shikijs/engine-javascript/node_modules/@shikijs/types": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.3.0.tgz", + "integrity": "sha512-oc8b9U2SYvofKZk8e/737nIX0qwf6eV2vHFATeObAu7r+mUVpLs8Re0BmVkIjAWAYgkmG/CzLNo7rzuBzRu/wQ==", "license": "MIT", "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" - } - }, - "node_modules/@shikijs/vscode-textmate": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", - "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", - "license": "MIT" - }, - "node_modules/@swc/html-wasm": { - "version": "1.15.40", - "resolved": "https://registry.npmjs.org/@swc/html-wasm/-/html-wasm-1.15.40.tgz", - "integrity": "sha512-WbRp7vSPK9bAGwpP1U8+RDE/xw1yj6P8ZYVqzA/64nlnFuB4MrW92EdkHiKvTPdlFDUZUno8yJKRKcRkE/UK6Q==", - "license": "Apache-2.0" - }, - "node_modules/@tailwindcss/node": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.2.tgz", - "integrity": "sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==", - "license": "MIT", - "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "^5.19.0", - "jiti": "^2.6.1", - "lightningcss": "1.32.0", - "magic-string": "^0.30.21", - "source-map-js": "^1.2.1", - "tailwindcss": "4.2.2" - } - }, - "node_modules/@tailwindcss/node/node_modules/tailwindcss": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz", - "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==", - "license": "MIT" - }, - "node_modules/@tailwindcss/oxide": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.2.tgz", - "integrity": "sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==", - "license": "MIT", - "engines": { - "node": ">= 20" }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.2.2", - "@tailwindcss/oxide-darwin-arm64": "4.2.2", - "@tailwindcss/oxide-darwin-x64": "4.2.2", - "@tailwindcss/oxide-freebsd-x64": "4.2.2", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.2", - "@tailwindcss/oxide-linux-arm64-gnu": "4.2.2", - "@tailwindcss/oxide-linux-arm64-musl": "4.2.2", - "@tailwindcss/oxide-linux-x64-gnu": "4.2.2", - "@tailwindcss/oxide-linux-x64-musl": "4.2.2", - "@tailwindcss/oxide-wasm32-wasi": "4.2.2", - "@tailwindcss/oxide-win32-arm64-msvc": "4.2.2", - "@tailwindcss/oxide-win32-x64-msvc": "4.2.2" - } - }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.2.tgz", - "integrity": "sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.2.tgz", - "integrity": "sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.2.tgz", - "integrity": "sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.2.tgz", - "integrity": "sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], "engines": { - "node": ">= 20" + "node": ">=20" } }, - "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.2.tgz", - "integrity": "sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==", - "cpu": [ - "arm" - ], + "node_modules/@shikijs/engine-oniguruma": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.3.0.tgz", + "integrity": "sha512-1vMdN3gHfnKfLYwecUI2ITJI4RhHt96xEaJumVn7Heb0IlJ8WQMIH0Voak+2j22BpSNKdnOfB/pCTPnPm2gq7A==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@shikijs/types": "4.3.0", + "@shikijs/vscode-textmate": "^10.0.2" + }, "engines": { - "node": ">= 20" + "node": ">=20" } }, - "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.2.tgz", - "integrity": "sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==", - "cpu": [ - "arm64" - ], + "node_modules/@shikijs/engine-oniguruma/node_modules/@shikijs/types": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.3.0.tgz", + "integrity": "sha512-oc8b9U2SYvofKZk8e/737nIX0qwf6eV2vHFATeObAu7r+mUVpLs8Re0BmVkIjAWAYgkmG/CzLNo7rzuBzRu/wQ==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, "engines": { - "node": ">= 20" + "node": ">=20" } }, - "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.2.tgz", - "integrity": "sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==", - "cpu": [ - "arm64" - ], + "node_modules/@shikijs/langs": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.3.0.tgz", + "integrity": "sha512-rnlqFbBRSys9bT4gl/5rw9RnS0W/I84ZldXPkO7cvlEMoV85TyF/aU01N7/NbSR776RNLjrJKjfFUXJR6wN1Cg==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@shikijs/types": "4.3.0" + }, "engines": { - "node": ">= 20" + "node": ">=20" } }, - "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.2.tgz", - "integrity": "sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==", - "cpu": [ - "x64" - ], + "node_modules/@shikijs/langs/node_modules/@shikijs/types": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.3.0.tgz", + "integrity": "sha512-oc8b9U2SYvofKZk8e/737nIX0qwf6eV2vHFATeObAu7r+mUVpLs8Re0BmVkIjAWAYgkmG/CzLNo7rzuBzRu/wQ==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, "engines": { - "node": ">= 20" + "node": ">=20" } }, - "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.2.tgz", - "integrity": "sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==", - "cpu": [ - "x64" - ], + "node_modules/@shikijs/primitive": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.3.0.tgz", + "integrity": "sha512-CPkz64PTa5diRW1ggzMZH9VM/du4RNChYgVtgqrFcgruvIybmCvySv8GkiHSczUHXYuuR8TdKEwFx+UnZMpgdg==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@shikijs/types": "4.3.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, "engines": { - "node": ">= 20" + "node": ">=20" } }, - "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.2.tgz", - "integrity": "sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==", - "bundleDependencies": [ - "@napi-rs/wasm-runtime", - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util", - "@emnapi/wasi-threads", - "tslib" - ], - "cpu": [ - "wasm32" - ], + "node_modules/@shikijs/primitive/node_modules/@shikijs/types": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.3.0.tgz", + "integrity": "sha512-oc8b9U2SYvofKZk8e/737nIX0qwf6eV2vHFATeObAu7r+mUVpLs8Re0BmVkIjAWAYgkmG/CzLNo7rzuBzRu/wQ==", "license": "MIT", - "optional": true, "dependencies": { - "@emnapi/core": "^1.8.1", - "@emnapi/runtime": "^1.8.1", - "@emnapi/wasi-threads": "^1.1.0", - "@napi-rs/wasm-runtime": "^1.1.1", - "@tybys/wasm-util": "^0.10.1", - "tslib": "^2.8.1" + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" }, "engines": { - "node": ">=14.0.0" + "node": ">=20" } }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.2.tgz", - "integrity": "sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==", - "cpu": [ - "arm64" - ], + "node_modules/@shikijs/themes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.3.0.tgz", + "integrity": "sha512-Avgt05YiT+Y3prjIc9lmQxhJzHBcCfR6cjiFW4OyaMBbt2A6trX5rfjUzx+Vj/mE9qpArYjatnqo9XPjQNW/AQ==", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "@shikijs/types": "4.3.0" + }, "engines": { - "node": ">= 20" + "node": ">=20" } }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.2.tgz", - "integrity": "sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==", - "cpu": [ - "x64" - ], + "node_modules/@shikijs/themes/node_modules/@shikijs/types": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.3.0.tgz", + "integrity": "sha512-oc8b9U2SYvofKZk8e/737nIX0qwf6eV2vHFATeObAu7r+mUVpLs8Re0BmVkIjAWAYgkmG/CzLNo7rzuBzRu/wQ==", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, "engines": { - "node": ">= 20" + "node": ">=20" + } + }, + "node_modules/@shikijs/twoslash": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/twoslash/-/twoslash-3.23.0.tgz", + "integrity": "sha512-pNaLJWMA3LU7PhT8tm9OQBZ1epy0jmdgeJzntBtr1EVXLbHxGzTj3mnf9vOdcl84l96qnlJXkJ/NGXZYBpXl5g==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "3.23.0", + "@shikijs/types": "3.23.0", + "twoslash": "^0.3.6" + }, + "peerDependencies": { + "typescript": ">=5.5.0" } }, - "node_modules/@tailwindcss/postcss": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.2.2.tgz", - "integrity": "sha512-n4goKQbW8RVXIbNKRB/45LzyUqN451deQK0nzIeauVEqjlI49slUlgKYJM2QyUzap/PcpnS7kzSUmPb1sCRvYQ==", + "node_modules/@shikijs/types": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.23.0.tgz", + "integrity": "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==", "license": "MIT", "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/node": "4.2.2", - "@tailwindcss/oxide": "4.2.2", - "postcss": "^8.5.6", - "tailwindcss": "4.2.2" + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" } }, - "node_modules/@tailwindcss/postcss/node_modules/tailwindcss": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz", - "integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==", + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", "license": "MIT" }, + "node_modules/@swc/html-wasm": { + "version": "1.15.40", + "resolved": "https://registry.npmjs.org/@swc/html-wasm/-/html-wasm-1.15.40.tgz", + "integrity": "sha512-WbRp7vSPK9bAGwpP1U8+RDE/xw1yj6P8ZYVqzA/64nlnFuB4MrW92EdkHiKvTPdlFDUZUno8yJKRKcRkE/UK6Q==", + "license": "Apache-2.0" + }, "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", "license": "MIT", "optional": true, "dependencies": { @@ -2783,10 +2032,11 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -2894,43 +2144,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/aria-hidden": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", @@ -2962,36 +2175,12 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "license": "ISC" }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -3042,68 +2231,12 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "node_modules/classnames": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", "license": "MIT" }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, "node_modules/comma-separated-tokens": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", @@ -3139,23 +2272,12 @@ ], "license": "MIT" }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/csstype": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/debug": { "version": "4.4.3", @@ -3201,15 +2323,6 @@ } } }, - "node_modules/dependency-graph": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-1.0.0.tgz", - "integrity": "sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -3219,15 +2332,6 @@ "node": ">=6" } }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, "node_modules/detect-node-es": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", @@ -3247,25 +2351,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/enhanced-resolve": { - "version": "5.20.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", - "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.3.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/entities": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", @@ -3310,15 +2395,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/escape-string-regexp": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", @@ -3389,53 +2465,21 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs-extra": { - "version": "11.3.4", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", - "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "license": "ISC", + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, "node_modules/get-nonce": { @@ -3453,24 +2497,6 @@ "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", "license": "ISC" }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" - }, "node_modules/hast-util-from-parse5": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", @@ -3719,18 +2745,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-decimal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", @@ -3750,15 +2764,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -3781,15 +2786,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -3802,236 +2798,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, - "node_modules/jsonfile": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", - "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/lightningcss": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", - "cpu": [ - "arm" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", - "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", - "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, "node_modules/lightningcss-wasm": { "version": "1.32.0", "resolved": "https://registry.npmjs.org/lightningcss-wasm/-/lightningcss-wasm-1.32.0.tgz", @@ -4052,61 +2818,9 @@ } }, "node_modules/lightningcss-wasm/node_modules/napi-wasm": { - "version": "1.1.3", - "inBundle": true, - "license": "MIT" - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", - "cpu": [ - "x64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } + "version": "1.1.3", + "inBundle": true, + "license": "MIT" }, "node_modules/longest-streak": { "version": "3.1.0", @@ -4118,15 +2832,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, "node_modules/markdown-table": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", @@ -4291,6 +2996,23 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdast-util-mdx": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz", + "integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/mdast-util-mdx-expression": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", @@ -4644,6 +3366,108 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/micromark-extension-mdx-expression": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.1.tgz", + "integrity": "sha512-dD/ADLJ1AeMvSAKBwO22zG22N4ybhe7kFIZ3LsDI0GlsNr2A3KYxb0LdC1u5rj4Nw+CHKY0RVdnHX8vj8ejm4Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-mdx-jsx": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.2.tgz", + "integrity": "sha512-e5+q1DjMh62LZAJOnDraSSbDMvGJ8x3cbjygy2qFEi7HCeUT4BDKCvMozPozcD6WmOt6sVvYDNBKhFSz3kjOVQ==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "micromark-factory-mdx-expression": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdx-md": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz", + "integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz", + "integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==", + "license": "MIT", + "dependencies": { + "acorn": "^8.0.0", + "acorn-jsx": "^5.0.0", + "micromark-extension-mdx-expression": "^3.0.0", + "micromark-extension-mdx-jsx": "^3.0.0", + "micromark-extension-mdx-md": "^2.0.0", + "micromark-extension-mdxjs-esm": "^3.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-mdxjs-esm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz", + "integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/micromark-factory-destination": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", @@ -4687,6 +3511,33 @@ "micromark-util-types": "^2.0.0" } }, + "node_modules/micromark-factory-mdx-expression": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.3.tgz", + "integrity": "sha512-kQnEtA3vzucU2BkrIa8/VaSAsP+EJ3CKOvhMuJgOEGg9KDC6OAY6nSnNDVRiVNRqj7Y4SlSzcStaH/5jge8JdQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-events-to-acorn": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-position-from-estree": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, "node_modules/micromark-factory-space": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", @@ -4888,6 +3739,31 @@ ], "license": "MIT" }, + "node_modules/micromark-util-events-to-acorn": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.3.tgz", + "integrity": "sha512-jmsiEIiZ1n7X1Rr5k8wVExBQCg5jy4UXVADItHmNk1zkwEVhBuIUKRu3fqv+hs4nxLISi2DQGlqIOGiFxgbfHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/unist": "^3.0.0", + "devlop": "^1.0.0", + "estree-util-visit": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "vfile-message": "^4.0.0" + } + }, "node_modules/micromark-util-html-tag-name": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", @@ -5023,33 +3899,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -5063,258 +3912,87 @@ } }, "node_modules/oniguruma-parser": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz", - "integrity": "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==", - "license": "MIT" - }, - "node_modules/oniguruma-to-es": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.5.tgz", - "integrity": "sha512-Zjygswjpsewa0NLTsiizVuMQZbp0MDyM6lIt66OxsF21npUDlzpHi1Mgb/qhQdkb+dWFTzJmFbEWdvZgRho8eQ==", - "license": "MIT", - "dependencies": { - "oniguruma-parser": "^0.12.1", - "regex": "^6.1.0", - "regex-recursion": "^6.0.2" - } - }, - "node_modules/parse-entities": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", - "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", - "license": "MIT", - "dependencies": { - "@types/unist": "^2.0.0", - "character-entities-legacy": "^3.0.0", - "character-reference-invalid": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "is-alphanumerical": "^2.0.0", - "is-decimal": "^2.0.0", - "is-hexadecimal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/parse-entities/node_modules/@types/unist": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz", + "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==", "license": "MIT" }, - "node_modules/parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", - "license": "MIT", - "dependencies": { - "entities": "^6.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/piscina": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-5.2.0.tgz", - "integrity": "sha512-DszUCKeVN/5G5QKo6jAVHL8fmKnkJvQ0ACiVgY7YGCq3TUB2oznAOayvZPIAdEThvhczkXR+qm3IHsNXpFCYfA==", - "license": "MIT", - "engines": { - "node": ">=20.x" - }, - "optionalDependencies": { - "@napi-rs/nice": "^1.0.4" - } - }, - "node_modules/postcss": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", - "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-calc": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-10.1.1.tgz", - "integrity": "sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==", - "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^7.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^18.12 || ^20.9 || >=22.0" - }, - "peerDependencies": { - "postcss": "^8.4.38" - } - }, - "node_modules/postcss-cli": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-11.0.1.tgz", - "integrity": "sha512-0UnkNPSayHKRe/tc2YGW6XnSqqOA9eqpiRMgRlV1S6HdGi16vwJBx7lviARzbV1HpQHqLLRH3o8vTcB0cLc+5g==", + "node_modules/oniguruma-to-es": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.6.tgz", + "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==", "license": "MIT", "dependencies": { - "chokidar": "^3.3.0", - "dependency-graph": "^1.0.0", - "fs-extra": "^11.0.0", - "picocolors": "^1.0.0", - "postcss-load-config": "^5.0.0", - "postcss-reporter": "^7.0.0", - "pretty-hrtime": "^1.0.3", - "read-cache": "^1.0.0", - "slash": "^5.0.0", - "tinyglobby": "^0.2.12", - "yargs": "^17.0.0" - }, - "bin": { - "postcss": "index.js" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.0.0" + "oniguruma-parser": "^0.12.2", + "regex": "^6.1.0", + "regex-recursion": "^6.0.2" } }, - "node_modules/postcss-load-config": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-5.1.0.tgz", - "integrity": "sha512-G5AJ+IX0aD0dygOE0yFZQ/huFFMSNneyfp0e3/bT05a8OfPC5FUoZRPfGijUdGOJNMewJiwzcHJXFafFzeKFVA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", "license": "MIT", "dependencies": { - "lilconfig": "^3.1.1", - "yaml": "^2.4.2" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1" + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - } + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/postcss-reporter": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.1.0.tgz", - "integrity": "sha512-/eoEylGWyy6/DOiMP5lmFRdmDKThqgn7D6hP2dXKJI/0rJSO1ADFNngZfDzxL0YAxFvws+Rtpuji1YIHj4mySA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", "license": "MIT", "dependencies": { - "picocolors": "^1.0.0", - "thenby": "^1.3.4" + "entities": "^6.0.0" }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=12" }, - "peerDependencies": { - "postcss": "^8.1.0" + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/postcss-selector-parser": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", - "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "node_modules/piscina": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-5.2.0.tgz", + "integrity": "sha512-DszUCKeVN/5G5QKo6jAVHL8fmKnkJvQ0ACiVgY7YGCq3TUB2oznAOayvZPIAdEThvhczkXR+qm3IHsNXpFCYfA==", "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, "engines": { - "node": ">=4" + "node": ">=20.x" + }, + "optionalDependencies": { + "@napi-rs/nice": "^1.0.4" } }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "license": "MIT" - }, "node_modules/preact": { - "version": "10.29.1", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.1.tgz", - "integrity": "sha512-gQCLc/vWroE8lIpleXtdJhTFDogTdZG9AjMUpVkDf2iTCNwYNWA+u16dL41TqUDJO4gm2IgrcMv3uTpjd4Pwmg==", + "version": "10.29.3", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.3.tgz", + "integrity": "sha512-D9NL1GAnJZhc3RndVs4gDdxEeU9TcHgywMrhhOsnpdlvFjdbx0gAsLUnH6JEhlJH5giL7Tx5biWPUSEXE/HPzw==", "license": "MIT", "funding": { "type": "opencollective", @@ -5322,23 +4000,14 @@ } }, "node_modules/preact-render-to-string": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.6.7.tgz", - "integrity": "sha512-3XdbsX3+vn9dQW+jJI/FsI9rlkgl6dbeUpqLsChak6jp3j3auFqBCkno7VChbMFs5Q8ylBj6DrUkKRwtVN3nvw==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.7.0.tgz", + "integrity": "sha512-Z4WR8fmLMRpdYqJ9i7vrlXSsSrxVJydwrkEXHapexfARbWfGb7vGcnvNQnIzN0cXciMVOlz/XLoiMCi9gUsy9Q==", "license": "MIT", "peerDependencies": { "preact": ">=10 || >= 11.0.0-0" } }, - "node_modules/pretty-hrtime": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/prism-react-renderer": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-1.3.5.tgz", @@ -5359,25 +4028,25 @@ } }, "node_modules/react": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", - "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", + "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", - "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", + "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", "license": "MIT", "peer": true, "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.4" + "react": "^19.2.7" } }, "node_modules/react-markdown": { @@ -5476,27 +4145,6 @@ } } }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "license": "MIT", - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/reading-time": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", @@ -5642,6 +4290,20 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remark-mdx": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.1.1.tgz", + "integrity": "sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==", + "license": "MIT", + "dependencies": { + "mdast-util-mdx": "^3.0.0", + "micromark-extension-mdxjs": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/remark-parse": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", @@ -5690,23 +4352,14 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/rolldown": { - "version": "1.0.0-rc.17", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", - "integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.2.tgz", + "integrity": "sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==", "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.127.0", - "@rolldown/pluginutils": "1.0.0-rc.17" + "@oxc-project/types": "=0.132.0", + "@rolldown/pluginutils": "^1.0.0" }, "bin": { "rolldown": "bin/cli.mjs" @@ -5715,21 +4368,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.17", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.17", - "@rolldown/binding-darwin-x64": "1.0.0-rc.17", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.17", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.17", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.17", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.17", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" + "@rolldown/binding-android-arm64": "1.0.2", + "@rolldown/binding-darwin-arm64": "1.0.2", + "@rolldown/binding-darwin-x64": "1.0.2", + "@rolldown/binding-freebsd-x64": "1.0.2", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.2", + "@rolldown/binding-linux-arm64-gnu": "1.0.2", + "@rolldown/binding-linux-arm64-musl": "1.0.2", + "@rolldown/binding-linux-ppc64-gnu": "1.0.2", + "@rolldown/binding-linux-s390x-gnu": "1.0.2", + "@rolldown/binding-linux-x64-gnu": "1.0.2", + "@rolldown/binding-linux-x64-musl": "1.0.2", + "@rolldown/binding-openharmony-arm64": "1.0.2", + "@rolldown/binding-wasm32-wasi": "1.0.2", + "@rolldown/binding-win32-arm64-msvc": "1.0.2", + "@rolldown/binding-win32-x64-msvc": "1.0.2" } }, "node_modules/scheduler": { @@ -5752,17 +4405,17 @@ } }, "node_modules/shiki": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.0.2.tgz", - "integrity": "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.3.0.tgz", + "integrity": "sha512-NKKjWzR6LIGL3sXBrWDw9sDS9cxx42/DkysaNqJEeOWE8Kix5gpak0bc00OfDVEO4oyXSyz8+aRaqKoBD1yo7A==", "license": "MIT", "dependencies": { - "@shikijs/core": "4.0.2", - "@shikijs/engine-javascript": "4.0.2", - "@shikijs/engine-oniguruma": "4.0.2", - "@shikijs/langs": "4.0.2", - "@shikijs/themes": "4.0.2", - "@shikijs/types": "4.0.2", + "@shikijs/core": "4.3.0", + "@shikijs/engine-javascript": "4.3.0", + "@shikijs/engine-oniguruma": "4.3.0", + "@shikijs/langs": "4.3.0", + "@shikijs/themes": "4.3.0", + "@shikijs/types": "4.3.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" }, @@ -5771,13 +4424,13 @@ } }, "node_modules/shiki/node_modules/@shikijs/core": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.0.2.tgz", - "integrity": "sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.3.0.tgz", + "integrity": "sha512-EooU3i9F6IAE8kEu+AnGf9DFZWkQBZ+hJn3tLVbsH+61mtQiva5biai66fAA6nvFPXkLgvrh7BrR7YcJU83xQQ==", "license": "MIT", "dependencies": { - "@shikijs/primitive": "4.0.2", - "@shikijs/types": "4.0.2", + "@shikijs/primitive": "4.3.0", + "@shikijs/types": "4.3.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" @@ -5786,37 +4439,10 @@ "node": ">=20" } }, - "node_modules/shiki/node_modules/@shikijs/engine-javascript": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.0.2.tgz", - "integrity": "sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "4.0.2", - "@shikijs/vscode-textmate": "^10.0.2", - "oniguruma-to-es": "^4.3.4" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/shiki/node_modules/@shikijs/engine-oniguruma": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.0.2.tgz", - "integrity": "sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg==", - "license": "MIT", - "dependencies": { - "@shikijs/types": "4.0.2", - "@shikijs/vscode-textmate": "^10.0.2" - }, - "engines": { - "node": ">=20" - } - }, "node_modules/shiki/node_modules/@shikijs/types": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.2.tgz", - "integrity": "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.3.0.tgz", + "integrity": "sha512-oc8b9U2SYvofKZk8e/737nIX0qwf6eV2vHFATeObAu7r+mUVpLs8Re0BmVkIjAWAYgkmG/CzLNo7rzuBzRu/wQ==", "license": "MIT", "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", @@ -5826,18 +4452,6 @@ "node": ">=20" } }, - "node_modules/slash": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", - "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", - "license": "MIT", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/source-map": { "version": "0.7.6", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", @@ -5847,15 +4461,6 @@ "node": ">= 12" } }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/space-separated-tokens": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", @@ -5866,20 +4471,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/stringify-entities": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", @@ -5894,18 +4485,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/style-to-js": { "version": "1.1.21", "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", @@ -5924,31 +4503,6 @@ "inline-style-parser": "0.2.7" } }, - "node_modules/tailwindcss": { - "version": "4.1.18", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", - "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", - "license": "MIT" - }, - "node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/thenby": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/thenby/-/thenby-1.3.4.tgz", - "integrity": "sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ==", - "license": "Apache-2.0" - }, "node_modules/throttleit": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-2.1.0.tgz", @@ -5962,13 +4516,13 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -5977,47 +4531,6 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -6253,15 +4766,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/use-callback-ref": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", @@ -6305,21 +4809,6 @@ } } }, - "node_modules/use-sync-external-store": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", - "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", @@ -6372,32 +4861,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, "node_modules/yaml": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", @@ -6413,33 +4876,6 @@ "url": "https://github.com/sponsors/eemeli" } }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/tools/doc/package.json b/tools/doc/package.json index 42e9916b908571..9d59db21ef0e1a 100644 --- a/tools/doc/package.json +++ b/tools/doc/package.json @@ -2,6 +2,6 @@ "name": "doc", "private": true, "dependencies": { - "@node-core/doc-kit": "1.3.9" + "@node-core/doc-kit": "1.4.1" } } From 0854482671a7d487d066c205988c45a0673213e6 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Thu, 2 Jul 2026 12:39:18 +0200 Subject: [PATCH 078/131] doc: clarify defense-in-depth issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Matteo Collina PR-URL: https://github.com/nodejs/node/pull/64215 Reviewed-By: Ulises Gascón Reviewed-By: Michaël Zasso Reviewed-By: René Reviewed-By: Marco Ippolito Reviewed-By: Luigi Pinca Reviewed-By: Rafael Gonzaga Reviewed-By: Trivikram Kamat --- SECURITY.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/SECURITY.md b/SECURITY.md index e32ca8208adf87..4dde9920a4e161 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -276,6 +276,14 @@ the community they pose. ### Examples of non-vulnerabilities +#### Defense-in-depth issues + +* Bugs whose fixes would only improve resilience after another security + boundary has already failed, or reduce the impact of an issue outside the + Node.js threat model, are considered defense-in-depth issues. +* Defense-in-depth issues are never treated as Node.js security vulnerabilities, + do not receive CVEs, and are handled as regular bugs or hardening improvements. + #### Malicious Third-Party Modules (CWE-1357) * Code is trusted by Node.js. Therefore any scenario that requires a malicious From 2699fe470640e7b01da5658e84f654bcab2be5ed Mon Sep 17 00:00:00 2001 From: Marten Richter Date: Thu, 2 Jul 2026 16:39:30 +0200 Subject: [PATCH 079/131] quic: fixes undefined handle in QuicStream kInspect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the #handle is undefined and not QuicStream, while kInspect is called `DataViewPrototypeGetByteLength` will throw. Signed-off-by: Marten Richter PR-URL: https://github.com/nodejs/node/pull/64170 Reviewed-By: James M Snell Reviewed-By: Gürgün Dayıoğlu Reviewed-By: Tim Perry --- lib/internal/quic/state.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/internal/quic/state.js b/lib/internal/quic/state.js index 22763c1df31b68..8815b0bb4c32cf 100644 --- a/lib/internal/quic/state.js +++ b/lib/internal/quic/state.js @@ -933,7 +933,8 @@ class QuicStreamState { } [kInspect](depth, options) { - if (DataViewPrototypeGetByteLength(this.#handle) === 0) { + if (this.#handle === undefined || + DataViewPrototypeGetByteLength(this.#handle) === 0) { return 'QuicStreamState { }'; } From 92a3dc3191c083bbcf98d70dca828d1929112508 Mon Sep 17 00:00:00 2001 From: Martin Wagner Date: Thu, 2 Jul 2026 17:28:24 +0200 Subject: [PATCH 080/131] lib,permission: fix addon permission drop Signed-off-by: Martin PR-URL: https://github.com/nodejs/node/pull/64007 Reviewed-By: Rafael Gonzaga Reviewed-By: Edy Silva --- src/node_binding.cc | 3 ++ test/parallel/test-permission-drop-addons.js | 38 ++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 test/parallel/test-permission-drop-addons.js diff --git a/src/node_binding.cc b/src/node_binding.cc index db90d76853ac16..2286af2e3c424a 100644 --- a/src/node_binding.cc +++ b/src/node_binding.cc @@ -5,6 +5,7 @@ #include "node_errors.h" #include "node_external_reference.h" #include "node_url_pattern.h" +#include "permission/permission.h" #include "util.h" #include @@ -449,6 +450,8 @@ void DLOpen(const FunctionCallbackInfo& args) { return THROW_ERR_DLOPEN_DISABLED( env, "Cannot load native addon because loading addons is disabled."); } + THROW_IF_INSUFFICIENT_PERMISSIONS( + env, permission::PermissionScope::kAddon, ""); auto context = env->context(); diff --git a/test/parallel/test-permission-drop-addons.js b/test/parallel/test-permission-drop-addons.js new file mode 100644 index 00000000000000..baf87c3b95b858 --- /dev/null +++ b/test/parallel/test-permission-drop-addons.js @@ -0,0 +1,38 @@ +// Flags: --permission --allow-addons --allow-fs-read=* +'use strict'; + +const common = require('../common'); +const { isMainThread } = require('worker_threads'); + +if (!isMainThread) { + common.skip('This test only works on a main thread'); +} + +const assert = require('assert'); + +let bindingPath; +try { + bindingPath = require.resolve( + `../addons/hello-world/build/${common.buildType}/binding`); +} catch (err) { + if (err.code !== 'MODULE_NOT_FOUND') { + throw err; + } + common.skip('addon not found'); +} + +function openAddon() { + process.dlopen({ exports: {} }, bindingPath); +} + +assert.ok(process.permission.has('addon')); +openAddon(); + +process.permission.drop('addon'); +assert.ok(!process.permission.has('addon')); +assert.throws(() => { + openAddon(); +}, common.expectsError({ + code: 'ERR_ACCESS_DENIED', + permission: 'Addon', +})); From aeb539a383c1a40e9bc7ca3971be552393f95460 Mon Sep 17 00:00:00 2001 From: David Evans Date: Thu, 2 Jul 2026 16:28:39 +0100 Subject: [PATCH 081/131] http: fix drain event with cork/uncork When using cork() and uncork() with ServerResponse, the drain event was not reliably emitted after uncorking. This occurred because the uncork() method did not check if a drain was pending (kNeedDrain flag) after flushing the chunked buffer. This fix ensures that when uncork() successfully flushes buffered data and a drain was needed, the drain event is emitted immediately. This commit is a copy of PR #60437 (abandoned) with minor linting fixes. Fixes: https://github.com/nodejs/node/issues/60432 Signed-off-by: David Evans PR-URL: https://github.com/nodejs/node/pull/64038 Reviewed-By: Robert Nagy Reviewed-By: Matteo Collina Reviewed-By: Tim Perry --- lib/_http_outgoing.js | 6 ++ .../parallel/test-http-response-drain-cork.js | 64 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 test/parallel/test-http-response-drain-cork.js diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index b07cfc9b3419d9..085fbc139eb6dd 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -323,6 +323,12 @@ OutgoingMessage.prototype.uncork = function uncork() { this[kChunkedBuffer].length = 0; this[kChunkedLength] = 0; + + // If we had a pending drain and flushed all data, emit the drain event. + if (this[kNeedDrain] && this.writableLength === 0) { + this[kNeedDrain] = false; + this.emit('drain'); + } }; OutgoingMessage.prototype.setTimeout = function setTimeout(msecs, callback) { diff --git a/test/parallel/test-http-response-drain-cork.js b/test/parallel/test-http-response-drain-cork.js new file mode 100644 index 00000000000000..18678748b9c2a4 --- /dev/null +++ b/test/parallel/test-http-response-drain-cork.js @@ -0,0 +1,64 @@ +'use strict'; +const common = require('../common'); +const http = require('http'); +const assert = require('assert'); + +// Test that drain event is emitted correctly when using cork/uncork +// with ServerResponse and the write buffer is full + +const server = http.createServer(common.mustCall(async (req, res) => { + res.cork(); + + // Write small amount - won't need drain + assert.strictEqual(res.write('1'.repeat(10)), true); + + // Write enough to exceed highWaterMark (set in 'connection' listener) + assert.strictEqual(res.write('2'.repeat(1000)), false); + + // Verify writableNeedDrain is set + assert.strictEqual(res.writableNeedDrain, true); + + // Wait for drain event after uncorking + const drainPromise = new Promise((resolve) => { + res.once('drain', common.mustCall(() => { + // After drain, writableNeedDrain should be false + assert.strictEqual(res.writableNeedDrain, false); + resolve(); + })); + }); + + // Uncork should trigger drain + res.uncork(); + await drainPromise; + + res.end(); +})); + +server.on('connection', common.mustCall((socket) => { + // Set high water mark large enough to cover HTTP overhead + first + // small content batch, but not enough to cover second batch. + socket._writableState.highWaterMark = 1000; +})); + +server.listen(0, common.localhostIPv4, common.mustCall(() => { + http.get({ + host: common.localhostIPv4, + port: server.address().port, + }, common.mustCall((res) => { + let data = ''; + res.setEncoding('utf8'); + + res.on('data', (chunk) => { + data += chunk; + }); + + res.on('end', common.mustCall(() => { + // Verify we got all the data + assert.strictEqual(data.length, 10 + 1000); + assert.strictEqual(data.substring(0, 10), '1'.repeat(10)); + assert.strictEqual(data.substring(10), '2'.repeat(1000)); + + server.close(common.mustCall()); + })); + })); +})); From 322230d6414de5fc0db65032ab220c9a03041e0c Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Thu, 2 Jul 2026 08:28:55 -0700 Subject: [PATCH 082/131] vfs: support writeFileSync with virtual fds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Route fs.writeFileSync() and fs.appendFileSync() calls with VFS-owned file descriptors through the virtual file handle instead of falling back to the native fs binding. This preserves descriptor semantics for both memory-backed VFS files and RealFSProvider handles. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.5 PR-URL: https://github.com/nodejs/node/pull/64165 Fixes: https://github.com/nodejs/node/issues/64164 Reviewed-By: Matteo Collina Reviewed-By: Gürgün Dayıoğlu Reviewed-By: James M Snell --- lib/internal/vfs/setup.js | 38 ++++++++++++-- test/parallel/test-vfs-fs-writeFileSync.js | 59 ++++++++++++++++++++++ 2 files changed, 93 insertions(+), 4 deletions(-) diff --git a/lib/internal/vfs/setup.js b/lib/internal/vfs/setup.js index fe06f578b2f6ca..e2e641ad841561 100644 --- a/lib/internal/vfs/setup.js +++ b/lib/internal/vfs/setup.js @@ -9,6 +9,7 @@ const { } = primordials; const { Buffer } = require('buffer'); +const { isArrayBufferView } = require('internal/util/types'); const { resolve, sep } = require('path'); const { fileURLToPath, URL } = require('internal/url'); const { kEmptyObject } = require('internal/util'); @@ -46,6 +47,31 @@ function noopFd(fd) { return undefined; } +function toWriteBuffer(data, options) { + if (Buffer.isBuffer(data)) return data; + if (isArrayBufferView(data)) { + return Buffer.from(data.buffer, data.byteOffset, data.byteLength); + } + const encoding = typeof options === 'string' ? options : options?.encoding; + return Buffer.from(data, encoding || 'utf8'); +} + +function writeFileSyncFd(fd, data, options) { + const vfd = getVirtualFd(fd); + if (vfd === undefined) return undefined; + + const buffer = toWriteBuffer(data, options); + let offset = 0; + let length = buffer.byteLength; + while (length > 0) { + const written = vfd.entry.writeSync(buffer, offset, length, null); + offset += written; + length -= written; + } + + return true; +} + // Registry of active VFS instances. const activeVFSList = []; @@ -288,10 +314,14 @@ function createVfsHandlers() { // ==================== Sync path-based write ops ==================== - writeFileSync: (path, data, options) => - vfsOpVoid(path, (vfs, n) => vfs.writeFileSync(n, data, options)), - appendFileSync: (path, data, options) => - vfsOpVoid(path, (vfs, n) => vfs.appendFileSync(n, data, options)), + writeFileSync(path, data, options) { + if (typeof path === 'number') return writeFileSyncFd(path, data, options); + return vfsOpVoid(path, (vfs, n) => vfs.writeFileSync(n, data, options)); + }, + appendFileSync(path, data, options) { + if (typeof path === 'number') return writeFileSyncFd(path, data, options); + return vfsOpVoid(path, (vfs, n) => vfs.appendFileSync(n, data, options)); + }, mkdirSync: (path, options) => vfsOp(path, (vfs, n) => ({ result: vfs.mkdirSync(n, options) })), rmdirSync: (path) => vfsOpVoid(path, (vfs, n) => vfs.rmdirSync(n)), diff --git a/test/parallel/test-vfs-fs-writeFileSync.js b/test/parallel/test-vfs-fs-writeFileSync.js index 7469127bb1fde3..eeed2a685f08e3 100644 --- a/test/parallel/test-vfs-fs-writeFileSync.js +++ b/test/parallel/test-vfs-fs-writeFileSync.js @@ -26,4 +26,63 @@ assert.strictEqual(fs.readFileSync(target, 'utf8'), 'fresh more'); fs.writeFileSync(target, Buffer.from('binary')); assert.strictEqual(fs.readFileSync(target, 'utf8'), 'binary'); +// writeFileSync via a VFS fd writes through the open descriptor. +{ + const fdTarget = path.join(mountPoint, 'src/fd.txt'); + const fd = fs.openSync(fdTarget, 'w+'); + try { + fs.writeFileSync(fd, 'hello'); + fs.writeFileSync(fd, new Uint8Array(Buffer.from(' world'))); + assert.strictEqual(fs.readFileSync(fdTarget, 'utf8'), 'hello world'); + } finally { + fs.closeSync(fd); + } +} + +// appendFileSync via a VFS fd follows normal fd write semantics. +{ + const fdTarget = path.join(mountPoint, 'src/append-fd.txt'); + fs.writeFileSync(fdTarget, 'start'); + const fd = fs.openSync(fdTarget, 'a'); + try { + fs.appendFileSync(fd, ' end'); + assert.strictEqual(fs.readFileSync(fdTarget, 'utf8'), 'start end'); + } finally { + fs.closeSync(fd); + } +} + myVfs.unmount(); + +// writeFileSync via a RealFSProvider fd remains tied to the open descriptor +// after the backing path is renamed. +{ + const root = path.join('/tmp', 'vfs-real-writeFileSync-' + process.pid); + const realMountPoint = path.join('/tmp', 'vfs-real-writeFileSync-mount-' + process.pid); + fs.rmSync(root, { recursive: true, force: true }); + fs.rmSync(realMountPoint, { recursive: true, force: true }); + fs.mkdirSync(root, { recursive: true }); + fs.mkdirSync(realMountPoint, { recursive: true }); + + const realVfs = vfs + .create(new vfs.RealFSProvider(root), { emitExperimentalWarning: false }) + .mount(realMountPoint); + try { + const mountedFile = path.join(realMountPoint, 'a.txt'); + fs.writeFileSync(path.join(root, 'a.txt'), 'old'); + const fd = fs.openSync(mountedFile, 'r+'); + try { + fs.renameSync(path.join(root, 'a.txt'), path.join(root, 'b.txt')); + fs.writeFileSync(path.join(root, 'a.txt'), 'new'); + fs.writeFileSync(fd, 'updated'); + assert.strictEqual(fs.readFileSync(path.join(root, 'b.txt'), 'utf8'), 'updated'); + assert.strictEqual(fs.readFileSync(path.join(root, 'a.txt'), 'utf8'), 'new'); + } finally { + fs.closeSync(fd); + } + } finally { + realVfs.unmount(); + fs.rmSync(root, { recursive: true, force: true }); + fs.rmSync(realMountPoint, { recursive: true, force: true }); + } +} From 87648c0a6c5f6669c82876cdb80f9f7ca2f71f5f Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Thu, 2 Jul 2026 17:29:07 +0200 Subject: [PATCH 083/131] benchmark: trim down the argon2 sets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Filip Skokan PR-URL: https://github.com/nodejs/node/pull/64218 Reviewed-By: Luigi Pinca Reviewed-By: Vinícius Lourenço Claro Cardoso Reviewed-By: Yagiz Nizipli --- benchmark/crypto/argon2.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/benchmark/crypto/argon2.js b/benchmark/crypto/argon2.js index ce6a824233e636..c11d5837954a05 100644 --- a/benchmark/crypto/argon2.js +++ b/benchmark/crypto/argon2.js @@ -17,10 +17,12 @@ if (!hasOpenSSL(3, 2)) { const bench = common.createBenchmark(main, { mode: ['sync', 'async'], algorithm: ['argon2d', 'argon2i', 'argon2id'], - passes: [1, 3], - parallelism: [2, 4, 8], - memory: [2 ** 11, 2 ** 16, 2 ** 21], - n: [50], + passes: [3], + parallelism: [1], + // Argon2 memory cost dominates runtime. Keep the default suite small enough + // to finish while still covering a low-cost and a memory-heavy derivation. + memory: [2 ** 11, 2 ** 16], + n: [5], }); function measureSync(n, algorithm, message, nonce, options) { From 7f26c54aa6fbacfbe2e0ae56b6e058f5be335e65 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Thu, 2 Jul 2026 18:57:42 +0200 Subject: [PATCH 084/131] child_process: fix permission model propagation via NODE_OPTIONS The substring check env[key].indexOf(--permission) !== -1 in copyPermissionModelFlagsToEnv falsely treats unrelated NODE_OPTIONS values like --title=--permission as if the child already has an explicit Permission Model policy. This prevents flag propagation, causing the child to run without process.permission. Signed-off-by: Matteo Collina PR-URL: https://github.com/nodejs/node/pull/63972 Reviewed-By: Rafael Gonzaga Reviewed-By: Paolo Insogna --- lib/child_process.js | 18 +++- ...n-child-process-inherit-flags-substring.js | 96 +++++++++++++++++++ 2 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 test/parallel/test-permission-child-process-inherit-flags-substring.js diff --git a/lib/child_process.js b/lib/child_process.js index 824af65556e32b..0e3e04af0d6e32 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -547,10 +547,26 @@ function getPermissionModelFlagsToCopy() { return permissionModelFlagsToCopy; } +function hasPermissionFlagInEnv(nodeOptions) { + // Parse NODE_OPTIONS into individual tokens and check if any token + // is an actual --permission or --permission-audit flag. We use exact + // token matching rather than substring matching to avoid false positives + // when unrelated option values contain '--permission' (e.g., + // --title=--permission). + if (!nodeOptions) return false; + const tokens = nodeOptions.split(/\s+/); + return tokens.some((token) => + token === '--permission' || + token.startsWith('--permission=') || + token === '--permission-audit' || + token.startsWith('--permission-audit='), + ); +} + function copyPermissionModelFlagsToEnv(env, key, args) { // Do not override if permission was already passed to file if (args.includes('--permission') || args.includes('--permission-audit') || - (env[key] && env[key].indexOf('--permission') !== -1)) { + hasPermissionFlagInEnv(env[key])) { return; } diff --git a/test/parallel/test-permission-child-process-inherit-flags-substring.js b/test/parallel/test-permission-child-process-inherit-flags-substring.js new file mode 100644 index 00000000000000..f992a1f3dc8f3b --- /dev/null +++ b/test/parallel/test-permission-child-process-inherit-flags-substring.js @@ -0,0 +1,96 @@ +// Flags: --permission --allow-child-process --allow-fs-read=* --allow-worker +// Tests that NODE_OPTIONS values containing '--permission' as a substring +// in unrelated option values (e.g., --title=--permission) do NOT suppress +// Permission Model flag propagation to child processes. +'use strict'; + +const common = require('../common'); +const { isMainThread } = require('worker_threads'); + +if (!isMainThread) { + common.skip('This test only works on a main thread'); +} +if (process.config.variables.node_without_node_options) { + common.skip('missing NODE_OPTIONS support'); +} + +const assert = require('assert'); +const childProcess = require('child_process'); + +// Verify that the parent has Permission Model enabled +assert.ok(process.permission.has('child')); +assert.strictEqual(process.env.NODE_OPTIONS, undefined); + +// Test cases: NODE_OPTIONS values that contain '--permission' as a substring +// but are NOT actual permission flags. These should NOT suppress propagation. +const testCases = [ + { name: 'title', nodeOptions: '--title=--permission' }, + { name: 'conditions', nodeOptions: '--conditions=--permission' }, + { name: 'trace-event-categories', nodeOptions: '--trace-event-categories=--permission' }, + { name: 'title-audit', nodeOptions: '--title=--permission-audit' }, +]; + +for (const { name, nodeOptions } of testCases) { + // Spawn a child with the problematic NODE_OPTIONS value. + // Without the fix, the substring check causes propagation to be skipped, + // and the child will not have process.permission. + const { status, stdout } = childProcess.spawnSync( + process.execPath, + [ + '-e', + ` + console.log(typeof process.permission); + console.log(process.permission && process.permission.has("child")); + console.log(process.env.NODE_OPTIONS); + `, + ], + { + env: { + ...process.env, + 'NODE_OPTIONS': nodeOptions, + } + } + ); + + assert.strictEqual(status, 0, `child process for ${name} exited with status ${status}`); + + const [permType, hasChild] = stdout.toString().split('\n'); + + // Verify the child has Permission Model enabled (the bug caused it to be absent) + assert.strictEqual(permType, 'object', `child ${name} should have process.permission object`); + + // Verify the child inherited child permission + assert.strictEqual(hasChild, 'true', `child ${name} should have child permission`); +} + +// Also verify that a child with a real --permission flag in NODE_OPTIONS +// still gets its own flags honored (regression test for existing behavior). +{ + const { status, stdout } = childProcess.spawnSync( + process.execPath, + [ + '-e', + ` + console.log(process.permission.has("fs.write")); + console.log(process.permission.has("fs.read")); + console.log(process.permission.has("child")); + `, + ], + { + env: { + ...process.env, + 'NODE_OPTIONS': '--permission --allow-fs-write=*', + } + } + ); + + assert.strictEqual(status, 0); + const [fsWrite, fsRead, child] = stdout.toString().split('\n'); + assert.strictEqual(fsWrite, 'true'); + assert.strictEqual(fsRead, 'false'); + assert.strictEqual(child, 'false'); +} + +{ + assert.strictEqual(process.env.NODE_OPTIONS, undefined); +} From 48c5c86363e6905b4dca0520da55e01e4b9213b1 Mon Sep 17 00:00:00 2001 From: Chengzhong Wu Date: Thu, 2 Jul 2026 15:21:02 -0400 Subject: [PATCH 085/131] module: enable import support for addons by default Signed-off-by: Chengzhong Wu PR-URL: https://github.com/nodejs/node/pull/64221 Reviewed-By: Marco Ippolito Reviewed-By: Edy Silva Reviewed-By: Joyee Cheung --- doc/api/cli.md | 6 +++++- src/node_options.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/doc/api/cli.md b/doc/api/cli.md index e5d653337a870c..eeaa97daded0c3 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -1039,9 +1039,13 @@ It is possible to run code containing inline types unless the added: - v23.6.0 - v22.20.0 +changes: + - version: REPLACEME + pr-url: https://github.com/nodejs/node/pull/64221 + description: This is enabled by default. --> -> Stability: 1.0 - Early development +> Stability: 1.2 - Release candidate Enable experimental import support for `.node` addons. diff --git a/src/node_options.h b/src/node_options.h index f2f87289c25200..5b740b5ae6b838 100644 --- a/src/node_options.h +++ b/src/node_options.h @@ -126,7 +126,7 @@ class EnvironmentOptions : public Options { bool require_module = true; std::string dns_result_order; bool enable_source_maps = false; - bool experimental_addon_modules = EXPERIMENTALS_DEFAULT_VALUE; + bool experimental_addon_modules = true; bool experimental_eventsource = EXPERIMENTALS_DEFAULT_VALUE; bool experimental_ffi = EXPERIMENTALS_DEFAULT_VALUE; bool experimental_websocket = true; From 12a2b9daa3912da3af54aa95851b2790a9c2a8e8 Mon Sep 17 00:00:00 2001 From: Hamid Reza Ghavami <161077982+hamidrezaghavami@users.noreply.github.com> Date: Fri, 3 Jul 2026 09:45:29 +0300 Subject: [PATCH 086/131] doc: fix typo in node-config-schema.json MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Hamid Reza Ghavami PR-URL: https://github.com/nodejs/node/pull/64188 Reviewed-By: Marco Ippolito Reviewed-By: René Reviewed-By: Daijiro Wachi Reviewed-By: Luigi Pinca --- doc/node-config-schema.json | 2 +- src/node_options.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/node-config-schema.json b/doc/node-config-schema.json index a78031061dca87..414943e571d839 100644 --- a/doc/node-config-schema.json +++ b/doc/node-config-schema.json @@ -242,7 +242,7 @@ }, "experimental-print-required-tla": { "type": "boolean", - "description": "Print pending top-level await. If --require-module is true, evaluate asynchronous graphs loaded by `require()` but do not run the microtasks, in order to to find and print top-level await in the graph" + "description": "Print pending top-level await. If --require-module is true, evaluate asynchronous graphs loaded by `require()` but do not run the microtasks, in order to find and print top-level await in the graph" }, "experimental-repl-await": { "type": "boolean", diff --git a/src/node_options.cc b/src/node_options.cc index a4422ac9c00e14..b0ddfb9eb91186 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -524,7 +524,7 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { AddOption("--experimental-print-required-tla", "Print pending top-level await. If --require-module " "is true, evaluate asynchronous graphs loaded by `require()` but " - "do not run the microtasks, in order to to find and print " + "do not run the microtasks, in order to find and print " "top-level await in the graph", &EnvironmentOptions::print_required_tla, kAllowedInEnvvar); From f49704b9d0d656cdadc0fba24c100ac1827248a6 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Fri, 3 Jul 2026 10:56:47 +0200 Subject: [PATCH 087/131] meta: clarify V8 flags are outside threat model Signed-off-by: Matteo Collina Co-authored-by: Chengzhong Wu PR-URL: https://github.com/nodejs/node/pull/64224 Reviewed-By: Paolo Insogna Reviewed-By: Filip Skokan Reviewed-By: Marco Ippolito Reviewed-By: Chengzhong Wu Reviewed-By: Antoine du Hamel Reviewed-By: Luigi Pinca --- SECURITY.md | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 4dde9920a4e161..f5cee908d0b881 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -124,23 +124,32 @@ This policy recognizes that experimental platforms may not compile, may not pass the test suite, and do not have the same level of testing and support infrastructure as Tier 1 and Tier 2 platforms. -### Experimental features behind compile-time flags +### Experimental features behind compile-time flags and V8 flags Node.js includes certain experimental features that are only available when Node.js is compiled with specific flags. These features are intended for development, debugging, or testing purposes and are not enabled in official releases. +Node.js may also expose V8 features that are controlled by V8 command-line flags +(e.g., `--js-staging`, `--max_old_space_size`). These flags +enable or modify V8-level JavaScript engine behavior that is not part of the +ECMAScript specification that Node.js implements and is not part of the +Node.js documented API surface. + * Security vulnerabilities that only affect features behind compile-time flags - will **not** be accepted as valid security issues. + or V8 flags will **not** be accepted as valid security issues. * Any issues with these features will be treated as normal bugs. -* No CVEs will be issued for issues that only affect compile-time flag features. -* Bug bounty rewards are not available for compile-time flag feature issues. +* No CVEs will be issued for issues that only affect compile-time flag or V8 flag features. +* Bug bounty rewards are not available for compile-time flag or V8 flag feature issues. This policy recognizes that experimental features behind compile-time flags are not ready for public consumption and may have incomplete implementations, missing security hardening, or other limitations that make them unsuitable -for production use. +for production use. Similarly, V8 flags expose internal V8 engine options that +are not part of the Node.js documented API surface, are not enabled by +default in production builds, and may have incomplete implementations or +missing security hardening. ### What constitutes a vulnerability From eacfbd0ca5309dca478e728c9e03478c31c84a32 Mon Sep 17 00:00:00 2001 From: Archkon <180910180+Archkon@users.noreply.github.com> Date: Fri, 3 Jul 2026 20:34:27 +0800 Subject: [PATCH 088/131] http: add CONNECT method handling for default Host header with proxy Signed-off-by: Archkon <180910180+Archkon@users.noreply.github.com> PR-URL: https://github.com/nodejs/node/pull/64114 Fixes: https://github.com/nodejs/node/issues/63945 Reviewed-By: Matteo Collina Reviewed-By: Tim Perry --- lib/_http_client.js | 4 +- .../test-http-connect-default-host-header.js | 37 +++++++++++++++++++ test/parallel/test-tls-over-http-tunnel.js | 2 +- 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 test/parallel/test-http-connect-default-host-header.js diff --git a/lib/_http_client.js b/lib/_http_client.js index e6bd38aa35ac9d..891da4e3f9a984 100644 --- a/lib/_http_client.js +++ b/lib/_http_client.js @@ -526,7 +526,9 @@ function ClientRequest(input, options, cb) { const userHostHeader = this.getHeader('host'); if (host && !this.getHeader('host') && setHost) { - this.setHeader('Host', hostHeaderFromOptions); + const hostHeader = method === 'CONNECT' && options.path ? + String(this.path) : hostHeaderFromOptions; + this.setHeader('Host', hostHeader); } if (options.auth && !this.getHeader('Authorization')) { diff --git a/test/parallel/test-http-connect-default-host-header.js b/test/parallel/test-http-connect-default-host-header.js new file mode 100644 index 00000000000000..9522f028f5165b --- /dev/null +++ b/test/parallel/test-http-connect-default-host-header.js @@ -0,0 +1,37 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const http = require('http'); +const net = require('net'); + +const target = 'target.example.com:443'; + +const server = net.createServer(common.mustCall((socket) => { + socket.once('data', common.mustCall((data) => { + const rawRequest = data.toString(); + const requestLines = rawRequest.split('\r\n'); + + assert.strictEqual(requestLines[0], `CONNECT ${target} HTTP/1.1`); + assert(requestLines.includes(`Host: ${target}`)); + + socket.end('HTTP/1.1 200 Connection established\r\n\r\n'); + })); +})); + +server.listen(0, common.localhostIPv4, common.mustCall(() => { + const req = http.request({ + host: common.localhostIPv4, + port: server.address().port, + method: 'CONNECT', + path: target, + }, common.mustNotCall()); + + req.on('connect', common.mustCall((res, socket) => { + assert.strictEqual(res.statusCode, 200); + socket.destroy(); + server.close(); + })); + + req.end(); +})); diff --git a/test/parallel/test-tls-over-http-tunnel.js b/test/parallel/test-tls-over-http-tunnel.js index baef7a56f6884a..e16400d06aece9 100644 --- a/test/parallel/test-tls-over-http-tunnel.js +++ b/test/parallel/test-tls-over-http-tunnel.js @@ -61,7 +61,7 @@ const proxy = net.createServer(common.mustCall((clientSocket) => { `CONNECT localhost:${server.address().port} ` + 'HTTP/1.1\r\n' + 'Proxy-Connections: keep-alive\r\n' + - `Host: localhost:${proxy.address().port}\r\n` + + `Host: localhost:${server.address().port}\r\n` + 'Connection: keep-alive\r\n\r\n'); console.log('PROXY: got CONNECT request'); From 34a537c0edfc36949fb3b4d7168e3589f52c5570 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Fri, 3 Jul 2026 20:25:34 +0200 Subject: [PATCH 089/131] lib: use `__proto__: null` when calling `ObjectDefineProperty` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Antoine du Hamel PR-URL: https://github.com/nodejs/node/pull/64239 Reviewed-By: Jordan Harband Reviewed-By: René --- lib/internal/debugger/inspect_repl.js | 20 ++++++++++++-------- lib/internal/http2/core.js | 1 + lib/internal/per_context/domexception.js | 2 +- lib/internal/test_runner/mock/mock.js | 17 +++++++++++------ lib/internal/test_runner/mock/mock_timers.js | 5 +++-- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/lib/internal/debugger/inspect_repl.js b/lib/internal/debugger/inspect_repl.js index 87388b41a47b2c..548df089fb14e2 100644 --- a/lib/internal/debugger/inspect_repl.js +++ b/lib/internal/debugger/inspect_repl.js @@ -19,15 +19,17 @@ const { JSONStringify, MathMax, ObjectAssign, + ObjectDefineProperties, ObjectDefineProperty, + ObjectGetOwnPropertyDescriptors, ObjectKeys, + ObjectSetPrototypeOf, ObjectValues, Promise, PromisePrototypeThen, PromiseResolve, PromiseWithResolvers, ReflectGetOwnPropertyDescriptor, - ReflectOwnKeys, RegExpPrototypeExec, SafeMap, SafePromiseAllReturnArrayLike, @@ -347,18 +349,20 @@ class ScopeSnapshot { } function copyOwnProperties(target, source) { - ArrayPrototypeForEach( - ReflectOwnKeys(source), - (prop) => { - const desc = ReflectGetOwnPropertyDescriptor(source, prop); - ObjectDefineProperty(target, prop, desc); - }); + const descriptors = ObjectGetOwnPropertyDescriptors(source); + + const descValues = ObjectValues(descriptors); + for (let i = 0; i < descValues.length; ++i) { + ObjectSetPrototypeOf(descValues[i], null); + } + + ObjectDefineProperties(target, descriptors); } function aliasProperties(target, mapping) { ArrayPrototypeForEach(ObjectKeys(mapping), (key) => { const desc = ReflectGetOwnPropertyDescriptor(target, key); - ObjectDefineProperty(target, mapping[key], desc); + ObjectDefineProperty(target, mapping[key], { __proto__: null, ...desc }); }); } diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index ce8940edf0a5e4..d322839dd4df46 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -3246,6 +3246,7 @@ function handleHeaderContinue(headers) { } const setTimeoutValue = { + __proto__: null, configurable: true, enumerable: true, writable: true, diff --git a/lib/internal/per_context/domexception.js b/lib/internal/per_context/domexception.js index 05a2002a399043..67def5017ed626 100644 --- a/lib/internal/per_context/domexception.js +++ b/lib/internal/per_context/domexception.js @@ -199,7 +199,7 @@ for (const { 0: name, 1: codeName, 2: value } of [ // There are some more error names, but since they don't have codes assigned, // we don't need to care about them. ]) { - const desc = { enumerable: true, value }; + const desc = { __proto__: null, enumerable: true, value }; ObjectDefineProperty(DOMException, codeName, desc); ObjectDefineProperty(DOMExceptionPrototype, codeName, desc); nameToCodeMap.set(name, value); diff --git a/lib/internal/test_runner/mock/mock.js b/lib/internal/test_runner/mock/mock.js index d15ace222b2132..970356bcae3aa0 100644 --- a/lib/internal/test_runner/mock/mock.js +++ b/lib/internal/test_runner/mock/mock.js @@ -7,10 +7,14 @@ const { FunctionPrototypeBind, FunctionPrototypeCall, ObjectAssign, + ObjectDefineProperties, ObjectDefineProperty, ObjectGetOwnPropertyDescriptor, + ObjectGetOwnPropertyDescriptors, ObjectGetPrototypeOf, ObjectKeys, + ObjectSetPrototypeOf, + ObjectValues, Proxy, ReflectApply, ReflectConstruct, @@ -146,7 +150,7 @@ class MockFunctionContext { if (typeof methodName === 'string') { // This is an object method spy. - ObjectDefineProperty(object, methodName, descriptor); + ObjectDefineProperty(object, methodName, { __proto__: null, ...descriptor }); } else { // This is a bare function spy. There isn't much to do here but make // the mock call the original function. @@ -880,13 +884,14 @@ function normalizeModuleMockOptions(options) { function copyOwnProperties(from, to) { - const keys = ObjectKeys(from); + const descriptors = ObjectGetOwnPropertyDescriptors(from); - for (let i = 0; i < keys.length; ++i) { - const key = keys[i]; - const descriptor = ObjectGetOwnPropertyDescriptor(from, key); - ObjectDefineProperty(to, key, descriptor); + const descValues = ObjectValues(descriptors); + for (let i = 0; i < descValues.length; ++i) { + ObjectSetPrototypeOf(descValues[i], null); } + + ObjectDefineProperties(to, descriptors); } function setupSharedModuleState() { diff --git a/lib/internal/test_runner/mock/mock_timers.js b/lib/internal/test_runner/mock/mock_timers.js index 57f68fc290da6b..77c54aee815362 100644 --- a/lib/internal/test_runner/mock/mock_timers.js +++ b/lib/internal/test_runner/mock/mock_timers.js @@ -12,6 +12,7 @@ const { ObjectDefineProperty, ObjectGetOwnPropertyDescriptor, ObjectGetOwnPropertyDescriptors, + ObjectSetPrototypeOf, PromiseWithResolvers, ReflectApply, Symbol, @@ -325,7 +326,7 @@ class MockTimers { } #restoreOriginalAbortSignalTimeout() { - ObjectDefineProperty(AbortSignal, 'timeout', this.#realAbortSignalTimeout); + ObjectDefineProperty(AbortSignal, 'timeout', ObjectSetPrototypeOf(this.#realAbortSignalTimeout, null)); } #createTimer(isInterval, callback, delay, ...args) { @@ -633,7 +634,7 @@ class MockTimers { ); }, 'Date': () => { - this.#nativeDateDescriptor = ObjectGetOwnPropertyDescriptor(globalThis, 'Date'); + this.#nativeDateDescriptor = ObjectSetPrototypeOf(ObjectGetOwnPropertyDescriptor(globalThis, 'Date'), null); globalThis.Date = this.#createDate(); }, 'AbortSignal.timeout': () => { From 0cd443df3966fdf9d0b68f724b6316bc17d7d9b5 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Thu, 2 Jul 2026 11:42:32 +0200 Subject: [PATCH 090/131] esm: print required top-level await locations without evaluating Previously in order to collect the locations of the TLA, we wait until right before evalutation to ensure instantiation is completed so that we can use v8::Module::GetStalledTopLevelAwaitMessages(). Now we try to add an additioanl shortcut to the source code in the module wraps instead during compilation for modules that contain TLAs and use acron to locate the TLAs when we need to throw ERR_REQUIRE_AYNSC_MODULE, so we can do this as early as before instantiation and do not need to run the module again to collect the locations. In addition, we now collect the require stack for ERR_REQUIRE_ASYNC_MODULE too for better metadata in the errors. Signed-off-by: Joyee Cheung PR-URL: https://github.com/nodejs/node/pull/64154 Reviewed-By: Yagiz Nizipli Reviewed-By: Antoine du Hamel --- doc/api/cli.md | 9 +- lib/internal/errors.js | 28 ++- lib/internal/modules/cjs/loader.js | 12 +- lib/internal/modules/esm/loader.js | 10 +- lib/internal/modules/esm/module_job.js | 179 +++++++++++++++--- lib/internal/modules/esm/translators.js | 2 +- lib/internal/modules/esm/utils.js | 9 + lib/internal/modules/helpers.js | 19 +- src/module_wrap.cc | 20 +- src/node_errors.h | 23 --- test/common/index.js | 16 ++ .../test-require-module-cached-tla.js | 6 +- .../test-require-module-tla-execution.js | 6 +- ...-require-module-tla-instantiation-error.js | 21 ++ .../test-require-module-tla-nested.js | 3 +- .../test-require-module-tla-print-arrow.js | 29 +++ ...test-require-module-tla-print-execution.js | 16 +- .../test-require-module-tla-print-nested.js | 31 +++ .../test-require-module-tla-print-preload.js | 32 ++++ .../test-require-module-tla-print.mjs | 39 ++++ .../test-require-module-tla-rejected.js | 3 +- .../test-require-module-tla-resolved.js | 3 +- .../test-require-module-tla-unresolved.js | 3 +- test/fixtures/es-modules/tla/awaitusing.mjs | 5 + test/fixtures/es-modules/tla/preload-main.js | 1 + .../es-modules/tla/preload-main.snapshot | 15 ++ .../es-modules/tla/require-awaitusing.js | 1 + .../tla/require-awaitusing.snapshot | 17 ++ .../es-modules/tla/require-execution.snapshot | 17 ++ .../es-modules/tla/require-indented.js | 1 + .../es-modules/tla/require-indented.snapshot | 22 +++ .../es-modules/tla/require-nested-dep.js | 1 + .../fixtures/es-modules/tla/require-nested.js | 1 + .../es-modules/tla/require-nested.snapshot | 19 ++ .../es-modules/tla/tla-and-missing-export.mjs | 3 + test/fixtures/es-modules/tla/tla-indented.mjs | 9 + 36 files changed, 522 insertions(+), 109 deletions(-) create mode 100644 test/es-module/test-require-module-tla-instantiation-error.js create mode 100644 test/es-module/test-require-module-tla-print-arrow.js create mode 100644 test/es-module/test-require-module-tla-print-nested.js create mode 100644 test/es-module/test-require-module-tla-print-preload.js create mode 100644 test/es-module/test-require-module-tla-print.mjs create mode 100644 test/fixtures/es-modules/tla/awaitusing.mjs create mode 100644 test/fixtures/es-modules/tla/preload-main.js create mode 100644 test/fixtures/es-modules/tla/preload-main.snapshot create mode 100644 test/fixtures/es-modules/tla/require-awaitusing.js create mode 100644 test/fixtures/es-modules/tla/require-awaitusing.snapshot create mode 100644 test/fixtures/es-modules/tla/require-execution.snapshot create mode 100644 test/fixtures/es-modules/tla/require-indented.js create mode 100644 test/fixtures/es-modules/tla/require-indented.snapshot create mode 100644 test/fixtures/es-modules/tla/require-nested-dep.js create mode 100644 test/fixtures/es-modules/tla/require-nested.js create mode 100644 test/fixtures/es-modules/tla/require-nested.snapshot create mode 100644 test/fixtures/es-modules/tla/tla-and-missing-export.mjs create mode 100644 test/fixtures/es-modules/tla/tla-indented.mjs diff --git a/doc/api/cli.md b/doc/api/cli.md index eeaa97daded0c3..da4a618239967b 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -1349,11 +1349,14 @@ resolution algorithm. added: - v22.0.0 - v20.17.0 +changes: + - version: REPLACEME + pr-url: https://github.com/nodejs/node/pull/64154 + description: Print the top-level awaits without evaluating the modules. --> -If the ES module being `require()`'d contains top-level `await`, this flag -allows Node.js to evaluate the module, try to locate the -top-level awaits, and print their location to help users find them. +If the ES module graph cannot be `require()`'d because it contains any top-level `await`, +this flag allows Node.js to locate and print their locations. ### `--experimental-quic` diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 51e4ebfe0d1c50..a8ce308436ecc3 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -48,6 +48,7 @@ const { StringPrototypeEndsWith, StringPrototypeIncludes, StringPrototypeIndexOf, + StringPrototypeRepeat, StringPrototypeSlice, StringPrototypeSplit, StringPrototypeStartsWith, @@ -1707,15 +1708,26 @@ E('ERR_QUIC_STREAM_ABORTED', '%s', Error); E('ERR_QUIC_STREAM_RESET', 'The QUIC stream was reset by the peer with error code %d', Error); E('ERR_QUIC_VERSION_NEGOTIATION_ERROR', 'The QUIC session requires version negotiation', Error); -E('ERR_REQUIRE_ASYNC_MODULE', function(filename, parentFilename) { - let message = 'require() cannot be used on an ESM ' + - 'graph with top-level await. Use import() instead. To see where the' + - ' top-level await comes from, use --experimental-print-required-tla.'; - if (parentFilename) { - message += `\n From ${parentFilename} `; +E('ERR_REQUIRE_ASYNC_MODULE', function(filename, parent, locations) { + let message = 'require() cannot be used on an ESM graph with top-level await. Use import() instead.'; + const { getOptionValue } = require('internal/options'); + if (!getOptionValue('--experimental-print-required-tla')) { + message += ' To see where the top-level await comes from, use --experimental-print-required-tla.'; } - if (filename) { - message += `\n Requiring ${filename} `; + if (parent) { + const { getRequireStack } = require('internal/modules/helpers'); + const requireStack = getRequireStack(parent); + if (requireStack.length > 0) { + message += '\nRequire stack:\n- ' + + ArrayPrototypeJoin(requireStack, '\n- '); + } + this.requireStack = requireStack; + } + if (locations && locations.length > 0) { + const { urlToFilename } = require('internal/modules/helpers'); + const frames = ArrayPrototypeMap(locations, ({ url, line, column, sourceLine }) => + `${urlToFilename(url)}:${line}\n\n${sourceLine}\n${StringPrototypeRepeat(' ', column)}^\n`); + setArrowMessage(this, ArrayPrototypeJoin(frames, '\n')); } return message; }, Error); diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index a97a5f27a24805..e1f8a0eed31e4e 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -168,6 +168,7 @@ const { setHasStartedUserCJSExecution, stripBOM, toRealPath, + getRequireStack, } = require('internal/modules/helpers'); const { convertCJSFilenameToURL, @@ -1572,17 +1573,6 @@ Module._resolveFilename = function(request, parent, isMain, options) { throw err; }; -function getRequireStack(parent) { - const requireStack = []; - for (let cursor = parent; - cursor; - // TODO(joyeecheung): it makes more sense to use kLastModuleParent here. - cursor = cursor[kFirstModuleParent]) { - ArrayPrototypePush(requireStack, cursor.filename || cursor.id); - } - return requireStack; -} - function getRequireStackMessage(request, requireStack) { let message = `Cannot find module '${request}'`; if (requireStack.length > 0) { diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index b274b9c00a0466..1a6622140382ba 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -25,7 +25,6 @@ const { imported_cjs_symbol } = internalBinding('symbols'); const assert = require('internal/assert'); const { - ERR_REQUIRE_ASYNC_MODULE, ERR_REQUIRE_CYCLE_MODULE, ERR_REQUIRE_ESM, ERR_REQUIRE_ESM_RACE_CONDITION, @@ -293,7 +292,7 @@ class ModuleLoader { debug('Module status', job, status); // hasAsyncGraph is available after module been instantiated. if (status >= kInstantiated && job.module.hasAsyncGraph) { - throw new ERR_REQUIRE_ASYNC_MODULE(filename, parentFilename); + job.throwAsyncGraphError(parent); } if (status === kEvaluated) { return { wrap: job.module, namespace: job.module.getNamespace() }; @@ -321,6 +320,9 @@ class ModuleLoader { } if (status !== kEvaluating) { assert(status === kUninstantiated, `Unexpected module status ${status}`); + // A previous require() of the same graph may have bailed out before + // instantiation because it contains top-level await. + job.throwIfAsyncGraph(parent); throw new ERR_REQUIRE_ESM_RACE_CONDITION(filename, parentFilename, false); } let message = `Cannot require() ES Module ${filename} in a cycle.`; @@ -371,8 +373,8 @@ class ModuleLoader { // Otherwise the module could be imported before but the evaluation may be already // completed (e.g. the require call is lazy) so it's okay. We will return the - // job and check asynchronicity of the entire graph later, after the - // graph is instantiated. + // job and check asynchronicity of the entire graph later, before the + // graph is evaluated. } /** diff --git a/lib/internal/modules/esm/module_job.js b/lib/internal/modules/esm/module_job.js index a09af9ea990b37..ee055c95d6d5c7 100644 --- a/lib/internal/modules/esm/module_job.js +++ b/lib/internal/modules/esm/module_job.js @@ -4,8 +4,11 @@ const { Array, ArrayPrototypeFind, ArrayPrototypeJoin, + ArrayPrototypePop, ArrayPrototypePush, + ArrayPrototypeSort, FunctionPrototype, + ObjectAssign, ObjectSetPrototypeOf, PromisePrototypeThen, PromiseResolve, @@ -128,6 +131,77 @@ const explainCommonJSGlobalLikeNotDefinedError = (e, url, hasTopLevelAwait) => { } }; +/** + * @typedef {object} TopLevelAwaitLocation + * @property {string} url URL of the module containing the top-level await. + * @property {number} line 1-based line number of the top-level await. + * @property {number} column 0-based column number of the top-level await. + * @property {string} sourceLine The source line containing the top-level await. + */ + +/** + * Locate the top-level awaits in the given module by parsing the source with acron. + * @param {string} source Module source code. + * @returns {object[]} The acorn AST nodes of the top-level awaits, in source order. + */ +function findTopLevelAwait(source) { + const { Parser } = require('internal/deps/acorn/acorn/dist/acorn'); + const walk = require('internal/deps/acorn/acorn-walk/dist/walk'); + let ast; + try { + ast = Parser.parse(source, { + __proto__: null, ecmaVersion: 'latest', sourceType: 'module', locations: true, + }); + } catch { + return []; // The source is not parsable, skip. + } + // We are looking for _top-level_ await, so we don't traverse into function bodies. + const baseVisitor = ObjectAssign({ __proto__: null }, walk.base, { Function: noop }); + const found = []; + walk.simple(ast, { + __proto__: null, + AwaitExpression(node) { ArrayPrototypePush(found, node); }, + // `for await (...)` is a ForOfStatement with `await: true`, not an AwaitExpression. + ForOfStatement(node) { + if (node.await) { ArrayPrototypePush(found, node); } + }, + // `await using x = ...` is a VariableDeclaration, not an AwaitExpression. + VariableDeclaration(node) { + if (node.kind === 'await using') { ArrayPrototypePush(found, node); } + }, + }, baseVisitor); + ArrayPrototypeSort(found, (a, b) => a.start - b.start); + return found; +} + +/** + * Locate the top-level awaits in the given modules. + * @param {ModuleWrap[]} modules Modules that may contain top-level await. + * @returns {TopLevelAwaitLocation[]} The locations of the top-level awaits. + */ +function getTopLevelAwaitLocations(modules) { + const locations = []; + for (let i = 0; i < modules.length; i++) { + const module = modules[i]; + const source = module.source; + if (typeof source !== 'string') { continue; } // Not retained during compilation. Skip. + const found = findTopLevelAwait(source); + if (found.length === 0) { continue; } + const lines = StringPrototypeSplit(source, '\n'); + for (let j = 0; j < found.length; j++) { + const { start } = found[j].loc; + ArrayPrototypePush(locations, { + __proto__: null, + url: module.url, + line: start.line, + column: start.column, + sourceLine: lines[start.line - 1], + }); + } + } + return locations; +} + class ModuleJobBase { constructor(loader, url, importAttributes, phase, isMain, inspectBrk) { assert(typeof phase === 'number'); @@ -186,6 +260,64 @@ class ModuleJobBase { return evaluationDepJobs; } + /** + * Collect the modules that contain top-level await in the linked graph of + * this job. Whether each module contains top-level await is known at + * compilation, so for a synchronously linked graph this finds asynchronous + * graphs before instantiation. + * On the (deprecated) async loader hook worker thread, linking may be asynchronous, in + * which case the subgraphs that are not synchronously linked are skipped + * and callers should still consult hasAsyncGraph after instantiation. + * @returns {ModuleWrap[]} + */ + findModulesWithTopLevelAwait() { + const found = []; + const seen = new SafeSet(); + const stack = [this]; + while (stack.length > 0) { + const job = ArrayPrototypePop(stack); + if (seen.has(job)) { continue; } + seen.add(job); + if (job.module?.hasTopLevelAwait) { + ArrayPrototypePush(found, job.module); + } + // job.linked is the array of evaluation-phase dependency jobs when the + // linking is synchronous. Skip it if it's still a promise. + if (!isPromise(job.linked)) { + for (let i = 0; i < job.linked.length; i++) { + ArrayPrototypePush(stack, job.linked[i]); + } + } + } + return found; + } + + /** + * Throw the ERR_REQUIRE_ASYNC_MODULE with metadata for a require()'d graph that + * contains top-level await. + * @param {Module|undefined} parent CommonJS module that require()'d this, if any. + * @param {ModuleWrap[]} [modules] Modules with top-level await, when already + * collected by the caller, to avoid walking the graph again. + */ + throwAsyncGraphError(parent, modules = this.findModulesWithTopLevelAwait()) { + const locations = getOptionValue('--experimental-print-required-tla') ? getTopLevelAwaitLocations(modules) : []; + const filename = urlToFilename(this.url); + throw new ERR_REQUIRE_ASYNC_MODULE(filename, parent, locations); + } + + /** + * If the a require()'d graph contains top-level await, collect the source locations + * of the top-level awaits using source code retained during compilation and throw + * ERR_REQUIRE_ASYNC_MODULE. This can be run before instantiation is complete. + * @param {Module|undefined} parent CommonJS module that require()'d this, if any. + */ + throwIfAsyncGraph(parent) { + const modules = this.findModulesWithTopLevelAwait(); + if (modules.length > 0) { + this.throwAsyncGraphError(parent, modules); + } + } + /** * Ensure that this ModuleJob is moving towards the required phase * (does not necessarily mean it is ready at that phase - run does that) @@ -394,6 +526,8 @@ class ModuleJob extends ModuleJobBase { debug('ModuleJob.runSync()', status, this.module); if (status === kUninstantiated) { + // TODO(joyeecheung): Reject graphs with top-level await _before_ instantiation, so that + // the async graph error supersedes instantiation (mismatch export) errors in the graph. // FIXME(joyeecheung): this cannot fully handle < kInstantiated. Make the linking // fully synchronous instead. if (this.module.getModuleRequests().length === 0) { @@ -403,22 +537,18 @@ class ModuleJob extends ModuleJobBase { status = this.module.getStatus(); } if (status === kInstantiated || status === kErrored) { - const filename = urlToFilename(this.url); - const parentFilename = urlToFilename(parent?.filename); - if (this.module.hasAsyncGraph && !getOptionValue('--experimental-print-required-tla')) { - throw new ERR_REQUIRE_ASYNC_MODULE(filename, parentFilename); + if (this.module.hasAsyncGraph) { + this.throwAsyncGraphError(parent); } if (status === kInstantiated) { setHasStartedUserESMExecution(); - const namespace = this.module.evaluateSync(filename, parentFilename); + const namespace = this.module.evaluateSync(); return { __proto__: null, module: this.module, namespace }; } throw this.module.getError(); } else if (status === kEvaluating || status === kEvaluated) { if (this.module.hasAsyncGraph) { - const filename = urlToFilename(this.url); - const parentFilename = urlToFilename(parent?.filename); - throw new ERR_REQUIRE_ASYNC_MODULE(filename, parentFilename); + this.throwAsyncGraphError(parent); } // kEvaluating can show up when this is being used to deal with CJS <-> CJS cycles. // Allow it for now, since we only need to ban ESM <-> CJS cycles which would be @@ -514,9 +644,16 @@ class ModuleJobSync extends ModuleJobBase { await this.evaluationPromise; } return { __proto__: null, module: this.module }; - } else if (status === kInstantiated) { - // The evaluation may have been canceled because instantiate() detected TLA first. - // But when it is imported again, it's fine to re-evaluate it asynchronously. + } else if (status === kInstantiated || status === kUninstantiated) { + // The require() of this (synchronously linked) module bailed out: either + // it was rejected for containing top-level await after instantiation + // (kInstantiated), or its instantiation failed and left it uninstantiated + // (kUninstantiated, e.g. a missing named export). When it's reached via async + // run() from import, finish the instantiation and evaluate it asynchronously, + // re-throwing any instantiation error. + if (status === kUninstantiated) { + this.module.instantiate(); + } const timeout = -1; const breakOnSigint = false; this.evaluationPromise = this.module.evaluate(timeout, breakOnSigint); @@ -532,23 +669,19 @@ class ModuleJobSync extends ModuleJobBase { runSync(parent) { debug('ModuleJobSync.runSync()', this.module); assert(this.shouldRunModule(this.phase)); + // TODO(joyeecheung): Reject graphs with top-level await _before_ instantiation, so that the + // async graph error supersedes instantiation (mismatch export) errors in the graph. // TODO(joyeecheung): add the error decoration logic from the async instantiate. this.module.instantiate(); - // If --experimental-print-required-tla is true, proceeds to evaluation even - // if it's async because we want to search for the TLA and help users locate - // them. - // TODO(joyeecheung): track the asynchroniticy using v8::Module::HasTopLevelAwait() - // and we'll be able to throw right after compilation of the modules, using acron - // to find and print the TLA. This requires the linking to be synchronous in case - // it runs into cached asynchronous modules that are not yet fetched. - const parentFilename = urlToFilename(parent?.filename); - const filename = urlToFilename(this.url); - if (this.module.hasAsyncGraph && !getOptionValue('--experimental-print-required-tla')) { - throw new ERR_REQUIRE_ASYNC_MODULE(filename, parentFilename); + // On the deprecated async loader hook worker thread, dependencies linked by an + // earlier import may not be walkable synchronously, so double-check with + // V8 now that the graph is instantiated. + if (this.module.hasAsyncGraph) { + this.throwAsyncGraphError(parent); } setHasStartedUserESMExecution(); try { - const namespace = this.module.evaluateSync(filename, parentFilename); + const namespace = this.module.evaluateSync(); return { __proto__: null, module: this.module, namespace }; } catch (e) { explainCommonJSGlobalLikeNotDefinedError(e, this.module.url, this.module.hasTopLevelAwait); diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js index 0ea07739c17018..37b289fae60dee 100644 --- a/lib/internal/modules/esm/translators.js +++ b/lib/internal/modules/esm/translators.js @@ -145,7 +145,7 @@ function loadCJSModuleWithSpecialRequire(module, source, url, filename, isMain, // On the main thread, the authentic require() is used instead (fixed by #60380). const request = { specifier, attributes: importAttributes, phase: kEvaluationPhase, __proto__: null }; const job = cascadedLoader.getOrCreateModuleJob(url, request, kRequireInImportedCJS); - job.runSync(); + job.runSync(module); let mod = cjsCache.get(job.url); assert(job.module, `Imported CJS module ${url} failed to load module ${job.url} using require() due to race condition`); diff --git a/lib/internal/modules/esm/utils.js b/lib/internal/modules/esm/utils.js index f977bfaf57498f..7e453171026757 100644 --- a/lib/internal/modules/esm/utils.js +++ b/lib/internal/modules/esm/utils.js @@ -362,6 +362,15 @@ function compileSourceTextModule(url, source, type, context = kEmptyObject) { wrap.isMain = true; } + // Add an extra reference to the source of modules containing top-level await so that if the + // module ends up being require()'d, we can parse the location of the top-level awaits to print + // better errors. There will be other references to the same source in the module in V8 so this + // only serves as a shortcut. + if (wrap.hasTopLevelAwait && + getOptionValue('--experimental-print-required-tla')) { + wrap.source = source; + } + // Cache the source map for the module if present. if (wrap.sourceMapURL) { maybeCacheSourceMap(url, source, wrap, false, wrap.sourceURL, wrap.sourceMapURL); diff --git a/lib/internal/modules/helpers.js b/lib/internal/modules/helpers.js index 839ce9af4bb678..62b8a743942b7a 100644 --- a/lib/internal/modules/helpers.js +++ b/lib/internal/modules/helpers.js @@ -2,6 +2,7 @@ const { ArrayPrototypeForEach, + ArrayPrototypePush, ObjectDefineProperty, ObjectFreeze, ObjectPrototypeHasOwnProperty, @@ -30,7 +31,11 @@ const { getOptionValue } = require('internal/options'); const { setOwnProperty, getLazy } = require('internal/util'); const { inspect } = require('internal/util/inspect'); const { emitWarningSync } = require('internal/process/warning'); - +const { + privateSymbols: { + module_first_parent_private_symbol: kFirstModuleParent, + }, +} = internalBinding('util'); const lazyTmpdir = getLazy(() => require('os').tmpdir()); const { join } = path; @@ -513,6 +518,17 @@ function getCompileCacheDir() { return _getCompileCacheDir() || undefined; } +function getRequireStack(parent) { + const requireStack = []; + for (let cursor = parent; + cursor; + // TODO(joyeecheung): it makes more sense to use kLastModuleParent here. + cursor = cursor[kFirstModuleParent]) { + ArrayPrototypePush(requireStack, cursor.filename || cursor.id); + } + return requireStack; +} + module.exports = { addBuiltinLibsToObject, assertBufferSource, @@ -544,4 +560,5 @@ module.exports = { _hasStartedUserESMExecution = true; }, urlToFilename, + getRequireStack, }; diff --git a/src/module_wrap.cc b/src/module_wrap.cc index 4f47648f15135f..38ac15b337f366 100644 --- a/src/module_wrap.cc +++ b/src/module_wrap.cc @@ -940,23 +940,9 @@ void ModuleWrap::EvaluateSync(const FunctionCallbackInfo& args) { return; } - if (obj->HasAsyncGraph()) { - CHECK(env->options()->print_required_tla); - auto stalled_messages = - std::get<1>(module->GetStalledTopLevelAwaitMessages(isolate)); - if (stalled_messages.size() != 0) { - for (auto& message : stalled_messages) { - std::string reason = "Error: unexpected top-level await at "; - std::string info = - FormatErrorMessage(isolate, context, "", message, true); - reason += info; - FPrintF(stderr, "%s\n", reason); - } - } - THROW_ERR_REQUIRE_ASYNC_MODULE(env, args[0], args[1]); - return; - } - + // Graphs with top-level await are rejected by the caller before evaluation + // starts, so the promise must have been settled synchronously. + CHECK(!obj->HasAsyncGraph()); CHECK_EQ(promise->State(), Promise::PromiseState::kFulfilled); args.GetReturnValue().Set(module->GetModuleNamespace()); diff --git a/src/node_errors.h b/src/node_errors.h index ed8e7eed9e3d9b..62cfba88f00d43 100644 --- a/src/node_errors.h +++ b/src/node_errors.h @@ -121,7 +121,6 @@ void OOMErrorHandler(const char* location, const v8::OOMDetails& details); V(ERR_OPERATION_FAILED, TypeError) \ V(ERR_OPTIONS_BEFORE_BOOTSTRAPPING, Error) \ V(ERR_OUT_OF_RANGE, RangeError) \ - V(ERR_REQUIRE_ASYNC_MODULE, Error) \ V(ERR_SCRIPT_EXECUTION_INTERRUPTED, Error) \ V(ERR_SCRIPT_EXECUTION_TIMEOUT, Error) \ V(ERR_SOURCE_PHASE_NOT_DEFINED, SyntaxError) \ @@ -268,28 +267,6 @@ inline void THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(Environment* env, env, "Script execution timed out after %dms", timeout); } -inline void THROW_ERR_REQUIRE_ASYNC_MODULE( - Environment* env, - v8::Local filename, - v8::Local parent_filename) { - static constexpr const char* prefix = - "require() cannot be used on an ESM graph with top-level await. Use " - "import() instead. To see where the top-level await comes from, use " - "--experimental-print-required-tla."; - std::string message = prefix; - if (!parent_filename.IsEmpty() && parent_filename->IsString()) { - Utf8Value utf8(env->isolate(), parent_filename); - message += "\n From "; - message += utf8.ToStringView(); - } - if (!filename.IsEmpty() && filename->IsString()) { - Utf8Value utf8(env->isolate(), filename); - message += "\n Requiring "; - message += utf8.ToStringView(); - } - THROW_ERR_REQUIRE_ASYNC_MODULE(env, message); -} - inline v8::Local ERR_BUFFER_TOO_LARGE(v8::Isolate* isolate) { char message[128]; snprintf(message, diff --git a/test/common/index.js b/test/common/index.js index 09962cecd31932..30d567c2c3f4dc 100755 --- a/test/common/index.js +++ b/test/common/index.js @@ -953,6 +953,21 @@ function expectRequiredTLAError(err) { } } +// Extract the entries of the rendered "Require stack:" list (each shown as +// "- ") from an error message or a process output string. +function parseRequireStack(output) { + const lines = output.replace(/\r/g, '').split('\n'); + const start = lines.indexOf('Require stack:'); + if (start === -1) { + return []; + } + const stack = []; + for (let i = start + 1; i < lines.length && lines[i].startsWith('- '); i++) { + stack.push(lines[i].slice(2)); + } + return stack; +} + function sleepSync(ms) { const sab = new SharedArrayBuffer(4); const i32 = new Int32Array(sab); @@ -1009,6 +1024,7 @@ const common = { mustSucceed, nodeProcessAborted, PIPE, + parseRequireStack, parseTestMetadata, platformTimeout, printSkipMessage, diff --git a/test/es-module/test-require-module-cached-tla.js b/test/es-module/test-require-module-cached-tla.js index d98b012c349aa1..5c707269cc2a4f 100644 --- a/test/es-module/test-require-module-cached-tla.js +++ b/test/es-module/test-require-module-cached-tla.js @@ -8,7 +8,9 @@ const assert = require('assert'); await import('../fixtures/es-modules/tla/resolved.mjs'); assert.throws(() => { require('../fixtures/es-modules/tla/resolved.mjs'); - }, { - code: 'ERR_REQUIRE_ASYNC_MODULE', + }, (err) => { + common.expectRequiredTLAError(err); + assert.deepStrictEqual(common.parseRequireStack(err.message), [__filename]); + return true; }); })().then(common.mustCall()); diff --git a/test/es-module/test-require-module-tla-execution.js b/test/es-module/test-require-module-tla-execution.js index cd9f1b972c63e5..dab795dbdaa406 100644 --- a/test/es-module/test-require-module-tla-execution.js +++ b/test/es-module/test-require-module-tla-execution.js @@ -17,8 +17,10 @@ const fixtures = require('../common/fixtures'); stderr(output) { assert.doesNotMatch(output, /I am executed/); common.expectRequiredTLAError(output); - assert.match(output, /From .*require-execution\.js/); - assert.match(output, /Requiring .*execution\.mjs/); + assert.deepStrictEqual( + common.parseRequireStack(output), + [fixtures.path('es-modules/tla/require-execution.js')], + ); return true; }, stdout: '', diff --git a/test/es-module/test-require-module-tla-instantiation-error.js b/test/es-module/test-require-module-tla-instantiation-error.js new file mode 100644 index 00000000000000..287d2a292453f0 --- /dev/null +++ b/test/es-module/test-require-module-tla-instantiation-error.js @@ -0,0 +1,21 @@ +'use strict'; + +// Tests that when a require()'d graph contains both top-level await and an +// instantiation error, the instantiation error currently takes precedence. +// TODO(joyeecheung): make ERR_REQUIRE_ASYNC_MODULE take precedence. + +const common = require('../common'); +const assert = require('assert'); +const fixtures = require('../common/fixtures'); + +assert.throws(() => { + require(fixtures.path('es-modules/tla/tla-and-missing-export.mjs')); +}, { + name: 'SyntaxError', + message: /does not provide an export named 'doesNotExist'/, +}); + +assert.rejects(import(fixtures.fileURL('es-modules/tla/tla-and-missing-export.mjs')), { + name: 'SyntaxError', + message: /does not provide an export named 'doesNotExist'/, +}).then(common.mustCall()); diff --git a/test/es-module/test-require-module-tla-nested.js b/test/es-module/test-require-module-tla-nested.js index 583cd7cd0c95db..0b73af5ad35235 100644 --- a/test/es-module/test-require-module-tla-nested.js +++ b/test/es-module/test-require-module-tla-nested.js @@ -9,7 +9,6 @@ assert.throws(() => { require('../fixtures/es-modules/tla/parent.mjs'); }, (err) => { common.expectRequiredTLAError(err); - assert.match(err.message, /From .*test-require-module-tla-nested\.js/); - assert.match(err.message, /Requiring .*parent\.mjs/); + assert.deepStrictEqual(common.parseRequireStack(err.message), [__filename]); return true; }); diff --git a/test/es-module/test-require-module-tla-print-arrow.js b/test/es-module/test-require-module-tla-print-arrow.js new file mode 100644 index 00000000000000..2ba7c165a2bdd0 --- /dev/null +++ b/test/es-module/test-require-module-tla-print-arrow.js @@ -0,0 +1,29 @@ +'use strict'; + +// Tests that require(esm) with --experimental-print-required-tla points the +// caret at the right column for indented top-level await and for-await-of. + +const common = require('../common'); +const assert = require('assert'); +const { spawnSyncAndExit } = require('../common/child_process'); +const fixtures = require('../common/fixtures'); + +{ + spawnSyncAndExit(process.execPath, [ + '--experimental-print-required-tla', + fixtures.path('es-modules/tla/require-indented.js'), + ], { + signal: null, + status: 1, + stderr(output) { + output = output.replace(/\r/g, ''); + common.expectRequiredTLAError(output); + // Indented await: the caret is aligned under the await. + assert(output.includes(' await Promise.resolve(ready);\n ^'), output); + // for-await-of: the caret points at the for keyword. + assert(output.includes('for await (const x of [Promise.resolve(1)]) {\n^'), output); + return true; + }, + stdout: '', + }); +} diff --git a/test/es-module/test-require-module-tla-print-execution.js b/test/es-module/test-require-module-tla-print-execution.js index d831856fe676dd..68b4dc5a6557e9 100644 --- a/test/es-module/test-require-module-tla-print-execution.js +++ b/test/es-module/test-require-module-tla-print-execution.js @@ -1,6 +1,7 @@ 'use strict'; -// Tests that require(esm) with top-level-await throws after execution +// Tests that require(esm) with top-level-await throws before execution starts +// and attaches the location of the top-level await to the error // if --experimental-print-required-tla is enabled. const common = require('../common'); @@ -16,12 +17,15 @@ const fixtures = require('../common/fixtures'); signal: null, status: 1, stderr(output) { - assert.match(output, /I am executed/); + output = output.replace(/\r/g, ''); + assert.doesNotMatch(output, /I am executed/); common.expectRequiredTLAError(output); - assert.match(output, /Error: unexpected top-level await at.*execution\.mjs:3/); - assert.match(output, /await Promise\.resolve\('hi'\)/); - assert.match(output, /From .*require-execution\.js/); - assert.match(output, /Requiring .*execution\.mjs/); + // The location of the top-level await is shown with a caret. + assert(output.includes(`${fixtures.path('es-modules/tla/execution.mjs')}:3`), output); + assert(output.includes("await Promise.resolve('hi');\n^"), output); + // The require() chain is shown as a require stack. + assert.match(output, /Require stack:/); + assert.match(output, /require-execution\.js/); return true; }, stdout: '', diff --git a/test/es-module/test-require-module-tla-print-nested.js b/test/es-module/test-require-module-tla-print-nested.js new file mode 100644 index 00000000000000..5f48c9b18e6d91 --- /dev/null +++ b/test/es-module/test-require-module-tla-print-nested.js @@ -0,0 +1,31 @@ +'use strict'; + +// Tests that require(esm) attaches the location of a top-level await found in +// an inner dependency of the graph if --experimental-print-required-tla is +// enabled. The entry point is a real CommonJS file that require()s the ESM. + +const common = require('../common'); +const assert = require('assert'); +const { spawnSyncAndExit } = require('../common/child_process'); +const fixtures = require('../common/fixtures'); + +{ + spawnSyncAndExit(process.execPath, [ + '--experimental-print-required-tla', + fixtures.path('es-modules/tla/require-nested.js'), + ], { + signal: null, + status: 1, + stderr(output) { + output = output.replace(/\r/g, ''); + common.expectRequiredTLAError(output); + // The top-level await lives in a transitive dependency (a.mjs). + assert(output.includes(`${fixtures.path('es-modules/tla/a.mjs')}:3`), output); + assert(output.includes('await new Promise((resolve) => {\n^'), output); + assert.match(output, /Require stack:/); + assert.match(output, /require-nested\.js/); + return true; + }, + stdout: '', + }); +} diff --git a/test/es-module/test-require-module-tla-print-preload.js b/test/es-module/test-require-module-tla-print-preload.js new file mode 100644 index 00000000000000..b53d4e89026c3e --- /dev/null +++ b/test/es-module/test-require-module-tla-print-preload.js @@ -0,0 +1,32 @@ +'use strict'; + +// Tests that preloading an ESM with top-level await via -r throws before +// execution starts and attaches the location of the top-level await +// if --experimental-print-required-tla is enabled. + +const common = require('../common'); +const assert = require('assert'); +const { spawnSyncAndExit } = require('../common/child_process'); +const fixtures = require('../common/fixtures'); + +{ + spawnSyncAndExit(process.execPath, [ + '--experimental-print-required-tla', + '-r', fixtures.path('es-modules/tla/execution.mjs'), + '-e', 'console.log("main ran")', + ], { + signal: null, + status: 1, + stderr(output) { + output = output.replace(/\r/g, ''); + // The main script should not run because preloading fails first. + assert.doesNotMatch(output, /main ran/); + assert.doesNotMatch(output, /I am executed/); + common.expectRequiredTLAError(output); + assert(output.includes(`${fixtures.path('es-modules/tla/execution.mjs')}:3`), output); + assert(output.includes("await Promise.resolve('hi');\n^"), output); + return true; + }, + stdout: '', + }); +} diff --git a/test/es-module/test-require-module-tla-print.mjs b/test/es-module/test-require-module-tla-print.mjs new file mode 100644 index 00000000000000..41b44376fdc3e6 --- /dev/null +++ b/test/es-module/test-require-module-tla-print.mjs @@ -0,0 +1,39 @@ +// Tests the output of require(esm) on a graph with top-level await when +// --experimental-print-required-tla is enabled: the location of the +// top-level await (with a caret) and the require stack. + +import '../common/index.mjs'; +import * as fixtures from '../common/fixtures.mjs'; +import * as snapshot from '../common/assertSnapshot.js'; +import { describe, it } from 'node:test'; + +const flags = ['--experimental-print-required-tla']; + +describe('require(esm) with top-level await and --experimental-print-required-tla', () => { + const tests = [ + // require()'d directly from a CommonJS entry point. + { name: 'es-modules/tla/require-execution.js' }, + // require()'d through a chain of CommonJS files (multi-entry require stack), + // with the top-level await in a transitive ES module dependency. + { name: 'es-modules/tla/require-nested.js' }, + // Indented top-level await and for-await-of, to check caret alignment. + { name: 'es-modules/tla/require-indented.js' }, + // `await using` declaration, which is top-level await without an + // AwaitExpression or for-await-of node. + { name: 'es-modules/tla/require-awaitusing.js' }, + // Preloaded via -r, so the require stack comes from internal/preload. + { + name: 'es-modules/tla/preload-main.js', + flags: ['-r', fixtures.path('es-modules/tla/execution.mjs')], + }, + ]; + for (const { name, flags: extraFlags = [] } of tests) { + it(name, async () => { + await snapshot.spawnAndAssert( + fixtures.path(name), + snapshot.defaultTransform, + { flags: [...flags, ...extraFlags] }, + ); + }); + } +}); diff --git a/test/es-module/test-require-module-tla-rejected.js b/test/es-module/test-require-module-tla-rejected.js index 0c1f8de2c307f6..07e8da183eca64 100644 --- a/test/es-module/test-require-module-tla-rejected.js +++ b/test/es-module/test-require-module-tla-rejected.js @@ -9,7 +9,6 @@ assert.throws(() => { require('../fixtures/es-modules/tla/rejected.mjs'); }, (err) => { common.expectRequiredTLAError(err); - assert.match(err.message, /From .*test-require-module-tla-rejected\.js/); - assert.match(err.message, /Requiring .*rejected\.mjs/); + assert.deepStrictEqual(common.parseRequireStack(err.message), [__filename]); return true; }); diff --git a/test/es-module/test-require-module-tla-resolved.js b/test/es-module/test-require-module-tla-resolved.js index f35bb68b7dc180..1545ab446819fa 100644 --- a/test/es-module/test-require-module-tla-resolved.js +++ b/test/es-module/test-require-module-tla-resolved.js @@ -9,7 +9,6 @@ assert.throws(() => { require('../fixtures/es-modules/tla/resolved.mjs'); }, (err) => { common.expectRequiredTLAError(err); - assert.match(err.message, /From .*test-require-module-tla-resolved\.js/); - assert.match(err.message, /Requiring .*resolved\.mjs/); + assert.deepStrictEqual(common.parseRequireStack(err.message), [__filename]); return true; }); diff --git a/test/es-module/test-require-module-tla-unresolved.js b/test/es-module/test-require-module-tla-unresolved.js index 35cf12c446129b..2226b2ebba436a 100644 --- a/test/es-module/test-require-module-tla-unresolved.js +++ b/test/es-module/test-require-module-tla-unresolved.js @@ -9,7 +9,6 @@ assert.throws(() => { require('../fixtures/es-modules/tla/unresolved.mjs'); }, (err) => { common.expectRequiredTLAError(err); - assert.match(err.message, /From .*test-require-module-tla-unresolved\.js/); - assert.match(err.message, /Requiring .*unresolved\.mjs/); + assert.deepStrictEqual(common.parseRequireStack(err.message), [__filename]); return true; }); diff --git a/test/fixtures/es-modules/tla/awaitusing.mjs b/test/fixtures/es-modules/tla/awaitusing.mjs new file mode 100644 index 00000000000000..30a670d49b0a28 --- /dev/null +++ b/test/fixtures/es-modules/tla/awaitusing.mjs @@ -0,0 +1,5 @@ +export const ready = true; + +await using lock = { + async [Symbol.asyncDispose]() {}, +}; diff --git a/test/fixtures/es-modules/tla/preload-main.js b/test/fixtures/es-modules/tla/preload-main.js new file mode 100644 index 00000000000000..91de17919a06f1 --- /dev/null +++ b/test/fixtures/es-modules/tla/preload-main.js @@ -0,0 +1 @@ +console.log('main should not run'); diff --git a/test/fixtures/es-modules/tla/preload-main.snapshot b/test/fixtures/es-modules/tla/preload-main.snapshot new file mode 100644 index 00000000000000..81279b9e2c017d --- /dev/null +++ b/test/fixtures/es-modules/tla/preload-main.snapshot @@ -0,0 +1,15 @@ +/test/fixtures/es-modules/tla/execution.mjs:3 + +await Promise.resolve('hi'); +^ + +Error [ERR_REQUIRE_ASYNC_MODULE]: require() cannot be used on an ESM graph with top-level await. Use import() instead. +Require stack: +- internal/preload + at + at { + code: 'ERR_REQUIRE_ASYNC_MODULE', + requireStack: [ 'internal/preload' ] +} + +Node.js diff --git a/test/fixtures/es-modules/tla/require-awaitusing.js b/test/fixtures/es-modules/tla/require-awaitusing.js new file mode 100644 index 00000000000000..6045e6c0c7a8eb --- /dev/null +++ b/test/fixtures/es-modules/tla/require-awaitusing.js @@ -0,0 +1 @@ +require('./awaitusing.mjs'); diff --git a/test/fixtures/es-modules/tla/require-awaitusing.snapshot b/test/fixtures/es-modules/tla/require-awaitusing.snapshot new file mode 100644 index 00000000000000..ae2a0b7c690217 --- /dev/null +++ b/test/fixtures/es-modules/tla/require-awaitusing.snapshot @@ -0,0 +1,17 @@ +/test/fixtures/es-modules/tla/awaitusing.mjs:3 + +await using lock = { +^ + +Error [ERR_REQUIRE_ASYNC_MODULE]: require() cannot be used on an ESM graph with top-level await. Use import() instead. +Require stack: +- /test/fixtures/es-modules/tla/require-awaitusing.js + at + at { + code: 'ERR_REQUIRE_ASYNC_MODULE', + requireStack: [ + '/test/fixtures/es-modules/tla/require-awaitusing.js' + ] +} + +Node.js diff --git a/test/fixtures/es-modules/tla/require-execution.snapshot b/test/fixtures/es-modules/tla/require-execution.snapshot new file mode 100644 index 00000000000000..65f312c9d9c606 --- /dev/null +++ b/test/fixtures/es-modules/tla/require-execution.snapshot @@ -0,0 +1,17 @@ +/test/fixtures/es-modules/tla/execution.mjs:3 + +await Promise.resolve('hi'); +^ + +Error [ERR_REQUIRE_ASYNC_MODULE]: require() cannot be used on an ESM graph with top-level await. Use import() instead. +Require stack: +- /test/fixtures/es-modules/tla/require-execution.js + at + at { + code: 'ERR_REQUIRE_ASYNC_MODULE', + requireStack: [ + '/test/fixtures/es-modules/tla/require-execution.js' + ] +} + +Node.js diff --git a/test/fixtures/es-modules/tla/require-indented.js b/test/fixtures/es-modules/tla/require-indented.js new file mode 100644 index 00000000000000..728bba6259a26f --- /dev/null +++ b/test/fixtures/es-modules/tla/require-indented.js @@ -0,0 +1 @@ +require('./tla-indented.mjs'); diff --git a/test/fixtures/es-modules/tla/require-indented.snapshot b/test/fixtures/es-modules/tla/require-indented.snapshot new file mode 100644 index 00000000000000..1bc7bf6e46edfd --- /dev/null +++ b/test/fixtures/es-modules/tla/require-indented.snapshot @@ -0,0 +1,22 @@ +/test/fixtures/es-modules/tla/tla-indented.mjs:4 + + await Promise.resolve(ready); + ^ + +/test/fixtures/es-modules/tla/tla-indented.mjs:7 + +for await (const x of [Promise.resolve(1)]) { +^ + +Error [ERR_REQUIRE_ASYNC_MODULE]: require() cannot be used on an ESM graph with top-level await. Use import() instead. +Require stack: +- /test/fixtures/es-modules/tla/require-indented.js + at + at { + code: 'ERR_REQUIRE_ASYNC_MODULE', + requireStack: [ + '/test/fixtures/es-modules/tla/require-indented.js' + ] +} + +Node.js diff --git a/test/fixtures/es-modules/tla/require-nested-dep.js b/test/fixtures/es-modules/tla/require-nested-dep.js new file mode 100644 index 00000000000000..c771d3cdf4851e --- /dev/null +++ b/test/fixtures/es-modules/tla/require-nested-dep.js @@ -0,0 +1 @@ +require('./parent.mjs'); diff --git a/test/fixtures/es-modules/tla/require-nested.js b/test/fixtures/es-modules/tla/require-nested.js new file mode 100644 index 00000000000000..5e820bffa3c2ae --- /dev/null +++ b/test/fixtures/es-modules/tla/require-nested.js @@ -0,0 +1 @@ +require('./require-nested-dep.js'); diff --git a/test/fixtures/es-modules/tla/require-nested.snapshot b/test/fixtures/es-modules/tla/require-nested.snapshot new file mode 100644 index 00000000000000..bf818b8e939838 --- /dev/null +++ b/test/fixtures/es-modules/tla/require-nested.snapshot @@ -0,0 +1,19 @@ +/test/fixtures/es-modules/tla/a.mjs:3 + +await new Promise((resolve) => { +^ + +Error [ERR_REQUIRE_ASYNC_MODULE]: require() cannot be used on an ESM graph with top-level await. Use import() instead. +Require stack: +- /test/fixtures/es-modules/tla/require-nested-dep.js +- /test/fixtures/es-modules/tla/require-nested.js + at + at { + code: 'ERR_REQUIRE_ASYNC_MODULE', + requireStack: [ + '/test/fixtures/es-modules/tla/require-nested-dep.js', + '/test/fixtures/es-modules/tla/require-nested.js' + ] +} + +Node.js diff --git a/test/fixtures/es-modules/tla/tla-and-missing-export.mjs b/test/fixtures/es-modules/tla/tla-and-missing-export.mjs new file mode 100644 index 00000000000000..69f3fdcb1c25b5 --- /dev/null +++ b/test/fixtures/es-modules/tla/tla-and-missing-export.mjs @@ -0,0 +1,3 @@ +import { doesNotExist } from './order.mjs'; + +await Promise.resolve(doesNotExist); diff --git a/test/fixtures/es-modules/tla/tla-indented.mjs b/test/fixtures/es-modules/tla/tla-indented.mjs new file mode 100644 index 00000000000000..db97c273afd80e --- /dev/null +++ b/test/fixtures/es-modules/tla/tla-indented.mjs @@ -0,0 +1,9 @@ +export const ready = true; + +if (ready) { + await Promise.resolve(ready); +} + +for await (const x of [Promise.resolve(1)]) { + void x; +} From c0a8760d2f64edf679e76c765d1040f1e785c8c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 18:53:08 +0000 Subject: [PATCH 091/131] meta: bump github/codeql-action/upload-sarif from 4.36.1 to 4.36.2 Bumps [github/codeql-action/upload-sarif](https://github.com/github/codeql-action) from 4.36.1 to 4.36.2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/87557b9c84dde89fdd9b10e88954ac2f4248e463...8aad20d150bbac5944a9f9d289da16a4b0d87c1e) --- updated-dependencies: - dependency-name: github/codeql-action/upload-sarif dependency-version: 4.36.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] PR-URL: https://github.com/nodejs/node/pull/64240 Reviewed-By: Colin Ihrig Reviewed-By: Antoine du Hamel --- .github/workflows/scorecard.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 630757a7fb4c9e..a6a5b030220559 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -76,6 +76,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: Upload to code-scanning - uses: github/codeql-action/upload-sarif@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v4.36.1 + uses: github/codeql-action/upload-sarif@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 with: sarif_file: results.sarif From 0ddde950c7d324973132ceec531ebd37da155860 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 18:53:20 +0000 Subject: [PATCH 092/131] meta: bump actions/setup-python from 6.2.0 to 6.3.0 Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6.2.0 to 6.3.0. - [Release notes](https://github.com/actions/setup-python/releases) - [Commits](https://github.com/actions/setup-python/compare/a309ff8b426b58ec0e2a45f0f869d46889d02405...ece7cb06caefa5fff74198d8649806c4678c61a1) --- updated-dependencies: - dependency-name: actions/setup-python dependency-version: 6.3.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] PR-URL: https://github.com/nodejs/node/pull/64241 Reviewed-By: Luigi Pinca Reviewed-By: Antoine du Hamel Reviewed-By: Colin Ihrig --- .github/workflows/build-tarball.yml | 4 ++-- .github/workflows/coverage-linux-without-intl.yml | 2 +- .github/workflows/coverage-linux.yml | 2 +- .github/workflows/coverage-windows.yml | 2 +- .github/workflows/daily-wpt-fyi.yml | 2 +- .github/workflows/linters.yml | 8 ++++---- .github/workflows/stress-test.yml | 2 +- .github/workflows/test-internet.yml | 2 +- .github/workflows/test-linux-quic.yml | 2 +- .github/workflows/test-linux.yml | 2 +- .github/workflows/test-macos.yml | 2 +- .github/workflows/tools.yml | 2 +- 12 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/build-tarball.yml b/.github/workflows/build-tarball.yml index 20b1a1a115b3e3..1b6ea61dfe702a 100644 --- a/.github/workflows/build-tarball.yml +++ b/.github/workflows/build-tarball.yml @@ -78,7 +78,7 @@ jobs: with: persist-credentials: false - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true @@ -115,7 +115,7 @@ jobs: with: clang-version: ${{ env.CLANG_VERSION }} - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true diff --git a/.github/workflows/coverage-linux-without-intl.yml b/.github/workflows/coverage-linux-without-intl.yml index e8844e7f328e46..6dc0990c21aa6b 100644 --- a/.github/workflows/coverage-linux-without-intl.yml +++ b/.github/workflows/coverage-linux-without-intl.yml @@ -58,7 +58,7 @@ jobs: with: clang-version: ${{ env.CLANG_VERSION }} - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true diff --git a/.github/workflows/coverage-linux.yml b/.github/workflows/coverage-linux.yml index d8ba57a1ec647e..1ffc1e9969511e 100644 --- a/.github/workflows/coverage-linux.yml +++ b/.github/workflows/coverage-linux.yml @@ -58,7 +58,7 @@ jobs: with: clang-version: ${{ env.CLANG_VERSION }} - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true diff --git a/.github/workflows/coverage-windows.yml b/.github/workflows/coverage-windows.yml index 35b6b2803db281..d4f87fe4d184e7 100644 --- a/.github/workflows/coverage-windows.yml +++ b/.github/workflows/coverage-windows.yml @@ -73,7 +73,7 @@ jobs: with: persist-credentials: false - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true diff --git a/.github/workflows/daily-wpt-fyi.yml b/.github/workflows/daily-wpt-fyi.yml index 5c42f482be7a0f..30a94ea4d7cfd5 100644 --- a/.github/workflows/daily-wpt-fyi.yml +++ b/.github/workflows/daily-wpt-fyi.yml @@ -39,7 +39,7 @@ jobs: runs-on: ubuntu-24.04-arm steps: - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index e5716cc16c9f22..271bc8fecd3421 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -44,7 +44,7 @@ jobs: with: persist-credentials: false - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true @@ -65,7 +65,7 @@ jobs: with: node-version: ${{ env.NODE_VERSION }} - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true @@ -179,7 +179,7 @@ jobs: *.py sparse-checkout-cone-mode: false - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true @@ -203,7 +203,7 @@ jobs: *.yaml sparse-checkout-cone-mode: false - name: Use Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true diff --git a/.github/workflows/stress-test.yml b/.github/workflows/stress-test.yml index e3846cf4d387ac..bfd3ffca7fe52d 100644 --- a/.github/workflows/stress-test.yml +++ b/.github/workflows/stress-test.yml @@ -67,7 +67,7 @@ jobs: if: runner.os == 'macOS' run: sudo xcode-select -s /Applications/Xcode_${{ env.XCODE_VERSION }}.app - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true diff --git a/.github/workflows/test-internet.yml b/.github/workflows/test-internet.yml index 0e678216ba4816..788e01eb5eba5c 100644 --- a/.github/workflows/test-internet.yml +++ b/.github/workflows/test-internet.yml @@ -55,7 +55,7 @@ jobs: with: clang-version: ${{ env.CLANG_VERSION }} - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true diff --git a/.github/workflows/test-linux-quic.yml b/.github/workflows/test-linux-quic.yml index d59bb5c3a01e85..945bfb3ce5462c 100644 --- a/.github/workflows/test-linux-quic.yml +++ b/.github/workflows/test-linux-quic.yml @@ -60,7 +60,7 @@ jobs: rustup override set "$RUSTC_VERSION" rustup --version - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true diff --git a/.github/workflows/test-linux.yml b/.github/workflows/test-linux.yml index 65a34b73a44c8a..afae5a8ade2774 100644 --- a/.github/workflows/test-linux.yml +++ b/.github/workflows/test-linux.yml @@ -71,7 +71,7 @@ jobs: rustup override set "$RUSTC_VERSION" rustup --version - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true diff --git a/.github/workflows/test-macos.yml b/.github/workflows/test-macos.yml index dfcb1f987606ea..f72b20feaf2005 100644 --- a/.github/workflows/test-macos.yml +++ b/.github/workflows/test-macos.yml @@ -88,7 +88,7 @@ jobs: persist-credentials: false path: node - name: Set up Python ${{ env.PYTHON_VERSION }} - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true diff --git a/.github/workflows/tools.yml b/.github/workflows/tools.yml index 7966102b467671..289395ee577462 100644 --- a/.github/workflows/tools.yml +++ b/.github/workflows/tools.yml @@ -315,7 +315,7 @@ jobs: if: | (matrix.id == 'icu' || matrix.id == 'inspector_protocol') && (github.event_name == 'schedule' || inputs.id == 'all' || inputs.id == matrix.id) - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true From 2cad2d6de574161cb48099296d0014294da69e3b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 18:53:30 +0000 Subject: [PATCH 093/131] meta: bump github/codeql-action/init from 4.36.1 to 4.36.2 Bumps [github/codeql-action/init](https://github.com/github/codeql-action) from 4.36.1 to 4.36.2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/87557b9c84dde89fdd9b10e88954ac2f4248e463...8aad20d150bbac5944a9f9d289da16a4b0d87c1e) --- updated-dependencies: - dependency-name: github/codeql-action/init dependency-version: 4.36.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] PR-URL: https://github.com/nodejs/node/pull/64242 Reviewed-By: Colin Ihrig Reviewed-By: Antoine du Hamel --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 5baa62ad198cd7..f5a8113103d69c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -28,7 +28,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v4.36.1 + uses: github/codeql-action/init@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 with: languages: ${{ matrix.language }} config-file: ./.github/codeql-config.yml From 845c63ed5043f163f036deddf9db8f97b9f702f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 18:53:46 +0000 Subject: [PATCH 094/131] meta: bump rtCamp/action-slack-notify from 2.3.3 to 2.4.0 Bumps [rtCamp/action-slack-notify](https://github.com/rtcamp/action-slack-notify) from 2.3.3 to 2.4.0. - [Release notes](https://github.com/rtcamp/action-slack-notify/releases) - [Commits](https://github.com/rtcamp/action-slack-notify/compare/e31e87e03dd19038e411e38ae27cbad084a90661...33ca3be66c6f378fe1610fd1d5258632dbed5e58) --- updated-dependencies: - dependency-name: rtCamp/action-slack-notify dependency-version: 2.4.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] PR-URL: https://github.com/nodejs/node/pull/64243 Reviewed-By: Colin Ihrig Reviewed-By: Antoine du Hamel --- .github/workflows/notify-on-push.yml | 4 ++-- .github/workflows/notify-on-review-wanted.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/notify-on-push.yml b/.github/workflows/notify-on-push.yml index 9ca33943c968c5..e709df93a8d7f7 100644 --- a/.github/workflows/notify-on-push.yml +++ b/.github/workflows/notify-on-push.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-24.04-arm steps: - name: Slack Notification - uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # 2.3.3 + uses: rtCamp/action-slack-notify@33ca3be66c6f378fe1610fd1d5258632dbed5e58 # 2.4.0 env: SLACK_COLOR: '#DE512A' SLACK_ICON: https://github.com/nodejs.png?size=48 @@ -47,7 +47,7 @@ jobs: COMMITS: ${{ toJSON(github.event.commits) }} - name: Slack Notification if: ${{ failure() && steps.commit-check.conclusion == 'failure' && github.repository == 'nodejs/node' }} - uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # 2.3.3 + uses: rtCamp/action-slack-notify@33ca3be66c6f378fe1610fd1d5258632dbed5e58 # 2.4.0 env: SLACK_COLOR: '#DE512A' SLACK_ICON: https://github.com/nodejs.png?size=48 diff --git a/.github/workflows/notify-on-review-wanted.yml b/.github/workflows/notify-on-review-wanted.yml index 1d3124e336b80b..2f1f3af8139bd0 100644 --- a/.github/workflows/notify-on-review-wanted.yml +++ b/.github/workflows/notify-on-review-wanted.yml @@ -34,7 +34,7 @@ jobs: fi - name: Slack Notification - uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # 2.3.3 + uses: rtCamp/action-slack-notify@33ca3be66c6f378fe1610fd1d5258632dbed5e58 # 2.4.0 env: MSG_MINIMAL: actions url SLACK_COLOR: '#3d85c6' From fe460ccf0b6d541bf7e1ad7f3c06b5721436a10d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 18:53:58 +0000 Subject: [PATCH 095/131] meta: bump codecov/codecov-action from 6.0.1 to 7.0.0 Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 6.0.1 to 7.0.0. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/e79a6962e0d4c0c17b229090214935d2e33f8354...fb8b3582c8e4def4969c97caa2f19720cb33a72f) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] PR-URL: https://github.com/nodejs/node/pull/64244 Reviewed-By: Colin Ihrig Reviewed-By: Antoine du Hamel Reviewed-By: Luigi Pinca --- .github/workflows/coverage-linux-without-intl.yml | 2 +- .github/workflows/coverage-linux.yml | 2 +- .github/workflows/coverage-windows.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/coverage-linux-without-intl.yml b/.github/workflows/coverage-linux-without-intl.yml index 6dc0990c21aa6b..fc4c2c03d2c190 100644 --- a/.github/workflows/coverage-linux-without-intl.yml +++ b/.github/workflows/coverage-linux-without-intl.yml @@ -87,6 +87,6 @@ jobs: - name: Clean tmp run: rm -rf coverage/tmp && rm -rf out - name: Upload - uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 with: directory: ./coverage diff --git a/.github/workflows/coverage-linux.yml b/.github/workflows/coverage-linux.yml index 1ffc1e9969511e..2e3ac97ee7007b 100644 --- a/.github/workflows/coverage-linux.yml +++ b/.github/workflows/coverage-linux.yml @@ -87,6 +87,6 @@ jobs: - name: Clean tmp run: rm -rf coverage/tmp && rm -rf out - name: Upload - uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 with: directory: ./coverage diff --git a/.github/workflows/coverage-windows.yml b/.github/workflows/coverage-windows.yml index d4f87fe4d184e7..0f2e0b38258e7f 100644 --- a/.github/workflows/coverage-windows.yml +++ b/.github/workflows/coverage-windows.yml @@ -100,6 +100,6 @@ jobs: - name: Clean tmp run: npx rimraf ./coverage/tmp - name: Upload - uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # v6.0.1 + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 with: directory: ./coverage From 873d1e0412ef7722c2cfc050a5b3d937648f13bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 18:54:10 +0000 Subject: [PATCH 096/131] meta: bump actions/checkout from 6.0.2 to 7.0.0 Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.2 to 7.0.0. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6.0.2...9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] PR-URL: https://github.com/nodejs/node/pull/64245 Reviewed-By: Antoine du Hamel Reviewed-By: Colin Ihrig Reviewed-By: Luigi Pinca --- .github/workflows/benchmark.yml | 4 ++-- .github/workflows/build-tarball.yml | 4 ++-- .github/workflows/codeql.yml | 2 +- .github/workflows/commit-lint.yml | 2 +- .github/workflows/commit-queue.yml | 2 +- .../workflows/coverage-linux-without-intl.yml | 2 +- .github/workflows/coverage-linux.yml | 2 +- .github/workflows/coverage-windows.yml | 2 +- .github/workflows/create-release-proposal.yml | 2 +- .github/workflows/daily-wpt-fyi.yml | 6 ++--- .github/workflows/daily.yml | 2 +- .github/workflows/doc.yml | 2 +- .../workflows/find-inactive-collaborators.yml | 2 +- .github/workflows/find-inactive-tsc.yml | 4 ++-- .github/workflows/license-builder.yml | 2 +- .github/workflows/lint-release-proposal.yml | 2 +- .github/workflows/linters.yml | 22 +++++++++---------- .github/workflows/scorecard.yml | 2 +- .github/workflows/stress-test.yml | 2 +- .github/workflows/test-internet.yml | 2 +- .github/workflows/test-linux-quic.yml | 2 +- .github/workflows/test-linux.yml | 2 +- .github/workflows/test-macos.yml | 2 +- .github/workflows/test-shared.yml | 2 +- .github/workflows/timezone-update.yml | 4 ++-- .github/workflows/tools.yml | 2 +- .github/workflows/update-openssl.yml | 2 +- .github/workflows/update-v8.yml | 2 +- .github/workflows/update-wpt.yml | 2 +- 29 files changed, 45 insertions(+), 45 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 2e0ea4680ade2a..b989dd1faaef45 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -46,7 +46,7 @@ jobs: name: '${{ matrix.system }}: with shared libraries' runs-on: ${{ matrix.runner }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: repository: ${{ inputs.repo || github.repository }} ref: refs/pull/${{ inputs.pr_id }}/merge @@ -159,7 +159,7 @@ jobs: name: Aggregate benchmark results runs-on: ubuntu-slim steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false sparse-checkout: | diff --git a/.github/workflows/build-tarball.yml b/.github/workflows/build-tarball.yml index 1b6ea61dfe702a..fb0e7dbd323baa 100644 --- a/.github/workflows/build-tarball.yml +++ b/.github/workflows/build-tarball.yml @@ -74,7 +74,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-slim steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Set up Python ${{ env.PYTHON_VERSION }} @@ -105,7 +105,7 @@ jobs: SCCACHE_GHA_ENABLED: ${{ github.base_ref == 'main' || github.ref_name == 'main' }} SCCACHE_IDLE_TIMEOUT: '0' steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false sparse-checkout: .github/actions/install-clang diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f5a8113103d69c..3e50efed887521 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/commit-lint.yml b/.github/workflows/commit-lint.yml index 93ca3425be496e..896340ba3a820c 100644 --- a/.github/workflows/commit-lint.yml +++ b/.github/workflows/commit-lint.yml @@ -20,7 +20,7 @@ jobs: run: | echo "plusOne=$((${{ github.event.pull_request.commits }} + 1))" >> $GITHUB_OUTPUT echo "minusOne=$((${{ github.event.pull_request.commits }} - 1))" >> $GITHUB_OUTPUT - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: ${{ steps.nb-of-commits.outputs.plusOne }} persist-credentials: false diff --git a/.github/workflows/commit-queue.yml b/.github/workflows/commit-queue.yml index 8b5f37807b12af..7af71226871159 100644 --- a/.github/workflows/commit-queue.yml +++ b/.github/workflows/commit-queue.yml @@ -59,7 +59,7 @@ jobs: if: needs.get_mergeable_prs.outputs.numbers != '' runs-on: ubuntu-slim steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: # A personal token is required because pushing with GITHUB_TOKEN will # prevent commits from running CI after they land. It needs diff --git a/.github/workflows/coverage-linux-without-intl.yml b/.github/workflows/coverage-linux-without-intl.yml index fc4c2c03d2c190..60da6dc3d3646d 100644 --- a/.github/workflows/coverage-linux-without-intl.yml +++ b/.github/workflows/coverage-linux-without-intl.yml @@ -50,7 +50,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Install Clang ${{ env.CLANG_VERSION }} diff --git a/.github/workflows/coverage-linux.yml b/.github/workflows/coverage-linux.yml index 2e3ac97ee7007b..879ef11be362bc 100644 --- a/.github/workflows/coverage-linux.yml +++ b/.github/workflows/coverage-linux.yml @@ -50,7 +50,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-24.04-arm steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Install Clang ${{ env.CLANG_VERSION }} diff --git a/.github/workflows/coverage-windows.yml b/.github/workflows/coverage-windows.yml index 0f2e0b38258e7f..e4c9d5af0fca9f 100644 --- a/.github/workflows/coverage-windows.yml +++ b/.github/workflows/coverage-windows.yml @@ -69,7 +69,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: windows-2025 steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Set up Python ${{ env.PYTHON_VERSION }} diff --git a/.github/workflows/create-release-proposal.yml b/.github/workflows/create-release-proposal.yml index ae4c4240a25ca7..883bb48b0df240 100644 --- a/.github/workflows/create-release-proposal.yml +++ b/.github/workflows/create-release-proposal.yml @@ -33,7 +33,7 @@ jobs: RELEASE_LINE: ${{ inputs.release-line }} runs-on: ubuntu-slim steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: ref: ${{ env.STAGING_BRANCH }} persist-credentials: false diff --git a/.github/workflows/daily-wpt-fyi.yml b/.github/workflows/daily-wpt-fyi.yml index 30a94ea4d7cfd5..b798a5c05fbf73 100644 --- a/.github/workflows/daily-wpt-fyi.yml +++ b/.github/workflows/daily-wpt-fyi.yml @@ -64,7 +64,7 @@ jobs: SHORT_SHA=$(node -p 'process.version.split(/-nightly\d{8}/)[1]') echo "NIGHTLY_REF=$(gh api /repos/nodejs/node/commits/$SHORT_SHA --jq '.sha')" >> $GITHUB_ENV - name: Checkout ${{ steps.setup-node.outputs.node-version }} - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false ref: ${{ env.NIGHTLY_REF || steps.setup-node.outputs.node-version }} @@ -80,7 +80,7 @@ jobs: run: rm -rf wpt working-directory: test/fixtures - name: Checkout epochs/daily WPT - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: repository: web-platform-tests/wpt persist-credentials: false @@ -111,7 +111,7 @@ jobs: # version-specific checkout above overwrites .github/actions/ - name: Checkout undici WPT actions if: ${{ env.WPT_REPORT != '' }} - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: sparse-checkout: | .github/actions/undici-wpt-current diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml index a6298f2ef6a66a..1f6bf82d312659 100644 --- a/.github/workflows/daily.yml +++ b/.github/workflows/daily.yml @@ -16,7 +16,7 @@ jobs: if: github.repository == 'nodejs/node' || github.event_name == 'workflow_dispatch' runs-on: ubuntu-24.04-arm steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Use Node.js ${{ env.NODE_VERSION }} diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 9fc4ea329c0567..9dc73f7810f881 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -24,7 +24,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-slim steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Use Node.js ${{ env.NODE_VERSION }} diff --git a/.github/workflows/find-inactive-collaborators.yml b/.github/workflows/find-inactive-collaborators.yml index 35a0f4b1f5c77d..e6e0c7f54f69fa 100644 --- a/.github/workflows/find-inactive-collaborators.yml +++ b/.github/workflows/find-inactive-collaborators.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-slim steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 persist-credentials: false diff --git a/.github/workflows/find-inactive-tsc.yml b/.github/workflows/find-inactive-tsc.yml index 8deeaccf5dfdd3..c1804b78d378cb 100644 --- a/.github/workflows/find-inactive-tsc.yml +++ b/.github/workflows/find-inactive-tsc.yml @@ -20,13 +20,13 @@ jobs: steps: - name: Checkout the repo - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 persist-credentials: false - name: Clone nodejs/TSC repository - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 path: .tmp diff --git a/.github/workflows/license-builder.yml b/.github/workflows/license-builder.yml index 36d303f9e121ab..a95ee13c45f4de 100644 --- a/.github/workflows/license-builder.yml +++ b/.github/workflows/license-builder.yml @@ -17,7 +17,7 @@ jobs: if: github.repository == 'nodejs/node' runs-on: ubuntu-slim steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - run: ./tools/license-builder.sh # Run the license builder tool diff --git a/.github/workflows/lint-release-proposal.yml b/.github/workflows/lint-release-proposal.yml index 93c67df521d289..e8ffab178458c9 100644 --- a/.github/workflows/lint-release-proposal.yml +++ b/.github/workflows/lint-release-proposal.yml @@ -23,7 +23,7 @@ jobs: contents: read pull-requests: read steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false fetch-depth: 2 diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index 271bc8fecd3421..2153b743988208 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -25,7 +25,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-slim steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Use Node.js ${{ env.NODE_VERSION }} @@ -40,7 +40,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-slim steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Set up Python ${{ env.PYTHON_VERSION }} @@ -56,7 +56,7 @@ jobs: if: ${{ github.event.pull_request && github.event.pull_request.draft == false && github.base_ref == github.event.repository.default_branch }} runs-on: ubuntu-slim steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 persist-credentials: false @@ -95,7 +95,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-slim steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Use Node.js ${{ env.NODE_VERSION }} @@ -144,7 +144,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-slim steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false sparse-checkout: '*.nix' @@ -165,7 +165,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-slim steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false sparse-checkout: | @@ -193,7 +193,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-slim steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false sparse-checkout: | @@ -218,7 +218,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-slim steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false sparse-checkout: | @@ -234,7 +234,7 @@ jobs: # cannot use ubuntu-24.04-arm here because the docker image is x86 only runs-on: ubuntu-latest steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - uses: mszostok/codeowners-validator@7f3f5e28c6d7b8dfae5731e54ce2272ca384592f @@ -244,7 +244,7 @@ jobs: if: ${{ github.event.pull_request }} runs-on: ubuntu-slim steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 2 persist-credentials: false @@ -259,7 +259,7 @@ jobs: lint-readme: runs-on: ubuntu-slim steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false sparse-checkout: | diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index a6a5b030220559..4bd4411530113f 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -41,7 +41,7 @@ jobs: egress-policy: audit # TODO: change to 'egress-policy: block' after couple of runs - name: Checkout code - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/stress-test.yml b/.github/workflows/stress-test.yml index bfd3ffca7fe52d..d8cedf535f3dd7 100644 --- a/.github/workflows/stress-test.yml +++ b/.github/workflows/stress-test.yml @@ -54,7 +54,7 @@ jobs: SCCACHE_GHA_ENABLED: 'true' SCCACHE_IDLE_TIMEOUT: '0' steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false path: node diff --git a/.github/workflows/test-internet.yml b/.github/workflows/test-internet.yml index 788e01eb5eba5c..7f52b65e7e90cb 100644 --- a/.github/workflows/test-internet.yml +++ b/.github/workflows/test-internet.yml @@ -47,7 +47,7 @@ jobs: if: (github.event_name == 'schedule' && github.repository == 'nodejs/node') || (github.event.pull_request && github.event.pull_request.draft == false) runs-on: ubuntu-24.04-arm steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Install Clang ${{ env.CLANG_VERSION }} diff --git a/.github/workflows/test-linux-quic.yml b/.github/workflows/test-linux-quic.yml index 945bfb3ce5462c..cf717ec6926c10 100644 --- a/.github/workflows/test-linux-quic.yml +++ b/.github/workflows/test-linux-quic.yml @@ -47,7 +47,7 @@ jobs: if: github.event.pull_request.draft == false runs-on: ubuntu-24.04-arm steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false path: node diff --git a/.github/workflows/test-linux.yml b/.github/workflows/test-linux.yml index afae5a8ade2774..ad9286e9d941c1 100644 --- a/.github/workflows/test-linux.yml +++ b/.github/workflows/test-linux.yml @@ -58,7 +58,7 @@ jobs: matrix: os: [ubuntu-24.04, ubuntu-24.04-arm] steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false path: node diff --git a/.github/workflows/test-macos.yml b/.github/workflows/test-macos.yml index f72b20feaf2005..58ec23a4f1632e 100644 --- a/.github/workflows/test-macos.yml +++ b/.github/workflows/test-macos.yml @@ -83,7 +83,7 @@ jobs: SCCACHE_GHA_ENABLED: ${{ github.base_ref == 'main' || github.ref_name == 'main' }} SCCACHE_IDLE_TIMEOUT: '0' steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false path: node diff --git a/.github/workflows/test-shared.yml b/.github/workflows/test-shared.yml index ef22c29f478c86..cd9804d0d87d04 100644 --- a/.github/workflows/test-shared.yml +++ b/.github/workflows/test-shared.yml @@ -115,7 +115,7 @@ jobs: name: ${{ github.event_name == 'workflow_dispatch' && 'Skipped job' || 'Build slim tarball' }} runs-on: ubuntu-slim steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false diff --git a/.github/workflows/timezone-update.yml b/.github/workflows/timezone-update.yml index 02299e66b31ffc..94961f8ae6ed52 100644 --- a/.github/workflows/timezone-update.yml +++ b/.github/workflows/timezone-update.yml @@ -21,12 +21,12 @@ jobs: steps: - name: Checkout nodejs/node - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Checkout unicode-org/icu-data - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: path: icu-data persist-credentials: false diff --git a/.github/workflows/tools.yml b/.github/workflows/tools.yml index 289395ee577462..e5ea38b755c31f 100644 --- a/.github/workflows/tools.yml +++ b/.github/workflows/tools.yml @@ -307,7 +307,7 @@ jobs: tail -n1 temp-output | grep "NEW_VERSION=" >> "$GITHUB_ENV" || true rm temp-output steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 if: github.event_name == 'schedule' || inputs.id == 'all' || inputs.id == matrix.id with: persist-credentials: false diff --git a/.github/workflows/update-openssl.yml b/.github/workflows/update-openssl.yml index d87f6b3a4b5912..49f0006526b0a5 100644 --- a/.github/workflows/update-openssl.yml +++ b/.github/workflows/update-openssl.yml @@ -15,7 +15,7 @@ jobs: # Cannot use ubuntu-slim here because the update script requires Docker runs-on: ubuntu-latest steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Check and download new OpenSSL version diff --git a/.github/workflows/update-v8.yml b/.github/workflows/update-v8.yml index f75f5f8104d3fc..cb0642c1b06a79 100644 --- a/.github/workflows/update-v8.yml +++ b/.github/workflows/update-v8.yml @@ -16,7 +16,7 @@ jobs: if: github.repository == 'nodejs/node' runs-on: ubuntu-slim steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - name: Cache node modules and update-v8 diff --git a/.github/workflows/update-wpt.yml b/.github/workflows/update-wpt.yml index 49e234b2bb2396..4f752cc18985d5 100644 --- a/.github/workflows/update-wpt.yml +++ b/.github/workflows/update-wpt.yml @@ -27,7 +27,7 @@ jobs: subsystem: ${{ fromJSON(github.event.inputs.subsystems || '["url", "urlpattern", "WebCryptoAPI"]') }} steps: - - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false From 64aa17058f5d477fdbf209b093ea39ed650b3750 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 18:54:21 +0000 Subject: [PATCH 097/131] meta: bump github/codeql-action/analyze from 4.36.1 to 4.36.2 Bumps [github/codeql-action/analyze](https://github.com/github/codeql-action) from 4.36.1 to 4.36.2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/87557b9c84dde89fdd9b10e88954ac2f4248e463...8aad20d150bbac5944a9f9d289da16a4b0d87c1e) --- updated-dependencies: - dependency-name: github/codeql-action/analyze dependency-version: 4.36.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] PR-URL: https://github.com/nodejs/node/pull/64246 Reviewed-By: Colin Ihrig Reviewed-By: Antoine du Hamel --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 3e50efed887521..d8431944bc990e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -37,6 +37,6 @@ jobs: uses: github/codeql-action/autobuild@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v4.36.1 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v4.36.1 + uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 with: category: /language:${{matrix.language}} From 0808dcd31cdab3ecbdf4f8a88bd0838f5d7b29f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 18:54:34 +0000 Subject: [PATCH 098/131] meta: bump github/codeql-action/autobuild from 4.36.1 to 4.36.2 Bumps [github/codeql-action/autobuild](https://github.com/github/codeql-action) from 4.36.1 to 4.36.2. - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/github/codeql-action/compare/87557b9c84dde89fdd9b10e88954ac2f4248e463...8aad20d150bbac5944a9f9d289da16a4b0d87c1e) --- updated-dependencies: - dependency-name: github/codeql-action/autobuild dependency-version: 4.36.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] PR-URL: https://github.com/nodejs/node/pull/64247 Reviewed-By: Colin Ihrig Reviewed-By: Antoine du Hamel --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index d8431944bc990e..fea54e9b885249 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -34,7 +34,7 @@ jobs: config-file: ./.github/codeql-config.yml - name: Autobuild - uses: github/codeql-action/autobuild@87557b9c84dde89fdd9b10e88954ac2f4248e463 # v4.36.1 + uses: github/codeql-action/autobuild@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@8aad20d150bbac5944a9f9d289da16a4b0d87c1e # v4.36.2 From 829c4a5913a64f14a9a72d90d6abc9590f059c96 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 18:54:50 +0000 Subject: [PATCH 099/131] meta: bump actions/cache from 5.0.5 to 6.1.0 Bumps [actions/cache](https://github.com/actions/cache) from 5.0.5 to 6.1.0. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/27d5ce7f107fe9357f9df03efb73ab90386fccae...55cc8345863c7cc4c66a329aec7e433d2d1c52a9) --- updated-dependencies: - dependency-name: actions/cache dependency-version: 6.1.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] PR-URL: https://github.com/nodejs/node/pull/64248 Reviewed-By: Antoine du Hamel Reviewed-By: Colin Ihrig --- .github/workflows/update-v8.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/update-v8.yml b/.github/workflows/update-v8.yml index cb0642c1b06a79..e365cf77017422 100644 --- a/.github/workflows/update-v8.yml +++ b/.github/workflows/update-v8.yml @@ -20,7 +20,7 @@ jobs: with: persist-credentials: false - name: Cache node modules and update-v8 - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 id: cache-v8-npm env: cache-name: cache-v8-npm From d940f02e8b49fb4cd03df303887d1c3ad8e6823b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jul 2026 18:55:03 +0000 Subject: [PATCH 100/131] tools: bump the eslint group in /tools/eslint with 8 updates Bumps the eslint group in /tools/eslint with 8 updates: | Package | From | To | | --- | --- | --- | | [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) | `8.0.0-rc.6` | `8.0.1` | | [@babel/eslint-parser](https://github.com/babel/babel/tree/HEAD/eslint/babel-eslint-parser) | `8.0.0-rc.6` | `8.0.1` | | [@babel/plugin-syntax-import-defer](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-syntax-import-defer) | `8.0.0-rc.6` | `8.0.1` | | [@babel/plugin-syntax-import-source](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-syntax-import-source) | `8.0.0-rc.6` | `8.0.1` | | [eslint](https://github.com/eslint/eslint) | `10.4.0` | `10.5.0` | | [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) | `63.0.0` | `63.0.9` | | [eslint-plugin-regexp](https://github.com/ota-meshi/eslint-plugin-regexp) | `3.1.0` | `3.1.1` | | [globals](https://github.com/sindresorhus/globals) | `17.6.0` | `17.7.0` | Updates `@babel/core` from 8.0.0-rc.6 to 8.0.1 - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v8.0.1/packages/babel-core) Updates `@babel/eslint-parser` from 8.0.0-rc.6 to 8.0.1 - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v8.0.1/eslint/babel-eslint-parser) Updates `@babel/plugin-syntax-import-defer` from 8.0.0-rc.6 to 8.0.1 - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v8.0.1/packages/babel-plugin-syntax-import-defer) Updates `@babel/plugin-syntax-import-source` from 8.0.0-rc.6 to 8.0.1 - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v8.0.1/packages/babel-plugin-syntax-import-source) Updates `eslint` from 10.4.0 to 10.5.0 - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](https://github.com/eslint/eslint/compare/v10.4.0...v10.5.0) Updates `eslint-plugin-jsdoc` from 63.0.0 to 63.0.9 - [Release notes](https://github.com/gajus/eslint-plugin-jsdoc/releases) - [Commits](https://github.com/gajus/eslint-plugin-jsdoc/compare/v63.0.0...v63.0.9) Updates `eslint-plugin-regexp` from 3.1.0 to 3.1.1 - [Release notes](https://github.com/ota-meshi/eslint-plugin-regexp/releases) - [Changelog](https://github.com/ota-meshi/eslint-plugin-regexp/blob/master/CHANGELOG.md) - [Commits](https://github.com/ota-meshi/eslint-plugin-regexp/compare/v3.1.0...v3.1.1) Updates `globals` from 17.6.0 to 17.7.0 - [Release notes](https://github.com/sindresorhus/globals/releases) - [Commits](https://github.com/sindresorhus/globals/compare/v17.6.0...v17.7.0) --- updated-dependencies: - dependency-name: "@babel/core" dependency-version: 8.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: eslint - dependency-name: "@babel/eslint-parser" dependency-version: 8.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: eslint - dependency-name: "@babel/plugin-syntax-import-defer" dependency-version: 8.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: eslint - dependency-name: "@babel/plugin-syntax-import-source" dependency-version: 8.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: eslint - dependency-name: eslint dependency-version: 10.5.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: eslint - dependency-name: eslint-plugin-jsdoc dependency-version: 63.0.9 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: eslint - dependency-name: eslint-plugin-regexp dependency-version: 3.1.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: eslint - dependency-name: globals dependency-version: 17.7.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: eslint ... Signed-off-by: dependabot[bot] PR-URL: https://github.com/nodejs/node/pull/64249 Reviewed-By: Antoine du Hamel Reviewed-By: Colin Ihrig Reviewed-By: Luigi Pinca --- tools/eslint/package-lock.json | 357 +++++++++++++++++---------------- tools/eslint/package.json | 16 +- 2 files changed, 188 insertions(+), 185 deletions(-) diff --git a/tools/eslint/package-lock.json b/tools/eslint/package-lock.json index 47edf403673e5d..de8e6862cdb1b6 100644 --- a/tools/eslint/package-lock.json +++ b/tools/eslint/package-lock.json @@ -8,27 +8,27 @@ "name": "eslint-tools", "version": "0.0.0", "dependencies": { - "@babel/core": "^8.0.0-rc.6", - "@babel/eslint-parser": "^8.0.0-rc.6", - "@babel/plugin-syntax-import-defer": "^8.0.0-rc.6", - "@babel/plugin-syntax-import-source": "^8.0.0-rc.6", + "@babel/core": "^8.0.1", + "@babel/eslint-parser": "^8.0.1", + "@babel/plugin-syntax-import-defer": "^8.0.1", + "@babel/plugin-syntax-import-source": "^8.0.1", "@eslint/js": "^10.0.1", "@eslint/markdown": "^8.0.2", "@stylistic/eslint-plugin": "^5.10.0", - "eslint": "^10.4.0", + "eslint": "^10.5.0", "eslint-formatter-tap": "^9.0.1", - "eslint-plugin-jsdoc": "^63.0.0", - "eslint-plugin-regexp": "^3.1.0", - "globals": "^17.6.0" + "eslint-plugin-jsdoc": "^63.0.9", + "eslint-plugin-regexp": "^3.1.1", + "globals": "^17.7.0" } }, "node_modules/@babel/code-frame": { - "version": "8.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-8.0.0-rc.6.tgz", - "integrity": "sha512-Ru0EdYEptXbJGAGDMsenx+RcelHazuj8spqi7l0geXEPXv0X7qVisqWX+2pMaEZsWhS3Q6Um7oITwhnLe0cHJQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-8.0.0.tgz", + "integrity": "sha512-dYYg153EyN2Ekbqw2zAsbd6/JR+9N2SEoC7YV2GyyqMM7x9bLDTjBD6XBhSMLH0wtIVyJj03jWNriQhaN+eoCw==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^8.0.0-rc.6", + "@babel/helper-validator-identifier": "^8.0.0", "js-tokens": "^10.0.0" }, "engines": { @@ -36,31 +36,31 @@ } }, "node_modules/@babel/compat-data": { - "version": "8.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-8.0.0-rc.6.tgz", - "integrity": "sha512-9ikfbIp7PCtV/mo8NYrzag1TYInVJAKLwpSoA28+3Bl5z1KVYt5ZGvBZD57yJlf/0HsCntlTlHHodu+eMpUffQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-8.0.0.tgz", + "integrity": "sha512-DOjnob/cXOUgDOozCDeq/aK2p5y8dUIVdf6tNhEV1HQRd6I8aQ4f4fbtHRVEvb6lP3BGomrKHiS8ICAASSVQSw==", "license": "MIT", "engines": { "node": "^22.18.0 || >=24.11.0" } }, "node_modules/@babel/core": { - "version": "8.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-8.0.0-rc.6.tgz", - "integrity": "sha512-89SVbTu7p+M/W052SFC7R5QuQYgypfuO6HmBBbhA/Kzl6gME8Ly2QrVpIegvTxmcQKOzAPIxiEIfNk+Jxd26mw==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^8.0.0-rc.6", - "@babel/generator": "^8.0.0-rc.6", - "@babel/helper-compilation-targets": "^8.0.0-rc.6", - "@babel/helpers": "^8.0.0-rc.6", - "@babel/parser": "^8.0.0-rc.6", - "@babel/template": "^8.0.0-rc.6", - "@babel/traverse": "^8.0.0-rc.6", - "@babel/types": "^8.0.0-rc.6", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-8.0.1.tgz", + "integrity": "sha512-5FgxM4dLQpMJHSiVATk8foW263dVHQHBVpXYiimNECVWG01f4nFyEbQixeT6Mwvg7TayREJ2gpKl3o2RoMdnqw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^8.0.0", + "@babel/generator": "^8.0.0", + "@babel/helper-compilation-targets": "^8.0.0", + "@babel/helpers": "^8.0.0", + "@babel/parser": "^8.0.0", + "@babel/template": "^8.0.0", + "@babel/traverse": "^8.0.0", + "@babel/types": "^8.0.0", "@types/gensync": "^1.0.5", "convert-source-map": "^2.0.0", - "find-up-simple": "^1.0.1", + "empathic": "^2.0.1", "gensync": "^1.0.0-beta.2", "import-meta-resolve": "^4.2.0", "json5": "^2.2.3", @@ -76,9 +76,9 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "8.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-8.0.0-rc.6.tgz", - "integrity": "sha512-qVHD7K5PyUXj57bsJWbyT5V9JtOX/4dtX9QSQpqGfBG4xiVE/mrCYCT25Ih+wHvISR98Lctl9BtvEUtGyYsrvA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-8.0.1.tgz", + "integrity": "sha512-2javO8pAQv/ld6sS6OcxoLAlzZEZy+xm99bnoAfMhzKSumKhdF5wylpbZB7XTorWr3KLPtx5K95eduJPOy1mzA==", "license": "MIT", "dependencies": { "eslint-scope": "^9.1.0", @@ -89,18 +89,18 @@ "node": "^22.18.0 || >=24.11.0" }, "peerDependencies": { - "@babel/core": "^8.0.0-rc.6", + "@babel/core": "^8.0.0", "eslint": "^9.0.0 || ^10.0.0" } }, "node_modules/@babel/generator": { - "version": "8.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-8.0.0-rc.6.tgz", - "integrity": "sha512-6mIzgVK8DgEzvIapoQwhXTMnnkuE4STQmVv9H03i/tZ2ml8oev3TRvZJgTenK2Bsq0YWNtzOrFdTyNzCMFtjJQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-8.0.0.tgz", + "integrity": "sha512-NT9NrVwJsbSV6Y2FSstWa71EETOnzrjkL5/wX3D2mYHtKM+qvqB1DvR4D0Setb/gDBsHzRICifwEWMO8CnTF6g==", "license": "MIT", "dependencies": { - "@babel/parser": "^8.0.0-rc.6", - "@babel/types": "^8.0.0-rc.6", + "@babel/parser": "^8.0.0", + "@babel/types": "^8.0.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "@types/jsesc": "^2.5.0", @@ -111,15 +111,15 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "8.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-8.0.0-rc.6.tgz", - "integrity": "sha512-jqQD45/yUSy63U8zs9hE5FMXS8J1TLAI/NTMx76C6xWO021e13gJACQvuGmEF7syloC39LkkKwhqtAbMku1rwg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-8.0.0.tgz", + "integrity": "sha512-JwculLABZvyPvyLBpwU/E/IbH2uM3mnxNtIJpxnIfb24y1PrdVxK5Dqjle4DpgqpGRnwgC7G8IkzPdSXZrO1Ew==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^8.0.0-rc.6", - "@babel/helper-validator-option": "^8.0.0-rc.6", + "@babel/compat-data": "^8.0.0", + "@babel/helper-validator-option": "^8.0.0", "browserslist": "^4.24.0", - "lru-cache": "^7.14.1", + "lru-cache": "^11.0.0", "semver": "^7.7.3" }, "engines": { @@ -127,73 +127,73 @@ } }, "node_modules/@babel/helper-globals": { - "version": "8.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-8.0.0-rc.6.tgz", - "integrity": "sha512-ZF5FsxE4y7Eb6DiEbsLW3Gz3e73U/Uq3/ZotWf/moxv0DnZziXSMnW/tcXJF8b1mQE8XJnwPNSQOksKcKTz8kQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-8.0.0.tgz", + "integrity": "sha512-lLozHOM6sWWlxNo8CYqHy4MBZeTvHXNgVPBfPOGsjPKUzHC2Az9QwB6gxdQmpwHl6GlQtbGgS+lj5887guDiLw==", "license": "MIT", "engines": { "node": "^22.18.0 || >=24.11.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "8.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-8.0.0-rc.6.tgz", - "integrity": "sha512-sLAjvuIcjzUQJR+CoHwU0JA4i706o71bCJtF+W9sc4KuHK3LCIJCjbKRuzbVn1eubUc66uAEZdBNWSqhLpwp2g==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-8.0.1.tgz", + "integrity": "sha512-3PKFgjTyPlhFhorfP+SjKQxLViIL++zWjFOO4hGriYU+Bsm983DxEM1JmDRJVWXV0O9npu+xXRqz7Pbd3mh70g==", "license": "MIT", "engines": { "node": "^22.18.0 || >=24.11.0" }, "peerDependencies": { - "@babel/core": "^8.0.0-rc.6" + "@babel/core": "^8.0.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "8.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0-rc.6.tgz", - "integrity": "sha512-BCkFy+zN6kXQed3YOT7aJl93NfDSzQc3pBfsvTVPs9gU9X3V0aefEF5kwBT0E+mDWH9QgKaZstYUQN9VdQZT4g==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-8.0.0.tgz", + "integrity": "sha512-6mJgmFFFIIO82vvoLt9XtRC7/TkzXfts1t/SpRX4IHSzMgqoPYCWesVu1udUPUWioAE/2fcG6WuI8zrkE1gwrg==", "license": "MIT", "engines": { "node": "^22.18.0 || >=24.11.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "8.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.0-rc.6.tgz", - "integrity": "sha512-nVJ+1JcCgntv8d78rRo++o2wuODT0Irknx2BF8Np4Ft2CRgjLqIs4qzSZ8b66yGbBdMWGmZBO9WEZv1hhNiSpg==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.2.tgz", + "integrity": "sha512-9Fr9QeyCAyi1BR1jKZ6uYQ24EIhQUx5ReHfQU7drOE+TPOb+w11/dsqLkMOT2U29OdCT71XajrOT8xDc1C7orA==", "license": "MIT", "engines": { "node": "^22.18.0 || >=24.11.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "8.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-8.0.0-rc.6.tgz", - "integrity": "sha512-uonhzCIL2Vf0xA10g5C0zD5thR7a6XxOSwZAzYfyl8n2zEev5bAB9J4b2oZ7u5YkyqdONfkptl2DesvW2P56Kg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-8.0.0.tgz", + "integrity": "sha512-U4Dybxh4WESWHt5XhBeExi4DrY0/DNK1aHpQbsrQXCUbFHuMweT0TpLEWKvaraV2Y6fS+ZXunsZ8zIuZIgvF2Q==", "license": "MIT", "engines": { "node": "^22.18.0 || >=24.11.0" } }, "node_modules/@babel/helpers": { - "version": "8.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-8.0.0-rc.6.tgz", - "integrity": "sha512-kTTqnw+Ubp1/WGXiIpDcl+WYVGTUVGjrQKswGI9VOamk7eWVf5ZYOcCB+o1UxaaHjs/L+QK7IRPlyP7vg579OQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-8.0.0.tgz", + "integrity": "sha512-wfbi91pM3py96oIiJEz7qIpyXDytgr9zQC1HEWwlGNVRAEmItuU/0a41ZUKu1sJGyhhOIpc4t5vk4PYzt8wpsg==", "license": "MIT", "dependencies": { - "@babel/template": "^8.0.0-rc.6", - "@babel/types": "^8.0.0-rc.6" + "@babel/template": "^8.0.0", + "@babel/types": "^8.0.0" }, "engines": { "node": "^22.18.0 || >=24.11.0" } }, "node_modules/@babel/parser": { - "version": "8.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.0-rc.6.tgz", - "integrity": "sha512-rOS8IpdO7mQELkTPlCsTgPejO0bFuZdEDCGQJouYbYf9e1FLTym7Fei2pEjq8q7MWbX0ravcd7QQYKs1TxOuog==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.0.tgz", + "integrity": "sha512-aLxAE+imI9bCcyaPrUDjBv3uSkWieifjLe0kuFOZF0zli0L6GCsTmsePnTr55adbIAgYz2zhN1vnFimCBUYcRQ==", "license": "MIT", "dependencies": { - "@babel/types": "^8.0.0-rc.6" + "@babel/types": "^8.0.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -203,61 +203,61 @@ } }, "node_modules/@babel/plugin-syntax-import-defer": { - "version": "8.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-defer/-/plugin-syntax-import-defer-8.0.0-rc.6.tgz", - "integrity": "sha512-VUzalsGv2W89DJbKyXy8mP7uhsXFZoE4td5iDndOGART94WLXvnKuF72ndJFFYE8t4eRS0zX5PZFmMGBVGmIUw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-defer/-/plugin-syntax-import-defer-8.0.1.tgz", + "integrity": "sha512-fRveH6xm797m3R8dIP0JlW/pGVsWeBPArVoh0+QG3biW8o66oukSKtTkjGRVCwTTdfspra/XU0Jq482mECzB+g==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^8.0.0-rc.6" + "@babel/helper-plugin-utils": "^8.0.1" }, "engines": { "node": "^22.18.0 || >=24.11.0" }, "peerDependencies": { - "@babel/core": "^8.0.0-rc.6" + "@babel/core": "^8.0.0" } }, "node_modules/@babel/plugin-syntax-import-source": { - "version": "8.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-source/-/plugin-syntax-import-source-8.0.0-rc.6.tgz", - "integrity": "sha512-kvUkjNZhBdZleJjJ60gH5QGHD2ttZBzEZACPnqaAMraDdPz0bERCWNyptdiCZFTOBo6LRhD9QtMAzdZK3jvPZQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-source/-/plugin-syntax-import-source-8.0.1.tgz", + "integrity": "sha512-qtgn6T5XL3GxNq+7MPj/12D8lCnVHBJQVzRYqHbgZhu+Y5XEYeEM6h9FlMinGkrbS5SMH/b6oTX7ewXtfcMR8A==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^8.0.0-rc.6" + "@babel/helper-plugin-utils": "^8.0.1" }, "engines": { "node": "^22.18.0 || >=24.11.0" }, "peerDependencies": { - "@babel/core": "^8.0.0-rc.6" + "@babel/core": "^8.0.0" } }, "node_modules/@babel/template": { - "version": "8.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-8.0.0-rc.6.tgz", - "integrity": "sha512-CZFjZblLiIUEFghbB3sKs3rpYrwo65rLIklw/gNpwBm326cU6TH/xzvJZlZ+H9HpDi00eDXqNJR8CtEKW3oc/A==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-8.0.0.tgz", + "integrity": "sha512-eAD0QW/AlbamBbw0FeGiwasbCVPq5ncW0HNVyLP3B9czqLyh4gvw+5JTSNt6le9+ziAU7mqDZsKTHf3jTb4chQ==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^8.0.0-rc.6", - "@babel/parser": "^8.0.0-rc.6", - "@babel/types": "^8.0.0-rc.6" + "@babel/code-frame": "^8.0.0", + "@babel/parser": "^8.0.0", + "@babel/types": "^8.0.0" }, "engines": { "node": "^22.18.0 || >=24.11.0" } }, "node_modules/@babel/traverse": { - "version": "8.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-8.0.0-rc.6.tgz", - "integrity": "sha512-/txuBViGaE9gpM8MSGShru1O2Bzp3zb3m/XKZNUsNv2SyNn++lKDDIWkiIQ/345j2FBy7CHiYTZuKhewHWyefw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-8.0.0.tgz", + "integrity": "sha512-bxTj/W2VclGE6CctlfQOpxg8MPDzXArRqkOBePw8EHfebcjF7fETWSS3BriEECo+UiU/Yblq+xUtSImFu7cTbw==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^8.0.0-rc.6", - "@babel/generator": "^8.0.0-rc.6", - "@babel/helper-globals": "^8.0.0-rc.6", - "@babel/parser": "^8.0.0-rc.6", - "@babel/template": "^8.0.0-rc.6", - "@babel/types": "^8.0.0-rc.6", + "@babel/code-frame": "^8.0.0", + "@babel/generator": "^8.0.0", + "@babel/helper-globals": "^8.0.0", + "@babel/parser": "^8.0.0", + "@babel/template": "^8.0.0", + "@babel/types": "^8.0.0", "obug": "^2.1.1" }, "engines": { @@ -265,27 +265,27 @@ } }, "node_modules/@babel/types": { - "version": "8.0.0-rc.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.0-rc.6.tgz", - "integrity": "sha512-p7/ABylAYlexb31wtRdIfH9L9A0Z2T/9H6zAqzqndkY2PLkvNNc580wGhp/gGKN4Sp9sQvSkhc6Oga8/O+wTyw==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.0.tgz", + "integrity": "sha512-K8ponJDxBwDHigkeFqaqT5wLGl4bTlwMafR8k7b5CPxr6Ww+UG9ls8Yx6Tcpboxu97eeGVEEyKcHmEyOwN1vSw==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^8.0.0-rc.6", - "@babel/helper-validator-identifier": "^8.0.0-rc.6" + "@babel/helper-string-parser": "^8.0.0", + "@babel/helper-validator-identifier": "^8.0.0" }, "engines": { "node": "^22.18.0 || >=24.11.0" } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.86.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.86.0.tgz", - "integrity": "sha512-ukZmRQ81WiTpDWO6D/cTBM7XbrNtutHKvAVnZN/8pldAwLoJArGOvkNyxPTBGsPjsoaQBJxlH+tE2TNA/92Qgw==", + "version": "0.87.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.87.0.tgz", + "integrity": "sha512-mFXZloZMzuJZXSHUmAFu/pXTk0ZJTJBluuAkrvbzidpTN8W6F2bpRFuedSH+85kbdlRLJqc+gfN+kD3JOLJK5g==", "license": "MIT", "dependencies": { - "@types/estree": "^1.0.8", - "@typescript-eslint/types": "^8.58.0", - "comment-parser": "1.4.6", + "@types/estree": "^1.0.9", + "@typescript-eslint/types": "^8.59.4", + "comment-parser": "1.4.7", "esquery": "^1.7.0", "jsdoc-type-pratt-parser": "~7.2.0" }, @@ -589,9 +589,9 @@ "license": "MIT" }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "license": "MIT" }, "node_modules/@types/gensync": { @@ -649,9 +649,9 @@ "license": "MIT" }, "node_modules/@typescript-eslint/types": { - "version": "8.59.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.0.tgz", - "integrity": "sha512-nLzdsT1gdOgFxxxwrlNVUBzSNBEEHJ86bblmk4QAS6stfig7rcJzWKqCyxFy3YRRHXDWEkb2NralA1nOYkkm/A==", + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.1.tgz", + "integrity": "sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -723,9 +723,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.10.33", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.33.tgz", - "integrity": "sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==", + "version": "2.10.40", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.40.tgz", + "integrity": "sha512-BSSLZ9/Cjjv7Gtj5B68ZzXcXUg8iOf3fme+FCuh8rC/Go+Kmh8cox7M3A8dolou16s64QjLPOSdngh7GxXvkSw==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.cjs" @@ -747,9 +747,9 @@ } }, "node_modules/browserslist": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", - "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "version": "4.28.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.4.tgz", + "integrity": "sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==", "funding": [ { "type": "opencollective", @@ -766,10 +766,10 @@ ], "license": "MIT", "dependencies": { - "baseline-browser-mapping": "^2.10.12", - "caniuse-lite": "^1.0.30001782", - "electron-to-chromium": "^1.5.328", - "node-releases": "^2.0.36", + "baseline-browser-mapping": "^2.10.38", + "caniuse-lite": "^1.0.30001799", + "electron-to-chromium": "^1.5.376", + "node-releases": "^2.0.48", "update-browserslist-db": "^1.2.3" }, "bin": { @@ -780,9 +780,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001793", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", - "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", + "version": "1.0.30001800", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001800.tgz", + "integrity": "sha512-MMHtuAz9Ys840zAY5F4k6fV5GaivZ9sPk+nz0mY+GYVzRBnYkN0mpqkSR92oWRQ19yQWo4HvBV/FnC16AJX8MA==", "funding": [ { "type": "opencollective", @@ -829,9 +829,9 @@ } }, "node_modules/comment-parser": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.6.tgz", - "integrity": "sha512-ObxuY6vnbWTN6Od72xfwN9DbzC7Y2vv8u1Soi9ahRKL37gb6y1qk6/dgjs+3JWuXJHWvsg3BXIwzd/rkmAwavg==", + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.7.tgz", + "integrity": "sha512-0h+uSNtQGW3D98eQt3jJ8L06Fves8hncB4V/PKdw/Qb8Hnk19VaKuTr55UNRYiSoVa7WwrFls+rh3ux9agmkeQ==", "license": "MIT", "engines": { "node": ">= 12.0.0" @@ -916,11 +916,20 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.366", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.366.tgz", - "integrity": "sha512-OlRuhb688YTCzzU3gXPLn6nGyd+F+53INE1qaKKlu6kETErE8FYsyDh0XqXEU+uBRn0MpCzz2vfNwORhkap8qg==", + "version": "1.5.383", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.383.tgz", + "integrity": "sha512-I2484/KkAvl8lm9VyjH2JnbOIV0d/UCqT7gbzs6l+o6Vmn9wgB66uVcKX+Vk6HrXtY6fbWTOEXuv8waDTuFNCw==", "license": "ISC" }, + "node_modules/empathic": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.1.tgz", + "integrity": "sha512-YGRs8knHhKHVShLkFET/rWAU8kmHbOV5LwN938RHI0pljAJ1Gf6SzXsSmRaEzcXTtOOmVqJ5+WtQPL5uigY50Q==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -943,17 +952,20 @@ } }, "node_modules/eslint": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.4.0.tgz", - "integrity": "sha512-loXy6bWOoP3EP6JA7jo6p5jMpBJmHmsNZM5SFRHLdh1MGOPurMnNBj4ZlAbaqUAaQWbCr7jHV4P7gzAyryZWkQ==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.5.0.tgz", + "integrity": "sha512-1y+7C+vi12bUK1IpZeaV3gsH9fHLBmPvYmPx42pvT/E9yG0IC8g3PUZZgp0+JLJl7ZDK0flc2gc+Aw9dpCvIsQ==", "license": "MIT", + "workspaces": [ + "packages/*" + ], "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", "@eslint/config-array": "^0.23.5", "@eslint/config-helpers": "^0.6.0", "@eslint/core": "^1.2.1", - "@eslint/plugin-kit": "^0.7.1", + "@eslint/plugin-kit": "^0.7.2", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", @@ -1010,23 +1022,23 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "63.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-63.0.0.tgz", - "integrity": "sha512-eDHuVGyZydr4BKgjXouU7bsn5qaqUlObXBSWRJk3vXcQgXVFnrwWIqpP7uBhRX9NQpk6NIIFyRc6F6omZNi/8g==", + "version": "63.0.9", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-63.0.9.tgz", + "integrity": "sha512-SJskF1zzPPRVfsmJyr/PqUXcpjA7o5Y0YnEoLBMDQlQWhELbYMRvK/8Fzlvh5XwEwJW8glAtKGKucaL0WGPMkw==", "license": "BSD-3-Clause", "dependencies": { - "@es-joy/jsdoccomment": "~0.86.0", + "@es-joy/jsdoccomment": "~0.87.0", "@es-joy/resolve.exports": "1.2.0", "are-docs-informative": "^0.0.2", - "comment-parser": "1.4.6", + "comment-parser": "1.4.7", "debug": "^4.4.3", "escape-string-regexp": "^4.0.0", "espree": "^11.2.0", "esquery": "^1.7.0", "html-entities": "^2.6.0", - "object-deep-merge": "^2.0.0", + "object-deep-merge": "^2.0.1", "parse-imports-exports": "^0.2.4", - "semver": "^7.8.0", + "semver": "^7.8.2", "spdx-expression-parse": "^4.0.0", "to-valid-identifier": "^1.0.0" }, @@ -1055,9 +1067,9 @@ } }, "node_modules/eslint-plugin-regexp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-3.1.0.tgz", - "integrity": "sha512-qGXIC3DIKZHcK1H9A9+Byz9gmndY6TTSRkSMTZpNXdyCw2ObSehRgccJv35n9AdUakEjQp5VFNLas6BMXizCZg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-regexp/-/eslint-plugin-regexp-3.1.1.tgz", + "integrity": "sha512-MxR5nqoQCtVWmJwia0D2+NlXX1xzdpkslsVOZLEYQ4PQWEaL65PCZXURxaBc3lPnkNFpNxzMIRmYVxdl8giXRA==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", @@ -1252,18 +1264,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/find-up-simple": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", - "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/flat-cache": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", @@ -1319,9 +1319,9 @@ } }, "node_modules/globals": { - "version": "17.6.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz", - "integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==", + "version": "17.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.7.0.tgz", + "integrity": "sha512-Czmyns5dUsq4seFBR/Kdydhmo8y9kC79hiSkPn0YcGtNnYWnrgt0vjrSjx9tspoDGWm2CMarffRuLjM4xUz8xg==", "license": "MIT", "engines": { "node": ">=18" @@ -1544,12 +1544,12 @@ } }, "node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "license": "ISC", + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=12" + "node": "20 || >=22" } }, "node_modules/markdown-table": { @@ -2438,29 +2438,32 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.47", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz", - "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==", + "version": "2.0.50", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.50.tgz", + "integrity": "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==", "license": "MIT", "engines": { "node": ">=18" } }, "node_modules/object-deep-merge": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/object-deep-merge/-/object-deep-merge-2.0.0.tgz", - "integrity": "sha512-3DC3UMpeffLTHiuXSy/UG4NOIYTLlY9u3V82+djSCLYClWobZiS4ivYzpIUWrRY/nfsJ8cWsKyG3QfyLePmhvg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object-deep-merge/-/object-deep-merge-2.0.1.tgz", + "integrity": "sha512-aKttDKcU3pyZqKcCkDhsMn70WmZFG2JGDQLP9EcLyTSIFQRCPWLAmBZRLJnrVUrhPG1jETEEbfdgbNtJf1LyMg==", "license": "MIT" }, "node_modules/obug": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", - "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.3.tgz", + "integrity": "sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==", "funding": [ "https://github.com/sponsors/sxzz", "https://opencollective.com/debug" ], - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } }, "node_modules/optionator": { "version": "0.9.4", @@ -2630,9 +2633,9 @@ } }, "node_modules/semver": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", - "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "license": "ISC", "bin": { "semver": "bin/semver.js" diff --git a/tools/eslint/package.json b/tools/eslint/package.json index 0002933967b711..3199c2bb7b175a 100644 --- a/tools/eslint/package.json +++ b/tools/eslint/package.json @@ -3,17 +3,17 @@ "version": "0.0.0", "private": true, "dependencies": { - "@babel/core": "^8.0.0-rc.6", - "@babel/eslint-parser": "^8.0.0-rc.6", - "@babel/plugin-syntax-import-defer": "^8.0.0-rc.6", - "@babel/plugin-syntax-import-source": "^8.0.0-rc.6", + "@babel/core": "^8.0.1", + "@babel/eslint-parser": "^8.0.1", + "@babel/plugin-syntax-import-defer": "^8.0.1", + "@babel/plugin-syntax-import-source": "^8.0.1", "@eslint/js": "^10.0.1", "@eslint/markdown": "^8.0.2", "@stylistic/eslint-plugin": "^5.10.0", - "eslint": "^10.4.0", + "eslint": "^10.5.0", "eslint-formatter-tap": "^9.0.1", - "eslint-plugin-jsdoc": "^63.0.0", - "eslint-plugin-regexp": "^3.1.0", - "globals": "^17.6.0" + "eslint-plugin-jsdoc": "^63.0.9", + "eslint-plugin-regexp": "^3.1.1", + "globals": "^17.7.0" } } From c81f894ebe01f3923b18c4864dfa3f44a985eaa5 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Sat, 4 Jul 2026 07:54:40 +0200 Subject: [PATCH 101/131] stream: cut per-chunk overhead in WHATWG streams Consolidate the spec's per-chunk predicate chains (CanCloseOrEnqueue, IsLocked, HasDefaultReader, GetNumReadRequests, GetDesiredSize and the writable-side equivalents) into single passes over the controller and stream state, mirror "close queued or in flight" as a boolean flag maintained at the few close-request transition sites, and materialize the TransformStream [[backpressureChangePromise]] record lazily on first observation so backpressure flips nobody is waiting on allocate nothing. Assisted-by: Claude Code Signed-off-by: Matteo Collina PR-URL: https://github.com/nodejs/node/pull/64252 Reviewed-By: Antoine du Hamel Reviewed-By: Yagiz Nizipli Reviewed-By: Filip Skokan --- lib/internal/webstreams/readablestream.js | 83 ++++++++++++---------- lib/internal/webstreams/transformstream.js | 44 ++++++------ lib/internal/webstreams/util.js | 37 +++++----- lib/internal/webstreams/writablestream.js | 53 ++++++++------ 4 files changed, 119 insertions(+), 98 deletions(-) diff --git a/lib/internal/webstreams/readablestream.js b/lib/internal/webstreams/readablestream.js index ee496f30e5934e..92508613e8883e 100644 --- a/lib/internal/webstreams/readablestream.js +++ b/lib/internal/webstreams/readablestream.js @@ -2480,21 +2480,26 @@ function readableStreamDefaultControllerClose(controller) { } function readableStreamDefaultControllerEnqueue(controller, chunk) { - if (!readableStreamDefaultControllerCanCloseOrEnqueue(controller)) + // Equivalent to readableStreamDefaultControllerCanCloseOrEnqueue() + // followed by isReadableStreamLocked() and + // readableStreamGetNumReadRequests(), but with the state loaded once: + // this runs for every enqueued chunk. + const controllerState = controller[kState]; + const stream = controllerState.stream; + if (controllerState.closeRequested || stream[kState].state !== 'readable') return; - const { - stream, - } = controller[kState]; - - if (isReadableStreamLocked(stream) && - readableStreamGetNumReadRequests(stream)) { + const reader = stream[kState].reader; + if (reader !== undefined && + reader[kState] !== undefined && + reader[kType] === 'ReadableStreamDefaultReader' && + reader[kState].readRequests.length) { readableStreamFulfillReadRequest(stream, chunk, false); } else { try { const chunkSize = FunctionPrototypeCall( - controller[kState].sizeAlgorithm, + controllerState.sizeAlgorithm, undefined, chunk); enqueueValueWithSize(controller, chunk, chunkSize); @@ -2533,22 +2538,27 @@ function readableStreamDefaultControllerGetDesiredSize(controller) { } function readableStreamDefaultControllerShouldCallPull(controller) { - const { - stream, - } = controller[kState]; - if (!readableStreamDefaultControllerCanCloseOrEnqueue(controller) || - !controller[kState].started) + // Single-pass version of the spec's predicate chain (CanCloseOrEnqueue, + // IsLocked, HasDefaultReader, GetNumReadRequests, GetDesiredSize): this + // runs at least once per chunk on every default-stream path. The + // desired-size computation is inlined because the stream state is + // already known to be 'readable' here. + const controllerState = controller[kState]; + const stream = controllerState.stream; + if (controllerState.closeRequested || + stream[kState].state !== 'readable' || + !controllerState.started) return false; - if (isReadableStreamLocked(stream) && - readableStreamGetNumReadRequests(stream)) { + const reader = stream[kState].reader; + if (reader !== undefined && + reader[kState] !== undefined && + reader[kType] === 'ReadableStreamDefaultReader' && + reader[kState].readRequests.length) { return true; } - const desiredSize = readableStreamDefaultControllerGetDesiredSize(controller); - assert(desiredSize !== null); - - return desiredSize > 0; + return controllerState.highWaterMark - controllerState.queueTotalSize > 0; } function readableStreamDefaultControllerCallPullIfNeeded(controller) { @@ -2798,28 +2808,29 @@ function readableByteStreamControllerGetDesiredSize(controller) { } function readableByteStreamControllerShouldCallPull(controller) { - const { - stream, - } = controller[kState]; + // Single-pass version of the spec's predicate chain (HasDefaultReader, + // GetNumReadRequests, HasBYOBReader, GetNumReadIntoRequests, + // GetDesiredSize): this runs at least once per chunk on every byte + // stream path. The desired-size computation is inlined because the + // stream state is already known to be 'readable' here. + const controllerState = controller[kState]; + const stream = controllerState.stream; if (stream[kState].state !== 'readable' || - controller[kState].closeRequested || - !controller[kState].started) { + controllerState.closeRequested || + !controllerState.started) { return false; } - if (readableStreamHasDefaultReader(stream) && - readableStreamGetNumReadRequests(stream) > 0) { - return true; - } - - if (readableStreamHasBYOBReader(stream) && - readableStreamGetNumReadIntoRequests(stream) > 0) { - return true; + const reader = stream[kState].reader; + if (reader !== undefined && reader[kState] !== undefined) { + const type = reader[kType]; + if (type === 'ReadableStreamDefaultReader') { + if (reader[kState].readRequests.length) return true; + } else if (type === 'ReadableStreamBYOBReader') { + if (reader[kState].readIntoRequests.length) return true; + } } - const desiredSize = readableByteStreamControllerGetDesiredSize(controller); - assert(desiredSize !== null); - - return desiredSize > 0; + return controllerState.highWaterMark - controllerState.queueTotalSize > 0; } function readableByteStreamControllerHandleQueueDrain(controller) { diff --git a/lib/internal/webstreams/transformstream.js b/lib/internal/webstreams/transformstream.js index 5b1be9e3aa7a65..535c783a3a31c3 100644 --- a/lib/internal/webstreams/transformstream.js +++ b/lib/internal/webstreams/transformstream.js @@ -258,12 +258,7 @@ function InternalTransferredTransformStream() { readable: undefined, writable: undefined, backpressure: undefined, - backpressureChange: { - __proto__: null, - promise: undefined, - resolve: undefined, - reject: undefined, - }, + backpressureChange: undefined, controller: undefined, }; } @@ -390,12 +385,7 @@ function initializeTransformStream( writable, controller: undefined, backpressure: undefined, - backpressureChange: { - __proto__: null, - promise: undefined, - resolve: undefined, - reject: undefined, - }, + backpressureChange: undefined, }; transformStreamSetBackpressure(stream, true); @@ -429,12 +419,27 @@ function transformStreamUnblockWrite(stream) { transformStreamSetBackpressure(stream, false); } +// The spec's [[backpressureChangePromise]] is only ever observed by the +// source pull algorithm (settles when backpressure next becomes true) and +// by a sink write arriving while backpressure is set (settles when +// backpressure next becomes false). Instead of allocating a fresh promise +// record on every flip, the record is materialized lazily on first +// observation and dropped once settled; flips nobody is waiting on +// allocate nothing. +function transformStreamBackpressureChangePromise(stream) { + const state = stream[kState]; + return (state.backpressureChange ??= PromiseWithResolvers()).promise; +} + function transformStreamSetBackpressure(stream, backpressure) { - assert(stream[kState].backpressure !== backpressure); - if (stream[kState].backpressureChange.promise !== undefined) - stream[kState].backpressureChange.resolve?.(); - stream[kState].backpressureChange = PromiseWithResolvers(); - stream[kState].backpressure = backpressure; + const state = stream[kState]; + assert(state.backpressure !== backpressure); + const backpressureChange = state.backpressureChange; + if (backpressureChange !== undefined) { + state.backpressureChange = undefined; + backpressureChange.resolve(); + } + state.backpressure = backpressure; } function setupTransformStreamDefaultController( @@ -554,7 +559,7 @@ function transformStreamDefaultSinkWriteAlgorithm(stream, chunk) { } = stream[kState]; assert(writable[kState].state === 'writable'); if (stream[kState].backpressure) { - const backpressureChange = stream[kState].backpressureChange.promise; + const backpressureChange = transformStreamBackpressureChangePromise(stream); return PromisePrototypeThen( backpressureChange, () => { @@ -638,9 +643,8 @@ function transformStreamDefaultSinkCloseAlgorithm(stream) { function transformStreamDefaultSourcePullAlgorithm(stream) { assert(stream[kState].backpressure); - assert(stream[kState].backpressureChange.promise !== undefined); transformStreamSetBackpressure(stream, false); - return stream[kState].backpressureChange.promise; + return transformStreamBackpressureChangePromise(stream); } function transformStreamDefaultSourceCancelAlgorithm(stream, reason) { diff --git a/lib/internal/webstreams/util.js b/lib/internal/webstreams/util.js index 836e1de130505b..cd203b77c2d22a 100644 --- a/lib/internal/webstreams/util.js +++ b/lib/internal/webstreams/util.js @@ -134,45 +134,44 @@ function isBrandCheck(brand) { }; } +// The queue helpers below run once per chunk on the hot paths of every +// default readable/writable stream, so they load the controller state a +// single time and don't assert the existence of the queue fields (both +// are unconditionally initialized during controller setup and only ever +// replaced wholesale). function dequeueValue(controller) { - assert(controller[kState].queue !== undefined); - assert(controller[kState].queueTotalSize !== undefined); - assert(controller[kState].queue.length); + const state = controller[kState]; + assert(state.queue.length); const { value, size, - } = ArrayPrototypeShift(controller[kState].queue); - controller[kState].queueTotalSize = - MathMax(0, controller[kState].queueTotalSize - size); + } = ArrayPrototypeShift(state.queue); + state.queueTotalSize = MathMax(0, state.queueTotalSize - size); return value; } function resetQueue(controller) { - assert(controller[kState].queue !== undefined); - assert(controller[kState].queueTotalSize !== undefined); - controller[kState].queue = []; - controller[kState].queueTotalSize = 0; + const state = controller[kState]; + state.queue = []; + state.queueTotalSize = 0; } function peekQueueValue(controller) { - assert(controller[kState].queue !== undefined); - assert(controller[kState].queueTotalSize !== undefined); - assert(controller[kState].queue.length); - return controller[kState].queue[0].value; + const state = controller[kState]; + assert(state.queue.length); + return state.queue[0].value; } function enqueueValueWithSize(controller, value, size) { - assert(controller[kState].queue !== undefined); - assert(controller[kState].queueTotalSize !== undefined); + const state = controller[kState]; const coercedSize = +size; if (NumberIsNaN(coercedSize) || coercedSize < 0 || coercedSize === Infinity) { throw new ERR_INVALID_ARG_VALUE.RangeError('size', size); } - size = coercedSize; - ArrayPrototypePush(controller[kState].queue, { value, size }); - controller[kState].queueTotalSize += size; + ArrayPrototypePush(state.queue, { value, size: coercedSize }); + state.queueTotalSize += coercedSize; } // Arity-specialized variants of the promise-callback wrapper. The generic diff --git a/lib/internal/webstreams/writablestream.js b/lib/internal/webstreams/writablestream.js index bc7f58a05fc2b9..37ef513a4e4166 100644 --- a/lib/internal/webstreams/writablestream.js +++ b/lib/internal/webstreams/writablestream.js @@ -601,6 +601,10 @@ function createWritableStreamState() { __proto__: null, closedPromise: undefined, closeRequest: kNilRequest, + // Mirrors "closeRequest or inFlightCloseRequest is pending"; kept as a + // flag because the predicate runs several times per chunk on the write + // hot path. + closeQueuedOrInFlight: false, inFlightWriteRequest: kNilRequest, inFlightCloseRequest: kNilRequest, pendingAbortRequest: kNilPendingAbortRequest, @@ -742,6 +746,7 @@ function writableStreamClose(stream) { assert(state === 'writable' || state === 'erroring'); assert(!writableStreamCloseQueuedOrInFlight(stream)); stream[kState].closeRequest = PromiseWithResolvers(); + stream[kState].closeQueuedOrInFlight = true; const { promise } = stream[kState].closeRequest; if (writer !== undefined && backpressure && state === 'writable') writer[kState].ready?.resolve?.(); @@ -750,12 +755,13 @@ function writableStreamClose(stream) { } function writableStreamUpdateBackpressure(stream, backpressure) { - assert(stream[kState].state === 'writable'); - assert(!writableStreamCloseQueuedOrInFlight(stream)); + const streamState = stream[kState]; + assert(streamState.state === 'writable'); + assert(!streamState.closeQueuedOrInFlight); const { writer, - } = stream[kState]; - if (writer !== undefined && stream[kState].backpressure !== backpressure) { + } = streamState; + if (writer !== undefined && streamState.backpressure !== backpressure) { if (backpressure) { // The spec replaces [[readyPromise]] with a fresh pending promise; // dropping the cache lets the next observation derive it. @@ -764,7 +770,7 @@ function writableStreamUpdateBackpressure(stream, backpressure) { writer[kState].ready?.resolve?.(); } } - stream[kState].backpressure = backpressure; + streamState.backpressure = backpressure; } function writableStreamStartErroring(stream, reason) { @@ -792,6 +798,7 @@ function writableStreamRejectCloseAndClosedPromiseIfNeeded(stream) { assert(stream[kState].inFlightCloseRequest.promise === undefined); stream[kState].closeRequest.reject?.(stream[kState].storedError); stream[kState].closeRequest = kNilRequest; + stream[kState].closeQueuedOrInFlight = false; } const closedPromiseCache = stream[kState].closedPromise; @@ -857,6 +864,7 @@ function writableStreamFinishInFlightCloseWithError(stream, error) { assert(stream[kState].inFlightCloseRequest.promise !== undefined); stream[kState].inFlightCloseRequest.reject?.(error); stream[kState].inFlightCloseRequest = kNilRequest; + stream[kState].closeQueuedOrInFlight = false; assert(stream[kState].state === 'writable' || stream[kState].state === 'erroring'); if (stream[kState].pendingAbortRequest.abort.promise !== undefined) { @@ -870,6 +878,7 @@ function writableStreamFinishInFlightClose(stream) { assert(stream[kState].inFlightCloseRequest.promise !== undefined); stream[kState].inFlightCloseRequest.resolve?.(); stream[kState].inFlightCloseRequest = kNilRequest; + stream[kState].closeQueuedOrInFlight = false; if (stream[kState].state === 'erroring') { stream[kState].storedError = undefined; if (stream[kState].pendingAbortRequest.abort.promise !== undefined) { @@ -933,11 +942,7 @@ function writableStreamDealWithRejection(stream, error) { } function writableStreamCloseQueuedOrInFlight(stream) { - if (stream[kState].closeRequest.promise === undefined && - stream[kState].inFlightCloseRequest.promise === undefined) { - return false; - } - return true; + return stream[kState].closeQueuedOrInFlight; } function writableStreamAddWriteRequest(stream) { @@ -951,34 +956,34 @@ function writableStreamAddWriteRequest(stream) { } function writableStreamDefaultWriterWrite(writer, chunk) { - const { - stream, - } = writer[kState]; + const writerState = writer[kState]; + const stream = writerState.stream; assert(stream !== undefined); + const streamState = stream[kState]; const { controller, - } = stream[kState]; + } = streamState; const chunkSize = writableStreamDefaultControllerGetChunkSize( controller, chunk); - if (stream !== writer[kState].stream) { + if (stream !== writerState.stream) { return PromiseReject( new ERR_INVALID_STATE.TypeError('Mismatched WritableStreams')); } const { state, - } = stream[kState]; + } = streamState; if (state === 'errored') - return PromiseReject(stream[kState].storedError); + return PromiseReject(streamState.storedError); - if (writableStreamCloseQueuedOrInFlight(stream) || state === 'closed') { + if (streamState.closeQueuedOrInFlight || state === 'closed') { return PromiseReject( new ERR_INVALID_STATE.TypeError('WritableStream is closed')); } if (state === 'erroring') - return PromiseReject(stream[kState].storedError); + return PromiseReject(streamState.storedError); assert(state === 'writable'); @@ -1085,8 +1090,9 @@ function writableStreamDefaultControllerWrite(controller, chunk, chunkSize) { const { stream, } = controller[kState]; - if (!writableStreamCloseQueuedOrInFlight(stream) && - stream[kState].state === 'writable') { + const streamState = stream[kState]; + if (!streamState.closeQueuedOrInFlight && + streamState.state === 'writable') { writableStreamUpdateBackpressure( stream, writableStreamDefaultControllerGetBackpressure(controller)); @@ -1107,12 +1113,13 @@ function writableStreamDefaultControllerProcessWrite(controller, chunk) { // subsequent write instead of allocating two fresh closures per chunk. controller[kState].writeFulfilled = () => { writableStreamFinishInFlightWrite(stream); + const streamState = stream[kState]; const { state, - } = stream[kState]; + } = streamState; assert(state === 'writable' || state === 'erroring'); dequeueValue(controller); - if (!writableStreamCloseQueuedOrInFlight(stream) && + if (!streamState.closeQueuedOrInFlight && state === 'writable') { writableStreamUpdateBackpressure( stream, From 0b6af910819098ae79a95d66ff2dccc2bdbe0515 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Sat, 4 Jul 2026 00:58:04 -0700 Subject: [PATCH 102/131] vfs: handle current-position sentinel in memory files Treat -1 as the current file position in MemoryFileHandle read and write operations. This matches the value passed by fs.readSync() after normalizing a null position. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.5 PR-URL: https://github.com/nodejs/node/pull/64163 Fixes: https://github.com/nodejs/node/issues/64162 Reviewed-By: Matteo Collina --- lib/internal/vfs/file_handle.js | 16 ++++++++++------ test/parallel/test-vfs-fd.js | 20 ++++++++++++++++++++ test/parallel/test-vfs-file-handle.js | 6 ++++++ test/parallel/test-vfs-fs-openSync.js | 13 +++++++++++++ 4 files changed, 49 insertions(+), 6 deletions(-) diff --git a/lib/internal/vfs/file_handle.js b/lib/internal/vfs/file_handle.js index e8a37e07f26495..7b60c9def2b5b4 100644 --- a/lib/internal/vfs/file_handle.js +++ b/lib/internal/vfs/file_handle.js @@ -28,6 +28,10 @@ const kMode = Symbol('kMode'); const kPosition = Symbol('kPosition'); const kClosed = Symbol('kClosed'); +function isCurrentPosition(position) { + return position === null || position === undefined || position === -1; +} + /** * Base class for virtual file handles. * Provides the interface that file handles must implement. @@ -467,8 +471,8 @@ class MemoryFileHandle extends VirtualFileHandle { // Get content (resolves dynamic content providers) const content = this.content; - const readPos = position !== null && position !== undefined ? - Number(position) : this.position; + const useCurrentPosition = isCurrentPosition(position); + const readPos = useCurrentPosition ? this.position : Number(position); const available = content.length - readPos; if (available <= 0) { @@ -479,7 +483,7 @@ class MemoryFileHandle extends VirtualFileHandle { content.copy(buffer, offset, readPos, readPos + bytesToRead); // Update position if not using explicit position - if (position === null || position === undefined) { + if (useCurrentPosition) { this.position = readPos + bytesToRead; } @@ -512,10 +516,10 @@ class MemoryFileHandle extends VirtualFileHandle { this.#checkWritable(); // In append mode, always write at the end + const useCurrentPosition = isCurrentPosition(position); const writePos = this.#isAppend() ? this.#size : - (position !== null && position !== undefined ? - Number(position) : this.position); + (useCurrentPosition ? this.position : Number(position)); const data = buffer.subarray(offset, offset + length); // Expand buffer if needed (geometric doubling for amortized O(1) appends) @@ -544,7 +548,7 @@ class MemoryFileHandle extends VirtualFileHandle { } // Update position if not using explicit position - if (position === null || position === undefined) { + if (useCurrentPosition) { this.position = writePos + length; } diff --git a/test/parallel/test-vfs-fd.js b/test/parallel/test-vfs-fd.js index ec9145189da299..f9f6b25f51ce57 100644 --- a/test/parallel/test-vfs-fd.js +++ b/test/parallel/test-vfs-fd.js @@ -80,6 +80,26 @@ const vfs = require('node:vfs'); myVfs.closeSync(fd); } +// Test readSync with Node's current-position sentinel +{ + const myVfs = vfs.create(); + myVfs.writeFileSync('/file.txt', 'hello world'); + + const fd = myVfs.openSync('/file.txt'); + const buffer1 = Buffer.alloc(5); + const buffer2 = Buffer.alloc(6); + + let bytesRead = myVfs.readSync(fd, buffer1, 0, 5, -1); + assert.strictEqual(bytesRead, 5); + assert.strictEqual(buffer1.toString(), 'hello'); + + bytesRead = myVfs.readSync(fd, buffer2, 0, 6, -1); + assert.strictEqual(bytesRead, 6); + assert.strictEqual(buffer2.toString(), ' world'); + + myVfs.closeSync(fd); +} + // Test readSync with explicit position { const myVfs = vfs.create(); diff --git a/test/parallel/test-vfs-file-handle.js b/test/parallel/test-vfs-file-handle.js index 6c653593ce7ea2..d9d919446b8ea6 100644 --- a/test/parallel/test-vfs-file-handle.js +++ b/test/parallel/test-vfs-file-handle.js @@ -82,6 +82,12 @@ myVfs.writeFileSync('/file.txt', 'hello world'); myVfs.writeSync(fd, buf, 0, 3, 0); myVfs.closeSync(fd); + const fd3 = myVfs.openSync('/sync-current.txt', 'w'); + myVfs.writeSync(fd3, Buffer.from('abc'), 0, 3, -1); + myVfs.writeSync(fd3, Buffer.from('def'), 0, 3, -1); + myVfs.closeSync(fd3); + assert.strictEqual(myVfs.readFileSync('/sync-current.txt', 'utf8'), 'abcdef'); + const fd2 = myVfs.openSync('/sync.txt', 'r'); const out = Buffer.alloc(3); myVfs.readSync(fd2, out, 0, 3, 0); diff --git a/test/parallel/test-vfs-fs-openSync.js b/test/parallel/test-vfs-fs-openSync.js index f2c73f0d634469..28fa17d28b3cf6 100644 --- a/test/parallel/test-vfs-fs-openSync.js +++ b/test/parallel/test-vfs-fs-openSync.js @@ -30,6 +30,19 @@ myVfs.mount(mountPoint); fs.closeSync(fd); } +// readSync with position null uses and advances the current file position +{ + const fd = fs.openSync(path.join(mountPoint, 'src/hello.txt'), 'r'); + const b1 = Buffer.alloc(5); + const b2 = Buffer.alloc(6); + + assert.strictEqual(fs.readSync(fd, b1, 0, 5, null), 5); + assert.strictEqual(fs.readSync(fd, b2, 0, 6, null), 6); + assert.strictEqual(b1.toString(), 'hello'); + assert.strictEqual(b2.toString(), ' world'); + fs.closeSync(fd); +} + // openSync + writeSync (buffer) + closeSync { const fd = fs.openSync(path.join(mountPoint, 'src/wfd.txt'), 'w'); From ce659a1cf9045e8bea6c6094658cdd01d8d53d66 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 4 Jul 2026 10:56:09 +0200 Subject: [PATCH 103/131] src: fix escaping of single quotes in task runner Signed-off-by: Antoine du Hamel PR-URL: https://github.com/nodejs/node/pull/64089 Refs: https://hackerone.com/reports/3817602 Reviewed-By: Yagiz Nizipli --- src/node_task_runner.cc | 4 ++-- test/cctest/test_node_task_runner.cc | 6 +++--- .../fixtures/run-script/node_modules/.bin/positional-args | 2 +- .../run-script/node_modules/.bin/positional-args.bat | 2 +- test/parallel/test-node-run.js | 8 ++++---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/node_task_runner.cc b/src/node_task_runner.cc index 3e15a70e72660c..22c02e83e12ed6 100644 --- a/src/node_task_runner.cc +++ b/src/node_task_runner.cc @@ -171,10 +171,10 @@ std::string EscapeShell(const std::string_view input) { escaped = std::regex_replace(escaped, leadingQuotePairs, ""); escaped = std::regex_replace(escaped, tripleSingleQuote, "\\\""); #else - // Replace single quotes("'") with "\\'" and wrap the result + // Replace single quotes("'") with `'"'"'` and wrap the result // in single quotes. std::string escaped = - std::regex_replace(std::string(input), std::regex("'"), "\\'"); + std::regex_replace(std::string(input), std::regex("'"), "'\"'\"'"); escaped = "'" + escaped + "'"; // Remove excessive quote pairs and handle edge cases static const std::regex tripleSingleQuote("\\\\'''"); diff --git a/test/cctest/test_node_task_runner.cc b/test/cctest/test_node_task_runner.cc index a2c520d2709f2e..1c715124bd88ee 100644 --- a/test/cctest/test_node_task_runner.cc +++ b/test/cctest/test_node_task_runner.cc @@ -28,12 +28,12 @@ TEST_F(TaskRunnerTest, EscapeShell) { {"test words", "'test words'"}, {"$1", "'$1'"}, {"\"$1\"", "'\"$1\"'"}, - {"'$1'", "'\\'$1\\''"}, + {"'$1'", "\"'\"'$1'\"'\"''"}, {"\\$1", "'\\$1'"}, {"--arg=\"$1\"", "'--arg=\"$1\"'"}, {"--arg=node exec -c \"$1\"", "'--arg=node exec -c \"$1\"'"}, - {"--arg=node exec -c '$1'", "'--arg=node exec -c \\'$1\\''"}, - {"'--arg=node exec -c \"$1\"'", "'\\'--arg=node exec -c \"$1\"\\''"} + {"--arg=node exec -c '$1'", "'--arg=node exec -c '\"'\"'$1'\"'\"''"}, + {"'--arg=node exec -c \"$1\"'", "\"'\"'--arg=node exec -c \"$1\"'\"'\"''"} #endif }; diff --git a/test/fixtures/run-script/node_modules/.bin/positional-args b/test/fixtures/run-script/node_modules/.bin/positional-args index 2d8092378ba1da..18c7bfa0e466a7 100755 --- a/test/fixtures/run-script/node_modules/.bin/positional-args +++ b/test/fixtures/run-script/node_modules/.bin/positional-args @@ -1,3 +1,3 @@ #!/bin/bash echo "Arguments: '$@'" -echo "The total number of arguments are: $#" +echo "The total number of arguments is: $#" diff --git a/test/fixtures/run-script/node_modules/.bin/positional-args.bat b/test/fixtures/run-script/node_modules/.bin/positional-args.bat index 4b94ed34d51daf..35c80ceda496ea 100755 --- a/test/fixtures/run-script/node_modules/.bin/positional-args.bat +++ b/test/fixtures/run-script/node_modules/.bin/positional-args.bat @@ -12,4 +12,4 @@ for %%x in (%*) do ( ) @echo Raw '%*' @echo Arguments: '%output%' -@echo The total number of arguments are: %argv% +@echo The total number of arguments is: %argv% diff --git a/test/parallel/test-node-run.js b/test/parallel/test-node-run.js index 26295256849702..e24117f6b1658b 100644 --- a/test/parallel/test-node-run.js +++ b/test/parallel/test-node-run.js @@ -143,15 +143,15 @@ describe('node --run [command]', () => { it('appends positional arguments', async () => { const child = await common.spawnPromisified( process.execPath, - [ '--run', `positional-args${envSuffix}`, '--', '--help "hello world test"', 'A', 'B', 'C'], + [ '--run', `positional-args${envSuffix}`, '--', '--help "hello world test"', 'A', 'B', 'C', 'I think therefore I\'m'], { cwd: fixtures.path('run-script') }, ); if (common.isWindows) { - assert.match(child.stdout, /Arguments: '--help ""hello world test"" A B C'/); + assert.match(child.stdout, /Arguments: '--help ""hello world test"" A B C I think therefore I'm'/); } else { - assert.match(child.stdout, /Arguments: '--help "hello world test" A B C'/); + assert.match(child.stdout, /Arguments: '--help "hello world test" A B C I think therefore I'm'/); } - assert.match(child.stdout, /The total number of arguments are: 4/); + assert.match(child.stdout, /The total number of arguments is: 5/); assert.strictEqual(child.stderr, ''); assert.strictEqual(child.code, 0); }); From 3966eb67e7591b56728f41ec728714600cff3249 Mon Sep 17 00:00:00 2001 From: Vas Sudanagunta Date: Sat, 4 Jul 2026 05:42:38 -0400 Subject: [PATCH 104/131] doc: fix typo in examples Signed-off-by: vassudanagunta PR-URL: https://github.com/nodejs/node/pull/64184 Reviewed-By: Luigi Pinca Reviewed-By: Jason Zhang --- doc/api/cli.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/api/cli.md b/doc/api/cli.md index da4a618239967b..5944d4f32ac45c 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -248,7 +248,7 @@ The valid arguments for the `--allow-fs-read` flag are: * `*` - To allow all `FileSystemRead` operations. * Multiple paths can be allowed using multiple `--allow-fs-read` flags. - Example `--allow-fs-read=/folder1/ --allow-fs-read=/folder1/` + Example `--allow-fs-read=/folder1/ --allow-fs-read=/folder2/` Examples can be found in the [File System Permissions][] documentation. @@ -290,7 +290,7 @@ The valid arguments for the `--allow-fs-write` flag are: * `*` - To allow all `FileSystemWrite` operations. * Multiple paths can be allowed using multiple `--allow-fs-write` flags. - Example `--allow-fs-write=/folder1/ --allow-fs-write=/folder1/` + Example `--allow-fs-write=/folder1/ --allow-fs-write=/folder2/` Paths delimited by comma (`,`) are no longer allowed. When passing a single flag with a comma a warning will be displayed. From ea3b870155ed1cf99d8cdad13805acf94cf33ae0 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 4 Jul 2026 16:23:30 +0200 Subject: [PATCH 105/131] tools: remove `envinfo` from our workflows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Antoine du Hamel PR-URL: https://github.com/nodejs/node/pull/64259 Reviewed-By: Richard Lau Reviewed-By: Joyee Cheung Reviewed-By: Marco Ippolito Reviewed-By: Filip Skokan Reviewed-By: Luigi Pinca Reviewed-By: René Reviewed-By: Colin Ihrig --- .github/workflows/build-tarball.yml | 4 ---- .github/workflows/coverage-linux-without-intl.yml | 2 -- .github/workflows/coverage-linux.yml | 2 -- .github/workflows/coverage-windows.yml | 2 -- .github/workflows/daily-wpt-fyi.yml | 2 -- .github/workflows/daily.yml | 2 -- .github/workflows/doc.yml | 2 -- .github/workflows/linters.yml | 12 ------------ .github/workflows/stress-test.yml | 2 -- .github/workflows/test-internet.yml | 2 -- .github/workflows/test-linux-quic.yml | 2 -- .github/workflows/test-linux.yml | 2 -- .github/workflows/test-macos.yml | 2 -- 13 files changed, 38 deletions(-) diff --git a/.github/workflows/build-tarball.yml b/.github/workflows/build-tarball.yml index fb0e7dbd323baa..bd72e7dd404794 100644 --- a/.github/workflows/build-tarball.yml +++ b/.github/workflows/build-tarball.yml @@ -82,8 +82,6 @@ jobs: with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true - - name: Environment Information - run: npx envinfo@7.21.0 - name: Make tarball run: | export DISTTYPE=nightly @@ -124,8 +122,6 @@ jobs: uses: Mozilla-Actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 # v0.0.10 with: version: v0.16.0 - - name: Environment Information - run: npx envinfo@7.21.0 - name: Download tarball uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: diff --git a/.github/workflows/coverage-linux-without-intl.yml b/.github/workflows/coverage-linux-without-intl.yml index 60da6dc3d3646d..8216c0913b1a27 100644 --- a/.github/workflows/coverage-linux-without-intl.yml +++ b/.github/workflows/coverage-linux-without-intl.yml @@ -67,8 +67,6 @@ jobs: uses: Mozilla-Actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 # v0.0.10 with: version: v0.16.0 - - name: Environment Information - run: npx envinfo@7.21.0 - name: Install gcovr run: pip install gcovr==7.2 - name: Configure diff --git a/.github/workflows/coverage-linux.yml b/.github/workflows/coverage-linux.yml index 879ef11be362bc..32f5db02e16638 100644 --- a/.github/workflows/coverage-linux.yml +++ b/.github/workflows/coverage-linux.yml @@ -67,8 +67,6 @@ jobs: uses: Mozilla-Actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 # v0.0.10 with: version: v0.16.0 - - name: Environment Information - run: npx envinfo@7.21.0 - name: Install gcovr run: pip install gcovr==7.2 - name: Configure diff --git a/.github/workflows/coverage-windows.yml b/.github/workflows/coverage-windows.yml index e4c9d5af0fca9f..5993bff42dfe20 100644 --- a/.github/workflows/coverage-windows.yml +++ b/.github/workflows/coverage-windows.yml @@ -83,8 +83,6 @@ jobs: run: | rustup override set "$RUSTC_VERSION" rustup --version - - name: Environment Information - run: npx envinfo@7.21.0 - name: Build run: ./vcbuild.bat clang-cl v8temporal # TODO(bcoe): investigate tests that fail with coverage enabled diff --git a/.github/workflows/daily-wpt-fyi.yml b/.github/workflows/daily-wpt-fyi.yml index b798a5c05fbf73..b6f7af237c9e98 100644 --- a/.github/workflows/daily-wpt-fyi.yml +++ b/.github/workflows/daily-wpt-fyi.yml @@ -43,8 +43,6 @@ jobs: with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true - - name: Environment Information - run: npx envinfo@7.21.0 # install a version and checkout - name: Get latest nightly diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml index 1f6bf82d312659..6c4b2ec9a4beb0 100644 --- a/.github/workflows/daily.yml +++ b/.github/workflows/daily.yml @@ -23,8 +23,6 @@ jobs: uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: ${{ env.NODE_VERSION }} - - name: Environment Information - run: npx envinfo@7.21.0 - name: Build lto run: | sudo apt-get update && sudo apt-get install ninja-build -y diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml index 9dc73f7810f881..6e5dfe73264641 100644 --- a/.github/workflows/doc.yml +++ b/.github/workflows/doc.yml @@ -31,8 +31,6 @@ jobs: uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: ${{ env.NODE_VERSION }} - - name: Environment Information - run: npx envinfo@7.21.0 - name: Build run: NODE=$(command -v node) make doc-only - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml index 2153b743988208..4e0fdab245e1f9 100644 --- a/.github/workflows/linters.yml +++ b/.github/workflows/linters.yml @@ -32,8 +32,6 @@ jobs: uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: ${{ env.NODE_VERSION }} - - name: Environment Information - run: npx envinfo@7.21.0 - name: Lint addon docs run: NODE=$(command -v node) make lint-addon-docs lint-cpp: @@ -48,8 +46,6 @@ jobs: with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true - - name: Environment Information - run: npx envinfo@7.21.0 - name: Lint C/C++ files run: make lint-cpp format-cpp: @@ -69,8 +65,6 @@ jobs: with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true - - name: Environment Information - run: npx envinfo@7.21.0 - name: Format C/C++ files run: | make format-cpp-build @@ -102,8 +96,6 @@ jobs: uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: ${{ env.NODE_VERSION }} - - name: Environment Information - run: npx envinfo@7.21.0 - name: Lint JavaScript files run: | set +e @@ -183,8 +175,6 @@ jobs: with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true - - name: Environment Information - run: npx envinfo@7.21.0 - name: Lint Python run: | make lint-py-build @@ -207,8 +197,6 @@ jobs: with: python-version: ${{ env.PYTHON_VERSION }} allow-prereleases: true - - name: Environment Information - run: npx envinfo@7.21.0 - name: Lint YAML run: | make lint-yaml-build || true diff --git a/.github/workflows/stress-test.yml b/.github/workflows/stress-test.yml index d8cedf535f3dd7..fbc31ac3b435a3 100644 --- a/.github/workflows/stress-test.yml +++ b/.github/workflows/stress-test.yml @@ -79,8 +79,6 @@ jobs: uses: Mozilla-Actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 # v0.0.10 with: version: v0.16.0 - - name: Environment Information - run: npx envinfo@7.21.0 # This is needed due to https://github.com/nodejs/build/issues/3878 - name: Cleanup if: runner.os == 'macOS' diff --git a/.github/workflows/test-internet.yml b/.github/workflows/test-internet.yml index 7f52b65e7e90cb..10b72c78ff5ed6 100644 --- a/.github/workflows/test-internet.yml +++ b/.github/workflows/test-internet.yml @@ -64,8 +64,6 @@ jobs: uses: Mozilla-Actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 # v0.0.10 with: version: v0.16.0 - - name: Environment Information - run: npx envinfo@7.21.0 - name: Build run: make build-ci -j4 V=1 CONFIG_FLAGS="--error-on-warn" - name: Test Internet diff --git a/.github/workflows/test-linux-quic.yml b/.github/workflows/test-linux-quic.yml index cf717ec6926c10..7524bada76d575 100644 --- a/.github/workflows/test-linux-quic.yml +++ b/.github/workflows/test-linux-quic.yml @@ -69,8 +69,6 @@ jobs: uses: Mozilla-Actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 # v0.0.10 with: version: v0.16.0 - - name: Environment Information - run: npx envinfo@7.21.0 - name: Build working-directory: node run: make build-ci -j4 V=1 CONFIG_FLAGS="--error-on-warn --v8-enable-temporal-support --experimental-quic" diff --git a/.github/workflows/test-linux.yml b/.github/workflows/test-linux.yml index ad9286e9d941c1..82efc85dd86b9a 100644 --- a/.github/workflows/test-linux.yml +++ b/.github/workflows/test-linux.yml @@ -80,8 +80,6 @@ jobs: uses: Mozilla-Actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 # v0.0.10 with: version: v0.16.0 - - name: Environment Information - run: npx envinfo@7.21.0 - name: Build working-directory: node run: make build-ci -j4 V=1 CONFIG_FLAGS="--error-on-warn --v8-enable-temporal-support" diff --git a/.github/workflows/test-macos.yml b/.github/workflows/test-macos.yml index 58ec23a4f1632e..c0bedf5327d77d 100644 --- a/.github/workflows/test-macos.yml +++ b/.github/workflows/test-macos.yml @@ -103,8 +103,6 @@ jobs: uses: Mozilla-Actions/sccache-action@9e7fa8a12102821edf02ca5dbea1acd0f89a2696 # v0.0.10 with: version: v0.16.0 - - name: Environment Information - run: npx envinfo@7.21.0 # The `npm ci` for this step fails a lot as part of the Test step. Run it # now so that we don't have to wait 2 hours for the Build step to pass # first before that failure happens. (And if there's something about From 851b460583b9619d9dcba6b254b506a6f6280e48 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Thu, 2 Jul 2026 16:24:19 +0200 Subject: [PATCH 106/131] esm: improve ERR_REQUIRE_ASYNC_MODULE This brings back several improvements that were reverted by mistake when landing https://redirect.github.com/nodejs/node/pull/64154 - Update the documentation about how the removal of side effects of source collection - Add non-enumerable `requireStack` and `topLevelAwaitLocations` properties to `ERR_REQUIRE_ASYNC_MODULE`, the latter is only populated when --experimental-print-required-tla is enabled - Add "Required module: " to the error message to identify the required ESM entry point regardless of whether the flag is enabled - Fix TLA caret column from 0-based to 1-based - Store module source via a private symbol instead of a public property - Use `hasAsyncGraph` (post-instantiation) in `throwIfAsyncGraph` instead of walking the graph before instantiation - Merge the require stack checking into the `common.expectRequiredTLAError` helper. - Removed tests that are made redundant by the snapshot tests Signed-off-by: Joyee Cheung PR-URL: https://github.com/nodejs/node/pull/64260 Reviewed-By: Matteo Collina Reviewed-By: Yagiz Nizipli --- doc/api/errors.md | 24 +++- doc/api/modules.md | 7 +- lib/internal/errors.js | 20 ++- lib/internal/modules/esm/loader.js | 12 +- lib/internal/modules/esm/module_job.js | 133 ++++++++---------- lib/internal/modules/esm/utils.js | 3 +- test/common/index.js | 37 +++-- .../test-require-module-cached-tla.js | 3 +- .../test-require-module-tla-error-metadata.js | 26 ++++ ...est-require-module-tla-error-snapshot.mjs} | 5 +- .../test-require-module-tla-execution.js | 16 +-- .../test-require-module-tla-nested.js | 3 +- .../test-require-module-tla-print-arrow.js | 29 ---- ...test-require-module-tla-print-execution.js | 12 +- .../test-require-module-tla-print-nested.js | 31 ---- .../test-require-module-tla-print-preload.js | 32 ----- .../test-require-module-tla-rejected.js | 3 +- .../test-require-module-tla-resolved.js | 3 +- .../test-require-module-tla-unresolved.js | 3 +- .../es-modules/tla/preload-main.snapshot | 4 +- .../tla/require-awaitusing.snapshot | 6 +- .../es-modules/tla/require-execution.snapshot | 6 +- .../es-modules/tla/require-indented.snapshot | 6 +- .../es-modules/tla/require-nested.snapshot | 7 +- 24 files changed, 189 insertions(+), 242 deletions(-) create mode 100644 test/es-module/test-require-module-tla-error-metadata.js rename test/es-module/{test-require-module-tla-print.mjs => test-require-module-tla-error-snapshot.mjs} (87%) delete mode 100644 test/es-module/test-require-module-tla-print-arrow.js delete mode 100644 test/es-module/test-require-module-tla-print-nested.js delete mode 100644 test/es-module/test-require-module-tla-print-preload.js diff --git a/doc/api/errors.md b/doc/api/errors.md index 4ea14fdf734c0e..9239d04be23ba7 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -2803,12 +2803,30 @@ A QUIC session failed because version negotiation is required. ### `ERR_REQUIRE_ASYNC_MODULE` + + When trying to `require()` a [ES Module][], the module turns out to be asynchronous. That is, it contains top-level await. -To see where the top-level await is, use -`--experimental-print-required-tla` (this would execute the modules -before looking for the top-level awaits). +When uncaught, the flag `--experimental-print-required-tla` prints +the locations of the top-level awaits in the graph to stderr. + +This error has the following additional non-enumerable properties: + +* `requireStack` {string\[]} The chain of modules that led to the failing + `require()`, starting with the module that required the asynchronous module. +* `topLevelAwaitLocations` {Object\[]} The locations of the top-level awaits in + the graph. Only populated when `--experimental-print-required-tla` is enabled. + Each entry has the following properties: + * `url` {string} The URL of the module containing the top-level await. + * `line` {number} The 1-based line number of the top-level await. + * `column` {number} The 1-based column number of the top-level await. + * `sourceLine` {string} The source line containing the top-level await. diff --git a/doc/api/modules.md b/doc/api/modules.md index 0fb30b542e630c..3553139d8c641e 100644 --- a/doc/api/modules.md +++ b/doc/api/modules.md @@ -316,10 +316,9 @@ graph it `import`s contains top-level `await`, [`ERR_REQUIRE_ASYNC_MODULE`][] will be thrown. In this case, users should load the asynchronous module using [`import()`][]. -If `--experimental-print-required-tla` is enabled, instead of throwing -`ERR_REQUIRE_ASYNC_MODULE` before evaluation, Node.js will evaluate the -module, try to locate the top-level awaits, and print their location to -help users fix them. +If `--experimental-print-required-tla` is enabled and the error is uncaught, +Node.js will try to locate the top-level `await`s in the `require()`'d module graph +and print the locations in the stderr. If support for loading ES modules using `require()` results in unexpected breakage, it can be disabled using `--no-require-module`. diff --git a/lib/internal/errors.js b/lib/internal/errors.js index a8ce308436ecc3..95d639c80b8970 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -1714,6 +1714,9 @@ E('ERR_REQUIRE_ASYNC_MODULE', function(filename, parent, locations) { if (!getOptionValue('--experimental-print-required-tla')) { message += ' To see where the top-level await comes from, use --experimental-print-required-tla.'; } + if (filename) { + message += `\nRequired module: ${filename}`; + } if (parent) { const { getRequireStack } = require('internal/modules/helpers'); const requireStack = getRequireStack(parent); @@ -1721,13 +1724,26 @@ E('ERR_REQUIRE_ASYNC_MODULE', function(filename, parent, locations) { message += '\nRequire stack:\n- ' + ArrayPrototypeJoin(requireStack, '\n- '); } - this.requireStack = requireStack; + ObjectDefineProperty(this, 'requireStack', { + __proto__: null, + enumerable: false, + configurable: true, + writable: true, + value: requireStack, + }); } if (locations && locations.length > 0) { const { urlToFilename } = require('internal/modules/helpers'); const frames = ArrayPrototypeMap(locations, ({ url, line, column, sourceLine }) => - `${urlToFilename(url)}:${line}\n\n${sourceLine}\n${StringPrototypeRepeat(' ', column)}^\n`); + `${urlToFilename(url)}:${line}\n\n${sourceLine}\n${StringPrototypeRepeat(' ', column - 1)}^\n`); setArrowMessage(this, ArrayPrototypeJoin(frames, '\n')); + ObjectDefineProperty(this, 'topLevelAwaitLocations', { + __proto__: null, + enumerable: false, + configurable: true, + writable: true, + value: locations, + }); } return message; }, Error); diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index 1a6622140382ba..f92e87785ce12c 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -291,8 +291,8 @@ class ModuleLoader { const status = job.module.getStatus(); debug('Module status', job, status); // hasAsyncGraph is available after module been instantiated. - if (status >= kInstantiated && job.module.hasAsyncGraph) { - job.throwAsyncGraphError(parent); + if (status >= kInstantiated) { + job.throwIfAsyncGraph(parent); } if (status === kEvaluated) { return { wrap: job.module, namespace: job.module.getNamespace() }; @@ -320,9 +320,11 @@ class ModuleLoader { } if (status !== kEvaluating) { assert(status === kUninstantiated, `Unexpected module status ${status}`); - // A previous require() of the same graph may have bailed out before - // instantiation because it contains top-level await. - job.throwIfAsyncGraph(parent); + // If we get here, either there's a race where the job is still being instantiated + // by an in-flight import(), or the cached module previously encountered an + // instantiation error during a prior load (e.g. due to a mismatched import). + // TODO(joyeecheung): the current check is too broad. We should attempt to + // get the potential instantiation error and throw it. throw new ERR_REQUIRE_ESM_RACE_CONDITION(filename, parentFilename, false); } let message = `Cannot require() ES Module ${filename} in a cycle.`; diff --git a/lib/internal/modules/esm/module_job.js b/lib/internal/modules/esm/module_job.js index ee055c95d6d5c7..c54706a9e0af75 100644 --- a/lib/internal/modules/esm/module_job.js +++ b/lib/internal/modules/esm/module_job.js @@ -2,6 +2,7 @@ const { Array, + ArrayIsArray, ArrayPrototypeFind, ArrayPrototypeJoin, ArrayPrototypePop, @@ -14,6 +15,7 @@ const { PromiseResolve, RegExpPrototypeExec, RegExpPrototypeSymbolReplace, + RegExpPrototypeSymbolSplit, SafePromiseAllReturnArrayLike, SafePromiseAllReturnVoid, SafeSet, @@ -37,8 +39,10 @@ const { kUninstantiated, } = internalBinding('module_wrap'); const { + getPromiseDetails, privateSymbols: { entry_point_module_private_symbol, + module_source_private_symbol: kModuleSource, }, } = internalBinding('util'); /** @@ -135,12 +139,12 @@ const explainCommonJSGlobalLikeNotDefinedError = (e, url, hasTopLevelAwait) => { * @typedef {object} TopLevelAwaitLocation * @property {string} url URL of the module containing the top-level await. * @property {number} line 1-based line number of the top-level await. - * @property {number} column 0-based column number of the top-level await. + * @property {number} column 1-based column number of the top-level await. * @property {string} sourceLine The source line containing the top-level await. */ /** - * Locate the top-level awaits in the given module by parsing the source with acron. + * Locate the top-level awaits in the given module by parsing the source with acorn. * @param {string} source Module source code. * @returns {object[]} The acorn AST nodes of the top-level awaits, in source order. */ @@ -174,27 +178,62 @@ function findTopLevelAwait(source) { return found; } +/** + * Collect the modules that contain top-level await in the linked graph of a job. + * @param {ModuleJobBase} root The root of the module graph to search. + * @returns {ModuleWrap[]} Modules that contain top-level await. + */ +function findModulesWithTopLevelAwait(root) { + const found = []; + const seen = new SafeSet(); + const stack = [root]; + while (stack.length > 0) { + const job = ArrayPrototypePop(stack); + if (seen.has(job)) { continue; } + seen.add(job); + if (job.module?.hasTopLevelAwait) { + ArrayPrototypePush(found, job.module); + } + let linked = job.linked; + if (isPromise(linked)) { + linked = getPromiseDetails(linked)?.[1]; + } + // If `require(esm)` comes from the deprecated async loader hook worker thread, + // linked may be pending at this point. In that case, this branch would be skipped - + // we just allow lossy reporting of TLA locations in an edge case when a deprecated + // feature is used in combination with another experimental flag. + if (ArrayIsArray(linked)) { + for (let i = 0; i < linked.length; i++) { + ArrayPrototypePush(stack, linked[i]); + } + } + } + return found; +} + /** * Locate the top-level awaits in the given modules. - * @param {ModuleWrap[]} modules Modules that may contain top-level await. + * @param {ModuleJobBase} root The root of the module graph to search. * @returns {TopLevelAwaitLocation[]} The locations of the top-level awaits. */ -function getTopLevelAwaitLocations(modules) { +function getTopLevelAwaitLocations(root) { + const modules = findModulesWithTopLevelAwait(root); const locations = []; for (let i = 0; i < modules.length; i++) { const module = modules[i]; - const source = module.source; + const source = module[kModuleSource]; if (typeof source !== 'string') { continue; } // Not retained during compilation. Skip. const found = findTopLevelAwait(source); if (found.length === 0) { continue; } - const lines = StringPrototypeSplit(source, '\n'); + const lines = RegExpPrototypeSymbolSplit(/\r?\n/, source); for (let j = 0; j < found.length; j++) { const { start } = found[j].loc; ArrayPrototypePush(locations, { __proto__: null, url: module.url, line: start.line, - column: start.column, + // Acorn reports 0-based columns, convert them to 1-based to match `line`. + column: start.column + 1, sourceLine: lines[start.line - 1], }); } @@ -261,61 +300,18 @@ class ModuleJobBase { } /** - * Collect the modules that contain top-level await in the linked graph of - * this job. Whether each module contains top-level await is known at - * compilation, so for a synchronously linked graph this finds asynchronous - * graphs before instantiation. - * On the (deprecated) async loader hook worker thread, linking may be asynchronous, in - * which case the subgraphs that are not synchronously linked are skipped - * and callers should still consult hasAsyncGraph after instantiation. - * @returns {ModuleWrap[]} - */ - findModulesWithTopLevelAwait() { - const found = []; - const seen = new SafeSet(); - const stack = [this]; - while (stack.length > 0) { - const job = ArrayPrototypePop(stack); - if (seen.has(job)) { continue; } - seen.add(job); - if (job.module?.hasTopLevelAwait) { - ArrayPrototypePush(found, job.module); - } - // job.linked is the array of evaluation-phase dependency jobs when the - // linking is synchronous. Skip it if it's still a promise. - if (!isPromise(job.linked)) { - for (let i = 0; i < job.linked.length; i++) { - ArrayPrototypePush(stack, job.linked[i]); - } - } - } - return found; - } - - /** - * Throw the ERR_REQUIRE_ASYNC_MODULE with metadata for a require()'d graph that - * contains top-level await. - * @param {Module|undefined} parent CommonJS module that require()'d this, if any. - * @param {ModuleWrap[]} [modules] Modules with top-level await, when already - * collected by the caller, to avoid walking the graph again. - */ - throwAsyncGraphError(parent, modules = this.findModulesWithTopLevelAwait()) { - const locations = getOptionValue('--experimental-print-required-tla') ? getTopLevelAwaitLocations(modules) : []; - const filename = urlToFilename(this.url); - throw new ERR_REQUIRE_ASYNC_MODULE(filename, parent, locations); - } - - /** - * If the a require()'d graph contains top-level await, collect the source locations + * If the require()'d graph contains top-level await, collect the source locations * of the top-level awaits using source code retained during compilation and throw - * ERR_REQUIRE_ASYNC_MODULE. This can be run before instantiation is complete. + * ERR_REQUIRE_ASYNC_MODULE. The module must be at least instantiated. * @param {Module|undefined} parent CommonJS module that require()'d this, if any. */ throwIfAsyncGraph(parent) { - const modules = this.findModulesWithTopLevelAwait(); - if (modules.length > 0) { - this.throwAsyncGraphError(parent, modules); + if (!this.module.hasAsyncGraph) { + return; } + const locations = getOptionValue('--experimental-print-required-tla') ? getTopLevelAwaitLocations(this) : []; + const filename = urlToFilename(this.url); + throw new ERR_REQUIRE_ASYNC_MODULE(filename, parent, locations); } /** @@ -537,9 +533,7 @@ class ModuleJob extends ModuleJobBase { status = this.module.getStatus(); } if (status === kInstantiated || status === kErrored) { - if (this.module.hasAsyncGraph) { - this.throwAsyncGraphError(parent); - } + this.throwIfAsyncGraph(parent); if (status === kInstantiated) { setHasStartedUserESMExecution(); const namespace = this.module.evaluateSync(); @@ -547,9 +541,7 @@ class ModuleJob extends ModuleJobBase { } throw this.module.getError(); } else if (status === kEvaluating || status === kEvaluated) { - if (this.module.hasAsyncGraph) { - this.throwAsyncGraphError(parent); - } + this.throwIfAsyncGraph(parent); // kEvaluating can show up when this is being used to deal with CJS <-> CJS cycles. // Allow it for now, since we only need to ban ESM <-> CJS cycles which would be // detected earlier during the linking phase, though the CJS handling in the ESM @@ -645,12 +637,11 @@ class ModuleJobSync extends ModuleJobBase { } return { __proto__: null, module: this.module }; } else if (status === kInstantiated || status === kUninstantiated) { - // The require() of this (synchronously linked) module bailed out: either - // it was rejected for containing top-level await after instantiation - // (kInstantiated), or its instantiation failed and left it uninstantiated - // (kUninstantiated, e.g. a missing named export). When it's reached via async - // run() from import, finish the instantiation and evaluate it asynchronously, - // re-throwing any instantiation error. + // If we get here, the module was initially required and is now being imported. + // The require() module failed either because the graph has TLA (kInstantiated), + // or instantiation failed (kUninstantiated, e.g. missing named export). + // Try finishing the instantiation - if it succeeds, proceed to evaluation, + // otherwise the branch below re-throw any instantiation error. if (status === kUninstantiated) { this.module.instantiate(); } @@ -676,9 +667,7 @@ class ModuleJobSync extends ModuleJobBase { // On the deprecated async loader hook worker thread, dependencies linked by an // earlier import may not be walkable synchronously, so double-check with // V8 now that the graph is instantiated. - if (this.module.hasAsyncGraph) { - this.throwAsyncGraphError(parent); - } + this.throwIfAsyncGraph(parent); setHasStartedUserESMExecution(); try { const namespace = this.module.evaluateSync(); diff --git a/lib/internal/modules/esm/utils.js b/lib/internal/modules/esm/utils.js index 7e453171026757..9e27a2db1ebce8 100644 --- a/lib/internal/modules/esm/utils.js +++ b/lib/internal/modules/esm/utils.js @@ -11,6 +11,7 @@ const { const { privateSymbols: { host_defined_option_symbol, + module_source_private_symbol: kModuleSource, }, } = internalBinding('util'); const { @@ -368,7 +369,7 @@ function compileSourceTextModule(url, source, type, context = kEmptyObject) { // only serves as a shortcut. if (wrap.hasTopLevelAwait && getOptionValue('--experimental-print-required-tla')) { - wrap.source = source; + wrap[kModuleSource] = source; } // Cache the source map for the module if present. diff --git a/test/common/index.js b/test/common/index.js index 30d567c2c3f4dc..db48322f4a5b02 100755 --- a/test/common/index.js +++ b/test/common/index.js @@ -942,30 +942,37 @@ function expectRequiredModule(mod, expectation, checkESModule = true) { assert.deepStrictEqual(clone, { ...expectation }); } -function expectRequiredTLAError(err) { - const message = /require\(\) cannot be used on an ESM graph with top-level await/; - if (typeof err === 'string') { - assert.match(err, /ERR_REQUIRE_ASYNC_MODULE/); - assert.match(err, message); - } else { - assert.strictEqual(err.code, 'ERR_REQUIRE_ASYNC_MODULE'); - assert.match(err.message, message); - } -} - // Extract the entries of the rendered "Require stack:" list (each shown as // "- ") from an error message or a process output string. -function parseRequireStack(output) { +function expectRequireStack(output, expected) { const lines = output.replace(/\r/g, '').split('\n'); const start = lines.indexOf('Require stack:'); if (start === -1) { - return []; + assert.deepStrictEqual([], expected); + return; } const stack = []; for (let i = start + 1; i < lines.length && lines[i].startsWith('- '); i++) { stack.push(lines[i].slice(2)); } - return stack; + assert.deepStrictEqual(stack, expected); +} + +function expectRequiredTLAError(err, stack) { + const message = /require\(\) cannot be used on an ESM graph with top-level await/; + if (typeof err === 'string') { + assert.match(err, /ERR_REQUIRE_ASYNC_MODULE/); + assert.match(err, message); + if (stack) { + expectRequireStack(err, stack); + } + } else { + assert.strictEqual(err.code, 'ERR_REQUIRE_ASYNC_MODULE'); + assert.match(err.message, message); + if (stack) { + assert.deepStrictEqual(err.requireStack, stack); + } + } } function sleepSync(ms) { @@ -1024,7 +1031,7 @@ const common = { mustSucceed, nodeProcessAborted, PIPE, - parseRequireStack, + expectRequireStack, parseTestMetadata, platformTimeout, printSkipMessage, diff --git a/test/es-module/test-require-module-cached-tla.js b/test/es-module/test-require-module-cached-tla.js index 5c707269cc2a4f..ee99bfa224977f 100644 --- a/test/es-module/test-require-module-cached-tla.js +++ b/test/es-module/test-require-module-cached-tla.js @@ -9,8 +9,7 @@ const assert = require('assert'); assert.throws(() => { require('../fixtures/es-modules/tla/resolved.mjs'); }, (err) => { - common.expectRequiredTLAError(err); - assert.deepStrictEqual(common.parseRequireStack(err.message), [__filename]); + common.expectRequiredTLAError(err, [__filename]); return true; }); })().then(common.mustCall()); diff --git a/test/es-module/test-require-module-tla-error-metadata.js b/test/es-module/test-require-module-tla-error-metadata.js new file mode 100644 index 00000000000000..fc93c6efa94716 --- /dev/null +++ b/test/es-module/test-require-module-tla-error-metadata.js @@ -0,0 +1,26 @@ +// Flags: --experimental-print-required-tla +'use strict'; + +// Tests that ERR_REQUIRE_ASYNC_MODULE carries metadata about the failure +// when --experimental-print-required-tla is enabled. + +require('../common'); +const assert = require('assert'); +const fixtures = require('../common/fixtures'); + +const entrypoint = fixtures.path('es-modules/tla/require-indented.js'); +const url = fixtures.fileURL('es-modules/tla/tla-indented.mjs').href; + +assert.throws(() => { + require(entrypoint); +}, (err) => { + assert.strictEqual(err.code, 'ERR_REQUIRE_ASYNC_MODULE'); + assert.deepStrictEqual(err.requireStack, [entrypoint, __filename]); + assert.deepStrictEqual(err.topLevelAwaitLocations, [ + { __proto__: null, url, line: 4, column: 3, sourceLine: ' await Promise.resolve(ready);' }, + { __proto__: null, url, line: 7, column: 1, sourceLine: 'for await (const x of [Promise.resolve(1)]) {' }, + ]); + // The properties are not enumerable so they do not show up in the inspected error. + assert.deepStrictEqual(Object.keys(err), ['code']); + return true; +}); diff --git a/test/es-module/test-require-module-tla-print.mjs b/test/es-module/test-require-module-tla-error-snapshot.mjs similarity index 87% rename from test/es-module/test-require-module-tla-print.mjs rename to test/es-module/test-require-module-tla-error-snapshot.mjs index 41b44376fdc3e6..bba882437263c2 100644 --- a/test/es-module/test-require-module-tla-print.mjs +++ b/test/es-module/test-require-module-tla-error-snapshot.mjs @@ -1,6 +1,5 @@ -// Tests the output of require(esm) on a graph with top-level await when -// --experimental-print-required-tla is enabled: the location of the -// top-level await (with a caret) and the require stack. +// Snapshot tests for the output of require(esm) on a graph with top-level await when +// --experimental-print-required-tla is enabled. import '../common/index.mjs'; import * as fixtures from '../common/fixtures.mjs'; diff --git a/test/es-module/test-require-module-tla-execution.js b/test/es-module/test-require-module-tla-execution.js index dab795dbdaa406..688691103fdaa9 100644 --- a/test/es-module/test-require-module-tla-execution.js +++ b/test/es-module/test-require-module-tla-execution.js @@ -1,7 +1,7 @@ 'use strict'; -// Tests that require(esm) with top-level-await throws before execution starts -// if --experimental-print-required-tla is not enabled. +// Tests the output of require(esm) with top-level-await when --experimental-print-required-tla +// is NOT enabled. const common = require('../common'); const assert = require('assert'); @@ -9,18 +9,14 @@ const { spawnSyncAndExit } = require('../common/child_process'); const fixtures = require('../common/fixtures'); { - spawnSyncAndExit(process.execPath, [ - fixtures.path('es-modules/tla/require-execution.js'), - ], { + const filename = fixtures.path('es-modules/tla/require-execution.js'); + spawnSyncAndExit(process.execPath, [ filename ], { signal: null, status: 1, stderr(output) { + assert.match(output, /To see where the top-level await comes from, use --experimental-print-required-tla/); assert.doesNotMatch(output, /I am executed/); - common.expectRequiredTLAError(output); - assert.deepStrictEqual( - common.parseRequireStack(output), - [fixtures.path('es-modules/tla/require-execution.js')], - ); + common.expectRequiredTLAError(output, [filename]); return true; }, stdout: '', diff --git a/test/es-module/test-require-module-tla-nested.js b/test/es-module/test-require-module-tla-nested.js index 0b73af5ad35235..879e1ceab6bf1b 100644 --- a/test/es-module/test-require-module-tla-nested.js +++ b/test/es-module/test-require-module-tla-nested.js @@ -8,7 +8,6 @@ const assert = require('assert'); assert.throws(() => { require('../fixtures/es-modules/tla/parent.mjs'); }, (err) => { - common.expectRequiredTLAError(err); - assert.deepStrictEqual(common.parseRequireStack(err.message), [__filename]); + common.expectRequiredTLAError(err, [__filename]); return true; }); diff --git a/test/es-module/test-require-module-tla-print-arrow.js b/test/es-module/test-require-module-tla-print-arrow.js deleted file mode 100644 index 2ba7c165a2bdd0..00000000000000 --- a/test/es-module/test-require-module-tla-print-arrow.js +++ /dev/null @@ -1,29 +0,0 @@ -'use strict'; - -// Tests that require(esm) with --experimental-print-required-tla points the -// caret at the right column for indented top-level await and for-await-of. - -const common = require('../common'); -const assert = require('assert'); -const { spawnSyncAndExit } = require('../common/child_process'); -const fixtures = require('../common/fixtures'); - -{ - spawnSyncAndExit(process.execPath, [ - '--experimental-print-required-tla', - fixtures.path('es-modules/tla/require-indented.js'), - ], { - signal: null, - status: 1, - stderr(output) { - output = output.replace(/\r/g, ''); - common.expectRequiredTLAError(output); - // Indented await: the caret is aligned under the await. - assert(output.includes(' await Promise.resolve(ready);\n ^'), output); - // for-await-of: the caret points at the for keyword. - assert(output.includes('for await (const x of [Promise.resolve(1)]) {\n^'), output); - return true; - }, - stdout: '', - }); -} diff --git a/test/es-module/test-require-module-tla-print-execution.js b/test/es-module/test-require-module-tla-print-execution.js index 68b4dc5a6557e9..c0191e40959020 100644 --- a/test/es-module/test-require-module-tla-print-execution.js +++ b/test/es-module/test-require-module-tla-print-execution.js @@ -10,22 +10,22 @@ const { spawnSyncAndExit } = require('../common/child_process'); const fixtures = require('../common/fixtures'); { + const filename = fixtures.path('es-modules/tla/require-execution.js'); spawnSyncAndExit(process.execPath, [ '--experimental-print-required-tla', - fixtures.path('es-modules/tla/require-execution.js'), + filename, ], { signal: null, status: 1, stderr(output) { output = output.replace(/\r/g, ''); assert.doesNotMatch(output, /I am executed/); - common.expectRequiredTLAError(output); + common.expectRequiredTLAError(output, [filename]); + // The immediately required module is shown regardless of the flag. + assert.match(output, /Required module: .*tla[/\\]execution\.mjs/); // The location of the top-level await is shown with a caret. - assert(output.includes(`${fixtures.path('es-modules/tla/execution.mjs')}:3`), output); + assert.match(output, /tla[/\\]execution\.mjs:3/); assert(output.includes("await Promise.resolve('hi');\n^"), output); - // The require() chain is shown as a require stack. - assert.match(output, /Require stack:/); - assert.match(output, /require-execution\.js/); return true; }, stdout: '', diff --git a/test/es-module/test-require-module-tla-print-nested.js b/test/es-module/test-require-module-tla-print-nested.js deleted file mode 100644 index 5f48c9b18e6d91..00000000000000 --- a/test/es-module/test-require-module-tla-print-nested.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -// Tests that require(esm) attaches the location of a top-level await found in -// an inner dependency of the graph if --experimental-print-required-tla is -// enabled. The entry point is a real CommonJS file that require()s the ESM. - -const common = require('../common'); -const assert = require('assert'); -const { spawnSyncAndExit } = require('../common/child_process'); -const fixtures = require('../common/fixtures'); - -{ - spawnSyncAndExit(process.execPath, [ - '--experimental-print-required-tla', - fixtures.path('es-modules/tla/require-nested.js'), - ], { - signal: null, - status: 1, - stderr(output) { - output = output.replace(/\r/g, ''); - common.expectRequiredTLAError(output); - // The top-level await lives in a transitive dependency (a.mjs). - assert(output.includes(`${fixtures.path('es-modules/tla/a.mjs')}:3`), output); - assert(output.includes('await new Promise((resolve) => {\n^'), output); - assert.match(output, /Require stack:/); - assert.match(output, /require-nested\.js/); - return true; - }, - stdout: '', - }); -} diff --git a/test/es-module/test-require-module-tla-print-preload.js b/test/es-module/test-require-module-tla-print-preload.js deleted file mode 100644 index b53d4e89026c3e..00000000000000 --- a/test/es-module/test-require-module-tla-print-preload.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -// Tests that preloading an ESM with top-level await via -r throws before -// execution starts and attaches the location of the top-level await -// if --experimental-print-required-tla is enabled. - -const common = require('../common'); -const assert = require('assert'); -const { spawnSyncAndExit } = require('../common/child_process'); -const fixtures = require('../common/fixtures'); - -{ - spawnSyncAndExit(process.execPath, [ - '--experimental-print-required-tla', - '-r', fixtures.path('es-modules/tla/execution.mjs'), - '-e', 'console.log("main ran")', - ], { - signal: null, - status: 1, - stderr(output) { - output = output.replace(/\r/g, ''); - // The main script should not run because preloading fails first. - assert.doesNotMatch(output, /main ran/); - assert.doesNotMatch(output, /I am executed/); - common.expectRequiredTLAError(output); - assert(output.includes(`${fixtures.path('es-modules/tla/execution.mjs')}:3`), output); - assert(output.includes("await Promise.resolve('hi');\n^"), output); - return true; - }, - stdout: '', - }); -} diff --git a/test/es-module/test-require-module-tla-rejected.js b/test/es-module/test-require-module-tla-rejected.js index 07e8da183eca64..0922cc74de975b 100644 --- a/test/es-module/test-require-module-tla-rejected.js +++ b/test/es-module/test-require-module-tla-rejected.js @@ -8,7 +8,6 @@ const assert = require('assert'); assert.throws(() => { require('../fixtures/es-modules/tla/rejected.mjs'); }, (err) => { - common.expectRequiredTLAError(err); - assert.deepStrictEqual(common.parseRequireStack(err.message), [__filename]); + common.expectRequiredTLAError(err, [__filename]); return true; }); diff --git a/test/es-module/test-require-module-tla-resolved.js b/test/es-module/test-require-module-tla-resolved.js index 1545ab446819fa..3e15e97cce303d 100644 --- a/test/es-module/test-require-module-tla-resolved.js +++ b/test/es-module/test-require-module-tla-resolved.js @@ -8,7 +8,6 @@ const assert = require('assert'); assert.throws(() => { require('../fixtures/es-modules/tla/resolved.mjs'); }, (err) => { - common.expectRequiredTLAError(err); - assert.deepStrictEqual(common.parseRequireStack(err.message), [__filename]); + common.expectRequiredTLAError(err, [__filename]); return true; }); diff --git a/test/es-module/test-require-module-tla-unresolved.js b/test/es-module/test-require-module-tla-unresolved.js index 2226b2ebba436a..c38f4cb2c02b59 100644 --- a/test/es-module/test-require-module-tla-unresolved.js +++ b/test/es-module/test-require-module-tla-unresolved.js @@ -8,7 +8,6 @@ const assert = require('assert'); assert.throws(() => { require('../fixtures/es-modules/tla/unresolved.mjs'); }, (err) => { - common.expectRequiredTLAError(err); - assert.deepStrictEqual(common.parseRequireStack(err.message), [__filename]); + common.expectRequiredTLAError(err, [__filename]); return true; }); diff --git a/test/fixtures/es-modules/tla/preload-main.snapshot b/test/fixtures/es-modules/tla/preload-main.snapshot index 81279b9e2c017d..b8f0b17bcec0a7 100644 --- a/test/fixtures/es-modules/tla/preload-main.snapshot +++ b/test/fixtures/es-modules/tla/preload-main.snapshot @@ -4,12 +4,12 @@ await Promise.resolve('hi'); ^ Error [ERR_REQUIRE_ASYNC_MODULE]: require() cannot be used on an ESM graph with top-level await. Use import() instead. +Required module: /test/fixtures/es-modules/tla/execution.mjs Require stack: - internal/preload at at { - code: 'ERR_REQUIRE_ASYNC_MODULE', - requireStack: [ 'internal/preload' ] + code: 'ERR_REQUIRE_ASYNC_MODULE' } Node.js diff --git a/test/fixtures/es-modules/tla/require-awaitusing.snapshot b/test/fixtures/es-modules/tla/require-awaitusing.snapshot index ae2a0b7c690217..fcaa21d8580cac 100644 --- a/test/fixtures/es-modules/tla/require-awaitusing.snapshot +++ b/test/fixtures/es-modules/tla/require-awaitusing.snapshot @@ -4,14 +4,12 @@ await using lock = { ^ Error [ERR_REQUIRE_ASYNC_MODULE]: require() cannot be used on an ESM graph with top-level await. Use import() instead. +Required module: /test/fixtures/es-modules/tla/awaitusing.mjs Require stack: - /test/fixtures/es-modules/tla/require-awaitusing.js at at { - code: 'ERR_REQUIRE_ASYNC_MODULE', - requireStack: [ - '/test/fixtures/es-modules/tla/require-awaitusing.js' - ] + code: 'ERR_REQUIRE_ASYNC_MODULE' } Node.js diff --git a/test/fixtures/es-modules/tla/require-execution.snapshot b/test/fixtures/es-modules/tla/require-execution.snapshot index 65f312c9d9c606..9b3f813d0152ff 100644 --- a/test/fixtures/es-modules/tla/require-execution.snapshot +++ b/test/fixtures/es-modules/tla/require-execution.snapshot @@ -4,14 +4,12 @@ await Promise.resolve('hi'); ^ Error [ERR_REQUIRE_ASYNC_MODULE]: require() cannot be used on an ESM graph with top-level await. Use import() instead. +Required module: /test/fixtures/es-modules/tla/execution.mjs Require stack: - /test/fixtures/es-modules/tla/require-execution.js at at { - code: 'ERR_REQUIRE_ASYNC_MODULE', - requireStack: [ - '/test/fixtures/es-modules/tla/require-execution.js' - ] + code: 'ERR_REQUIRE_ASYNC_MODULE' } Node.js diff --git a/test/fixtures/es-modules/tla/require-indented.snapshot b/test/fixtures/es-modules/tla/require-indented.snapshot index 1bc7bf6e46edfd..d3b5f4fc551590 100644 --- a/test/fixtures/es-modules/tla/require-indented.snapshot +++ b/test/fixtures/es-modules/tla/require-indented.snapshot @@ -9,14 +9,12 @@ for await (const x of [Promise.resolve(1)]) { ^ Error [ERR_REQUIRE_ASYNC_MODULE]: require() cannot be used on an ESM graph with top-level await. Use import() instead. +Required module: /test/fixtures/es-modules/tla/tla-indented.mjs Require stack: - /test/fixtures/es-modules/tla/require-indented.js at at { - code: 'ERR_REQUIRE_ASYNC_MODULE', - requireStack: [ - '/test/fixtures/es-modules/tla/require-indented.js' - ] + code: 'ERR_REQUIRE_ASYNC_MODULE' } Node.js diff --git a/test/fixtures/es-modules/tla/require-nested.snapshot b/test/fixtures/es-modules/tla/require-nested.snapshot index bf818b8e939838..fe5ada075fdb39 100644 --- a/test/fixtures/es-modules/tla/require-nested.snapshot +++ b/test/fixtures/es-modules/tla/require-nested.snapshot @@ -4,16 +4,13 @@ await new Promise((resolve) => { ^ Error [ERR_REQUIRE_ASYNC_MODULE]: require() cannot be used on an ESM graph with top-level await. Use import() instead. +Required module: /test/fixtures/es-modules/tla/parent.mjs Require stack: - /test/fixtures/es-modules/tla/require-nested-dep.js - /test/fixtures/es-modules/tla/require-nested.js at at { - code: 'ERR_REQUIRE_ASYNC_MODULE', - requireStack: [ - '/test/fixtures/es-modules/tla/require-nested-dep.js', - '/test/fixtures/es-modules/tla/require-nested.js' - ] + code: 'ERR_REQUIRE_ASYNC_MODULE' } Node.js From 38b99140eda831bb66526dcc080030f401bee9d2 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 4 Jul 2026 19:14:16 +0200 Subject: [PATCH 107/131] stream: refactor unnecessary optional chaining away MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Antoine du Hamel PR-URL: https://github.com/nodejs/node/pull/64253 Reviewed-By: Yagiz Nizipli Reviewed-By: Matteo Collina Reviewed-By: Luigi Pinca Reviewed-By: Gürgün Dayıoğlu Reviewed-By: James M Snell --- lib/internal/webstreams/readablestream.js | 22 ++++++------- lib/internal/webstreams/transfer.js | 4 +-- lib/internal/webstreams/writablestream.js | 38 +++++++++++------------ 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/lib/internal/webstreams/readablestream.js b/lib/internal/webstreams/readablestream.js index 92508613e8883e..e0a84f30ec8380 100644 --- a/lib/internal/webstreams/readablestream.js +++ b/lib/internal/webstreams/readablestream.js @@ -848,15 +848,15 @@ class DefaultReadRequest { } [kChunk](value) { - this[kState].resolve?.({ done: false, value }); + this[kState].resolve({ done: false, value }); } [kClose]() { - this[kState].resolve?.({ done: true, value: undefined }); + this[kState].resolve({ done: true, value: undefined }); } [kError](error) { - this[kState].reject?.(error); + this[kState].reject(error); } get promise() { return this[kState].promise; } @@ -868,15 +868,15 @@ class ReadIntoRequest { } [kChunk](value) { - this[kState].resolve?.({ done: false, value }); + this[kState].resolve({ done: false, value }); } [kClose](value) { - this[kState].resolve?.({ done: true, value }); + this[kState].resolve({ done: true, value }); } [kError](error) { - this[kState].reject?.(error); + this[kState].reject(error); } get promise() { return this[kState].promise; } @@ -2169,7 +2169,7 @@ function readableStreamCancel(stream, reason) { function readableStreamClose(stream) { assert(stream[kState].state === 'readable'); stream[kState].state = 'closed'; - stream[kState].closedPromise?.resolve?.(); + stream[kState].closedPromise?.resolve(); const { reader, } = stream[kState]; @@ -2177,7 +2177,7 @@ function readableStreamClose(stream) { if (reader === undefined) return; - reader[kState].close?.resolve?.(); + reader[kState].close?.resolve(); if (readableStreamHasDefaultReader(stream)) { for (let n = 0; n < reader[kState].readRequests.length; n++) @@ -2193,7 +2193,7 @@ function readableStreamError(stream, error) { const closedPromiseCache = stream[kState].closedPromise; if (closedPromiseCache !== undefined) { setPromiseHandled(closedPromiseCache.promise); - closedPromiseCache.reject?.(error); + closedPromiseCache.reject(error); } const { @@ -2206,7 +2206,7 @@ function readableStreamError(stream, error) { const closeCache = reader[kState].close; if (closeCache !== undefined) { setPromiseHandled(closeCache.promise); - closeCache.reject?.(error); + closeCache.reject(error); } if (readableStreamHasDefaultReader(stream)) { @@ -2400,7 +2400,7 @@ function readableStreamReaderGenericRelease(reader) { const closeCache = reader[kState].close; if (stream[kState].state === 'readable') { if (closeCache !== undefined) { - closeCache.reject?.(lazyReadableReleasedError()); + closeCache.reject(lazyReadableReleasedError()); setPromiseHandled(closeCache.promise); } } else { diff --git a/lib/internal/webstreams/transfer.js b/lib/internal/webstreams/transfer.js index 9ce3f249ffd2bd..e007ada2e0f5e4 100644 --- a/lib/internal/webstreams/transfer.js +++ b/lib/internal/webstreams/transfer.js @@ -192,7 +192,7 @@ class CrossRealmTransformWritableSink { switch (type) { case 'pull': if (this[kState].backpressurePromise !== undefined) - this[kState].backpressurePromise.resolve?.(); + this[kState].backpressurePromise.resolve(); this[kState].backpressurePromise = undefined; break; case 'error': @@ -200,7 +200,7 @@ class CrossRealmTransformWritableSink { this[kState].controller, value); if (this[kState].backpressurePromise !== undefined) - this[kState].backpressurePromise.resolve?.(); + this[kState].backpressurePromise.resolve(); this[kState].backpressurePromise = undefined; break; } diff --git a/lib/internal/webstreams/writablestream.js b/lib/internal/webstreams/writablestream.js index 37ef513a4e4166..9a6af1aa4a1061 100644 --- a/lib/internal/webstreams/writablestream.js +++ b/lib/internal/webstreams/writablestream.js @@ -749,7 +749,7 @@ function writableStreamClose(stream) { stream[kState].closeQueuedOrInFlight = true; const { promise } = stream[kState].closeRequest; if (writer !== undefined && backpressure && state === 'writable') - writer[kState].ready?.resolve?.(); + writer[kState].ready?.resolve(); writableStreamDefaultControllerClose(controller); return promise; } @@ -767,7 +767,7 @@ function writableStreamUpdateBackpressure(stream, backpressure) { // dropping the cache lets the next observation derive it. writer[kState].ready = undefined; } else { - writer[kState].ready?.resolve?.(); + writer[kState].ready?.resolve(); } } streamState.backpressure = backpressure; @@ -796,7 +796,7 @@ function writableStreamRejectCloseAndClosedPromiseIfNeeded(stream) { assert(stream[kState].state === 'errored'); if (stream[kState].closeRequest.promise !== undefined) { assert(stream[kState].inFlightCloseRequest.promise === undefined); - stream[kState].closeRequest.reject?.(stream[kState].storedError); + stream[kState].closeRequest.reject(stream[kState].storedError); stream[kState].closeRequest = kNilRequest; stream[kState].closeQueuedOrInFlight = false; } @@ -804,7 +804,7 @@ function writableStreamRejectCloseAndClosedPromiseIfNeeded(stream) { const closedPromiseCache = stream[kState].closedPromise; if (closedPromiseCache !== undefined) { setPromiseHandled(closedPromiseCache.promise); - closedPromiseCache.reject?.(stream[kState].storedError); + closedPromiseCache.reject(stream[kState].storedError); } const { @@ -814,7 +814,7 @@ function writableStreamRejectCloseAndClosedPromiseIfNeeded(stream) { const closeCache = writer[kState].close; if (closeCache !== undefined) { setPromiseHandled(closeCache.promise); - closeCache.reject?.(stream[kState].storedError); + closeCache.reject(stream[kState].storedError); } } } @@ -847,7 +847,7 @@ function writableStreamHasOperationMarkedInFlight(stream) { function writableStreamFinishInFlightWriteWithError(stream, error) { assert(stream[kState].inFlightWriteRequest.promise !== undefined); - stream[kState].inFlightWriteRequest.reject?.(error); + stream[kState].inFlightWriteRequest.reject(error); stream[kState].inFlightWriteRequest = kNilRequest; assert(stream[kState].state === 'writable' || stream[kState].state === 'erroring'); @@ -856,19 +856,19 @@ function writableStreamFinishInFlightWriteWithError(stream, error) { function writableStreamFinishInFlightWrite(stream) { assert(stream[kState].inFlightWriteRequest.promise !== undefined); - stream[kState].inFlightWriteRequest.resolve?.(); + stream[kState].inFlightWriteRequest.resolve(); stream[kState].inFlightWriteRequest = kNilRequest; } function writableStreamFinishInFlightCloseWithError(stream, error) { assert(stream[kState].inFlightCloseRequest.promise !== undefined); - stream[kState].inFlightCloseRequest.reject?.(error); + stream[kState].inFlightCloseRequest.reject(error); stream[kState].inFlightCloseRequest = kNilRequest; stream[kState].closeQueuedOrInFlight = false; assert(stream[kState].state === 'writable' || stream[kState].state === 'erroring'); if (stream[kState].pendingAbortRequest.abort.promise !== undefined) { - stream[kState].pendingAbortRequest.abort.reject?.(error); + stream[kState].pendingAbortRequest.abort.reject(error); stream[kState].pendingAbortRequest = kNilPendingAbortRequest; } writableStreamDealWithRejection(stream, error); @@ -876,20 +876,20 @@ function writableStreamFinishInFlightCloseWithError(stream, error) { function writableStreamFinishInFlightClose(stream) { assert(stream[kState].inFlightCloseRequest.promise !== undefined); - stream[kState].inFlightCloseRequest.resolve?.(); + stream[kState].inFlightCloseRequest.resolve(); stream[kState].inFlightCloseRequest = kNilRequest; stream[kState].closeQueuedOrInFlight = false; if (stream[kState].state === 'erroring') { stream[kState].storedError = undefined; if (stream[kState].pendingAbortRequest.abort.promise !== undefined) { - stream[kState].pendingAbortRequest.abort.resolve?.(); + stream[kState].pendingAbortRequest.abort.resolve(); stream[kState].pendingAbortRequest = kNilPendingAbortRequest; } } stream[kState].state = 'closed'; if (stream[kState].writer !== undefined) - stream[kState].writer[kState].close?.resolve?.(); - stream[kState].closedPromise?.resolve?.(); + stream[kState].writer[kState].close?.resolve(); + stream[kState].closedPromise?.resolve(); assert(stream[kState].pendingAbortRequest.abort.promise === undefined); assert(stream[kState].storedError === undefined); } @@ -901,7 +901,7 @@ function writableStreamFinishErroring(stream) { stream[kState].controller[kError](); const storedError = stream[kState].storedError; for (let n = 0; n < stream[kState].writeRequests.length; n++) - stream[kState].writeRequests[n].reject?.(storedError); + stream[kState].writeRequests[n].reject(storedError); stream[kState].writeRequests = []; if (stream[kState].pendingAbortRequest.abort.promise === undefined) { @@ -912,18 +912,18 @@ function writableStreamFinishErroring(stream) { const abortRequest = stream[kState].pendingAbortRequest; stream[kState].pendingAbortRequest = kNilPendingAbortRequest; if (abortRequest.wasAlreadyErroring) { - abortRequest.abort.reject?.(storedError); + abortRequest.abort.reject(storedError); writableStreamRejectCloseAndClosedPromiseIfNeeded(stream); return; } PromisePrototypeThen( stream[kState].controller[kAbort](abortRequest.reason), () => { - abortRequest.abort.resolve?.(); + abortRequest.abort.resolve(); writableStreamRejectCloseAndClosedPromiseIfNeeded(stream); }, (error) => { - abortRequest.abort.reject?.(error); + abortRequest.abort.reject(error); writableStreamRejectCloseAndClosedPromiseIfNeeded(stream); }); } @@ -1024,7 +1024,7 @@ function writableStreamDefaultWriterGetDesiredSize(writer) { function writableStreamDefaultWriterEnsureReadyPromiseRejected(writer, error) { const ready = writer[kState].ready; if (ready !== undefined && isPromisePending(ready.promise)) { - ready.reject?.(error); + ready.reject(error); setPromiseHandled(ready.promise); } else { // The spec replaces [[readyPromise]] with a promise rejected with the @@ -1037,7 +1037,7 @@ function writableStreamDefaultWriterEnsureReadyPromiseRejected(writer, error) { function writableStreamDefaultWriterEnsureClosedPromiseRejected(writer, error) { const close = writer[kState].close; if (close !== undefined && isPromisePending(close.promise)) { - close.reject?.(error); + close.reject(error); setPromiseHandled(close.promise); } else { // See writableStreamDefaultWriterEnsureReadyPromiseRejected. From d3fa77c5e29fb8eb4f04c65c9781dbb67d862011 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Sat, 4 Jul 2026 12:47:30 -0700 Subject: [PATCH 108/131] stream: fix merge abort for pending sources Wake the multi-source merge loop when its abort signal fires so a pending read rejects instead of waiting for another source to settle. When the primary error is the abort reason, do not await iterator cleanup because sources may already be stuck in pending next() calls. Fixes: https://github.com/nodejs/node/issues/64012 Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.5 PR-URL: https://github.com/nodejs/node/pull/64013 Fixes: https://github.com/nodejs/node/issues/64012 Reviewed-By: James M Snell --- lib/internal/streams/iter/consumers.js | 40 +++++++++++++++++-- .../test-stream-iter-consumers-merge.js | 20 ++++++++++ 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/lib/internal/streams/iter/consumers.js b/lib/internal/streams/iter/consumers.js index 1162439bf88c3a..2c21a076dfc9d8 100644 --- a/lib/internal/streams/iter/consumers.js +++ b/lib/internal/streams/iter/consumers.js @@ -39,6 +39,10 @@ const { validateObject, } = require('internal/validators'); +const { + markPromiseAsHandled, +} = internalBinding('util'); + const { from, fromSync, @@ -434,6 +438,20 @@ function merge(...args) { const ready = []; let activeCount = normalized.length; let waitResolve = null; + let onAbort; + + if (signal) { + onAbort = () => { + if (waitResolve) { + waitResolve(); + waitResolve = null; + } + }; + signal.addEventListener('abort', onAbort, { + __proto__: null, + once: true, + }); + } // Called when a source's .next() settles. Pushes the result into // the ready queue and wakes the consumer if it's waiting. @@ -498,27 +516,43 @@ function merge(...args) { if (activeCount > 0) { await new Promise((resolve) => { waitResolve = resolve; + if (signal?.aborted) { + waitResolve = null; + resolve(); + } }); } } } catch (err) { primaryError = err; } finally { + if (onAbort !== undefined) { + signal.removeEventListener('abort', onAbort); + } // Clean up: return all iterators. Cleanup errors are not // swallowed - a broken iterator.return() (e.g., failing to // release a resource) should be visible to the caller. - await cleanupIterators(iterators, primaryError); + await cleanupIterators( + iterators, + primaryError, + signal?.aborted && primaryError === signal.reason, + ); } }, }; } -async function cleanupIterators(iterators, primaryError) { +async function cleanupIterators(iterators, primaryError, skipAwaitCleanup) { let cleanupError; await SafePromiseAllReturnVoid(iterators, async (iterator) => { if (iterator.return) { try { - await iterator.return(); + const result = iterator.return(); + if (skipAwaitCleanup) { + markPromiseAsHandled(result); + } else { + await result; + } } catch (err) { // Keep the first cleanup error encountered. cleanupError ??= err; diff --git a/test/parallel/test-stream-iter-consumers-merge.js b/test/parallel/test-stream-iter-consumers-merge.js index 97cc8b9ac89477..b551599f731462 100644 --- a/test/parallel/test-stream-iter-consumers-merge.js +++ b/test/parallel/test-stream-iter-consumers-merge.js @@ -151,6 +151,25 @@ async function testMergeSignalMidIteration() { await assert.rejects(() => iter.next(), { name: 'AbortError' }); } +async function testMergeSignalDuringPendingMultiSourceRead() { + const ac = new AbortController(); + + async function* pending() { + await new Promise(() => {}); + yield []; + } + + const iter = merge(pending(), pending(), { + __proto__: null, + signal: ac.signal, + })[Symbol.asyncIterator](); + + const next = iter.next(); + ac.abort(); + + await assert.rejects(next, { name: 'AbortError' }); +} + // merge() accepts string sources (normalized via from()) async function testMergeStringSources() { const batches = []; @@ -286,6 +305,7 @@ Promise.all([ testMergeSourceError(), testMergeConsumerBreak(), testMergeSignalMidIteration(), + testMergeSignalDuringPendingMultiSourceRead(), testMergeStringSources(), testMergeObjectLikeSources(), testMergeCleanupErrorOnly(), From ab5ed729034981fae19ec33fc8bd0b170b879767 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Sat, 4 Jul 2026 15:12:51 -0700 Subject: [PATCH 109/131] stream: reject iter consumers on abort Make stream/iter async consumers observe abort signals while waiting for a pending async iterator read. This lets bytes(), text(), arrayBuffer(), and array() reject promptly with the abort reason instead of waiting for another batch. Move the shared abort-aware iterator wrapper to stream/iter utils so pull and consumers use the same helper. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.5 PR-URL: https://github.com/nodejs/node/pull/64066 Fixes: https://github.com/nodejs/node/issues/64065 Reviewed-By: James M Snell --- lib/internal/streams/iter/consumers.js | 8 +- lib/internal/streams/iter/pull.js | 83 +----------------- lib/internal/streams/iter/utils.js | 84 +++++++++++++++++++ .../test-stream-iter-consumers-bytes.js | 52 ++++++++++++ 4 files changed, 143 insertions(+), 84 deletions(-) diff --git a/lib/internal/streams/iter/consumers.js b/lib/internal/streams/iter/consumers.js index 2c21a076dfc9d8..7d89607fee0a3b 100644 --- a/lib/internal/streams/iter/consumers.js +++ b/lib/internal/streams/iter/consumers.js @@ -52,6 +52,7 @@ const { const { concatBytes, + yieldAbortable, } = require('internal/streams/iter/utils'); const { @@ -125,7 +126,9 @@ async function collectAsync(source, signal, limit) { signal?.throwIfAborted(); // Normalize source via from() - accepts strings, ArrayBuffers, protocols, etc. - const normalized = from(source); + const abortableSource = signal && isAsyncIterable(source) ? + yieldAbortable(source, signal) : source; + const normalized = from(abortableSource); const chunks = []; // Fast path: no signal and no limit @@ -140,8 +143,9 @@ async function collectAsync(source, signal, limit) { // Slow path: with signal or limit checks let totalBytes = 0; + const iterable = signal ? yieldAbortable(normalized, signal) : normalized; - for await (const batch of normalized) { + for await (const batch of iterable) { signal?.throwIfAborted(); for (let i = 0; i < batch.length; i++) { const chunk = batch[i]; diff --git a/lib/internal/streams/iter/pull.js b/lib/internal/streams/iter/pull.js index f2ac4033dc051a..95ec2a084cdaf3 100644 --- a/lib/internal/streams/iter/pull.js +++ b/lib/internal/streams/iter/pull.js @@ -14,19 +14,12 @@ const { ArrayPrototypeSlice, PromisePrototypeThen, PromiseResolve, - PromiseWithResolvers, - SafePromisePrototypeFinally, - SafePromiseRace, SymbolAsyncIterator, SymbolIterator, TypedArrayPrototypeGetByteLength, Uint8Array, } = primordials; -const { - markPromiseAsHandled, -} = internalBinding('util'); - const { codes: { ERR_INVALID_ARG_TYPE, @@ -60,6 +53,7 @@ const { parsePullArgs, toUint8Array, wrapError, + yieldAbortable, } = require('internal/streams/iter/utils'); const { @@ -690,81 +684,6 @@ async function* applyValidatedStatefulAsyncTransform(source, transform, options) options.signal?.throwIfAborted(); } -function getOnAbort(reject, signal) { - return () => reject(signal.reason); -} - -/** - * Read one item from an async iterator, rejecting early if the signal aborts. - * @param {AsyncIterator} iterator - The iterator to read from. - * @param {AbortSignal|undefined} signal - Optional abort signal. - * @returns {Promise>|IteratorResult} - */ -function abortableNext(iterator, signal) { - if (signal === undefined) { - return iterator.next(); - } - - signal.throwIfAborted(); - - const next = iterator.next(); - const { promise, reject } = PromiseWithResolvers(); - const onAbort = getOnAbort(reject, signal); - signal.addEventListener('abort', onAbort, { __proto__: null, once: true }); - if (signal.aborted) { - onAbort(); - } - - return SafePromisePrototypeFinally(SafePromiseRace([next, promise]), () => { - signal.removeEventListener('abort', onAbort); - }); -} - -/** - * Wrap an async source so each pending read is abort-aware. - * @param {AsyncIterable} source - The source to read from. - * @param {AbortSignal|undefined} signal - Optional abort signal. - * @returns {AsyncIterable} - */ -function yieldAbortable(source, signal) { - if (signal === undefined) { - return source; - } - - return { - __proto__: null, - async *[SymbolAsyncIterator]() { - const iterator = source[SymbolAsyncIterator](); - let completed = false; - let aborted = false; - - try { - while (true) { - const { done, value } = await abortableNext(iterator, signal); - if (done) { - completed = true; - return; - } - signal.throwIfAborted(); - yield value; - } - } catch (error) { - aborted = signal.aborted; - throw error; - } finally { - if (!completed && typeof iterator.return === 'function') { - const result = iterator.return(); - if (aborted) { - markPromiseAsHandled(result); - } else { - await result; - } - } - } - }, - }; -} - /** * Create an async pipeline from source through transforms. * @yields {Uint8Array[]} diff --git a/lib/internal/streams/iter/utils.js b/lib/internal/streams/iter/utils.js index 7829afaade832f..ca3d2531d6f9e0 100644 --- a/lib/internal/streams/iter/utils.js +++ b/lib/internal/streams/iter/utils.js @@ -8,7 +8,11 @@ const { MathMin, NumberMAX_SAFE_INTEGER, PromiseResolve, + PromiseWithResolvers, + SafePromisePrototypeFinally, + SafePromiseRace, String, + SymbolAsyncIterator, TypedArrayPrototypeGetBuffer, TypedArrayPrototypeGetByteLength, TypedArrayPrototypeGetByteOffset, @@ -16,6 +20,10 @@ const { Uint8Array, } = primordials; +const { + markPromiseAsHandled, +} = internalBinding('util'); + const { TextEncoder } = require('internal/encoding'); const { codes: { @@ -69,6 +77,81 @@ function onSignalAbort(signal, handler) { } } +function getOnAbort(reject, signal) { + return () => reject(signal.reason); +} + +/** + * Read one item from an async iterator, rejecting early if the signal aborts. + * @param {AsyncIterator} iterator - The iterator to read from. + * @param {AbortSignal|undefined} signal - Optional abort signal. + * @returns {Promise>|IteratorResult} + */ +function abortableNext(iterator, signal) { + if (signal === undefined) { + return iterator.next(); + } + + signal.throwIfAborted(); + + const next = iterator.next(); + const { promise, reject } = PromiseWithResolvers(); + const onAbort = getOnAbort(reject, signal); + signal.addEventListener('abort', onAbort, { __proto__: null, once: true }); + if (signal.aborted) { + onAbort(); + } + + return SafePromisePrototypeFinally(SafePromiseRace([next, promise]), () => { + signal.removeEventListener('abort', onAbort); + }); +} + +/** + * Wrap an async source so each pending read is abort-aware. + * @param {AsyncIterable} source - The source to read from. + * @param {AbortSignal|undefined} signal - Optional abort signal. + * @returns {AsyncIterable} + */ +function yieldAbortable(source, signal) { + if (signal === undefined) { + return source; + } + + return { + __proto__: null, + async *[SymbolAsyncIterator]() { + const iterator = source[SymbolAsyncIterator](); + let completed = false; + let aborted = false; + + try { + while (true) { + const { done, value } = await abortableNext(iterator, signal); + if (done) { + completed = true; + return; + } + signal.throwIfAborted(); + yield value; + } + } catch (error) { + aborted = signal.aborted; + throw error; + } finally { + if (!completed && typeof iterator.return === 'function') { + const result = iterator.return(); + if (aborted) { + markPromiseAsHandled(result); + } else { + await result; + } + } + } + }, + }; +} + /** * Compute the minimum cursor across a set of consumers and count how many * consumers are at that cursor. @@ -301,4 +384,5 @@ module.exports = { toUint8Array, validateBackpressure, wrapError, + yieldAbortable, }; diff --git a/test/parallel/test-stream-iter-consumers-bytes.js b/test/parallel/test-stream-iter-consumers-bytes.js index e45ee991d587fd..53d0a3858f87ec 100644 --- a/test/parallel/test-stream-iter-consumers-bytes.js +++ b/test/parallel/test-stream-iter-consumers-bytes.js @@ -14,6 +14,7 @@ const { arrayBufferSync, array, arraySync, + toAsyncStreamable, } = require('stream/iter'); // ============================================================================= @@ -51,6 +52,55 @@ async function testBytesAsyncAbort() { ); } +async function testAsyncConsumersAbortPendingNext() { + const consumers = [ + ['bytes', bytes], + ['text', text], + ['arrayBuffer', arrayBuffer], + ['array', array], + ]; + + for (const [name, consumer] of consumers) { + const ac = new AbortController(); + const reason = new Error(`${name} boom`); + + async function* never() { + await new Promise(() => {}); + yield []; + } + + const promise = consumer(never(), { __proto__: null, signal: ac.signal }); + ac.abort(reason); + + await assert.rejects(promise, reason); + } +} + +async function testAsyncConsumersAbortPendingNormalization() { + const consumers = [ + ['bytes', bytes], + ['text', text], + ['arrayBuffer', arrayBuffer], + ['array', array], + ]; + + for (const [name, consumer] of consumers) { + const ac = new AbortController(); + const reason = new Error(`${name} normalization boom`); + const source = { + __proto__: null, + [toAsyncStreamable]() { + return new Promise(() => {}); + }, + }; + + const promise = consumer(source, { __proto__: null, signal: ac.signal }); + ac.abort(reason); + + await assert.rejects(promise, reason); + } +} + async function testBytesEmpty() { const data = await bytes(from([])); assert.ok(data instanceof Uint8Array); @@ -203,6 +253,8 @@ Promise.all([ testBytesAsync(), testBytesAsyncLimit(), testBytesAsyncAbort(), + testAsyncConsumersAbortPendingNext(), + testAsyncConsumersAbortPendingNormalization(), testBytesEmpty(), testArrayBufferSyncBasic(), testArrayBufferAsync(), From 999a83c937d56d0bcd839cba094ccb96eeebf350 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Sun, 5 Jul 2026 10:04:44 +0200 Subject: [PATCH 110/131] stream: expose ReadableStreamTee Signed-off-by: Matteo Collina PR-URL: https://github.com/nodejs/node/pull/64195 Refs: https://github.com/nodejs/undici/issues/5358 Reviewed-By: Matthew Aitken Reviewed-By: James M Snell --- doc/api/webstreams.md | 22 ++++++++++++++++++++ lib/stream/web.js | 21 +++++++++++++++++++ test/parallel/test-whatwg-readablestream.js | 23 +++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/doc/api/webstreams.md b/doc/api/webstreams.md index 55b27584361e1c..263106b5d9e74a 100644 --- a/doc/api/webstreams.md +++ b/doc/api/webstreams.md @@ -106,6 +106,28 @@ For more details refer to the relevant documentation: ## API +### `ReadableStreamTee(stream[, cloneForBranch2])` + + + +> Stability: 1 - Experimental + +* `stream` {ReadableStream} +* `cloneForBranch2` {boolean} When `true`, chunks enqueued into the second + branch are cloned from chunks enqueued into the first branch. **Default:** + `false`. +* Returns: {ReadableStream\[]} Two {ReadableStream} branches. + +Runs the WHATWG `ReadableStreamTee` abstract operation on `stream`. + +This differs from `readableStream.tee()` only when `cloneForBranch2` is +`true`. The `tee()` method always passes `false`, while other web platform +specifications, such as Fetch body cloning, pass `true` so that the second +branch receives cloned chunks and consumption of one branch cannot mutate chunks +seen by the other. + ### Class: `ReadableStream` " +replace="\n\n# [Unreleased] - ReleaseDate" +exactly=1 + +# Disable this replacement on the very first release +[[package.metadata.release.pre-release-replacements]] +file = "CHANGELOG.md" +search = "\\.\\.\\.HEAD" +replace="...{{tag_name}}" +exactly = 1 +# END SECTION, do not comment out the replacement below this, and do not reorder them + +[[package.metadata.release.pre-release-replacements]] +file="CHANGELOG.md" +search="" +replace="\n[Unreleased]: https://github.com/yaahc/{{crate_name}}/compare/{{tag_name}}...HEAD" +exactly=1 + diff --git a/deps/crates/vendor/icu_calendar/.cargo-checksum.json b/deps/crates/vendor/icu_calendar/.cargo-checksum.json index 24c90d80a0e937..d80a2b2841be47 100644 --- a/deps/crates/vendor/icu_calendar/.cargo-checksum.json +++ b/deps/crates/vendor/icu_calendar/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"133164f2c7c66053988a55b15ca4364f8ae03ae52836f2094630cde3eaf9351c","LICENSE":"f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2","README.md":"c51a6704a477876d2ebe131267a2a8023d3deaa3a2f208b9895dda192a2ff880","benches/convert.rs":"e266633d7a07629f1ab716084ee17aa8a919d9729ca482246406925a4e333369","benches/date.rs":"c614ace643c9121d92a742b03cd4748004fc99e708d012c0f49cc00994a294cd","benches/fixtures/datetimes.json":"ad8db74905ad8837b5e75ddc0bb51c1f277a8aa20e486d6927438a8fc7f094a6","benches/fixtures/mod.rs":"c927a527009af7d29bb16fdb893704178ac577ec2688baffa924f24da7f6b040","src/any_calendar.rs":"9437638ef54108b3aab83702eeb60ba02da17f18938787c9997cd60de766ab97","src/cal/buddhist.rs":"eac3e9ad36e24fdfc96b90775f7ef0e0ab3453f0c1ca4eb15559432910f275cf","src/cal/chinese.rs":"fb195492ca130c4264067b49a9b4145a32de6a33671cc66e4040daedde0e8949","src/cal/chinese_based.rs":"cd2d806da42fd9507109f5f8438d61f11a3a0cbbc94c0334afe60135f83fa879","src/cal/coptic.rs":"2462e5f644e3dbeeef8f907f35cb4768ec629360783e327b584bbc1f34d6a5ff","src/cal/dangi.rs":"a4e9e6f20f32b4e6900333ce5067301df0894892866ae035372b7c007fd58fc2","src/cal/ethiopian.rs":"34a9116c624c649909ff75dfe1920ea409d30b6d3ec7582ecce8f495abd66ed7","src/cal/gregorian.rs":"0f17844e2e5e7b6e318f1ab45c0dea9115826a3234a137861f8ef3938bf7287a","src/cal/hebrew.rs":"6d19e5219dd63e2ba7bac805653710b0cd84df758e7a85ab1944a8bef519e550","src/cal/hijri.rs":"a80e7c07c3fe8bced24716ef55e993f29f3ed191d93a44ee9d60b38329d9a164","src/cal/hijri/ummalqura_data.rs":"9e489ef9fd0fc7205213ca3c7ed1edb5523d8cf89d66d7e626a859b49dcbbe30","src/cal/indian.rs":"3d93134cd78b1e49c264eb0d345038e6448bf9ced1d0e1d3067b9cb6c4d8550a","src/cal/iso.rs":"101b81918a873cb58cdca2e98fa4349ca04c88b2cb6401c56244c7df44bebba9","src/cal/japanese.rs":"80ae17bb05141e2d91065f49b2aa8a41d37f6ecafed676ed94fa6b047fc44bc2","src/cal/julian.rs":"f5191def5442543bae6c1ae6a443ffd8ccd69c87361e21c035da52c190fac3d7","src/cal/mod.rs":"77450c6949e36e8496350d3664bd35aead278f4898ba543acfd8b1ca90ce848d","src/cal/persian.rs":"90b27551fe24de57d859c732ee034cc2cc4a60581472dc2ece174fa62f3deaef","src/cal/roc.rs":"c82aca51e24dd038cdc7a1b36d86b5c058f92753df20db8aac7282c057d6a079","src/calendar.rs":"976ef558a0574c717d214cb4d1464885ed79d0fc1f3668d775106f8eb66870be","src/calendar_arithmetic.rs":"f22cd14476b67e59c9b18d211c79bc2b9f0a5e9904d88add497cccd624c8d855","src/date.rs":"91a3b142b48783d6fd4e508bc9bf07026c668ec72f795c269379324507d230d3","src/duration.rs":"65bde57c0af6bd8b146b92bb45bb14f661c918defe6bd388b51569503ec8bd33","src/error.rs":"c01e5adebd4be2b6287173a02623a2ff20afa2269d9e2ba4ecc01b643c7189cf","src/ixdtf.rs":"691dd80767b1d9f4f5aa2202303b49df38f2cf6699c6976ba44d5aae74fa3073","src/lib.rs":"2a10cdd624c9dbce2d8490acaf7f115ce96219bf659dfcc0d6181c132968ed19","src/provider.rs":"89aabfc8fdae13f8e1d7ebfa14f54c9f0249cc17c4436ba24766873a5f4ad128","src/provider/chinese_based.rs":"75fa2be19454674c892b2ac4e54c2b08fbb7fdfcad091ae338c30a8693be9396","src/provider/hijri.rs":"bc2d77aae6c347ba2700381eb64abf1c8118a81a2ccd6f66be6eb5b8f4c10a7c","src/tests/continuity_test.rs":"d3c97c72efc0b23d0cdf55e2911f4962fa0f55e8261019a929f2fc7d8c6a680b","src/tests/mod.rs":"0925663ff594ebac9892d652d3576a9bc1ed938b2e4ee7a6d23a641899e8bf5a","src/types.rs":"fced40c1477ca7d66edbea8597c21bf233deb7d3fe0e72addbff03a6291862fc","src/week.rs":"803b68991584f3cee05bf051db601c0207f266b9139fa27731d0bc55b1cae88d"},"package":"362941891d17750e05cd8fdfca4a89a86552825d625a937020ee1a65580da1f9"} \ No newline at end of file +{"files":{".cargo_vcs_info.json":"5bf4d11031ba6544415af89fa62cacac923c8dddf49d4e292d24daff57d87571","Cargo.lock":"7c97bb97524646eb50dcb495e070eb99d6df27527119437923ff9f366023b76e","Cargo.toml":"5f2b9d93ec859d508a5c12f4f131cd7bc6cde61b65d63e824c0730d43e71d01b","Cargo.toml.orig":"93770e7fde059818db19ffdc3668cead2f95b4d4645a118b92e2386a586cf734","LICENSE":"f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2","README.md":"c51a6704a477876d2ebe131267a2a8023d3deaa3a2f208b9895dda192a2ff880","benches/convert.rs":"14b05e5328a2ffa347f4adba079de9bce8c0dad67bd0e2c7825e50c46affe342","benches/date.rs":"e1272dc8a6f4fac843ca1231983adaf7264a364932a9a3e06cadb32fd6e62013","benches/fixtures/datetimes.json":"ad8db74905ad8837b5e75ddc0bb51c1f277a8aa20e486d6927438a8fc7f094a6","src/any_calendar.rs":"fe0ddeccfeeb47dad36f88297e85d4823556b999079136b385dbdadb373c804f","src/cal/abstract_gregorian.rs":"ff0f57b889450cc0b376b02f46464e2bf86059e1faef649906eab86c07b46532","src/cal/buddhist.rs":"bc03a42366af670672db24a88ffadb4487bf6f31efcd47eaa68c76bac2d0dafe","src/cal/coptic.rs":"a06067a8585f74b96fe1a3995fc44e3547f0d843672d88af143ed5b3671b9cb6","src/cal/east_asian_traditional.rs":"6a54a8f8167703393c937db04e79f56851b8b5d77521f8d1afca998adc4336fa","src/cal/east_asian_traditional/china_data.rs":"f57440be085f5076125b2efcd92c66196a652655cb287ce124319dfd45052df5","src/cal/east_asian_traditional/korea_data.rs":"715ec9fe69500adfeba704143ebaabdeecc078ae7974b3db362e58b36e5d2189","src/cal/east_asian_traditional/qing_data.rs":"e8097d4ba4651863644ef2ed7247d57640e949eb2c2ef207a2d8ebf9b5c4f69e","src/cal/east_asian_traditional/simple.rs":"b362f75297198eaf71b6f84b39991e39705637198ae941ded8bf9a7563ddb867","src/cal/ethiopian.rs":"e315c63c36fea55b8626497489a1382cbc4cbcac521079d3ea6a77923128a72a","src/cal/gregorian.rs":"42f30696460caee5af1981b76100a8cf3e8460876d8f733b4828db99d5a9beea","src/cal/hebrew.rs":"6f995191f5205d6858a0afe28f9aed3ecb4f48e0e17075c5ebba7a294cf282a3","src/cal/hijri.rs":"17cca441ad57a596dcc44481f631d97fa3de413581c3aa9b437c0ea0921edfbb","src/cal/hijri/simulated_mecca_data.rs":"f1defaee03b91a503dd2d8039257ba297cda238cc23f6ba75ef35d622b70f483","src/cal/hijri/ummalqura_data.rs":"15118990b415f15ebf5d63502bebc0d6a99a5e021e14d87da4beb6fb136fdfa0","src/cal/indian.rs":"2b71744ee7a7beba6054424fcaa34acc96e7a2d293ac340600ecd448c0026425","src/cal/iso.rs":"b3e415ecc0aa5a44318fd7e24c879e5e2f2f03fc9a8c102a4613edb9c450744f","src/cal/japanese.rs":"baa085cf698af3ba88c31b0f9d876b082193b5004dde52d77f6594ebfcae8653","src/cal/julian.rs":"ffeac88c5bbe9c5288cbc9e89ac5c3366a7039e828ba48729e9266e447a5fcf7","src/cal/mod.rs":"2e65ce43eb8a19b0141407e3806d74d57724655605cd9cf1698ba836d69c2a12","src/cal/persian.rs":"10cd0d17116dd0887d20fa2fbf9c34eda7f3833817226f48e9fce2ef603e0e41","src/cal/roc.rs":"6c716c6fa00982ffbeaa905333c795022b7559e627a80920d72d5c9eefcaf7a0","src/calendar.rs":"961a67f72a1c5733b97c16c3b3e3bc1bda55f61e1f6819f7f40be0af4923c84c","src/calendar_arithmetic.rs":"8850422da53f06d19691b374b3476680cd0854f6c69e0816eaac3a750b477934","src/date.rs":"479681ce9eddd15b3dc10b6d96a597169932e5e6828722baccc3a414de823f3e","src/duration.rs":"7dd00f9f702c0f57796e0f9ec5d3f4a002a5739fda78879e482982b0a5c61385","src/error.rs":"a1e8bdf73bcbf533aac005050c2ebcc5e1decdec45091f2b0a3765b92544fec5","src/ixdtf.rs":"a9f3cddafd209e6f828825a2c42bf4280eb1a0456e9bae7e293d72072cc9c007","src/lib.rs":"03bab72eafec685d861d3ba075114483e751447a53c44455de81011e49ad2672","src/options.rs":"a6051b983427f035e9aea38be3607e4363998d6ad1adb341b63af4cce130fb9a","src/provider.rs":"37a27cd8f3ca98b58e0ca82ec570314ecb951371fcab772fd48af5eabc4daa98","src/tests/continuity_test.rs":"16ce3029e79a6b7148e898eac299c5a2d4efb9af51fa1d1d7157529be37cba7d","src/tests/extrema.rs":"4f752bfeb0fde51470c22bdb8cd2fbd74eb436af027a2ef2e3ba7ab7887d2d9a","src/tests/mod.rs":"aed1fc2784f1d66671477645ef6e6007a456977cc1502205ad5057ef62fc86a1","src/tests/not_enough_fields.rs":"570dc9696e1afa068aa6ca30625a01901003fc8689e316cda13adfac017a419b","src/types.rs":"a7bdc94f5a6bb44b08d188cf5e3a6e877fbf27b0a731285883b98afdc1e684b3","src/week.rs":"a69c1ad8b9399dcc4446f7bc259c6c0da281ac0b4fb3f6093ff897287674177c","tests/arithmetic.rs":"21ae8051246d706b3e5eb4d41010b1011e9ac82a19fdc687e38b0222ca84c4ca","tests/exhaustive.rs":"9bda342cfa8db3d73ebfd5cd03ab0c6692f5e8c0bd28ffd8d119242b705614e3","tests/extended_year.rs":"e63f358426bd6c5d290565822420fc313c4f31ac99e5cd35122024e6273e1a8e","tests/reference_year.rs":"fd2bbc54b5a932490669de2ba8cf62f36539e56737f6f296a076856712e0b6bb"},"package":"d6f0e52e009b6b16ba9c0693578796f2dd4aaa59a7f8f920423706714a89ac4e"} \ No newline at end of file diff --git a/deps/crates/vendor/icu_calendar/.cargo_vcs_info.json b/deps/crates/vendor/icu_calendar/.cargo_vcs_info.json new file mode 100644 index 00000000000000..d75612e253d45c --- /dev/null +++ b/deps/crates/vendor/icu_calendar/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "38a49da495248dd1ded84cf306e4ca42e64d5bb3" + }, + "path_in_vcs": "components/calendar" +} \ No newline at end of file diff --git a/deps/crates/vendor/icu_calendar/Cargo.lock b/deps/crates/vendor/icu_calendar/Cargo.lock new file mode 100644 index 00000000000000..80249d10b9ad78 --- /dev/null +++ b/deps/crates/vendor/icu_calendar/Cargo.lock @@ -0,0 +1,1317 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "calendrical_calculations" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a0b39595c6ee54a8d0900204ba4c401d0ab4eb45adaf07178e8d017541529e7" +dependencies = [ + "core_maths", + "displaydoc", + "log", +] + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.2.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror", +] + +[[package]] +name = "colored" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "core_maths" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30" +dependencies = [ + "libm", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools 0.10.5", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "databake" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6ee9e2d2afb173bcdeee45934c89ec341ab26f91c9933774fc15c2b58f83ef" +dependencies = [ + "databake-derive", + "proc-macro2", + "quote", +] + +[[package]] +name = "databake-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6834770958c7b84223607e49758ec0dde273c4df915e734aad50f62968a4c134" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "deranged" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "erased-serde" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "259d404d09818dec19332e31d94558aeb442fea04c817006456c24b5460bbd4b" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" + +[[package]] +name = "flate2" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "icu_calendar" +version = "2.1.1" +dependencies = [ + "calendrical_calculations", + "criterion", + "databake", + "displaydoc", + "icu_calendar_data", + "icu_locale", + "icu_locale_core", + "icu_provider", + "itertools 0.14.0", + "ixdtf", + "serde", + "serde_json", + "simple_logger", + "tinystr", + "ureq", + "zerovec", +] + +[[package]] +name = "icu_calendar_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "527f04223b17edfe0bd43baf14a0cb1b017830db65f3950dc00224860a9a446d" + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "532b11722e350ab6bf916ba6eb0efe3ee54b932666afec989465f9243fe6dd60" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_locale_data", + "icu_provider", + "potential_utf", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "serde", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locale_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f03e2fcaefecdf05619f3d6f91740e79ab969b4dd54f77cbf546b1d0d28e3147" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "databake", + "displaydoc", + "erased-serde", + "icu_locale_core", + "postcard", + "serde", + "stable_deref_trait", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "is-terminal" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "ixdtf" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84de9d95a6d2547d9b77ee3f25fa0ee32e3c3a6484d47a55adebc0439c077992" + +[[package]] +name = "js-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "serde", +] + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "serde_core", + "writeable", + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.23.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a9586e9ee2b4f8fab52a0048ca7334d7024eef48e2cb9407e3497bb7cab7fa7" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "simple_logger" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291bee647ce7310b0ea721bfd7e0525517b4468eb7c7e15eb8bd774343179702" +dependencies = [ + "colored", + "log", + "time", + "windows-sys 0.61.2", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + +[[package]] +name = "time-macros" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "databake", + "displaydoc", + "serde_core", + "zerovec", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "unicode-ident" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99ba1025f18a4a3fc3e9b48c868e9beb4f24f4b4b1a325bada26bd4119f46537" +dependencies = [ + "base64", + "flate2", + "log", + "percent-encoding", + "rustls", + "rustls-pemfile", + "rustls-pki-types", + "ureq-proto", + "utf-8", + "webpki-roots", +] + +[[package]] +name = "ureq-proto" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b4531c118335662134346048ddb0e54cc86bd7e81866757873055f0e38f5d2" +dependencies = [ + "base64", + "http", + "httparse", + "log", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "databake", + "serde", + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/deps/crates/vendor/icu_calendar/Cargo.toml b/deps/crates/vendor/icu_calendar/Cargo.toml index 79be24ad34b964..2987c1c4be7f9e 100644 --- a/deps/crates/vendor/icu_calendar/Cargo.toml +++ b/deps/crates/vendor/icu_calendar/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.82" +rust-version = "1.83" name = "icu_calendar" -version = "2.0.6" +version = "2.1.1" authors = ["The ICU4X Project Developers"] build = false include = [ @@ -42,8 +42,15 @@ repository = "https://github.com/unicode-org/icu4x" [package.metadata.docs.rs] all-features = true +[package.metadata.cargo-semver-checks.lints] +workspace = true + [features] -alloc = [] +alloc = [ + "icu_locale_core/alloc", + "tinystr/alloc", + "serde?/alloc", +] compiled_data = [ "dep:icu_calendar_data", "dep:icu_locale", @@ -70,11 +77,29 @@ serde = [ "tinystr/serde", "icu_provider/serde", ] +unstable = [] [lib] name = "icu_calendar" path = "src/lib.rs" +[[test]] +name = "arithmetic" +path = "tests/arithmetic.rs" +required-features = ["ixdtf"] + +[[test]] +name = "exhaustive" +path = "tests/exhaustive.rs" + +[[test]] +name = "extended_year" +path = "tests/extended_year.rs" + +[[test]] +name = "reference_year" +path = "tests/reference_year.rs" + [[bench]] name = "convert" path = "benches/convert.rs" @@ -86,7 +111,7 @@ path = "benches/date.rs" harness = false [dependencies.calendrical_calculations] -version = "0.2.2" +version = "0.2.3" default-features = false [dependencies.databake] @@ -100,58 +125,49 @@ version = "0.2.3" default-features = false [dependencies.icu_calendar_data] -version = "~2.0.0" +version = "~2.1.1" optional = true default-features = false [dependencies.icu_locale] -version = "~2.0.0" +version = "~2.1.1" optional = true default-features = false [dependencies.icu_locale_core] -version = "2.0.0" -features = ["alloc"] +version = "2.1.1" default-features = false [dependencies.icu_provider] -version = "2.0.0" -features = ["alloc"] +version = "2.1.1" default-features = false [dependencies.ixdtf] -version = "0.5.0" +version = "0.6.0" optional = true default-features = false [dependencies.serde] -version = "1.0.110" -features = [ - "derive", - "alloc", -] +version = "1.0.220" +features = ["derive"] optional = true default-features = false [dependencies.tinystr] version = "0.8.0" -features = [ - "alloc", - "zerovec", -] -default-features = false - -[dependencies.writeable] -version = "0.6.0" +features = ["zerovec"] default-features = false [dependencies.zerovec] -version = "0.11.1" +version = "0.11.3" features = ["derive"] default-features = false +[dev-dependencies.itertools] +version = "0.14.0" + [dev-dependencies.serde] -version = "1.0.110" +version = "1.0.220" features = [ "derive", "alloc", @@ -164,5 +180,8 @@ version = "1.0.45" [dev-dependencies.simple_logger] version = "5.0.0" +[dev-dependencies.ureq] +version = "3.0.0" + [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies.criterion] version = "0.5.0" diff --git a/deps/crates/vendor/icu_calendar/Cargo.toml.orig b/deps/crates/vendor/icu_calendar/Cargo.toml.orig new file mode 100644 index 00000000000000..1567ce4a40b65b --- /dev/null +++ b/deps/crates/vendor/icu_calendar/Cargo.toml.orig @@ -0,0 +1,75 @@ +# This file is part of ICU4X. For terms of use, please see the file +# called LICENSE at the top level of the ICU4X source tree +# (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +[package] +name = "icu_calendar" +description = "Date APIs for Gregorian and non-Gregorian calendars" +version.workspace = true + +authors.workspace = true +categories.workspace = true +edition.workspace = true +homepage.workspace = true +include.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +calendrical_calculations = { workspace = true } +displaydoc = { workspace = true } +icu_provider = { workspace = true } +icu_locale_core = { workspace = true } +ixdtf = { workspace = true, optional = true } +tinystr = { workspace = true, features = ["zerovec"] } +zerovec = { workspace = true, features = ["derive"] } + +databake = { workspace = true, features = ["derive"], optional = true } +serde = { workspace = true, features = ["derive"], optional = true } + +icu_calendar_data = { workspace = true, optional = true } +icu_locale = { workspace = true, optional = true } + +[dev-dependencies] +icu_provider = { path = "../../provider/core", features = ["logging"] } +icu = { path = "../../components/icu", default-features = false } +itertools = { workspace = true } +serde = { workspace = true, features = ["derive", "alloc"] } +serde_json = { workspace = true } +simple_logger = { workspace = true } +ureq = { workspace = true } + + +[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] +criterion = { workspace = true } + + +[features] +default = ["compiled_data", "ixdtf"] +ixdtf = ["dep:ixdtf"] +logging = ["calendrical_calculations/logging"] +serde = ["dep:serde", "zerovec/serde", "tinystr/serde", "icu_provider/serde"] +datagen = ["serde", "dep:databake", "zerovec/databake", "tinystr/databake", "alloc", "icu_provider/export"] +compiled_data = ["dep:icu_calendar_data", "dep:icu_locale", "icu_locale?/compiled_data", "icu_provider/baked"] +unstable = [] + +alloc = ["icu_locale_core/alloc", "tinystr/alloc", "serde?/alloc"] + +[[bench]] +name = "date" +harness = false + +[[bench]] +name = "convert" +harness = false + +[[test]] +name = "arithmetic" +required-features = ["ixdtf"] + +[package.metadata.cargo-semver-checks.lints] +workspace = true diff --git a/deps/crates/vendor/icu_calendar/benches/convert.rs b/deps/crates/vendor/icu_calendar/benches/convert.rs index 90b18f256cc8d6..7e84fb364f31f2 100644 --- a/deps/crates/vendor/icu_calendar/benches/convert.rs +++ b/deps/crates/vendor/icu_calendar/benches/convert.rs @@ -2,8 +2,6 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -mod fixtures; - use criterion::{ black_box, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion, }; @@ -49,16 +47,10 @@ fn convert_benches(c: &mut Criterion) { bench_calendar(&mut group, "calendar/julian", icu::calendar::cal::Julian); - bench_calendar( - &mut group, - "calendar/chinese_calculating", - icu::calendar::cal::Chinese::new_always_calculating(), - ); - bench_calendar( &mut group, "calendar/chinese_cached", - icu::calendar::cal::Chinese::new(), + icu::calendar::cal::ChineseTraditional::new(), ); bench_calendar( @@ -72,30 +64,30 @@ fn convert_benches(c: &mut Criterion) { bench_calendar( &mut group, "calendar/islamic/observational", - icu::calendar::cal::HijriSimulated::new_mecca_always_calculating(), + icu::calendar::cal::Hijri::new_simulated_mecca(), ); bench_calendar( &mut group, "calendar/islamic/civil", - icu::calendar::cal::HijriTabular::new( - icu::calendar::cal::HijriTabularLeapYears::TypeII, - icu::calendar::cal::HijriTabularEpoch::Friday, + icu::calendar::cal::Hijri::new_tabular( + icu::calendar::cal::hijri::TabularAlgorithmLeapYears::TypeII, + icu::calendar::cal::hijri::TabularAlgorithmEpoch::Friday, ), ); bench_calendar( &mut group, "calendar/islamic/ummalqura", - icu::calendar::cal::HijriUmmAlQura::new(), + icu::calendar::cal::Hijri::new_umm_al_qura(), ); bench_calendar( &mut group, "calendar/islamic/tabular", - icu::calendar::cal::HijriTabular::new( - icu::calendar::cal::HijriTabularLeapYears::TypeII, - icu::calendar::cal::HijriTabularEpoch::Thursday, + icu::calendar::cal::Hijri::new_tabular( + icu::calendar::cal::hijri::TabularAlgorithmLeapYears::TypeII, + icu::calendar::cal::hijri::TabularAlgorithmEpoch::Thursday, ), ); diff --git a/deps/crates/vendor/icu_calendar/benches/date.rs b/deps/crates/vendor/icu_calendar/benches/date.rs index 4cd5e5fecd22b9..25786ac3f458ae 100644 --- a/deps/crates/vendor/icu_calendar/benches/date.rs +++ b/deps/crates/vendor/icu_calendar/benches/date.rs @@ -2,23 +2,45 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -mod fixtures; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct DateFixture(pub Vec); + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Test { + pub year: i32, + pub month: u8, + pub day: u8, + pub hour: u8, + pub minute: u8, + pub second: u8, +} use criterion::{ black_box, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion, }; -use fixtures::DateFixture; -use icu_calendar::{AsCalendar, Calendar, Date, DateDuration}; +use icu_calendar::{ + options::{DateAddOptions, Overflow}, + types, AsCalendar, Calendar, Date, +}; fn bench_date(date: &mut Date) { // black_box used to avoid compiler optimization. // Arithmetic - date.add(DateDuration::new( - black_box(1), - black_box(2), - black_box(3), - black_box(4), - )); + let mut options = DateAddOptions::default(); + options.overflow = Some(Overflow::Constrain); + date.try_add_with_options( + types::DateDuration { + is_negative: false, + years: black_box(1), + months: black_box(2), + weeks: black_box(3), + days: black_box(4), + }, + options, + ) + .unwrap(); // Retrieving vals let _ = black_box(date.year()); @@ -34,13 +56,14 @@ fn bench_calendar( name: &str, fxs: &DateFixture, calendar: C, - calendar_date_init: impl Fn(i32, u8, u8) -> Date, + calendar_date_init: impl Fn(i32, u8, u8, C) -> Date, ) { group.bench_function(name, |b| { b.iter(|| { for fx in &fxs.0 { // Instantion from int - let mut instantiated_date_calendar = calendar_date_init(fx.year, fx.month, fx.day); + let mut instantiated_date_calendar = + calendar_date_init(fx.year, fx.month, fx.day, calendar.clone()); // Conversion from ISO let date_iso = Date::try_new_iso(fx.year, fx.month, fx.day).unwrap(); @@ -62,7 +85,7 @@ fn date_benches(c: &mut Criterion) { "calendar/overview", &fxs, icu::calendar::cal::Iso, - |y, m, d| Date::try_new_iso(y, m, d).unwrap(), + |y, m, d, _| Date::try_new_iso(y, m, d).unwrap(), ); bench_calendar( @@ -70,7 +93,7 @@ fn date_benches(c: &mut Criterion) { "calendar/buddhist", &fxs, icu::calendar::cal::Buddhist, - |y, m, d| Date::try_new_buddhist(y, m, d).unwrap(), + |y, m, d, _| Date::try_new_buddhist(y, m, d).unwrap(), ); bench_calendar( @@ -78,7 +101,7 @@ fn date_benches(c: &mut Criterion) { "calendar/coptic", &fxs, icu::calendar::cal::Coptic, - |y, m, d| Date::try_new_coptic(y, m, d).unwrap(), + |y, m, d, _| Date::try_new_coptic(y, m, d).unwrap(), ); bench_calendar( @@ -86,7 +109,7 @@ fn date_benches(c: &mut Criterion) { "calendar/ethiopic", &fxs, icu::calendar::cal::Ethiopian::new(), - |y, m, d| { + |y, m, d, _| { Date::try_new_ethiopian(icu::calendar::cal::EthiopianEraStyle::AmeteMihret, y, m, d) .unwrap() }, @@ -97,7 +120,7 @@ fn date_benches(c: &mut Criterion) { "calendar/indian", &fxs, icu::calendar::cal::Indian, - |y, m, d| Date::try_new_indian(y, m, d).unwrap(), + |y, m, d, _| Date::try_new_indian(y, m, d).unwrap(), ); bench_calendar( @@ -105,7 +128,7 @@ fn date_benches(c: &mut Criterion) { "calendar/persian", &fxs, icu::calendar::cal::Persian, - |y, m, d| Date::try_new_persian(y, m, d).unwrap(), + |y, m, d, _| Date::try_new_persian(y, m, d).unwrap(), ); bench_calendar( @@ -113,7 +136,7 @@ fn date_benches(c: &mut Criterion) { "calendar/roc", &fxs, icu::calendar::cal::Roc, - |y, m, d| Date::try_new_roc(y, m, d).unwrap(), + |y, m, d, _| Date::try_new_roc(y, m, d).unwrap(), ); bench_calendar( @@ -121,59 +144,28 @@ fn date_benches(c: &mut Criterion) { "calendar/julian", &fxs, icu::calendar::cal::Julian, - |y, m, d| Date::try_new_julian(y, m, d).unwrap(), - ); - - bench_calendar( - &mut group, - "calendar/chinese_calculating", - &fxs, - icu::calendar::cal::Chinese::new_always_calculating(), - |y, m, d| { - Date::try_new_chinese_with_calendar( - y, - m, - d, - icu::calendar::cal::Chinese::new_always_calculating(), - ) - .unwrap() - }, + |y, m, d, _| Date::try_new_julian(y, m, d).unwrap(), ); bench_calendar( &mut group, "calendar/chinese_cached", &fxs, - icu::calendar::cal::Chinese::new(), - |y, m, d| { - Date::try_new_chinese_with_calendar(y, m, d, icu::calendar::cal::Chinese::new()) + icu::calendar::cal::ChineseTraditional::new(), + |y, m, d, c| { + Date::try_new_from_codes(None, y, types::MonthCode::new_normal(m).unwrap(), d, c) .unwrap() }, ); - bench_calendar( - &mut group, - "calendar/dangi_calculating", - &fxs, - icu::calendar::cal::Dangi::new_always_calculating(), - |y, m, d| { - Date::try_new_dangi_with_calendar( - y, - m, - d, - icu::calendar::cal::Dangi::new_always_calculating(), - ) - .unwrap() - }, - ); - bench_calendar( &mut group, "calendar/dangi_cached", &fxs, - icu::calendar::cal::Dangi::new(), - |y, m, d| { - Date::try_new_dangi_with_calendar(y, m, d, icu::calendar::cal::Dangi::new()).unwrap() + icu::calendar::cal::KoreanTraditional::new(), + |y, m, d, c| { + Date::try_new_from_codes(None, y, types::MonthCode::new_normal(m).unwrap(), d, c) + .unwrap() }, ); @@ -182,7 +174,10 @@ fn date_benches(c: &mut Criterion) { "calendar/hebrew", &fxs, icu::calendar::cal::Hebrew, - |y, m, d| Date::try_new_hebrew(y, m, d).unwrap(), + |y, m, d, c| { + Date::try_new_from_codes(None, y, types::MonthCode::new_normal(m).unwrap(), d, c) + .unwrap() + }, ); bench_calendar( @@ -190,75 +185,45 @@ fn date_benches(c: &mut Criterion) { "calendar/gregorian", &fxs, icu::calendar::cal::Gregorian, - |y, m, d| Date::try_new_gregorian(y, m, d).unwrap(), + |y, m, d, _| Date::try_new_gregorian(y, m, d).unwrap(), ); bench_calendar( &mut group, "calendar/islamic/civil", &fxs, - icu::calendar::cal::HijriTabular::new( - icu::calendar::cal::HijriTabularLeapYears::TypeII, - icu::calendar::cal::HijriTabularEpoch::Friday, + icu::calendar::cal::Hijri::new_tabular( + icu::calendar::cal::hijri::TabularAlgorithmLeapYears::TypeII, + icu::calendar::cal::hijri::TabularAlgorithmEpoch::Friday, ), - |y, m, d| { - Date::try_new_hijri_tabular_with_calendar( - y, - m, - d, - icu::calendar::cal::HijriTabular::new( - icu::calendar::cal::HijriTabularLeapYears::TypeII, - icu::calendar::cal::HijriTabularEpoch::Friday, - ), - ) - .unwrap() - }, + |y, m, d, c| Date::try_new_hijri_with_calendar(y, m, d, c).unwrap(), ); bench_calendar( &mut group, "calendar/islamic/tabular", &fxs, - icu::calendar::cal::HijriTabular::new( - icu::calendar::cal::HijriTabularLeapYears::TypeII, - icu::calendar::cal::HijriTabularEpoch::Thursday, + icu::calendar::cal::Hijri::new_tabular( + icu::calendar::cal::hijri::TabularAlgorithmLeapYears::TypeII, + icu::calendar::cal::hijri::TabularAlgorithmEpoch::Thursday, ), - |y, m, d| { - Date::try_new_hijri_tabular_with_calendar( - y, - m, - d, - icu::calendar::cal::HijriTabular::new( - icu::calendar::cal::HijriTabularLeapYears::TypeII, - icu::calendar::cal::HijriTabularEpoch::Thursday, - ), - ) - .unwrap() - }, + |y, m, d, c| Date::try_new_hijri_with_calendar(y, m, d, c).unwrap(), ); bench_calendar( &mut group, "calendar/islamic/ummalqura", &fxs, - icu::calendar::cal::HijriUmmAlQura::new(), - |y, m, d| Date::try_new_ummalqura(y, m, d).unwrap(), + icu::calendar::cal::Hijri::new_umm_al_qura(), + |y, m, d, c| Date::try_new_hijri_with_calendar(y, m, d, c).unwrap(), ); bench_calendar( &mut group, "calendar/islamic/observational", &fxs, - icu::calendar::cal::HijriSimulated::new_mecca_always_calculating(), - |y, m, d| { - Date::try_new_simulated_hijri_with_calendar( - y, - m, - d, - icu::calendar::cal::HijriSimulated::new_mecca_always_calculating(), - ) - .unwrap() - }, + icu::calendar::cal::Hijri::new_simulated_mecca(), + |y, m, d, c| Date::try_new_hijri_with_calendar(y, m, d, c).unwrap(), ); group.finish(); diff --git a/deps/crates/vendor/icu_calendar/benches/fixtures/mod.rs b/deps/crates/vendor/icu_calendar/benches/fixtures/mod.rs deleted file mode 100644 index c4bc9336ea0aee..00000000000000 --- a/deps/crates/vendor/icu_calendar/benches/fixtures/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct DateFixture(pub Vec); - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct Test { - pub year: i32, - pub month: u8, - pub day: u8, - pub hour: u8, - pub minute: u8, - pub second: u8, -} diff --git a/deps/crates/vendor/icu_calendar/src/any_calendar.rs b/deps/crates/vendor/icu_calendar/src/any_calendar.rs index 6ce6ed1164e6bd..3032034600d8c2 100644 --- a/deps/crates/vendor/icu_calendar/src/any_calendar.rs +++ b/deps/crates/vendor/icu_calendar/src/any_calendar.rs @@ -4,20 +4,16 @@ //! Module for working with multiple calendars at once -use crate::cal::hijri::HijriSimulatedLocation; use crate::cal::iso::IsoDateInner; -use crate::cal::{ - Buddhist, Chinese, Coptic, Dangi, Ethiopian, EthiopianEraStyle, Gregorian, Hebrew, - HijriSimulated, HijriTabular, HijriTabularEpoch, HijriTabularLeapYears, HijriUmmAlQura, Indian, - Iso, Japanese, JapaneseExtended, Persian, Roc, -}; -use crate::error::DateError; -use crate::types::YearInfo; -use crate::{types, AsCalendar, Calendar, Date, DateDuration, DateDurationUnit, Ref}; +use crate::cal::*; +use crate::error::{DateError, DateFromFieldsError}; +use crate::options::DateFromFieldsOptions; +use crate::options::{DateAddOptions, DateDifferenceOptions}; +use crate::types::{DateFields, YearInfo}; +use crate::{types, AsCalendar, Calendar, Date, Ref}; use crate::preferences::{CalendarAlgorithm, HijriCalendarAlgorithm}; use icu_locale_core::preferences::define_preferences; -use icu_locale_core::subtags::region; use icu_provider::prelude::*; use core::fmt; @@ -44,7 +40,7 @@ define_preferences!( /// /// There are many ways of constructing an AnyCalendar'd date: /// ``` -/// use icu::calendar::{AnyCalendar, AnyCalendarKind, Date, cal::Japanese, types::MonthCode}; +/// use icu::calendar::{AnyCalendar, AnyCalendarKind, Date, cal::{Japanese, Gregorian}, types::MonthCode}; /// use icu::locale::locale; /// use tinystr::tinystr; /// # use std::rc::Rc; @@ -52,26 +48,26 @@ define_preferences!( /// let locale = locale!("en-u-ca-japanese"); // English with the Japanese calendar /// /// let calendar = AnyCalendar::new(AnyCalendarKind::new(locale.into())); -/// let calendar = Rc::new(calendar); // Avoid cloning it each time -/// // If everything is a local reference, you may use icu::calendar::Ref instead. /// -/// // construct from era code, year, month code, day, and a calendar -/// // This is March 28, 15 Heisei -/// let manual_date = Date::try_new_from_codes(Some("heisei"), 15, MonthCode(tinystr!(4, "M03")), 28, calendar.clone()) -/// .expect("Failed to construct Date manually"); -/// -/// -/// // construct another date by converting from ISO -/// let iso_date = Date::try_new_iso(2020, 9, 1) -/// .expect("Failed to construct ISO Date."); -/// let iso_converted = iso_date.to_calendar(calendar); +/// // This is a Date +/// let any_japanese_date = Date::try_new_gregorian(2020, 9, 1) +/// .expect("Failed to construct Gregorian Date.") +/// .to_calendar(calendar) +/// .to_any(); /// /// // Construct a date in the appropriate typed calendar and convert /// let japanese_calendar = Japanese::new(); -/// let japanese_date = Date::try_new_japanese_with_calendar("heisei", 15, 3, 28, +/// let japanese_date = Date::try_new_japanese_with_calendar("reiwa", 2, 9, 1, /// japanese_calendar).unwrap(); -/// // This is a Date -/// let any_japanese_date = japanese_date.to_any(); +/// assert_eq!(japanese_date.to_any(), any_japanese_date); +/// +/// // this is also Date, but it uses a different calendar +/// let any_gregorian_date = any_japanese_date.to_calendar(Gregorian).to_any(); +/// +/// // Date does not have a total order +/// assert!(any_gregorian_date <= any_gregorian_date); +/// assert!(any_japanese_date <= any_japanese_date); +/// assert!(!(any_gregorian_date <= any_japanese_date) && !(any_japanese_date <= any_gregorian_date)); /// ``` #[derive(Debug, Clone)] #[non_exhaustive] @@ -79,11 +75,11 @@ pub enum AnyCalendar { /// A [`Buddhist`] calendar Buddhist(Buddhist), /// A [`Chinese`] calendar - Chinese(Chinese), + Chinese(ChineseTraditional), /// A [`Coptic`] calendar Coptic(Coptic), /// A [`Dangi`] calendar - Dangi(Dangi), + Dangi(KoreanTraditional), /// An [`Ethiopian`] calendar Ethiopian(Ethiopian), /// A [`Gregorian`] calendar @@ -93,11 +89,11 @@ pub enum AnyCalendar { /// An [`Indian`] calendar Indian(Indian), /// A [`HijriTabular`] calendar - HijriTabular(HijriTabular), + HijriTabular(Hijri), /// A [`HijriSimulated`] calendar - HijriSimulated(HijriSimulated), + HijriSimulated(Hijri), /// A [`HijriUmmAlQura`] calendar - HijriUmmAlQura(HijriUmmAlQura), + HijriUmmAlQura(Hijri), /// An [`Iso`] calendar Iso(Iso), /// A [`Japanese`] calendar @@ -118,11 +114,11 @@ pub enum AnyDateInner { /// A date for a [`Buddhist`] calendar Buddhist(::DateInner), /// A date for a [`Chinese`] calendar - Chinese(::DateInner), + Chinese(::DateInner), /// A date for a [`Coptic`] calendar Coptic(::DateInner), /// A date for a [`Dangi`] calendar - Dangi(::DateInner), + Dangi(::DateInner), /// A date for an [`Ethiopian`] calendar Ethiopian(::DateInner), /// A date for a [`Gregorian`] calendar @@ -133,14 +129,13 @@ pub enum AnyDateInner { Indian(::DateInner), /// A date for a [`HijriTabular`] calendar HijriTabular( - ::DateInner, - HijriTabularLeapYears, - HijriTabularEpoch, + as Calendar>::DateInner, + hijri::TabularAlgorithm, ), /// A date for a [`HijriSimulated`] calendar - HijriSimulated(::DateInner), + HijriSimulated( as Calendar>::DateInner), /// A date for a [`HijriUmmAlQura`] calendar - HijriUmmAlQura(::DateInner), + HijriUmmAlQura( as Calendar>::DateInner), /// A date for an [`Iso`] calendar Iso(::DateInner), /// A date for a [`Japanese`] calendar @@ -153,6 +148,32 @@ pub enum AnyDateInner { Roc(::DateInner), } +impl PartialOrd for AnyDateInner { + #[rustfmt::skip] + fn partial_cmp(&self, other: &Self) -> Option { + use AnyDateInner::*; + match (self, other) { + (Buddhist(d1), Buddhist(d2)) => d1.partial_cmp(d2), + (Chinese(d1), Chinese(d2)) => d1.partial_cmp(d2), + (Coptic(d1), Coptic(d2)) => d1.partial_cmp(d2), + (Dangi(d1), Dangi(d2)) => d1.partial_cmp(d2), + (Ethiopian(d1), Ethiopian(d2)) => d1.partial_cmp(d2), + (Gregorian(d1), Gregorian(d2)) => d1.partial_cmp(d2), + (Hebrew(d1), Hebrew(d2)) => d1.partial_cmp(d2), + (Indian(d1), Indian(d2)) => d1.partial_cmp(d2), + (&HijriTabular(ref d1, s1), &HijriTabular(ref d2, s2)) if s1 == s2 => d1.partial_cmp(d2), + (HijriSimulated(d1), HijriSimulated(d2)) => d1.partial_cmp(d2), + (HijriUmmAlQura(d1), HijriUmmAlQura(d2)) => d1.partial_cmp(d2), + (Iso(d1), Iso(d2)) => d1.partial_cmp(d2), + (Japanese(d1), Japanese(d2)) => d1.partial_cmp(d2), + (JapaneseExtended(d1), JapaneseExtended(d2)) => d1.partial_cmp(d2), + (Persian(d1), Persian(d2)) => d1.partial_cmp(d2), + (Roc(d1), Roc(d2)) => d1.partial_cmp(d2), + _ => None, + } + } +} + macro_rules! match_cal_and_date { (match ($cal:ident, $date:ident): ($cal_matched:ident, $date_matched:ident) => $e:expr) => { match ($cal, $date) { @@ -166,8 +187,8 @@ macro_rules! match_cal_and_date { (&Self::Indian(ref $cal_matched), &AnyDateInner::Indian(ref $date_matched)) => $e, ( &Self::HijriTabular(ref $cal_matched), - &AnyDateInner::HijriTabular(ref $date_matched, leap_years, epoch), - ) if $cal_matched.epoch == epoch && $cal_matched.leap_years == leap_years => $e, + &AnyDateInner::HijriTabular(ref $date_matched, sighting), + ) if $cal_matched.0 == sighting => $e, ( &Self::HijriSimulated(ref $cal_matched), &AnyDateInner::HijriSimulated(ref $date_matched), @@ -184,11 +205,8 @@ macro_rules! match_cal_and_date { ) => $e, (&Self::Persian(ref $cal_matched), &AnyDateInner::Persian(ref $date_matched)) => $e, (&Self::Roc(ref $cal_matched), &AnyDateInner::Roc(ref $date_matched)) => $e, - _ => panic!( - "Found AnyCalendar with mixed calendar type {:?} and date type {:?}!", - $cal.kind().debug_name(), - $date.kind().debug_name() - ), + // This is only reached from misuse of from_raw, a semi-internal api + _ => panic!("AnyCalendar with mismatched date type"), } }; } @@ -205,9 +223,7 @@ macro_rules! match_cal { &Self::Hebrew(ref $cal_matched) => AnyDateInner::Hebrew($e), &Self::Indian(ref $cal_matched) => AnyDateInner::Indian($e), &Self::HijriSimulated(ref $cal_matched) => AnyDateInner::HijriSimulated($e), - &Self::HijriTabular(ref $cal_matched) => { - AnyDateInner::HijriTabular($e, $cal_matched.leap_years, $cal_matched.epoch) - } + &Self::HijriTabular(ref $cal_matched) => AnyDateInner::HijriTabular($e, $cal_matched.0), &Self::HijriUmmAlQura(ref $cal_matched) => AnyDateInner::HijriUmmAlQura($e), &Self::Iso(ref $cal_matched) => AnyDateInner::Iso($e), &Self::Japanese(ref $cal_matched) => AnyDateInner::Japanese($e), @@ -218,10 +234,45 @@ macro_rules! match_cal { }; } +/// Error returned when comparing two [`Date`]s with [`AnyCalendar`]. +#[derive(Clone, Copy, PartialEq, Debug)] +#[non_exhaustive] +#[doc(hidden)] // unstable, not yet graduated +pub enum AnyCalendarDifferenceError { + /// The calendars of the two dates being compared are not equal. + /// + /// To compare dates in different calendars, convert them to the same calendar first. + /// + /// # Examples + /// + /// ``` + /// use icu::calendar::cal::AnyCalendarDifferenceError; + /// use icu::calendar::Date; + /// + /// let d1 = Date::try_new_gregorian(2000, 1, 1).unwrap().to_any(); + /// let d2 = Date::try_new_persian(1562, 1, 1).unwrap().to_any(); + /// + /// assert_eq!( + /// d1.try_until_with_options(&d2, Default::default()) + /// .unwrap_err(), + /// AnyCalendarDifferenceError::MismatchedCalendars, + /// ); + /// + /// // To compare the dates, convert them to the same calendar, + /// // such as ISO. + /// + /// d1.to_iso() + /// .try_until_with_options(&d2.to_iso(), Default::default()) + /// .unwrap(); + /// ``` + MismatchedCalendars, +} + impl crate::cal::scaffold::UnstableSealed for AnyCalendar {} impl Calendar for AnyCalendar { type DateInner = AnyDateInner; type Year = YearInfo; + type DifferenceError = AnyCalendarDifferenceError; fn from_codes( &self, @@ -233,10 +284,44 @@ impl Calendar for AnyCalendar { Ok(match_cal!(match self: (c) => c.from_codes(era, year, month_code, day)?)) } + #[cfg(feature = "unstable")] + fn from_fields( + &self, + fields: DateFields, + options: DateFromFieldsOptions, + ) -> Result { + Ok(match_cal!(match self: (c) => c.from_fields(fields, options)?)) + } + + fn has_cheap_iso_conversion(&self) -> bool { + match self { + Self::Buddhist(ref c) => c.has_cheap_iso_conversion(), + Self::Chinese(ref c) => c.has_cheap_iso_conversion(), + Self::Coptic(ref c) => c.has_cheap_iso_conversion(), + Self::Dangi(ref c) => c.has_cheap_iso_conversion(), + Self::Ethiopian(ref c) => c.has_cheap_iso_conversion(), + Self::Gregorian(ref c) => c.has_cheap_iso_conversion(), + Self::Hebrew(ref c) => c.has_cheap_iso_conversion(), + Self::Indian(ref c) => c.has_cheap_iso_conversion(), + Self::HijriSimulated(ref c) => c.has_cheap_iso_conversion(), + Self::HijriTabular(ref c) => c.has_cheap_iso_conversion(), + Self::HijriUmmAlQura(ref c) => c.has_cheap_iso_conversion(), + Self::Iso(ref c) => c.has_cheap_iso_conversion(), + Self::Japanese(ref c) => c.has_cheap_iso_conversion(), + Self::JapaneseExtended(ref c) => c.has_cheap_iso_conversion(), + Self::Persian(ref c) => c.has_cheap_iso_conversion(), + Self::Roc(ref c) => c.has_cheap_iso_conversion(), + } + } + fn from_iso(&self, iso: IsoDateInner) -> AnyDateInner { match_cal!(match self: (c) => c.from_iso(iso)) } + fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { + match_cal_and_date!(match (self, date): (c, d) => c.to_iso(d)) + } + fn from_rata_die(&self, rd: calendrical_calculations::rata_die::RataDie) -> Self::DateInner { match_cal!(match self: (c) => c.from_rata_die(rd)) } @@ -245,10 +330,6 @@ impl Calendar for AnyCalendar { match_cal_and_date!(match (self, date): (c, d) => c.to_rata_die(d)) } - fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { - match_cal_and_date!(match (self, date): (c, d) => c.to_iso(d)) - } - fn months_in_year(&self, date: &Self::DateInner) -> u8 { match_cal_and_date!(match (self, date): (c, d) => c.months_in_year(d)) } @@ -261,222 +342,141 @@ impl Calendar for AnyCalendar { match_cal_and_date!(match (self, date): (c, d) => c.days_in_month(d)) } - fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) { - match (self, date) { + #[cfg(feature = "unstable")] + fn add( + &self, + date: &Self::DateInner, + duration: types::DateDuration, + options: DateAddOptions, + ) -> Result { + let mut date = *date; + match (self, &mut date) { (Self::Buddhist(c), AnyDateInner::Buddhist(ref mut d)) => { - c.offset_date(d, offset.cast_unit()) + *d = c.add(d, duration, options)? } (Self::Chinese(c), AnyDateInner::Chinese(ref mut d)) => { - c.offset_date(d, offset.cast_unit()) + *d = c.add(d, duration, options)? } (Self::Coptic(c), AnyDateInner::Coptic(ref mut d)) => { - c.offset_date(d, offset.cast_unit()) - } - (Self::Dangi(c), AnyDateInner::Dangi(ref mut d)) => { - c.offset_date(d, offset.cast_unit()) + *d = c.add(d, duration, options)? } + (Self::Dangi(c), AnyDateInner::Dangi(ref mut d)) => *d = c.add(d, duration, options)?, (Self::Ethiopian(c), AnyDateInner::Ethiopian(ref mut d)) => { - c.offset_date(d, offset.cast_unit()) + *d = c.add(d, duration, options)? } (Self::Gregorian(c), AnyDateInner::Gregorian(ref mut d)) => { - c.offset_date(d, offset.cast_unit()) + *d = c.add(d, duration, options)? } (Self::Hebrew(c), AnyDateInner::Hebrew(ref mut d)) => { - c.offset_date(d, offset.cast_unit()) + *d = c.add(d, duration, options)? } (Self::Indian(c), AnyDateInner::Indian(ref mut d)) => { - c.offset_date(d, offset.cast_unit()) + *d = c.add(d, duration, options)? } - ( - Self::HijriTabular(c), - &mut AnyDateInner::HijriTabular(ref mut d, leap_years, epoch), - ) if c.epoch == epoch && c.leap_years == leap_years => { - c.offset_date(d, offset.cast_unit()) + (Self::HijriTabular(c), AnyDateInner::HijriTabular(ref mut d, sighting)) + if c.0 == *sighting => + { + *d = c.add(d, duration, options)? } (Self::HijriSimulated(c), AnyDateInner::HijriSimulated(ref mut d)) => { - c.offset_date(d, offset.cast_unit()) + *d = c.add(d, duration, options)? } (Self::HijriUmmAlQura(c), AnyDateInner::HijriUmmAlQura(ref mut d)) => { - c.offset_date(d, offset.cast_unit()) + *d = c.add(d, duration, options)? } - (Self::Iso(c), AnyDateInner::Iso(ref mut d)) => c.offset_date(d, offset.cast_unit()), + (Self::Iso(c), AnyDateInner::Iso(ref mut d)) => *d = c.add(d, duration, options)?, (Self::Japanese(c), AnyDateInner::Japanese(ref mut d)) => { - c.offset_date(d, offset.cast_unit()) + *d = c.add(d, duration, options)? } (Self::JapaneseExtended(c), AnyDateInner::JapaneseExtended(ref mut d)) => { - c.offset_date(d, offset.cast_unit()) + *d = c.add(d, duration, options)? } (Self::Persian(c), AnyDateInner::Persian(ref mut d)) => { - c.offset_date(d, offset.cast_unit()) + *d = c.add(d, duration, options)? } - (Self::Roc(c), AnyDateInner::Roc(ref mut d)) => c.offset_date(d, offset.cast_unit()), + (Self::Roc(c), AnyDateInner::Roc(ref mut d)) => *d = c.add(d, duration, options)?, // This is only reached from misuse of from_raw, a semi-internal api - #[allow(clippy::panic)] - (_, d) => panic!( - "Found AnyCalendar with mixed calendar type {} and date type {}!", - self.kind().debug_name(), - d.kind().debug_name() - ), + #[expect(clippy::panic)] + _ => panic!("AnyCalendar with mismatched date type"), } + Ok(date) } + #[cfg(feature = "unstable")] fn until( &self, date1: &Self::DateInner, date2: &Self::DateInner, - calendar2: &Self, - largest_unit: DateDurationUnit, - smallest_unit: DateDurationUnit, - ) -> DateDuration { - match (self, calendar2, date1, date2) { - ( - Self::Buddhist(c1), - Self::Buddhist(c2), - AnyDateInner::Buddhist(d1), - AnyDateInner::Buddhist(d2), - ) => c1 - .until(d1, d2, c2, largest_unit, smallest_unit) - .cast_unit(), - ( - Self::Chinese(c1), - Self::Chinese(c2), - AnyDateInner::Chinese(d1), - AnyDateInner::Chinese(d2), - ) => c1 - .until(d1, d2, c2, largest_unit, smallest_unit) - .cast_unit(), - ( - Self::Coptic(c1), - Self::Coptic(c2), - AnyDateInner::Coptic(d1), - AnyDateInner::Coptic(d2), - ) => c1 - .until(d1, d2, c2, largest_unit, smallest_unit) - .cast_unit(), - ( - Self::Dangi(c1), - Self::Dangi(c2), - AnyDateInner::Dangi(d1), - AnyDateInner::Dangi(d2), - ) => c1 - .until(d1, d2, c2, largest_unit, smallest_unit) - .cast_unit(), - ( - Self::Ethiopian(c1), - Self::Ethiopian(c2), - AnyDateInner::Ethiopian(d1), - AnyDateInner::Ethiopian(d2), - ) => c1 - .until(d1, d2, c2, largest_unit, smallest_unit) - .cast_unit(), - ( - Self::Gregorian(c1), - Self::Gregorian(c2), - AnyDateInner::Gregorian(d1), - AnyDateInner::Gregorian(d2), - ) => c1 - .until(d1, d2, c2, largest_unit, smallest_unit) - .cast_unit(), - ( - Self::Hebrew(c1), - Self::Hebrew(c2), - AnyDateInner::Hebrew(d1), - AnyDateInner::Hebrew(d2), - ) => c1 - .until(d1, d2, c2, largest_unit, smallest_unit) - .cast_unit(), - ( - Self::Indian(c1), - Self::Indian(c2), - AnyDateInner::Indian(d1), - AnyDateInner::Indian(d2), - ) => c1 - .until(d1, d2, c2, largest_unit, smallest_unit) - .cast_unit(), + options: DateDifferenceOptions, + ) -> Result { + let Ok(r) = match (self, date1, date2) { + (Self::Buddhist(c1), AnyDateInner::Buddhist(d1), AnyDateInner::Buddhist(d2)) => { + c1.until(d1, d2, options) + } + (Self::Chinese(c1), AnyDateInner::Chinese(d1), AnyDateInner::Chinese(d2)) => { + c1.until(d1, d2, options) + } + (Self::Coptic(c1), AnyDateInner::Coptic(d1), AnyDateInner::Coptic(d2)) => { + c1.until(d1, d2, options) + } + (Self::Dangi(c1), AnyDateInner::Dangi(d1), AnyDateInner::Dangi(d2)) => { + c1.until(d1, d2, options) + } + (Self::Ethiopian(c1), AnyDateInner::Ethiopian(d1), AnyDateInner::Ethiopian(d2)) => { + c1.until(d1, d2, options) + } + (Self::Gregorian(c1), AnyDateInner::Gregorian(d1), AnyDateInner::Gregorian(d2)) => { + c1.until(d1, d2, options) + } + (Self::Hebrew(c1), AnyDateInner::Hebrew(d1), AnyDateInner::Hebrew(d2)) => { + c1.until(d1, d2, options) + } + (Self::Indian(c1), AnyDateInner::Indian(d1), AnyDateInner::Indian(d2)) => { + c1.until(d1, d2, options) + } ( Self::HijriTabular(c1), - Self::HijriTabular(c2), - &AnyDateInner::HijriTabular(ref d1, l1, e1), - &AnyDateInner::HijriTabular(ref d2, l2, e2), - ) if c1.epoch == c2.epoch - && c2.epoch == e1 - && e1 == e2 - && c1.leap_years == c2.leap_years - && c2.leap_years == l1 - && l1 == l2 => - { - c1.until(d1, d2, c2, largest_unit, smallest_unit) - .cast_unit() - } + &AnyDateInner::HijriTabular(ref d1, s1), + &AnyDateInner::HijriTabular(ref d2, s2), + ) if c1.0 == s1 && s1 == s2 => c1.until(d1, d2, options), ( Self::HijriSimulated(c1), - Self::HijriSimulated(c2), AnyDateInner::HijriSimulated(d1), AnyDateInner::HijriSimulated(d2), - ) => c1 - .until(d1, d2, c2, largest_unit, smallest_unit) - .cast_unit(), + ) => c1.until(d1, d2, options), ( Self::HijriUmmAlQura(c1), - Self::HijriUmmAlQura(c2), AnyDateInner::HijriUmmAlQura(d1), AnyDateInner::HijriUmmAlQura(d2), - ) => c1 - .until(d1, d2, c2, largest_unit, smallest_unit) - .cast_unit(), - (Self::Iso(c1), Self::Iso(c2), AnyDateInner::Iso(d1), AnyDateInner::Iso(d2)) => c1 - .until(d1, d2, c2, largest_unit, smallest_unit) - .cast_unit(), - ( - Self::Japanese(c1), - Self::Japanese(c2), - AnyDateInner::Japanese(d1), - AnyDateInner::Japanese(d2), - ) => c1 - .until(d1, d2, c2, largest_unit, smallest_unit) - .cast_unit(), + ) => c1.until(d1, d2, options), + (Self::Iso(c1), AnyDateInner::Iso(d1), AnyDateInner::Iso(d2)) => { + c1.until(d1, d2, options) + } + (Self::Japanese(c1), AnyDateInner::Japanese(d1), AnyDateInner::Japanese(d2)) => { + c1.until(d1, d2, options) + } ( Self::JapaneseExtended(c1), - Self::JapaneseExtended(c2), AnyDateInner::JapaneseExtended(d1), AnyDateInner::JapaneseExtended(d2), - ) => c1 - .until(d1, d2, c2, largest_unit, smallest_unit) - .cast_unit(), - ( - Self::Persian(c1), - Self::Persian(c2), - AnyDateInner::Persian(d1), - AnyDateInner::Persian(d2), - ) => c1 - .until(d1, d2, c2, largest_unit, smallest_unit) - .cast_unit(), - (Self::Roc(c1), Self::Roc(c2), AnyDateInner::Roc(d1), AnyDateInner::Roc(d2)) => c1 - .until(d1, d2, c2, largest_unit, smallest_unit) - .cast_unit(), + ) => c1.until(d1, d2, options), + (Self::Persian(c1), AnyDateInner::Persian(d1), AnyDateInner::Persian(d2)) => { + c1.until(d1, d2, options) + } + (Self::Roc(c1), AnyDateInner::Roc(d1), AnyDateInner::Roc(d2)) => { + c1.until(d1, d2, options) + } _ => { - // attempt to convert - let iso = calendar2.to_iso(date2); - - match_cal_and_date!(match (self, date1): - (c1, d1) => { - let d2 = c1.from_iso(iso); - let until = c1.until(d1, &d2, c1, largest_unit, smallest_unit); - until.cast_unit::() - } - ) + return Err(AnyCalendarDifferenceError::MismatchedCalendars); } - } + }; + Ok(r) } fn year_info(&self, date: &Self::DateInner) -> types::YearInfo { match_cal_and_date!(match (self, date): (c, d) => c.year_info(d).into()) } - fn extended_year(&self, date: &Self::DateInner) -> i32 { - match_cal_and_date!(match (self, date): (c, d) => c.extended_year(d)) - } - /// The calendar-specific check if `date` is in a leap year fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { match_cal_and_date!(match (self, date): (c, d) => c.is_in_leap_year(d)) @@ -556,9 +556,9 @@ impl AnyCalendar { pub const fn new(kind: AnyCalendarKind) -> Self { match kind { AnyCalendarKind::Buddhist => AnyCalendar::Buddhist(Buddhist), - AnyCalendarKind::Chinese => AnyCalendar::Chinese(Chinese::new()), + AnyCalendarKind::Chinese => AnyCalendar::Chinese(ChineseTraditional::new()), AnyCalendarKind::Coptic => AnyCalendar::Coptic(Coptic), - AnyCalendarKind::Dangi => AnyCalendar::Dangi(Dangi::new()), + AnyCalendarKind::Dangi => AnyCalendar::Dangi(KoreanTraditional::new()), AnyCalendarKind::Ethiopian => AnyCalendar::Ethiopian(Ethiopian::new_with_era_style( EthiopianEraStyle::AmeteMihret, )), @@ -569,21 +569,23 @@ impl AnyCalendar { AnyCalendarKind::Hebrew => AnyCalendar::Hebrew(Hebrew), AnyCalendarKind::Indian => AnyCalendar::Indian(Indian), AnyCalendarKind::HijriTabularTypeIIFriday => { - AnyCalendar::HijriTabular(HijriTabular::new( - crate::cal::hijri::HijriTabularLeapYears::TypeII, - HijriTabularEpoch::Friday, + AnyCalendar::HijriTabular(Hijri::new_tabular( + hijri::TabularAlgorithmLeapYears::TypeII, + hijri::TabularAlgorithmEpoch::Friday, )) } AnyCalendarKind::HijriSimulatedMecca => { - AnyCalendar::HijriSimulated(HijriSimulated::new_mecca()) + AnyCalendar::HijriSimulated(Hijri::new_simulated_mecca()) } AnyCalendarKind::HijriTabularTypeIIThursday => { - AnyCalendar::HijriTabular(HijriTabular::new( - crate::cal::hijri::HijriTabularLeapYears::TypeII, - HijriTabularEpoch::Thursday, + AnyCalendar::HijriTabular(Hijri::new_tabular( + hijri::TabularAlgorithmLeapYears::TypeII, + hijri::TabularAlgorithmEpoch::Thursday, )) } - AnyCalendarKind::HijriUmmAlQura => AnyCalendar::HijriUmmAlQura(HijriUmmAlQura::new()), + AnyCalendarKind::HijriUmmAlQura => { + AnyCalendar::HijriUmmAlQura(Hijri::new_umm_al_qura()) + } AnyCalendarKind::Iso => AnyCalendar::Iso(Iso), AnyCalendarKind::Japanese => AnyCalendar::Japanese(Japanese::new()), AnyCalendarKind::JapaneseExtended => { @@ -605,13 +607,9 @@ impl AnyCalendar { { Ok(match kind { AnyCalendarKind::Buddhist => AnyCalendar::Buddhist(Buddhist), - AnyCalendarKind::Chinese => { - AnyCalendar::Chinese(Chinese::try_new_with_buffer_provider(provider)?) - } + AnyCalendarKind::Chinese => AnyCalendar::Chinese(ChineseTraditional::new()), AnyCalendarKind::Coptic => AnyCalendar::Coptic(Coptic), - AnyCalendarKind::Dangi => { - AnyCalendar::Dangi(Dangi::try_new_with_buffer_provider(provider)?) - } + AnyCalendarKind::Dangi => AnyCalendar::Dangi(KoreanTraditional::new()), AnyCalendarKind::Ethiopian => AnyCalendar::Ethiopian(Ethiopian::new_with_era_style( EthiopianEraStyle::AmeteMihret, )), @@ -622,21 +620,23 @@ impl AnyCalendar { AnyCalendarKind::Hebrew => AnyCalendar::Hebrew(Hebrew), AnyCalendarKind::Indian => AnyCalendar::Indian(Indian), AnyCalendarKind::HijriTabularTypeIIFriday => { - AnyCalendar::HijriTabular(HijriTabular::new( - crate::cal::hijri::HijriTabularLeapYears::TypeII, - HijriTabularEpoch::Friday, + AnyCalendar::HijriTabular(Hijri::new_tabular( + hijri::TabularAlgorithmLeapYears::TypeII, + hijri::TabularAlgorithmEpoch::Friday, )) } - AnyCalendarKind::HijriSimulatedMecca => AnyCalendar::HijriSimulated( - HijriSimulated::try_new_mecca_with_buffer_provider(provider)?, - ), + AnyCalendarKind::HijriSimulatedMecca => { + AnyCalendar::HijriSimulated(Hijri::new_simulated_mecca()) + } AnyCalendarKind::HijriTabularTypeIIThursday => { - AnyCalendar::HijriTabular(HijriTabular::new( - crate::cal::hijri::HijriTabularLeapYears::TypeII, - HijriTabularEpoch::Thursday, + AnyCalendar::HijriTabular(Hijri::new_tabular( + hijri::TabularAlgorithmLeapYears::TypeII, + hijri::TabularAlgorithmEpoch::Thursday, )) } - AnyCalendarKind::HijriUmmAlQura => AnyCalendar::HijriUmmAlQura(HijriUmmAlQura::new()), + AnyCalendarKind::HijriUmmAlQura => { + AnyCalendar::HijriUmmAlQura(Hijri::new_umm_al_qura()) + } AnyCalendarKind::Iso => AnyCalendar::Iso(Iso), AnyCalendarKind::Japanese => { AnyCalendar::Japanese(Japanese::try_new_with_buffer_provider(provider)?) @@ -654,16 +654,13 @@ impl AnyCalendar { where P: DataProvider + DataProvider - + DataProvider - + DataProvider - + DataProvider + ?Sized, { Ok(match kind { AnyCalendarKind::Buddhist => AnyCalendar::Buddhist(Buddhist), - AnyCalendarKind::Chinese => AnyCalendar::Chinese(Chinese::try_new_unstable(provider)?), + AnyCalendarKind::Chinese => AnyCalendar::Chinese(ChineseTraditional::new()), AnyCalendarKind::Coptic => AnyCalendar::Coptic(Coptic), - AnyCalendarKind::Dangi => AnyCalendar::Dangi(Dangi::try_new_unstable(provider)?), + AnyCalendarKind::Dangi => AnyCalendar::Dangi(KoreanTraditional::new()), AnyCalendarKind::Ethiopian => AnyCalendar::Ethiopian(Ethiopian::new_with_era_style( EthiopianEraStyle::AmeteMihret, )), @@ -674,21 +671,23 @@ impl AnyCalendar { AnyCalendarKind::Hebrew => AnyCalendar::Hebrew(Hebrew), AnyCalendarKind::Indian => AnyCalendar::Indian(Indian), AnyCalendarKind::HijriTabularTypeIIFriday => { - AnyCalendar::HijriTabular(HijriTabular::new( - crate::cal::hijri::HijriTabularLeapYears::TypeII, - HijriTabularEpoch::Friday, + AnyCalendar::HijriTabular(Hijri::new_tabular( + hijri::TabularAlgorithmLeapYears::TypeII, + hijri::TabularAlgorithmEpoch::Friday, )) } AnyCalendarKind::HijriSimulatedMecca => { - AnyCalendar::HijriSimulated(HijriSimulated::try_new_mecca_unstable(provider)?) + AnyCalendar::HijriSimulated(Hijri::new_simulated_mecca()) } AnyCalendarKind::HijriTabularTypeIIThursday => { - AnyCalendar::HijriTabular(HijriTabular::new( - crate::cal::hijri::HijriTabularLeapYears::TypeII, - HijriTabularEpoch::Thursday, + AnyCalendar::HijriTabular(Hijri::new_tabular( + hijri::TabularAlgorithmLeapYears::TypeII, + hijri::TabularAlgorithmEpoch::Thursday, )) } - AnyCalendarKind::HijriUmmAlQura => AnyCalendar::HijriUmmAlQura(HijriUmmAlQura::new()), + AnyCalendarKind::HijriUmmAlQura => { + AnyCalendar::HijriUmmAlQura(Hijri::new_umm_al_qura()) + } AnyCalendarKind::Iso => AnyCalendar::Iso(Iso), AnyCalendarKind::Japanese => { AnyCalendar::Japanese(Japanese::try_new_unstable(provider)?) @@ -738,127 +737,107 @@ impl> Date { } } -impl AnyDateInner { - fn kind(&self) -> AnyCalendarKind { - match *self { - AnyDateInner::Buddhist(_) => AnyCalendarKind::Buddhist, - AnyDateInner::Chinese(_) => AnyCalendarKind::Chinese, - AnyDateInner::Coptic(_) => AnyCalendarKind::Coptic, - AnyDateInner::Dangi(_) => AnyCalendarKind::Dangi, - AnyDateInner::Ethiopian(_) => AnyCalendarKind::Ethiopian, - AnyDateInner::Gregorian(_) => AnyCalendarKind::Gregorian, - AnyDateInner::Hebrew(_) => AnyCalendarKind::Hebrew, - AnyDateInner::Indian(_) => AnyCalendarKind::Indian, - AnyDateInner::HijriTabular( - _, - HijriTabularLeapYears::TypeII, - HijriTabularEpoch::Friday, - ) => AnyCalendarKind::HijriTabularTypeIIFriday, - AnyDateInner::HijriSimulated(_) => AnyCalendarKind::HijriSimulatedMecca, - AnyDateInner::HijriTabular( - _, - HijriTabularLeapYears::TypeII, - HijriTabularEpoch::Thursday, - ) => AnyCalendarKind::HijriTabularTypeIIThursday, - AnyDateInner::HijriUmmAlQura(_) => AnyCalendarKind::HijriUmmAlQura, - AnyDateInner::Iso(_) => AnyCalendarKind::Iso, - AnyDateInner::Japanese(_) => AnyCalendarKind::Japanese, - AnyDateInner::JapaneseExtended(_) => AnyCalendarKind::JapaneseExtended, - AnyDateInner::Persian(_) => AnyCalendarKind::Persian, - AnyDateInner::Roc(_) => AnyCalendarKind::Roc, - } - } -} - /// Convenient type for selecting the kind of AnyCalendar to construct #[non_exhaustive] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)] pub enum AnyCalendarKind { /// The kind of a [`Buddhist`] calendar + /// + /// This corresponds to the `"buddhist"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). Buddhist, /// The kind of a [`Chinese`] calendar + /// + /// This corresponds to the `"chinese"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). Chinese, /// The kind of a [`Coptic`] calendar + /// + /// This corresponds to the `"coptic"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). Coptic, /// The kind of a [`Dangi`] calendar + /// + /// This corresponds to the `"dangi"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). Dangi, /// The kind of an [`Ethiopian`] calendar, with Amete Mihret era + /// + /// This corresponds to the `"ethiopic"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). Ethiopian, /// The kind of an [`Ethiopian`] calendar, with Amete Alem era + /// + /// This corresponds to the `"ethioaa"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). EthiopianAmeteAlem, /// The kind of a [`Gregorian`] calendar + /// + /// This corresponds to the `"gregory"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). Gregorian, /// The kind of a [`Hebrew`] calendar + /// + /// This corresponds to the `"hebrew"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). Hebrew, /// The kind of a [`Indian`] calendar + /// + /// This corresponds to the `"indian"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). Indian, /// The kind of an [`HijriTabular`] calendar using [`HijriTabularLeapYears::TypeII`] and [`HijriTabularEpoch::Friday`] + /// + /// This corresponds to the `"islamic-civil"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). HijriTabularTypeIIFriday, /// The kind of an [`HijriSimulated`], Mecca calendar + /// + /// This corresponds to the `"islamic-rgsa"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). HijriSimulatedMecca, /// The kind of an [`HijriTabular`] calendar using [`HijriTabularLeapYears::TypeII`] and [`HijriTabularEpoch::Thursday`] + /// + /// This corresponds to the `"islamic-tbla"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). HijriTabularTypeIIThursday, /// The kind of an [`HijriUmmAlQura`] calendar + /// + /// This corresponds to the `"islamic-umalqura"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). HijriUmmAlQura, /// The kind of an [`Iso`] calendar + /// + /// This corresponds to the `"iso8601"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). Iso, /// The kind of a [`Japanese`] calendar + /// + /// This corresponds to the `"japanese"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). Japanese, /// The kind of a [`JapaneseExtended`] calendar + /// + /// This corresponds to the `"japanext"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). JapaneseExtended, /// The kind of a [`Persian`] calendar + /// + /// This corresponds to the `"persian"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). Persian, /// The kind of a [`Roc`] calendar + /// + /// This corresponds to the `"roc"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). Roc, } impl AnyCalendarKind { /// Selects the [`AnyCalendarKind`] appropriate for the given [`CalendarPreferences`]. pub fn new(prefs: CalendarPreferences) -> Self { - let algo = prefs.calendar_algorithm; - let region = prefs.locale_preferences.region(); - if let Some(kind) = algo.and_then(|a| a.try_into().ok()) { + if let Some(kind) = prefs.calendar_algorithm.and_then(|a| a.try_into().ok()) { return kind; } - if region == Some(region!("TH")) { - AnyCalendarKind::Buddhist - } else if region == Some(region!("AF")) || region == Some(region!("IR")) { - AnyCalendarKind::Persian - } else if region == Some(region!("SA")) && algo == Some(CalendarAlgorithm::Hijri(None)) { - AnyCalendarKind::HijriSimulatedMecca - } else { - AnyCalendarKind::Gregorian - } - } - fn debug_name(self) -> &'static str { - match self { - AnyCalendarKind::Buddhist => Buddhist.debug_name(), - AnyCalendarKind::Chinese => Chinese::DEBUG_NAME, - AnyCalendarKind::Coptic => Coptic.debug_name(), - AnyCalendarKind::Dangi => Dangi::DEBUG_NAME, - AnyCalendarKind::Ethiopian => Ethiopian(false).debug_name(), - AnyCalendarKind::EthiopianAmeteAlem => Ethiopian(true).debug_name(), - AnyCalendarKind::Gregorian => Gregorian.debug_name(), - AnyCalendarKind::Hebrew => Hebrew.debug_name(), - AnyCalendarKind::Indian => Indian.debug_name(), - AnyCalendarKind::HijriTabularTypeIIFriday => HijriTabular::new( - crate::cal::hijri::HijriTabularLeapYears::TypeII, - HijriTabularEpoch::Friday, - ) - .debug_name(), - AnyCalendarKind::HijriSimulatedMecca => HijriSimulated::DEBUG_NAME, - AnyCalendarKind::HijriTabularTypeIIThursday => HijriTabular::new( - crate::cal::hijri::HijriTabularLeapYears::TypeII, - HijriTabularEpoch::Thursday, - ) - .debug_name(), - AnyCalendarKind::HijriUmmAlQura => HijriUmmAlQura::DEBUG_NAME, - AnyCalendarKind::Iso => Iso.debug_name(), - AnyCalendarKind::Japanese => Japanese::DEBUG_NAME, - AnyCalendarKind::JapaneseExtended => JapaneseExtended::DEBUG_NAME, - AnyCalendarKind::Persian => Persian.debug_name(), - AnyCalendarKind::Roc => Roc.debug_name(), + // This is tested to be consistent with CLDR in icu_provider_source::calendar::test_calendar_resolution + match ( + prefs.calendar_algorithm, + prefs + .locale_preferences + .region() + .as_ref() + .map(|r| r.as_str()), + ) { + (Some(CalendarAlgorithm::Hijri(None)), Some("AE" | "BH" | "KW" | "QA" | "SA")) => { + AnyCalendarKind::HijriUmmAlQura + } + (Some(CalendarAlgorithm::Hijri(None)), _) => AnyCalendarKind::HijriTabularTypeIIFriday, + (_, Some("TH")) => AnyCalendarKind::Buddhist, + (_, Some("AF" | "IR")) => AnyCalendarKind::Persian, + _ => AnyCalendarKind::Gregorian, } } } @@ -991,7 +970,7 @@ impl From for AnyCalendar { } } -impl IntoAnyCalendar for Chinese { +impl IntoAnyCalendar for ChineseTraditional { #[inline] fn to_any(self) -> AnyCalendar { AnyCalendar::Chinese(self) @@ -1022,8 +1001,8 @@ impl IntoAnyCalendar for Chinese { } } -impl From for AnyCalendar { - fn from(value: Chinese) -> AnyCalendar { +impl From for AnyCalendar { + fn from(value: ChineseTraditional) -> AnyCalendar { value.to_any() } } @@ -1065,7 +1044,7 @@ impl From for AnyCalendar { } } -impl IntoAnyCalendar for Dangi { +impl IntoAnyCalendar for KoreanTraditional { #[inline] fn to_any(self) -> AnyCalendar { AnyCalendar::Dangi(self) @@ -1096,8 +1075,8 @@ impl IntoAnyCalendar for Dangi { } } -impl From for AnyCalendar { - fn from(value: Dangi) -> AnyCalendar { +impl From for AnyCalendar { + fn from(value: KoreanTraditional) -> AnyCalendar { value.to_any() } } @@ -1110,10 +1089,9 @@ impl IntoAnyCalendar for Ethiopian { } #[inline] fn kind(&self) -> AnyCalendarKind { - if self.0 { - AnyCalendarKind::EthiopianAmeteAlem - } else { - AnyCalendarKind::Ethiopian + match self.era_style() { + EthiopianEraStyle::AmeteAlem => AnyCalendarKind::EthiopianAmeteAlem, + EthiopianEraStyle::AmeteMihret => AnyCalendarKind::Ethiopian, } } #[inline] @@ -1255,20 +1233,22 @@ impl From for AnyCalendar { } } -impl IntoAnyCalendar for HijriTabular { +impl IntoAnyCalendar for Hijri { #[inline] fn to_any(self) -> AnyCalendar { AnyCalendar::HijriTabular(self) } #[inline] fn kind(&self) -> AnyCalendarKind { - match (self.leap_years, self.epoch) { - (HijriTabularLeapYears::TypeII, HijriTabularEpoch::Friday) => { - AnyCalendarKind::HijriTabularTypeIIFriday - } - (HijriTabularLeapYears::TypeII, HijriTabularEpoch::Thursday) => { - AnyCalendarKind::HijriTabularTypeIIThursday - } + match self.0 { + hijri::TabularAlgorithm { + leap_years: hijri::TabularAlgorithmLeapYears::TypeII, + epoch: hijri::TabularAlgorithmEpoch::Friday, + } => AnyCalendarKind::HijriTabularTypeIIFriday, + hijri::TabularAlgorithm { + leap_years: hijri::TabularAlgorithmLeapYears::TypeII, + epoch: hijri::TabularAlgorithmEpoch::Thursday, + } => AnyCalendarKind::HijriTabularTypeIIThursday, } } #[inline] @@ -1289,25 +1269,27 @@ impl IntoAnyCalendar for HijriTabular { } #[inline] fn date_to_any(&self, d: &Self::DateInner) -> AnyDateInner { - AnyDateInner::HijriTabular(*d, self.leap_years, self.epoch) + AnyDateInner::HijriTabular(*d, self.0) } } -impl From for AnyCalendar { - fn from(value: HijriTabular) -> AnyCalendar { +impl From> for AnyCalendar { + fn from(value: Hijri) -> AnyCalendar { value.to_any() } } -impl IntoAnyCalendar for HijriSimulated { +impl IntoAnyCalendar for Hijri { #[inline] fn to_any(self) -> AnyCalendar { AnyCalendar::HijriSimulated(self) } #[inline] fn kind(&self) -> AnyCalendarKind { - match self.location { - HijriSimulatedLocation::Mecca => AnyCalendarKind::HijriSimulatedMecca, + match self.0.location { + crate::cal::hijri_internal::SimulatedLocation::Mecca => { + AnyCalendarKind::HijriSimulatedMecca + } } } #[inline] @@ -1332,13 +1314,13 @@ impl IntoAnyCalendar for HijriSimulated { } } -impl From for AnyCalendar { - fn from(value: HijriSimulated) -> AnyCalendar { +impl From> for AnyCalendar { + fn from(value: Hijri) -> AnyCalendar { value.to_any() } } -impl IntoAnyCalendar for HijriUmmAlQura { +impl IntoAnyCalendar for Hijri { #[inline] fn to_any(self) -> AnyCalendar { AnyCalendar::HijriUmmAlQura(self) @@ -1369,8 +1351,8 @@ impl IntoAnyCalendar for HijriUmmAlQura { } } -impl From for AnyCalendar { - fn from(value: HijriUmmAlQura) -> AnyCalendar { +impl From> for AnyCalendar { + fn from(value: Hijri) -> AnyCalendar { value.to_any() } } @@ -1587,29 +1569,37 @@ mod tests { }); let roundtrip_year = date.year(); - // FIXME: these APIs should be improved - let roundtrip_year = roundtrip_year.era_year_or_related_iso(); let roundtrip_month = date.month().standard_code; let roundtrip_day = date.day_of_month().0; assert_eq!( - (year, month, day), - (roundtrip_year, roundtrip_month, roundtrip_day), + (month, day), + (roundtrip_month, roundtrip_day), "Failed to roundtrip for calendar {}", calendar.debug_name() ); if let Some((era_code, era_index)) = era { let roundtrip_era_year = date.year().era().expect("year type should be era"); + + let roundtrip_year = roundtrip_year.era_year_or_related_iso(); assert_eq!( - (era_code, era_index), + (era_code, era_index, year), ( roundtrip_era_year.era.as_str(), - roundtrip_era_year.era_index + roundtrip_era_year.era_index, + roundtrip_year ), "Failed to roundtrip era for calendar {}", calendar.debug_name() ) + } else { + assert_eq!( + year, + date.extended_year(), + "Failed to roundtrip year for calendar {}", + calendar.debug_name() + ); } let iso = date.to_iso(); @@ -1678,7 +1668,8 @@ mod tests { let roc = Ref(&roc); single_test_roundtrip(buddhist, Some(("be", Some(0))), 100, "M03", 1); - single_test_roundtrip(buddhist, None, 2000, "M03", 1); + single_test_roundtrip(buddhist, None, 100, "M03", 1); + single_test_roundtrip(buddhist, None, -100, "M03", 1); single_test_roundtrip(buddhist, Some(("be", Some(0))), -100, "M03", 1); single_test_error( buddhist, @@ -1691,6 +1682,7 @@ mod tests { single_test_roundtrip(coptic, Some(("am", Some(0))), 100, "M03", 1); single_test_roundtrip(coptic, None, 2000, "M03", 1); + single_test_roundtrip(coptic, None, -100, "M03", 1); single_test_roundtrip(coptic, Some(("am", Some(0))), -99, "M03", 1); single_test_roundtrip(coptic, Some(("am", Some(0))), 100, "M13", 1); single_test_error( @@ -1704,8 +1696,11 @@ mod tests { single_test_roundtrip(ethiopian, Some(("am", Some(1))), 100, "M03", 1); single_test_roundtrip(ethiopian, None, 2000, "M03", 1); + single_test_roundtrip(ethiopian, None, -100, "M03", 1); single_test_roundtrip(ethiopian, Some(("am", Some(1))), 2000, "M13", 1); single_test_roundtrip(ethiopian, Some(("aa", Some(0))), 5400, "M03", 1); + // Since #6910, the era range is not enforced in try_from_codes + /* single_test_error( ethiopian, Some(("am", Some(0))), @@ -1732,6 +1727,7 @@ mod tests { max: 5500, }, ); + */ single_test_error( ethiopian, Some(("am", Some(0))), @@ -1743,6 +1739,7 @@ mod tests { single_test_roundtrip(ethioaa, Some(("aa", Some(0))), 7000, "M13", 1); single_test_roundtrip(ethioaa, None, 7000, "M13", 1); + single_test_roundtrip(ethioaa, None, -100, "M13", 1); single_test_roundtrip(ethioaa, Some(("aa", Some(0))), 100, "M03", 1); single_test_error( ethiopian, @@ -1755,7 +1752,10 @@ mod tests { single_test_roundtrip(gregorian, Some(("ce", Some(1))), 100, "M03", 1); single_test_roundtrip(gregorian, None, 2000, "M03", 1); + single_test_roundtrip(gregorian, None, -100, "M03", 1); single_test_roundtrip(gregorian, Some(("bce", Some(0))), 100, "M03", 1); + // Since #6910, the era range is not enforced in try_from_codes + /* single_test_error( gregorian, Some(("ce", Some(1))), @@ -1782,7 +1782,7 @@ mod tests { max: i32::MAX, }, ); - + */ single_test_error( gregorian, Some(("bce", Some(0))), @@ -1834,7 +1834,11 @@ mod tests { single_test_roundtrip(japanese, Some(("meiji", None)), 10, "M03", 1); single_test_roundtrip(japanese, Some(("ce", None)), 1000, "M03", 1); single_test_roundtrip(japanese, None, 1000, "M03", 1); + single_test_roundtrip(japanese, None, -100, "M03", 1); + single_test_roundtrip(japanese, None, 2024, "M03", 1); single_test_roundtrip(japanese, Some(("bce", None)), 10, "M03", 1); + // Since #6910, the era range is not enforced in try_from_codes + /* single_test_error( japanese, Some(("ce", None)), @@ -1861,7 +1865,7 @@ mod tests { max: i32::MAX, }, ); - + */ single_test_error( japanese, Some(("reiwa", None)), @@ -1877,6 +1881,8 @@ mod tests { single_test_roundtrip(japanext, Some(("tenpyokampo-749", None)), 1, "M04", 20); single_test_roundtrip(japanext, Some(("ce", None)), 100, "M03", 1); single_test_roundtrip(japanext, Some(("bce", None)), 10, "M03", 1); + // Since #6910, the era range is not enforced in try_from_codes + /* single_test_error( japanext, Some(("ce", None)), @@ -1903,7 +1909,7 @@ mod tests { max: i32::MAX, }, ); - + */ single_test_error( japanext, Some(("reiwa", None)), @@ -1915,6 +1921,7 @@ mod tests { single_test_roundtrip(persian, Some(("ap", Some(0))), 477, "M03", 1); single_test_roundtrip(persian, None, 2083, "M07", 21); + single_test_roundtrip(persian, None, -100, "M07", 21); single_test_roundtrip(persian, Some(("ap", Some(0))), 1600, "M12", 20); single_test_error( persian, @@ -1927,6 +1934,7 @@ mod tests { single_test_roundtrip(hebrew, Some(("am", Some(0))), 5773, "M03", 1); single_test_roundtrip(hebrew, None, 4993, "M07", 21); + single_test_roundtrip(hebrew, None, -100, "M07", 21); single_test_roundtrip(hebrew, Some(("am", Some(0))), 5012, "M12", 20); single_test_error( hebrew, @@ -1940,9 +1948,11 @@ mod tests { single_test_roundtrip(roc, Some(("roc", Some(1))), 10, "M05", 3); single_test_roundtrip(roc, Some(("broc", Some(0))), 15, "M01", 10); single_test_roundtrip(roc, None, 100, "M10", 30); + single_test_roundtrip(roc, None, -100, "M10", 30); single_test_roundtrip(hijri_simulated, Some(("ah", Some(0))), 477, "M03", 1); single_test_roundtrip(hijri_simulated, None, 2083, "M07", 21); + single_test_roundtrip(hijri_simulated, None, -100, "M07", 21); single_test_roundtrip(hijri_simulated, Some(("ah", Some(0))), 1600, "M12", 20); single_test_error( hijri_simulated, @@ -1955,6 +1965,7 @@ mod tests { single_test_roundtrip(hijri_civil, Some(("ah", Some(0))), 477, "M03", 1); single_test_roundtrip(hijri_civil, None, 2083, "M07", 21); + single_test_roundtrip(hijri_civil, None, -100, "M07", 21); single_test_roundtrip(hijri_civil, Some(("ah", Some(0))), 1600, "M12", 20); single_test_error( hijri_civil, @@ -1967,6 +1978,7 @@ mod tests { single_test_roundtrip(hijri_umm_al_qura, Some(("ah", Some(0))), 477, "M03", 1); single_test_roundtrip(hijri_umm_al_qura, None, 2083, "M07", 21); + single_test_roundtrip(hijri_umm_al_qura, None, -100, "M07", 21); single_test_roundtrip(hijri_umm_al_qura, Some(("ah", Some(0))), 1600, "M12", 20); single_test_error( hijri_umm_al_qura, @@ -1979,6 +1991,7 @@ mod tests { single_test_roundtrip(hijri_astronomical, Some(("ah", Some(0))), 477, "M03", 1); single_test_roundtrip(hijri_astronomical, None, 2083, "M07", 21); + single_test_roundtrip(hijri_astronomical, None, -100, "M07", 21); single_test_roundtrip(hijri_astronomical, Some(("ah", Some(0))), 1600, "M12", 20); single_test_error( hijri_astronomical, diff --git a/deps/crates/vendor/icu_calendar/src/cal/abstract_gregorian.rs b/deps/crates/vendor/icu_calendar/src/cal/abstract_gregorian.rs new file mode 100644 index 00000000000000..17cd85e3f581e6 --- /dev/null +++ b/deps/crates/vendor/icu_calendar/src/cal/abstract_gregorian.rs @@ -0,0 +1,367 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use crate::cal::iso::{IsoDateInner, IsoEra}; +use crate::calendar_arithmetic::{ArithmeticDate, DateFieldsResolver}; +use crate::error::{DateError, DateFromFieldsError, EcmaReferenceYearError, UnknownEraError}; +use crate::options::DateFromFieldsOptions; +use crate::options::{DateAddOptions, DateDifferenceOptions}; +use crate::preferences::CalendarAlgorithm; +use crate::types::EraYear; +use crate::{types, Calendar, RangeError}; +use calendrical_calculations::helpers::I32CastError; +use calendrical_calculations::rata_die::RataDie; + +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub(crate) struct AbstractGregorian(pub Y); + +pub(crate) trait GregorianYears: Clone + core::fmt::Debug { + // Positive if after 0 CE + const EXTENDED_YEAR_OFFSET: i32 = 0; + + fn extended_from_era_year(&self, era: Option<&[u8]>, year: i32) + -> Result; + + fn era_year_from_extended(&self, extended_year: i32, month: u8, day: u8) -> EraYear; + + fn calendar_algorithm(&self) -> Option { + None + } + + fn debug_name(&self) -> &'static str; +} + +impl ArithmeticDate> { + pub(crate) fn new_gregorian( + year: i32, + month: u8, + day: u8, + ) -> Result { + ArithmeticDate::try_from_ymd(year + Y::EXTENDED_YEAR_OFFSET, month, day) + } +} + +pub(crate) const REFERENCE_YEAR: i32 = 1972; +#[cfg(test)] +pub(crate) const LAST_DAY_OF_REFERENCE_YEAR: RataDie = + calendrical_calculations::gregorian::day_before_year(REFERENCE_YEAR + 1); + +impl DateFieldsResolver for AbstractGregorian { + // Gregorian year + type YearInfo = i32; + + fn days_in_provided_month(year: i32, month: u8) -> u8 { + // https://www.youtube.com/watch?v=J9KijLyP-yg&t=1394s + if month == 2 { + 28 + calendrical_calculations::gregorian::is_leap_year(year) as u8 + } else { + 30 | month ^ (month >> 3) + } + } + + fn months_in_provided_year(_: i32) -> u8 { + 12 + } + + #[inline] + fn year_info_from_era( + &self, + era: &[u8], + era_year: i32, + ) -> Result { + Ok(self.0.extended_from_era_year(Some(era), era_year)? + Y::EXTENDED_YEAR_OFFSET) + } + + #[inline] + fn year_info_from_extended(&self, extended_year: i32) -> Self::YearInfo { + extended_year + Y::EXTENDED_YEAR_OFFSET + } + + #[inline] + fn reference_year_from_month_day( + &self, + _month_code: types::ValidMonthCode, + _day: u8, + ) -> Result { + Ok(REFERENCE_YEAR) + } +} + +impl crate::cal::scaffold::UnstableSealed for AbstractGregorian {} + +impl Calendar for AbstractGregorian { + type DateInner = ArithmeticDate>; + type Year = types::EraYear; + type DifferenceError = core::convert::Infallible; + + fn from_codes( + &self, + era: Option<&str>, + year: i32, + month_code: types::MonthCode, + day: u8, + ) -> Result { + ArithmeticDate::from_codes(era, year, month_code, day, self).map(ArithmeticDate::cast) + } + + #[cfg(feature = "unstable")] + fn from_fields( + &self, + fields: types::DateFields, + options: DateFromFieldsOptions, + ) -> Result { + ArithmeticDate::from_fields(fields, options, self).map(ArithmeticDate::cast) + } + + fn from_rata_die(&self, date: RataDie) -> Self::DateInner { + let iso = match calendrical_calculations::gregorian::gregorian_from_fixed(date) { + Err(I32CastError::BelowMin) => { + ArithmeticDate::>::new_unchecked(i32::MIN, 1, 1) + } + Err(I32CastError::AboveMax) => ArithmeticDate::new_unchecked(i32::MAX, 12, 31), + Ok((year, month, day)) => ArithmeticDate::new_unchecked(year, month, day), + }; + + if iso.year.checked_sub(Y::EXTENDED_YEAR_OFFSET).is_none() { + if Y::EXTENDED_YEAR_OFFSET < 0 { + ArithmeticDate::new_unchecked(i32::MIN - Y::EXTENDED_YEAR_OFFSET, 1, 1) + } else { + ArithmeticDate::new_unchecked(i32::MAX - Y::EXTENDED_YEAR_OFFSET, 12, 31) + } + } else { + iso + } + } + + fn to_rata_die(&self, date: &Self::DateInner) -> RataDie { + calendrical_calculations::gregorian::fixed_from_gregorian(date.year, date.month, date.day) + } + + fn has_cheap_iso_conversion(&self) -> bool { + true + } + + fn from_iso(&self, iso: IsoDateInner) -> Self::DateInner { + iso.0 + } + + fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { + IsoDateInner(*date) + } + + fn months_in_year(&self, date: &Self::DateInner) -> u8 { + AbstractGregorian::::months_in_provided_year(date.year) + } + + fn days_in_year(&self, date: &Self::DateInner) -> u16 { + 365 + calendrical_calculations::gregorian::is_leap_year(date.year) as u16 + } + + fn days_in_month(&self, date: &Self::DateInner) -> u8 { + AbstractGregorian::::days_in_provided_month(date.year, date.month) + } + + #[cfg(feature = "unstable")] + fn add( + &self, + date: &Self::DateInner, + duration: types::DateDuration, + options: DateAddOptions, + ) -> Result { + date.added(duration, &AbstractGregorian(IsoEra), options) + } + + #[cfg(feature = "unstable")] + fn until( + &self, + date1: &Self::DateInner, + date2: &Self::DateInner, + options: DateDifferenceOptions, + ) -> Result { + Ok(date1.until(date2, &AbstractGregorian(IsoEra), options)) + } + + fn year_info(&self, date: &Self::DateInner) -> Self::Year { + self.0 + .era_year_from_extended(date.year - Y::EXTENDED_YEAR_OFFSET, date.month, date.day) + } + + fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { + calendrical_calculations::gregorian::is_leap_year(date.year) + } + + fn month(&self, date: &Self::DateInner) -> types::MonthInfo { + types::MonthInfo::non_lunisolar(date.month) + } + + fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { + types::DayOfMonth(date.day) + } + + fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear { + types::DayOfYear( + calendrical_calculations::gregorian::days_before_month(date.year, date.month) + + date.day as u16, + ) + } + + fn debug_name(&self) -> &'static str { + self.0.debug_name() + } + + fn calendar_algorithm(&self) -> Option { + self.0.calendar_algorithm() + } +} + +macro_rules! impl_with_abstract_gregorian { + ($cal_ty:ty, $inner_date_ty:ident, $eras_ty:ty, $self_ident:ident, $eras_expr:expr) => { + #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] + pub struct $inner_date_ty( + pub(crate) ArithmeticDate< + crate::cal::abstract_gregorian::AbstractGregorian, + >, + ); + + impl crate::cal::scaffold::UnstableSealed for $cal_ty {} + impl crate::Calendar for $cal_ty { + type DateInner = $inner_date_ty; + type Year = types::EraYear; + type DifferenceError = core::convert::Infallible; + + fn from_codes( + &self, + era: Option<&str>, + year: i32, + month_code: types::MonthCode, + day: u8, + ) -> Result { + let $self_ident = self; + crate::cal::abstract_gregorian::AbstractGregorian($eras_expr) + .from_codes(era, year, month_code, day) + .map($inner_date_ty) + } + + #[cfg(feature = "unstable")] + fn from_fields( + &self, + fields: crate::types::DateFields, + options: crate::options::DateFromFieldsOptions, + ) -> Result { + let $self_ident = self; + crate::cal::abstract_gregorian::AbstractGregorian($eras_expr) + .from_fields(fields, options) + .map($inner_date_ty) + } + + fn from_rata_die(&self, rd: crate::types::RataDie) -> Self::DateInner { + let $self_ident = self; + $inner_date_ty( + crate::cal::abstract_gregorian::AbstractGregorian($eras_expr).from_rata_die(rd), + ) + } + + fn to_rata_die(&self, date: &Self::DateInner) -> crate::types::RataDie { + let $self_ident = self; + crate::cal::abstract_gregorian::AbstractGregorian($eras_expr).to_rata_die(&date.0) + } + + fn has_cheap_iso_conversion(&self) -> bool { + let $self_ident = self; + crate::cal::abstract_gregorian::AbstractGregorian($eras_expr) + .has_cheap_iso_conversion() + } + + fn from_iso(&self, iso: crate::cal::iso::IsoDateInner) -> Self::DateInner { + let $self_ident = self; + $inner_date_ty( + crate::cal::abstract_gregorian::AbstractGregorian($eras_expr).from_iso(iso), + ) + } + + fn to_iso(&self, date: &Self::DateInner) -> crate::cal::iso::IsoDateInner { + let $self_ident = self; + crate::cal::abstract_gregorian::AbstractGregorian($eras_expr).to_iso(&date.0) + } + + fn months_in_year(&self, date: &Self::DateInner) -> u8 { + let $self_ident = self; + crate::cal::abstract_gregorian::AbstractGregorian($eras_expr) + .months_in_year(&date.0) + } + + fn days_in_year(&self, date: &Self::DateInner) -> u16 { + let $self_ident = self; + crate::cal::abstract_gregorian::AbstractGregorian($eras_expr).days_in_year(&date.0) + } + + fn days_in_month(&self, date: &Self::DateInner) -> u8 { + let $self_ident = self; + crate::cal::abstract_gregorian::AbstractGregorian($eras_expr).days_in_month(&date.0) + } + + #[cfg(feature = "unstable")] + fn add( + &self, + date: &Self::DateInner, + duration: crate::types::DateDuration, + options: crate::options::DateAddOptions, + ) -> Result { + let $self_ident = self; + crate::cal::abstract_gregorian::AbstractGregorian($eras_expr) + .add(&date.0, duration, options) + .map($inner_date_ty) + } + + #[cfg(feature = "unstable")] + fn until( + &self, + date1: &Self::DateInner, + date2: &Self::DateInner, + options: crate::options::DateDifferenceOptions, + ) -> Result { + let $self_ident = self; + crate::cal::abstract_gregorian::AbstractGregorian($eras_expr) + .until(&date1.0, &date2.0, options) + } + + fn year_info(&self, date: &Self::DateInner) -> Self::Year { + let $self_ident = self; + crate::cal::abstract_gregorian::AbstractGregorian($eras_expr).year_info(&date.0) + } + + fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { + let $self_ident = self; + crate::cal::abstract_gregorian::AbstractGregorian($eras_expr) + .is_in_leap_year(&date.0) + } + + fn month(&self, date: &Self::DateInner) -> types::MonthInfo { + let $self_ident = self; + crate::cal::abstract_gregorian::AbstractGregorian($eras_expr).month(&date.0) + } + + fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { + let $self_ident = self; + crate::cal::abstract_gregorian::AbstractGregorian($eras_expr).day_of_month(&date.0) + } + + fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear { + let $self_ident = self; + crate::cal::abstract_gregorian::AbstractGregorian($eras_expr).day_of_year(&date.0) + } + + fn debug_name(&self) -> &'static str { + let $self_ident = self; + crate::cal::abstract_gregorian::AbstractGregorian($eras_expr).debug_name() + } + + fn calendar_algorithm(&self) -> Option { + let $self_ident = self; + crate::cal::abstract_gregorian::AbstractGregorian($eras_expr).calendar_algorithm() + } + } + }; +} +pub(crate) use impl_with_abstract_gregorian; diff --git a/deps/crates/vendor/icu_calendar/src/cal/buddhist.rs b/deps/crates/vendor/icu_calendar/src/cal/buddhist.rs index 0e56b890d1eee9..f60f03e42f50b6 100644 --- a/deps/crates/vendor/icu_calendar/src/cal/buddhist.rs +++ b/deps/crates/vendor/icu_calendar/src/cal/buddhist.rs @@ -2,158 +2,74 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -//! This module contains types and implementations for the Buddhist calendar. -//! -//! ```rust -//! use icu::calendar::{cal::Buddhist, Date}; -//! -//! let date_iso = Date::try_new_iso(1970, 1, 2) -//! .expect("Failed to initialize ISO Date instance."); -//! let date_buddhist = Date::new_from_iso(date_iso, Buddhist); -//! -//! assert_eq!(date_buddhist.era_year().year, 2513); -//! assert_eq!(date_buddhist.month().ordinal, 1); -//! assert_eq!(date_buddhist.day_of_month().0, 2); -//! ``` - -use crate::cal::iso::{Iso, IsoDateInner}; -use crate::calendar_arithmetic::ArithmeticDate; -use crate::error::DateError; -use crate::{types, Calendar, Date, DateDuration, DateDurationUnit, RangeError}; -use calendrical_calculations::rata_die::RataDie; +use crate::error::UnknownEraError; +use crate::preferences::CalendarAlgorithm; +use crate::{ + cal::abstract_gregorian::{impl_with_abstract_gregorian, GregorianYears}, + calendar_arithmetic::ArithmeticDate, + types, Date, DateError, RangeError, +}; use tinystr::tinystr; -/// The number of years the Buddhist Era is ahead of C.E. by -/// -/// (1 AD = 544 BE) -const BUDDHIST_ERA_OFFSET: i32 = 543; - #[derive(Copy, Clone, Debug, Default)] -/// The [Thai Solar Buddhist Calendar][cal] +/// The [Thai Solar Buddhist Calendar](https://en.wikipedia.org/wiki/Thai_solar_calendar) /// -/// The [Thai Solar Buddhist Calendar][cal] is a solar calendar used in Thailand, with twelve months. -/// The months and days are identical to that of the Gregorian calendar, however the years are counted -/// differently using the Buddhist Era. +/// The Thai Solar Buddhist Calendar is a variant of the [`Gregorian`](crate::cal::Gregorian) calendar +/// created by the Thai government. It is identical to the Gregorian calendar except that is uses +/// the Buddhist Era (-543 CE) instead of the Common Era. /// -/// This type can be used with [`Date`] to represent dates in this calendar. +/// This implementation extends proleptically for dates before the calendar's creation +/// in 2484 BE (1941 CE). /// -/// [cal]: https://en.wikipedia.org/wiki/Thai_solar_calendar +/// This corresponds to the `"buddhist"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). /// /// # Era codes /// /// This calendar uses a single era code `be`, with 1 Buddhist Era being 543 BCE. Dates before this era use negative years. -/// -/// # Month codes -/// -/// This calendar supports 12 solar month codes (`"M01" - "M12"`) #[allow(clippy::exhaustive_structs)] // this type is stable pub struct Buddhist; -impl crate::cal::scaffold::UnstableSealed for Buddhist {} -impl Calendar for Buddhist { - type DateInner = IsoDateInner; - type Year = types::EraYear; +impl_with_abstract_gregorian!( + crate::cal::Buddhist, + BuddhistDateInner, + BuddhistEra, + _x, + BuddhistEra +); - fn from_codes( +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub(crate) struct BuddhistEra; + +impl GregorianYears for BuddhistEra { + const EXTENDED_YEAR_OFFSET: i32 = -543; + + fn extended_from_era_year( &self, - era: Option<&str>, + era: Option<&[u8]>, year: i32, - month_code: types::MonthCode, - day: u8, - ) -> Result { + ) -> Result { match era { - Some("be") | None => {} - _ => return Err(DateError::UnknownEra), + Some(b"be") | None => Ok(year), + _ => Err(UnknownEraError), } - let year = year - BUDDHIST_ERA_OFFSET; - - ArithmeticDate::new_from_codes(self, year, month_code, day).map(IsoDateInner) - } - - fn from_iso(&self, iso: IsoDateInner) -> Self::DateInner { - iso } - fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { - *date - } - - fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { - Iso.from_rata_die(rd) - } - - fn to_rata_die(&self, date: &Self::DateInner) -> RataDie { - Iso.to_rata_die(date) - } - - fn months_in_year(&self, date: &Self::DateInner) -> u8 { - Iso.months_in_year(date) - } - - fn days_in_year(&self, date: &Self::DateInner) -> u16 { - Iso.days_in_year(date) - } - - fn days_in_month(&self, date: &Self::DateInner) -> u8 { - Iso.days_in_month(date) - } - - fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) { - Iso.offset_date(date, offset.cast_unit()) - } - - #[allow(clippy::field_reassign_with_default)] // it's more clear this way - fn until( - &self, - date1: &Self::DateInner, - date2: &Self::DateInner, - _calendar2: &Self, - largest_unit: DateDurationUnit, - smallest_unit: DateDurationUnit, - ) -> DateDuration { - Iso.until(date1, date2, &Iso, largest_unit, smallest_unit) - .cast_unit() - } - - /// The calendar-specific year represented by `date` - fn year_info(&self, date: &Self::DateInner) -> Self::Year { + fn era_year_from_extended(&self, extended_year: i32, _month: u8, _day: u8) -> types::EraYear { types::EraYear { era: tinystr!(16, "be"), era_index: Some(0), - year: self.extended_year(date), + year: extended_year, + extended_year, ambiguity: types::YearAmbiguity::CenturyRequired, } } - fn extended_year(&self, date: &Self::DateInner) -> i32 { - Iso.extended_year(date) + BUDDHIST_ERA_OFFSET - } - - fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { - Iso.is_in_leap_year(date) - } - - /// The calendar-specific month represented by `date` - fn month(&self, date: &Self::DateInner) -> types::MonthInfo { - Iso.month(date) - } - - /// The calendar-specific day-of-month represented by `date` - fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { - Iso.day_of_month(date) - } - - /// Information of the day of the year - fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear { - Iso.day_of_year(date) - } - fn debug_name(&self) -> &'static str { "Buddhist" } - fn calendar_algorithm(&self) -> Option { - Some(crate::preferences::CalendarAlgorithm::Buddhist) + fn calendar_algorithm(&self) -> Option { + Some(CalendarAlgorithm::Buddhist) } } @@ -173,13 +89,15 @@ impl Date { /// assert_eq!(date_buddhist.day_of_month().0, 2); /// ``` pub fn try_new_buddhist(year: i32, month: u8, day: u8) -> Result, RangeError> { - Date::try_new_iso(year - BUDDHIST_ERA_OFFSET, month, day) - .map(|d| Date::new_from_iso(d, Buddhist)) + ArithmeticDate::new_gregorian::(year, month, day) + .map(BuddhistDateInner) + .map(|i| Date::from_raw(i, Buddhist)) } } #[cfg(test)] mod test { + use crate::cal::Iso; use calendrical_calculations::rata_die::RataDie; use super::*; diff --git a/deps/crates/vendor/icu_calendar/src/cal/chinese.rs b/deps/crates/vendor/icu_calendar/src/cal/chinese.rs deleted file mode 100644 index 43ec385369438a..00000000000000 --- a/deps/crates/vendor/icu_calendar/src/cal/chinese.rs +++ /dev/null @@ -1,1039 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -//! This module contains types and implementations for the Chinese calendar. -//! -//! ```rust -//! use icu::calendar::{cal::Chinese, Date}; -//! -//! let chinese = Chinese::new(); -//! let chinese_date = Date::try_new_chinese_with_calendar(2023, 6, 6, chinese) -//! .expect("Failed to initialize Chinese Date instance."); -//! -//! assert_eq!(chinese_date.cyclic_year().related_iso, 2023); -//! assert_eq!(chinese_date.cyclic_year().year, 40); -//! assert_eq!(chinese_date.month().ordinal, 6); -//! assert_eq!(chinese_date.day_of_month().0, 6); -//! ``` - -use crate::cal::chinese_based::{ChineseBasedPrecomputedData, ChineseBasedWithDataLoading}; -use crate::cal::iso::{Iso, IsoDateInner}; -use crate::calendar_arithmetic::PrecomputedDataSource; -use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic}; -use crate::error::DateError; -use crate::provider::chinese_based::CalendarChineseV1; -use crate::AsCalendar; -use crate::{types, Calendar, Date, DateDuration, DateDurationUnit}; -use calendrical_calculations::chinese_based; -use calendrical_calculations::rata_die::RataDie; -use core::cmp::Ordering; -use icu_provider::prelude::*; - -/// The [Chinese Calendar](https://en.wikipedia.org/wiki/Chinese_calendar) -/// -/// The Chinese Calendar is a lunisolar calendar used traditionally in China as well as in other -/// countries particularly in, but not limited to, East Asia. It is often used today to track important -/// cultural events and holidays like the Chinese Lunar New Year. -/// -/// This type can be used with [`Date`] to represent dates in the Chinese calendar. -/// -/// # Months -/// -/// The Chinese calendar is an astronomical calendar which uses the phases of the moon to track months. -/// Each month starts on the date of the new moon as observed from China, meaning that months last 29 -/// or 30 days. -/// -/// One year in the Chinese calendar is typically 12 lunar months; however, because 12 lunar months does -/// not line up to one solar year, the Chinese calendar will add an intercalary leap month approximately -/// every three years to keep Chinese calendar months in line with the solar year. -/// -/// Leap months can happen after any month; the month in which a leap month occurs is based on the alignment -/// of months with 24 solar terms into which the solar year is divided. -/// -/// # Year and Era codes -/// -/// Unlike the Gregorian calendar, the Chinese calendar does not traditionally count years in an infinitely -/// increasing sequence. Instead, 10 "celestial stems" and 12 "terrestrial branches" are combined to form a -/// cycle of year names which repeats every 60 years. However, for the purposes of calendar calculations and -/// conversions, this calendar also counts years based on the ISO (Gregorian) calendar. This "related ISO year" -/// marks the ISO year in which a Chinese year begins. -/// -/// Because the Chinese calendar does not traditionally count years, era codes are not used in this calendar. -/// -/// For more information, suggested reading materials include: -/// * _Calendrical Calculations_ by Reingold & Dershowitz -/// * _The Mathematics of the Chinese Calendar_ by Helmer Aslaksen -/// * Wikipedia: -/// -/// # Month codes -/// -/// This calendar is a lunisolar calendar. It supports regular month codes `"M01" - "M12"` as well -/// as leap month codes `"M01L" - "M12L"`. -/// -/// This calendar is currently in a preview state: formatting for this calendar is not -/// going to be perfect. -#[derive(Clone, Debug, Default)] -pub struct Chinese { - data: Option>, -} - -/// The inner date type used for representing [`Date`]s of [`Chinese`]. See [`Date`] and [`Chinese`] for more details. -#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)] -pub struct ChineseDateInner(ArithmeticDate); - -// we want these impls without the `C: Copy/Clone` bounds -impl Copy for ChineseDateInner {} -impl Clone for ChineseDateInner { - fn clone(&self) -> Self { - *self - } -} - -// These impls just make custom derives on types containing C -// work. They're basically no-ops -impl PartialEq for Chinese { - fn eq(&self, _: &Self) -> bool { - true - } -} -impl Eq for Chinese {} -#[allow(clippy::non_canonical_partial_ord_impl)] // this is intentional -impl PartialOrd for Chinese { - fn partial_cmp(&self, _: &Self) -> Option { - Some(Ordering::Equal) - } -} - -impl Ord for Chinese { - fn cmp(&self, _: &Self) -> Ordering { - Ordering::Equal - } -} - -impl Chinese { - /// Creates a new [`Chinese`] with some precomputed calendrical calculations. - /// - /// ✨ *Enabled with the `compiled_data` Cargo feature.* - /// - /// [📚 Help choosing a constructor](icu_provider::constructors) - #[cfg(feature = "compiled_data")] - pub const fn new() -> Self { - Self { - data: Some(DataPayload::from_static_ref( - crate::provider::Baked::SINGLETON_CALENDAR_CHINESE_V1, - )), - } - } - - icu_provider::gen_buffer_data_constructors!(() -> error: DataError, - functions: [ - new: skip, - try_new_with_buffer_provider, - try_new_unstable, - Self, - ]); - - #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new)] - pub fn try_new_unstable + ?Sized>( - provider: &D, - ) -> Result { - Ok(Self { - data: Some(provider.load(Default::default())?.payload), - }) - } - - /// Construct a new [`Chinese`] without any precomputed calendrical calculations. - pub fn new_always_calculating() -> Self { - Chinese { data: None } - } - - pub(crate) const DEBUG_NAME: &'static str = "Chinese"; -} - -impl crate::cal::scaffold::UnstableSealed for Chinese {} -impl Calendar for Chinese { - type DateInner = ChineseDateInner; - type Year = types::CyclicYear; - - // Construct a date from era/month codes and fields - fn from_codes( - &self, - era: Option<&str>, - year: i32, - month_code: types::MonthCode, - day: u8, - ) -> Result { - match era { - None => {} - _ => return Err(DateError::UnknownEra), - } - - let year = self.get_precomputed_data().load_or_compute_info(year); - - let Some(month) = year.parse_month_code(month_code) else { - return Err(DateError::UnknownMonthCode(month_code)); - }; - - year.validate_md(month, day)?; - - Ok(ChineseDateInner(ArithmeticDate::new_unchecked( - year, month, day, - ))) - } - - fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { - let iso = Iso.from_rata_die(rd); - let y = self - .get_precomputed_data() - .load_or_compute_info_for_rd(rd, iso.0); - let (m, d) = y.md_from_rd(rd); - ChineseDateInner(ArithmeticDate::new_unchecked(y, m, d)) - } - - fn to_rata_die(&self, date: &Self::DateInner) -> RataDie { - date.0.year.rd_from_md(date.0.month, date.0.day) - } - - fn from_iso(&self, iso: IsoDateInner) -> Self::DateInner { - let rd = Iso.to_rata_die(&iso); - let y = self - .get_precomputed_data() - .load_or_compute_info_for_rd(rd, iso.0); - let (m, d) = y.md_from_rd(rd); - ChineseDateInner(ArithmeticDate::new_unchecked(y, m, d)) - } - - fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { - Iso.from_rata_die(self.to_rata_die(date)) - } - - // Count the number of months in a given year, specified by providing a date - // from that year - fn days_in_year(&self, date: &Self::DateInner) -> u16 { - date.0.days_in_year() - } - - fn days_in_month(&self, date: &Self::DateInner) -> u8 { - date.0.days_in_month() - } - - #[doc(hidden)] // unstable - fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) { - date.0.offset_date(offset, &self.get_precomputed_data()); - } - - #[doc(hidden)] // unstable - #[allow(clippy::field_reassign_with_default)] - /// Calculate `date2 - date` as a duration - /// - /// `calendar2` is the calendar object associated with `date2`. In case the specific calendar objects - /// differ on date, the date for the first calendar is used, and `date2` may be converted if necessary. - fn until( - &self, - date1: &Self::DateInner, - date2: &Self::DateInner, - _calendar2: &Self, - _largest_unit: DateDurationUnit, - _smallest_unit: DateDurationUnit, - ) -> DateDuration { - date1.0.until(date2.0, _largest_unit, _smallest_unit) - } - - /// Obtain a name for the calendar for debug printing - fn debug_name(&self) -> &'static str { - Self::DEBUG_NAME - } - - fn year_info(&self, date: &Self::DateInner) -> Self::Year { - let year = date.0.year; - types::CyclicYear { - year: (year.related_iso - 4).rem_euclid(60) as u8 + 1, - related_iso: year.related_iso, - } - } - - fn extended_year(&self, date: &Self::DateInner) -> i32 { - chinese_based::extended_from_iso::(date.0.year.related_iso) - } - - fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { - Self::provided_year_is_leap(date.0.year) - } - - /// The calendar-specific month code represented by `date`; - /// since the Chinese calendar has leap months, an "L" is appended to the month code for - /// leap months. For example, in a year where an intercalary month is added after the second - /// month, the month codes for ordinal months 1, 2, 3, 4, 5 would be "M01", "M02", "M02L", "M03", "M04". - fn month(&self, date: &Self::DateInner) -> types::MonthInfo { - date.0.year.month(date.0.month) - } - - /// The calendar-specific day-of-month represented by `date` - fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { - date.0.day_of_month() - } - - /// Information of the day of the year - fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear { - types::DayOfYear(date.0.year.day_of_year(date.0.month, date.0.day)) - } - - fn calendar_algorithm(&self) -> Option { - Some(crate::preferences::CalendarAlgorithm::Chinese) - } - - fn months_in_year(&self, date: &Self::DateInner) -> u8 { - date.0.months_in_year() - } -} - -impl> Date { - /// Construct a new Chinese date from a `year`, `month`, and `day`. - /// `year` represents the [ISO](crate::Iso) year that roughly matches the Chinese year; - /// `month` represents the month of the year ordinally (ex. if it is a leap year, the last month will be 13, not 12); - /// `day` indicates the day of month - /// - /// This date will not use any precomputed calendrical calculations, - /// one that loads such data from a provider will be added in the future (#3933) - /// - /// ```rust - /// use icu::calendar::{cal::Chinese, Date}; - /// - /// let chinese = Chinese::new_always_calculating(); - /// - /// let date_chinese = - /// Date::try_new_chinese_with_calendar(2023, 6, 11, chinese) - /// .expect("Failed to initialize Chinese Date instance."); - /// - /// assert_eq!(date_chinese.cyclic_year().related_iso, 2023); - /// assert_eq!(date_chinese.cyclic_year().year, 40); - /// assert_eq!(date_chinese.month().ordinal, 6); - /// assert_eq!(date_chinese.day_of_month().0, 11); - /// ``` - pub fn try_new_chinese_with_calendar( - related_iso_year: i32, - month: u8, - day: u8, - calendar: A, - ) -> Result, DateError> { - let year = calendar - .as_calendar() - .get_precomputed_data() - .load_or_compute_info(related_iso_year); - year.validate_md(month, day)?; - Ok(Date::from_raw( - ChineseDateInner(ArithmeticDate::new_unchecked(year, month, day)), - calendar, - )) - } -} - -type ChineseCB = calendrical_calculations::chinese_based::Chinese; -impl ChineseBasedWithDataLoading for Chinese { - type CB = ChineseCB; - fn get_precomputed_data(&self) -> ChineseBasedPrecomputedData { - ChineseBasedPrecomputedData::new(self.data.as_ref().map(|d| d.get())) - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::types::MonthCode; - use calendrical_calculations::{iso::fixed_from_iso, rata_die::RataDie}; - use tinystr::tinystr; - - /// Run a test twice, with two calendars - fn do_twice( - chinese_calculating: &Chinese, - chinese_cached: &Chinese, - test: impl Fn(crate::Ref, &'static str), - ) { - test(crate::Ref(chinese_calculating), "calculating"); - test(crate::Ref(chinese_cached), "cached"); - } - - #[test] - fn test_chinese_from_rd() { - #[derive(Debug)] - struct TestCase { - rd: i64, - expected_year: i32, - expected_month: u8, - expected_day: u8, - } - - let cases = [ - TestCase { - rd: -964192, - expected_year: -2, - expected_month: 1, - expected_day: 1, - }, - TestCase { - rd: -963838, - expected_year: -1, - expected_month: 1, - expected_day: 1, - }, - TestCase { - rd: -963129, - expected_year: 0, - expected_month: 13, - expected_day: 1, - }, - TestCase { - rd: -963100, - expected_year: 0, - expected_month: 13, - expected_day: 30, - }, - TestCase { - rd: -963099, - expected_year: 1, - expected_month: 1, - expected_day: 1, - }, - TestCase { - rd: 738700, - expected_year: 4660, - expected_month: 6, - expected_day: 12, - }, - TestCase { - rd: fixed_from_iso(2319, 2, 20).to_i64_date(), - expected_year: 2319 + 2636, - expected_month: 13, - expected_day: 30, - }, - TestCase { - rd: fixed_from_iso(2319, 2, 21).to_i64_date(), - expected_year: 2319 + 2636 + 1, - expected_month: 1, - expected_day: 1, - }, - TestCase { - rd: 738718, - expected_year: 4660, - expected_month: 6, - expected_day: 30, - }, - TestCase { - rd: 738747, - expected_year: 4660, - expected_month: 7, - expected_day: 29, - }, - TestCase { - rd: 738748, - expected_year: 4660, - expected_month: 8, - expected_day: 1, - }, - TestCase { - rd: 738865, - expected_year: 4660, - expected_month: 11, - expected_day: 29, - }, - TestCase { - rd: 738895, - expected_year: 4660, - expected_month: 12, - expected_day: 29, - }, - TestCase { - rd: 738925, - expected_year: 4660, - expected_month: 13, - expected_day: 30, - }, - ]; - - let chinese_calculating = Chinese::new_always_calculating(); - let chinese_cached = Chinese::new(); - for case in cases { - let rata_die = RataDie::new(case.rd); - - do_twice( - &chinese_calculating, - &chinese_cached, - |chinese, calendar_type| { - let chinese = Date::from_rata_die(rata_die, chinese); - assert_eq!( - case.expected_year, - chinese.extended_year(), - "[{calendar_type}] Chinese from RD failed, case: {case:?}" - ); - assert_eq!( - case.expected_month, - chinese.month().ordinal, - "[{calendar_type}] Chinese from RD failed, case: {case:?}" - ); - assert_eq!( - case.expected_day, - chinese.day_of_month().0, - "[{calendar_type}] Chinese from RD failed, case: {case:?}" - ); - }, - ); - } - } - - #[test] - fn test_rd_from_chinese() { - #[derive(Debug)] - struct TestCase { - year: i32, - month: u8, - day: u8, - expected: i64, - } - - let cases = [ - TestCase { - year: 2023, - month: 6, - day: 6, - // June 23 2023 - expected: 738694, - }, - TestCase { - year: -2636, - month: 1, - day: 1, - expected: -963099, - }, - ]; - - let chinese_calculating = Chinese::new_always_calculating(); - let chinese_cached = Chinese::new(); - for case in cases { - do_twice( - &chinese_calculating, - &chinese_cached, - |chinese, calendar_type| { - let date = Date::try_new_chinese_with_calendar( - case.year, case.month, case.day, chinese, - ) - .unwrap(); - let rd = date.to_rata_die().to_i64_date(); - let expected = case.expected; - assert_eq!(rd, expected, "[{calendar_type}] RD from Chinese failed, with expected: {expected} and calculated: {rd}, for test case: {case:?}"); - }, - ); - } - } - - #[test] - fn test_rd_chinese_roundtrip() { - let mut rd = -1963020; - let max_rd = 1963020; - let mut iters = 0; - let max_iters = 560; - let chinese_calculating = Chinese::new_always_calculating(); - let chinese_cached = Chinese::new(); - while rd < max_rd && iters < max_iters { - let rata_die = RataDie::new(rd); - - do_twice( - &chinese_calculating, - &chinese_cached, - |chinese, calendar_type| { - let chinese = Date::from_rata_die(rata_die, chinese); - let result = chinese.to_rata_die(); - assert_eq!(result, rata_die, "[{calendar_type}] Failed roundtrip RD -> Chinese -> RD for RD: {rata_die:?}, with calculated: {result:?} from Chinese date:\n{chinese:?}"); - }, - ); - rd += 7043; - iters += 1; - } - } - - #[test] - fn test_chinese_epoch() { - let iso = Date::try_new_iso(-2636, 2, 15).unwrap(); - - do_twice( - &Chinese::new_always_calculating(), - &Chinese::new(), - |chinese, _calendar_type| { - let chinese = iso.to_calendar(chinese); - - assert_eq!(chinese.cyclic_year().related_iso, -2636); - assert_eq!(chinese.month().ordinal, 1); - assert_eq!(chinese.month().standard_code.0, "M01"); - assert_eq!(chinese.day_of_month().0, 1); - assert_eq!(chinese.cyclic_year().year, 1); - assert_eq!(chinese.cyclic_year().related_iso, -2636); - }, - ) - } - - #[test] - fn test_iso_to_chinese_negative_years() { - #[derive(Debug)] - struct TestCase { - iso_year: i32, - iso_month: u8, - iso_day: u8, - expected_year: i32, - expected_month: u8, - expected_day: u8, - } - - let cases = [ - TestCase { - iso_year: -2636, - iso_month: 2, - iso_day: 14, - expected_year: -2637, - expected_month: 13, - expected_day: 30, - }, - TestCase { - iso_year: -2636, - iso_month: 1, - iso_day: 15, - expected_year: -2637, - expected_month: 12, - expected_day: 30, - }, - ]; - - let chinese_calculating = Chinese::new_always_calculating(); - let chinese_cached = Chinese::new(); - - for case in cases { - let iso = Date::try_new_iso(case.iso_year, case.iso_month, case.iso_day).unwrap(); - do_twice( - &chinese_calculating, - &chinese_cached, - |chinese, calendar_type| { - let chinese = iso.to_calendar(chinese); - assert_eq!( - case.expected_year, - chinese.cyclic_year().related_iso, - "[{calendar_type}] ISO to Chinese failed for case: {case:?}" - ); - assert_eq!( - case.expected_month, - chinese.month().ordinal, - "[{calendar_type}] ISO to Chinese failed for case: {case:?}" - ); - assert_eq!( - case.expected_day, - chinese.day_of_month().0, - "[{calendar_type}] ISO to Chinese failed for case: {case:?}" - ); - }, - ); - } - } - - #[test] - fn test_chinese_leap_months() { - let expected = [ - (1933, 6), - (1938, 8), - (1984, 11), - (2009, 6), - (2017, 7), - (2028, 6), - ]; - let chinese_calculating = Chinese::new_always_calculating(); - let chinese_cached = Chinese::new(); - - for case in expected { - let year = case.0; - let expected_month = case.1; - let iso = Date::try_new_iso(year, 6, 1).unwrap(); - do_twice( - &chinese_calculating, - &chinese_cached, - |chinese, calendar_type| { - let chinese_date = iso.to_calendar(chinese); - assert!( - chinese_date.is_in_leap_year(), - "[{calendar_type}] {year} should be a leap year" - ); - let new_year = chinese_date.inner.0.year.new_year(); - assert_eq!( - expected_month, - calendrical_calculations::chinese_based::get_leap_month_from_new_year::< - calendrical_calculations::chinese_based::Chinese, - >(new_year), - "[{calendar_type}] {year} have leap month {expected_month}" - ); - }, - ); - } - } - - #[test] - fn test_month_days() { - let year = - ChineseBasedPrecomputedData::<::CB>::default() - .load_or_compute_info(2023); - let cases = [ - (1, 29), - (2, 30), - (3, 29), - (4, 29), - (5, 30), - (6, 30), - (7, 29), - (8, 30), - (9, 30), - (10, 29), - (11, 30), - (12, 29), - (13, 30), - ]; - for case in cases { - let days_in_month = Chinese::days_in_provided_month(year, case.0); - assert_eq!( - case.1, days_in_month, - "month_days test failed for case: {case:?}" - ); - } - } - - #[test] - fn test_ordinal_to_month_code() { - #[derive(Debug)] - struct TestCase { - year: i32, - month: u8, - day: u8, - expected_code: &'static str, - } - - let cases = [ - TestCase { - year: 2023, - month: 1, - day: 9, - expected_code: "M12", - }, - TestCase { - year: 2023, - month: 2, - day: 9, - expected_code: "M01", - }, - TestCase { - year: 2023, - month: 3, - day: 9, - expected_code: "M02", - }, - TestCase { - year: 2023, - month: 4, - day: 9, - expected_code: "M02L", - }, - TestCase { - year: 2023, - month: 5, - day: 9, - expected_code: "M03", - }, - TestCase { - year: 2023, - month: 6, - day: 9, - expected_code: "M04", - }, - TestCase { - year: 2023, - month: 7, - day: 9, - expected_code: "M05", - }, - TestCase { - year: 2023, - month: 8, - day: 9, - expected_code: "M06", - }, - TestCase { - year: 2023, - month: 9, - day: 9, - expected_code: "M07", - }, - TestCase { - year: 2023, - month: 10, - day: 9, - expected_code: "M08", - }, - TestCase { - year: 2023, - month: 11, - day: 9, - expected_code: "M09", - }, - TestCase { - year: 2023, - month: 12, - day: 9, - expected_code: "M10", - }, - TestCase { - year: 2024, - month: 1, - day: 9, - expected_code: "M11", - }, - TestCase { - year: 2024, - month: 2, - day: 9, - expected_code: "M12", - }, - TestCase { - year: 2024, - month: 2, - day: 10, - expected_code: "M01", - }, - ]; - - let chinese_calculating = Chinese::new_always_calculating(); - let chinese_cached = Chinese::new(); - - for case in cases { - let iso = Date::try_new_iso(case.year, case.month, case.day).unwrap(); - do_twice( - &chinese_calculating, - &chinese_cached, - |chinese, calendar_type| { - let chinese = iso.to_calendar(chinese); - let result_code = chinese.month().standard_code.0; - let expected_code = case.expected_code.to_string(); - assert_eq!( - expected_code, result_code, - "[{calendar_type}] Month codes did not match for test case: {case:?}" - ); - }, - ); - } - } - - #[test] - fn test_month_code_to_ordinal() { - // construct using ::default() to force recomputation - let year = - ChineseBasedPrecomputedData::<::CB>::default() - .load_or_compute_info(2023); - let codes = [ - (1, tinystr!(4, "M01")), - (2, tinystr!(4, "M02")), - (3, tinystr!(4, "M02L")), - (4, tinystr!(4, "M03")), - (5, tinystr!(4, "M04")), - (6, tinystr!(4, "M05")), - (7, tinystr!(4, "M06")), - (8, tinystr!(4, "M07")), - (9, tinystr!(4, "M08")), - (10, tinystr!(4, "M09")), - (11, tinystr!(4, "M10")), - (12, tinystr!(4, "M11")), - (13, tinystr!(4, "M12")), - ]; - for ordinal_code_pair in codes { - let code = MonthCode(ordinal_code_pair.1); - let ordinal = year.parse_month_code(code); - assert_eq!( - ordinal, - Some(ordinal_code_pair.0), - "Code to ordinal failed for year: {}, code: {code}", - year.related_iso - ); - } - } - - #[test] - fn check_invalid_month_code_to_ordinal() { - let non_leap_year = 4659; - let leap_year = 4660; - let invalid_codes = [ - (non_leap_year, tinystr!(4, "M2")), - (leap_year, tinystr!(4, "M0")), - (non_leap_year, tinystr!(4, "J01")), - (leap_year, tinystr!(4, "3M")), - (non_leap_year, tinystr!(4, "M04L")), - (leap_year, tinystr!(4, "M04L")), - (non_leap_year, tinystr!(4, "M13")), - (leap_year, tinystr!(4, "M13")), - ]; - for (year, code) in invalid_codes { - // construct using ::default() to force recomputation - let year = ChineseBasedPrecomputedData::< - ::CB, - >::default() - .load_or_compute_info(year); - let code = MonthCode(code); - let ordinal = year.parse_month_code(code); - assert_eq!( - ordinal, None, - "Invalid month code failed for year: {}, code: {code}", - year.related_iso - ); - } - } - - #[test] - fn test_iso_chinese_roundtrip() { - let chinese_calculating = Chinese::new_always_calculating(); - let chinese_cached = Chinese::new(); - - for i in -1000..=1000 { - let year = i; - let month = i as u8 % 12 + 1; - let day = i as u8 % 28 + 1; - let iso = Date::try_new_iso(year, month, day).unwrap(); - do_twice( - &chinese_calculating, - &chinese_cached, - |chinese, calendar_type| { - let chinese = iso.to_calendar(chinese); - let result = chinese.to_calendar(Iso); - assert_eq!(iso, result, "[{calendar_type}] ISO to Chinese roundtrip failed!\nIso: {iso:?}\nChinese: {chinese:?}\nResult: {result:?}"); - }, - ); - } - } - - #[test] - fn test_consistent_with_icu() { - #[derive(Debug)] - struct TestCase { - iso_year: i32, - iso_month: u8, - iso_day: u8, - expected_rel_iso: i32, - expected_cyclic: u8, - expected_month: u8, - expected_day: u8, - } - - let cases = [ - TestCase { - iso_year: -2332, - iso_month: 3, - iso_day: 1, - expected_rel_iso: -2332, - expected_cyclic: 5, - expected_month: 1, - expected_day: 16, - }, - TestCase { - iso_year: -2332, - iso_month: 2, - iso_day: 15, - expected_rel_iso: -2332, - expected_cyclic: 5, - expected_month: 1, - expected_day: 1, - }, - TestCase { - // This test case fails to match ICU - iso_year: -2332, - iso_month: 2, - iso_day: 14, - expected_rel_iso: -2333, - expected_cyclic: 4, - expected_month: 13, - expected_day: 30, - }, - TestCase { - // This test case fails to match ICU - iso_year: -2332, - iso_month: 1, - iso_day: 17, - expected_rel_iso: -2333, - expected_cyclic: 4, - expected_month: 13, - expected_day: 2, - }, - TestCase { - // This test case fails to match ICU - iso_year: -2332, - iso_month: 1, - iso_day: 16, - expected_rel_iso: -2333, - expected_cyclic: 4, - expected_month: 13, - expected_day: 1, - }, - TestCase { - iso_year: -2332, - iso_month: 1, - iso_day: 15, - expected_rel_iso: -2333, - expected_cyclic: 4, - expected_month: 12, - expected_day: 29, - }, - TestCase { - iso_year: -2332, - iso_month: 1, - iso_day: 1, - expected_rel_iso: -2333, - expected_cyclic: 4, - expected_month: 12, - expected_day: 15, - }, - TestCase { - iso_year: -2333, - iso_month: 1, - iso_day: 16, - expected_rel_iso: -2334, - expected_cyclic: 3, - expected_month: 12, - expected_day: 19, - }, - ]; - - let chinese_calculating = Chinese::new_always_calculating(); - let chinese_cached = Chinese::new(); - - for case in cases { - let iso = Date::try_new_iso(case.iso_year, case.iso_month, case.iso_day).unwrap(); - - do_twice( - &chinese_calculating, - &chinese_cached, - |chinese, calendar_type| { - let chinese = iso.to_calendar(chinese); - let chinese_rel_iso = chinese.cyclic_year().related_iso; - let chinese_cyclic = chinese.cyclic_year().year; - let chinese_month = chinese.month().ordinal; - let chinese_day = chinese.day_of_month().0; - - assert_eq!( - chinese_rel_iso, case.expected_rel_iso, - "[{calendar_type}] Related ISO failed for test case: {case:?}" - ); - assert_eq!( - chinese_cyclic, case.expected_cyclic, - "[{calendar_type}] Cyclic year failed for test case: {case:?}" - ); - assert_eq!( - chinese_month, case.expected_month, - "[{calendar_type}] Month failed for test case: {case:?}" - ); - assert_eq!( - chinese_day, case.expected_day, - "[{calendar_type}] Day failed for test case: {case:?}" - ); - }, - ); - } - } -} diff --git a/deps/crates/vendor/icu_calendar/src/cal/chinese_based.rs b/deps/crates/vendor/icu_calendar/src/cal/chinese_based.rs deleted file mode 100644 index 08ca5c81620104..00000000000000 --- a/deps/crates/vendor/icu_calendar/src/cal/chinese_based.rs +++ /dev/null @@ -1,446 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -//! This module contains types and traits for use in the Chinese traditional lunar calendar, -//! as well as in related and derived calendars such as the Korean and Vietnamese lunar calendars. - -use crate::{ - calendar_arithmetic::{ArithmeticDate, CalendarArithmetic, PrecomputedDataSource}, - error::DateError, - provider::chinese_based::{ChineseBasedCache, PackedChineseBasedYearInfo}, - types::{MonthCode, MonthInfo}, - Calendar, Iso, -}; - -use calendrical_calculations::chinese_based::{self, ChineseBased, YearBounds}; -use calendrical_calculations::rata_die::RataDie; -use core::marker::PhantomData; -use tinystr::tinystr; - -/// The trait ChineseBased is used by Chinese-based calendars to perform computations shared by such calendar. -/// -/// For an example of how to use this trait, see `impl ChineseBasedWithDataLoading for Chinese` in [`Chinese`]. -pub(crate) trait ChineseBasedWithDataLoading: Calendar { - type CB: ChineseBased; - /// Get the compiled const data for a ChineseBased calendar; can return `None` if the given year - /// does not correspond to any compiled data. - fn get_precomputed_data(&self) -> ChineseBasedPrecomputedData<'_, Self::CB>; -} - -/// Contains any loaded precomputed data. If constructed with Default, will -/// *not* contain any extra data and will always compute stuff from scratch -#[derive(Default)] -pub(crate) struct ChineseBasedPrecomputedData<'a, CB: ChineseBased> { - data: Option<&'a ChineseBasedCache<'a>>, - _cb: PhantomData, -} - -impl PrecomputedDataSource - for ChineseBasedPrecomputedData<'_, CB> -{ - fn load_or_compute_info(&self, related_iso: i32) -> ChineseBasedYearInfo { - self.data - .and_then(|d| { - Some(ChineseBasedYearInfo { - packed_data: d - .data - .get(usize::try_from(related_iso - d.first_related_iso_year).ok()?)?, - related_iso, - }) - }) - .unwrap_or_else(|| ChineseBasedYearInfo::compute::(related_iso)) - } -} - -impl<'b, CB: ChineseBased> ChineseBasedPrecomputedData<'b, CB> { - pub(crate) fn new(data: Option<&'b ChineseBasedCache<'b>>) -> Self { - Self { - data, - _cb: PhantomData, - } - } - - /// Given an ISO date (in both ArithmeticDate and R.D. format), returns the ChineseBasedYearInfo and extended year for that date, loading - /// from cache or computing. - pub(crate) fn load_or_compute_info_for_rd( - &self, - rd: RataDie, - iso: ArithmeticDate, - ) -> ChineseBasedYearInfo { - if let Some(cached) = self.data.and_then(|d| { - let delta = usize::try_from(iso.year - d.first_related_iso_year).ok()?; - if delta == 0 { - return None; - } - - let packed_data = d.data.get(delta)?; - if iso.day_of_year().0 > packed_data.ny_offset() as u16 { - Some(ChineseBasedYearInfo { - packed_data, - related_iso: iso.year, - }) - } else { - // We're dealing with an ISO day in the beginning of the year, before Chinese New Year. - // Return data for the previous Chinese year instead. - if delta <= 1 { - return None; - } - Some(ChineseBasedYearInfo { - packed_data: d.data.get(delta - 1)?, - related_iso: iso.year - 1, - }) - } - }) { - return cached; - }; - // compute - - let mid_year = calendrical_calculations::iso::fixed_from_iso(iso.year, 7, 1); - let year_bounds = YearBounds::compute::(mid_year); - let YearBounds { new_year, .. } = year_bounds; - if rd >= new_year { - ChineseBasedYearInfo::compute_with_yb::(iso.year, year_bounds) - } else { - ChineseBasedYearInfo::compute::(iso.year - 1) - } - } -} - -/// A data struct used to load and use information for a set of ChineseBasedDates -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] -// TODO(#3933): potentially make this smaller -pub(crate) struct ChineseBasedYearInfo { - /// Contains: - /// - length of each month in the year - /// - whether or not there is a leap month, and which month it is - /// - the date of Chinese New Year in the related ISO year - packed_data: PackedChineseBasedYearInfo, - pub(crate) related_iso: i32, -} - -impl From for i32 { - fn from(value: ChineseBasedYearInfo) -> Self { - value.related_iso - } -} - -impl ChineseBasedYearInfo { - /// Compute ChineseBasedYearInfo for a given extended year - fn compute(related_iso: i32) -> Self { - let mid_year = calendrical_calculations::iso::fixed_from_iso(related_iso, 7, 1); - let year_bounds = YearBounds::compute::(mid_year); - Self::compute_with_yb::(related_iso, year_bounds) - } - - /// Compute ChineseBasedYearInfo for a given extended year, for which you have already computed the YearBounds - fn compute_with_yb(related_iso: i32, year_bounds: YearBounds) -> Self { - let YearBounds { - new_year, - next_new_year, - .. - } = year_bounds; - let (month_lengths, leap_month) = - chinese_based::month_structure_for_year::(new_year, next_new_year); - - let ny_offset = new_year - calendrical_calculations::iso::fixed_from_iso(related_iso, 1, 1); - Self { - packed_data: PackedChineseBasedYearInfo::new(month_lengths, leap_month, ny_offset), - related_iso, - } - } - - /// Get the new year R.D. - pub(crate) fn new_year(self) -> RataDie { - calendrical_calculations::iso::fixed_from_iso(self.related_iso, 1, 1) - + self.packed_data.ny_offset() as i64 - } - - /// Get the next new year R.D. - fn next_new_year(self) -> RataDie { - self.new_year() + i64::from(self.days_in_year()) - } - - /// Get which month is the leap month. This produces the month *number* - /// that is the leap month (not the ordinal month). In other words, for - /// a year with an M05L, this will return Some(5). Note that the regular month precedes - /// the leap month. - fn leap_month(self) -> Option { - self.packed_data.leap_month() - } - - /// The last day of year in the previous month. - /// `month` is 1-indexed, and the returned value is also - /// a 1-indexed day of year - /// - /// Will be zero for the first month as the last day of the previous month - /// is not in this year - fn last_day_of_previous_month(self, month: u8) -> u16 { - debug_assert!((1..=13).contains(&month), "Month out of bounds!"); - // Get the last day of the previous month. - // Since `month` is 1-indexed, this needs to check if the month is 1 for the zero case - if month == 1 { - 0 - } else { - self.packed_data.last_day_of_month(month - 1) - } - } - - fn days_in_year(self) -> u16 { - self.last_day_of_month(self.months_in_year()) - } - - /// Return the number of months in a given year, which is 13 in a leap year, and 12 in a common year. - fn months_in_year(self) -> u8 { - if self.leap_month().is_some() { - 13 - } else { - 12 - } - } - - /// The last day of year in the current month. - /// `month` is 1-indexed, and the returned value is also - /// a 1-indexed day of year - /// - /// Will be zero for the first month as the last day of the previous month - /// is not in this year - fn last_day_of_month(self, month: u8) -> u16 { - debug_assert!((1..=13).contains(&month), "Month out of bounds!"); - self.packed_data.last_day_of_month(month) - } - - fn days_in_month(self, month: u8) -> u8 { - if self.packed_data.month_has_30_days(month) { - 30 - } else { - 29 - } - } - - pub(crate) fn md_from_rd(self, rd: RataDie) -> (u8, u8) { - debug_assert!( - rd < self.next_new_year(), - "Stored date {rd:?} out of bounds!" - ); - // 1-indexed day of year - let day_of_year = u16::try_from(rd - self.new_year() + 1); - debug_assert!(day_of_year.is_ok(), "Somehow got a very large year in data"); - let day_of_year = day_of_year.unwrap_or(1); - let mut month = 1; - // TODO(#3933) perhaps use a binary search - for iter_month in 1..=13 { - month = iter_month; - if self.last_day_of_month(iter_month) >= day_of_year { - break; - } - } - - debug_assert!((1..=13).contains(&month), "Month out of bounds!"); - - debug_assert!( - month < 13 || self.leap_month().is_some(), - "Cannot have 13 months in a non-leap year!" - ); - let day_before_month_start = self.last_day_of_previous_month(month); - let day_of_month = day_of_year - day_before_month_start; - let day_of_month = u8::try_from(day_of_month); - debug_assert!(day_of_month.is_ok(), "Month too big!"); - let day_of_month = day_of_month.unwrap_or(1); - - (month, day_of_month) - } - - pub(crate) fn rd_from_md(self, month: u8, day: u8) -> RataDie { - self.new_year() + self.day_of_year(month, day) as i64 - 1 - } - - /// Calculate the number of days in the year so far for a ChineseBasedDate; - /// similar to `CalendarArithmetic::day_of_year` - pub(crate) fn day_of_year(self, month: u8, day: u8) -> u16 { - self.last_day_of_previous_month(month) + day as u16 - } - - /// The calendar-specific month code represented by `month`; - /// since the Chinese calendar has leap months, an "L" is appended to the month code for - /// leap months. For example, in a year where an intercalary month is added after the second - /// month, the month codes for ordinal months 1, 2, 3, 4, 5 would be "M01", "M02", "M02L", "M03", "M04". - pub(crate) fn month(self, month: u8) -> MonthInfo { - // 1 indexed leap month name. This is also the ordinal for the leap month - // in the year (e.g. in `M01, M01L, M02, ..`, the leap month is for month 1, and it is also - // ordinally `month 2`, zero-indexed) - // 14 is a sentinel value - let leap_month = self.leap_month().unwrap_or(14); - let code_inner = if leap_month == month { - // Month cannot be 1 because a year cannot have a leap month before the first actual month, - // and the maximum num of months ina leap year is 13. - debug_assert!((2..=13).contains(&month)); - match month { - 2 => tinystr!(4, "M01L"), - 3 => tinystr!(4, "M02L"), - 4 => tinystr!(4, "M03L"), - 5 => tinystr!(4, "M04L"), - 6 => tinystr!(4, "M05L"), - 7 => tinystr!(4, "M06L"), - 8 => tinystr!(4, "M07L"), - 9 => tinystr!(4, "M08L"), - 10 => tinystr!(4, "M09L"), - 11 => tinystr!(4, "M10L"), - 12 => tinystr!(4, "M11L"), - 13 => tinystr!(4, "M12L"), - _ => tinystr!(4, "und"), - } - } else { - let mut adjusted_ordinal = month; - if month > leap_month { - // Before adjusting for leap month, if ordinal > leap_month, - // the month cannot be 1 because this implies the leap month is < 1, which is impossible; - // cannot be 2 because that implies the leap month is = 1, which is impossible, - // and cannot be more than 13 because max number of months in a year is 13. - debug_assert!((2..=13).contains(&month)); - adjusted_ordinal -= 1; - } - debug_assert!((1..=12).contains(&adjusted_ordinal)); - match adjusted_ordinal { - 1 => tinystr!(4, "M01"), - 2 => tinystr!(4, "M02"), - 3 => tinystr!(4, "M03"), - 4 => tinystr!(4, "M04"), - 5 => tinystr!(4, "M05"), - 6 => tinystr!(4, "M06"), - 7 => tinystr!(4, "M07"), - 8 => tinystr!(4, "M08"), - 9 => tinystr!(4, "M09"), - 10 => tinystr!(4, "M10"), - 11 => tinystr!(4, "M11"), - 12 => tinystr!(4, "M12"), - _ => tinystr!(4, "und"), - } - }; - let code = MonthCode(code_inner); - MonthInfo { - ordinal: month, - standard_code: code, - formatting_code: code, - } - } - - /// Create a new arithmetic date from a year, month ordinal, and day with bounds checking; returns the - /// result of creating this arithmetic date, as well as a ChineseBasedYearInfo - either the one passed in - /// optionally as an argument, or a new ChineseBasedYearInfo for the given year, month, and day args. - pub(crate) fn validate_md(self, month: u8, day: u8) -> Result<(), DateError> { - let max_month = self.months_in_year(); - if month == 0 || !(1..=max_month).contains(&month) { - return Err(DateError::Range { - field: "month", - value: month as i32, - min: 1, - max: max_month as i32, - }); - } - - let max_day = self.days_in_month(month); - if day == 0 || day > max_day { - return Err(DateError::Range { - field: "day", - value: day as i32, - min: 1, - max: max_day as i32, - }); - } - Ok(()) - } - - /// Get the ordinal lunar month from a code for chinese-based calendars. - pub(crate) fn parse_month_code(self, code: MonthCode) -> Option { - // 14 is a sentinel value, greater than all other months, for the purpose of computation only; - // it is impossible to actually have 14 months in a year. - let leap_month = self.leap_month().unwrap_or(14); - - if code.0.len() < 3 { - return None; - } - let bytes = code.0.all_bytes(); - if bytes[0] != b'M' { - return None; - } - if code.0.len() == 4 && bytes[3] != b'L' { - return None; - } - // Unadjusted is zero-indexed month index, must add one to it to use - let mut unadjusted = 0; - if bytes[1] == b'0' { - if bytes[2] >= b'1' && bytes[2] <= b'9' { - unadjusted = bytes[2] - b'0'; - } - } else if bytes[1] == b'1' && bytes[2] >= b'0' && bytes[2] <= b'2' { - unadjusted = 10 + bytes[2] - b'0'; - } - if bytes[3] == b'L' { - // Asked for a leap month that doesn't exist - if unadjusted + 1 != leap_month { - return None; - } else { - // The leap month occurs after the regular month of the same name - return Some(unadjusted + 1); - } - } - if unadjusted != 0 { - // If the month has an index greater than that of the leap month, - // bump it up by one - if unadjusted + 1 > leap_month { - return Some(unadjusted + 1); - } else { - return Some(unadjusted); - } - } - None - } -} - -impl CalendarArithmetic for C { - type YearInfo = ChineseBasedYearInfo; - - fn days_in_provided_month(year: ChineseBasedYearInfo, month: u8) -> u8 { - year.days_in_month(month) - } - - /// Returns the number of months in a given year, which is 13 in a leap year, and 12 in a common year. - fn months_in_provided_year(year: ChineseBasedYearInfo) -> u8 { - year.months_in_year() - } - - /// Returns true if the given year is a leap year, and false if not. - fn provided_year_is_leap(year: ChineseBasedYearInfo) -> bool { - year.leap_month().is_some() - } - - /// Returns the (month, day) of the last day in a Chinese year (the day before Chinese New Year). - /// The last month in a year will always be 12 in a common year or 13 in a leap year. The day is - /// determined by finding the day immediately before the next new year and calculating the number - /// of days since the last new moon (beginning of the last month in the year). - fn last_month_day_in_provided_year(year: ChineseBasedYearInfo) -> (u8, u8) { - if year.leap_month().is_some() { - (13, year.days_in_month(13)) - } else { - (12, year.days_in_month(12)) - } - } - - fn days_in_provided_year(year: ChineseBasedYearInfo) -> u16 { - year.days_in_year() - } -} - -#[cfg(feature = "datagen")] -impl ChineseBasedCache<'_> { - /// Compute this data for a range of years - pub fn compute_for(related_isos: core::ops::Range) -> Self { - ChineseBasedCache { - first_related_iso_year: related_isos.start, - data: related_isos - .map(|related_iso| ChineseBasedYearInfo::compute::(related_iso).packed_data) - .collect(), - } - } -} diff --git a/deps/crates/vendor/icu_calendar/src/cal/coptic.rs b/deps/crates/vendor/icu_calendar/src/cal/coptic.rs index 4eb8bd7f148909..3878168f9c9b4b 100644 --- a/deps/crates/vendor/icu_calendar/src/cal/coptic.rs +++ b/deps/crates/vendor/icu_calendar/src/cal/coptic.rs @@ -2,46 +2,49 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -//! This module contains types and implementations for the Coptic calendar. -//! -//! ```rust -//! use icu::calendar::{cal::Coptic, Date}; -//! -//! let date_iso = Date::try_new_iso(1970, 1, 2) -//! .expect("Failed to initialize ISO Date instance."); -//! let date_coptic = Date::new_from_iso(date_iso, Coptic); -//! -//! assert_eq!(date_coptic.era_year().year, 1686); -//! assert_eq!(date_coptic.month().ordinal, 4); -//! assert_eq!(date_coptic.day_of_month().0, 24); -//! ``` - -use crate::cal::iso::{Iso, IsoDateInner}; -use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic}; -use crate::error::DateError; -use crate::{types, Calendar, Date, DateDuration, DateDurationUnit, RangeError}; +use crate::calendar_arithmetic::ArithmeticDate; +use crate::calendar_arithmetic::DateFieldsResolver; +use crate::error::{ + DateError, DateFromFieldsError, EcmaReferenceYearError, MonthCodeError, UnknownEraError, +}; +use crate::options::DateFromFieldsOptions; +use crate::options::{DateAddOptions, DateDifferenceOptions}; +use crate::{types, Calendar, Date, RangeError}; use calendrical_calculations::helpers::I32CastError; use calendrical_calculations::rata_die::RataDie; use tinystr::tinystr; -/// The [Coptic Calendar] +/// The [Coptic Calendar](https://en.wikipedia.org/wiki/Coptic_calendar) /// -/// The [Coptic calendar] is a solar calendar used by the Coptic Orthodox Church, with twelve normal months -/// and a thirteenth small epagomenal month. +/// The Coptic calendar, also called the Alexandrian Calendar, is a solar calendar that +/// is influenced by both the ancient Egpytian calendar and the [`Julian`](crate::cal::Julian) +/// calendar. It was introduced in Egypt under Roman rule in the first century BCE, and +/// replaced for civil use in 1875, however continues to be used liturgically. /// -/// This type can be used with [`Date`] to represent dates in this calendar. +/// This implementation extends proleptically for dates before the calendar's creation. /// -/// [Coptic calendar]: https://en.wikipedia.org/wiki/Coptic_calendar +/// This corresponds to the `"coptic"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). /// /// # Era codes /// /// This calendar uses a single code: `am`, corresponding to the After Diocletian/Anno Martyrum /// era. 1 A.M. is equivalent to 284 C.E. /// -/// # Month codes +/// # Months and days /// -/// This calendar supports 13 solar month codes (`"M01" - "M13"`), with `"M13"` being used for the short epagomenal month -/// at the end of the year. +/// The 13 months are called Thout (`M01`, 30 days), Paopi (`M02`, 30 days), Hathor (`M03`, 30 days), +/// Koiak (`M04`, 30 days), Tobi (`M05`, 30 days), Meshir (`M06`, 30 days), Paremhat (`M07`, 30 days), +/// Parmouti (`M08`, 30 days), Pashons (`M09`, 30 days), Paoni (`M10`, 30 days), Epip (`M11`, 30 days), +/// Mesori (`M12`, 30 days), Pi Kogi Enavot (`M13`, 5 days). +/// +/// In leap years (years divisible by 4), Pi Kogi Enavot gains a 6th day. +/// +/// Standard years thus have 365 days, and leap years 366. +/// +/// # Calendar drift +/// +/// The Coptic calendar has the same year lengths and leap year rules as the Julian calendar, +/// so it experiences the same drift of 1 day in ~128 years with respect to the seasons. #[derive(Copy, Clone, Debug, Hash, Default, Eq, PartialEq, PartialOrd, Ord)] #[allow(clippy::exhaustive_structs)] // this type is stable pub struct Coptic; @@ -50,14 +53,14 @@ pub struct Coptic; #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] pub struct CopticDateInner(pub(crate) ArithmeticDate); -impl CalendarArithmetic for Coptic { +impl DateFieldsResolver for Coptic { type YearInfo = i32; fn days_in_provided_month(year: i32, month: u8) -> u8 { if (1..=12).contains(&month) { 30 } else if month == 13 { - if Self::provided_year_is_leap(year) { + if year.rem_euclid(4) == 3 { 6 } else { 5 @@ -70,25 +73,66 @@ impl CalendarArithmetic for Coptic { fn months_in_provided_year(_: i32) -> u8 { 13 } + #[inline] + fn year_info_from_era( + &self, + era: &[u8], + era_year: i32, + ) -> Result { + match era { + b"am" => Ok(era_year), + _ => Err(UnknownEraError), + } + } - fn provided_year_is_leap(year: i32) -> bool { - year.rem_euclid(4) == 3 + #[inline] + fn year_info_from_extended(&self, extended_year: i32) -> Self::YearInfo { + extended_year } - fn last_month_day_in_provided_year(year: i32) -> (u8, u8) { - if Self::provided_year_is_leap(year) { - (13, 6) - } else { - (13, 5) + #[inline] + fn reference_year_from_month_day( + &self, + month_code: types::ValidMonthCode, + day: u8, + ) -> Result { + Coptic::reference_year_from_month_day(month_code, day) + } + + #[inline] + fn ordinal_month_from_code( + &self, + _year: &Self::YearInfo, + month_code: types::ValidMonthCode, + _options: DateFromFieldsOptions, + ) -> Result { + match month_code.to_tuple() { + (month_number @ 1..=13, false) => Ok(month_number), + _ => Err(MonthCodeError::NotInCalendar), } } +} - fn days_in_provided_year(year: i32) -> u16 { - if Self::provided_year_is_leap(year) { - 366 +impl Coptic { + pub(crate) fn reference_year_from_month_day( + month_code: types::ValidMonthCode, + day: u8, + ) -> Result { + let (ordinal_month, false) = month_code.to_tuple() else { + return Err(EcmaReferenceYearError::MonthCodeNotInCalendar); + }; + // December 31, 1972 occurs on 4th month, 22nd day, 1689 AM + let anno_martyrum_year = if ordinal_month < 4 || (ordinal_month == 4 && day <= 22) { + 1689 + // Note: this must be >=6, not just == 6, since we have not yet + // applied a potential Overflow::Constrain. + } else if ordinal_month == 13 && day >= 6 { + // 1687 AM is a leap year + 1687 } else { - 365 - } + 1688 + }; + Ok(anno_martyrum_year) } } @@ -96,6 +140,8 @@ impl crate::cal::scaffold::UnstableSealed for Coptic {} impl Calendar for Coptic { type DateInner = CopticDateInner; type Year = types::EraYear; + type DifferenceError = core::convert::Infallible; + fn from_codes( &self, era: Option<&str>, @@ -103,19 +149,23 @@ impl Calendar for Coptic { month_code: types::MonthCode, day: u8, ) -> Result { - let year = match era { - Some("am") | None => year, - Some(_) => return Err(DateError::UnknownEra), - }; + ArithmeticDate::from_codes(era, year, month_code, day, self).map(CopticDateInner) + } - ArithmeticDate::new_from_codes(self, year, month_code, day).map(CopticDateInner) + #[cfg(feature = "unstable")] + fn from_fields( + &self, + fields: types::DateFields, + options: DateFromFieldsOptions, + ) -> Result { + ArithmeticDate::from_fields(fields, options, self).map(CopticDateInner) } fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { CopticDateInner( match calendrical_calculations::coptic::coptic_from_fixed(rd) { - Err(I32CastError::BelowMin) => ArithmeticDate::min_date(), - Err(I32CastError::AboveMax) => ArithmeticDate::max_date(), + Err(I32CastError::BelowMin) => ArithmeticDate::new_unchecked(i32::MIN, 1, 1), + Err(I32CastError::AboveMax) => ArithmeticDate::new_unchecked(i32::MAX, 13, 6), Ok((year, month, day)) => ArithmeticDate::new_unchecked(year, month, day), }, ) @@ -125,70 +175,71 @@ impl Calendar for Coptic { calendrical_calculations::coptic::fixed_from_coptic(date.0.year, date.0.month, date.0.day) } - fn from_iso(&self, iso: IsoDateInner) -> CopticDateInner { - self.from_rata_die(Iso.to_rata_die(&iso)) - } - - fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { - Iso.from_rata_die(self.to_rata_die(date)) + fn has_cheap_iso_conversion(&self) -> bool { + false } fn months_in_year(&self, date: &Self::DateInner) -> u8 { - date.0.months_in_year() + Self::months_in_provided_year(date.0.year) } fn days_in_year(&self, date: &Self::DateInner) -> u16 { - date.0.days_in_year() + if self.is_in_leap_year(date) { + 366 + } else { + 365 + } } fn days_in_month(&self, date: &Self::DateInner) -> u8 { - date.0.days_in_month() + Self::days_in_provided_month(date.0.year, date.0.month) } - fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) { - date.0.offset_date(offset, &()); + #[cfg(feature = "unstable")] + fn add( + &self, + date: &Self::DateInner, + duration: types::DateDuration, + options: DateAddOptions, + ) -> Result { + date.0.added(duration, self, options).map(CopticDateInner) } - #[allow(clippy::field_reassign_with_default)] + #[cfg(feature = "unstable")] fn until( &self, date1: &Self::DateInner, date2: &Self::DateInner, - _calendar2: &Self, - _largest_unit: DateDurationUnit, - _smallest_unit: DateDurationUnit, - ) -> DateDuration { - date1.0.until(date2.0, _largest_unit, _smallest_unit) + options: DateDifferenceOptions, + ) -> Result { + Ok(date1.0.until(&date2.0, self, options)) } fn year_info(&self, date: &Self::DateInner) -> Self::Year { - let year = self.extended_year(date); + let year = date.0.year; types::EraYear { era: tinystr!(16, "am"), era_index: Some(0), year, + extended_year: year, ambiguity: types::YearAmbiguity::CenturyRequired, } } - fn extended_year(&self, date: &Self::DateInner) -> i32 { - date.0.extended_year() - } - fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { - Self::provided_year_is_leap(date.0.year) + date.0.year.rem_euclid(4) == 3 } fn month(&self, date: &Self::DateInner) -> types::MonthInfo { - date.0.month() + types::MonthInfo::non_lunisolar(date.0.month) } fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { - date.0.day_of_month() + types::DayOfMonth(date.0.day) } fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear { - date.0.day_of_year() + types::DayOfYear(30 * (date.0.month as u16 - 1) + date.0.day as u16) } fn debug_name(&self) -> &'static str { @@ -214,7 +265,7 @@ impl Date { /// assert_eq!(date_coptic.day_of_month().0, 6); /// ``` pub fn try_new_coptic(year: i32, month: u8, day: u8) -> Result, RangeError> { - ArithmeticDate::new_from_ordinals(year, month, day) + ArithmeticDate::try_from_ymd(year, month, day) .map(CopticDateInner) .map(|inner| Date::from_raw(inner, Coptic)) } @@ -223,6 +274,9 @@ impl Date { #[cfg(test)] mod tests { use super::*; + use crate::options::{DateFromFieldsOptions, MissingFieldsStrategy, Overflow}; + use crate::types::DateFields; + #[test] fn test_coptic_regression() { // https://github.com/unicode-org/icu4x/issues/2254 @@ -231,4 +285,23 @@ mod tests { let recovered_iso = coptic.to_iso(); assert_eq!(iso_date, recovered_iso); } + + #[test] + fn test_from_fields_monthday_constrain() { + // M13-7 is not a real day, however this should resolve to M12-6 + // with Overflow::Constrain + let fields = DateFields { + month_code: Some(b"M13"), + day: Some(7), + ..Default::default() + }; + let options = DateFromFieldsOptions { + overflow: Some(Overflow::Constrain), + missing_fields_strategy: Some(MissingFieldsStrategy::Ecma), + ..Default::default() + }; + + let date = Date::try_from_fields(fields, options, Coptic).unwrap(); + assert_eq!(date.day_of_month().0, 6, "Day was successfully constrained"); + } } diff --git a/deps/crates/vendor/icu_calendar/src/cal/dangi.rs b/deps/crates/vendor/icu_calendar/src/cal/dangi.rs deleted file mode 100644 index e0eef839a53d85..00000000000000 --- a/deps/crates/vendor/icu_calendar/src/cal/dangi.rs +++ /dev/null @@ -1,932 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -//! This module contains types and implementations for the Korean Dangi calendar. -//! -//! ```rust -//! use icu::calendar::cal::Dangi; -//! use icu::calendar::Date; -//! -//! let dangi = Dangi::new(); -//! let dangi_date = Date::try_new_dangi_with_calendar(2023, 6, 6, dangi) -//! .expect("Failed to initialize Dangi Date instance."); -//! -//! assert_eq!(dangi_date.cyclic_year().related_iso, 2023); -//! assert_eq!(dangi_date.cyclic_year().year, 40); -//! assert_eq!(dangi_date.month().ordinal, 6); -//! assert_eq!(dangi_date.day_of_month().0, 6); -//! ``` - -use crate::cal::chinese_based::{ChineseBasedPrecomputedData, ChineseBasedWithDataLoading}; -use crate::cal::iso::{Iso, IsoDateInner}; -use crate::calendar_arithmetic::PrecomputedDataSource; -use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic}; -use crate::error::DateError; -use crate::provider::chinese_based::CalendarDangiV1; -use crate::types::CyclicYear; -use crate::AsCalendar; -use crate::{types, Calendar, Date}; -use calendrical_calculations::chinese_based; -use calendrical_calculations::rata_die::RataDie; -use core::cmp::Ordering; -use icu_provider::prelude::*; - -/// The [Traditional Korean (Dangi) Calendar](https://en.wikipedia.org/wiki/Korean_calendar) -/// -/// The Dangi Calendar is a lunisolar calendar used traditionally in North and South Korea. -/// It is often used today to track important cultural events and holidays like Seollal -/// (Korean lunar new year). It is similar to the Chinese lunar calendar (see [`Chinese`](super::Chinese)), -/// except that observations are based in Korea (currently UTC+9) rather than China (UTC+8). -/// This can cause some differences; for example, 2012 was a leap year, but in the Dangi -/// calendar the leap month was 3, while in the Chinese calendar the leap month was 4. -/// -/// This calendar is currently in a preview state: formatting for this calendar is not -/// going to be perfect. -/// -/// ```rust -/// use icu::calendar::cal::{Chinese, Dangi}; -/// use icu::calendar::Date; -/// use tinystr::tinystr; -/// -/// let iso_a = Date::try_new_iso(2012, 4, 23).unwrap(); -/// let dangi_a = iso_a.to_calendar(Dangi::new()); -/// let chinese_a = iso_a.to_calendar(Chinese::new()); -/// -/// assert_eq!(dangi_a.month().standard_code.0, tinystr!(4, "M03L")); -/// assert_eq!(chinese_a.month().standard_code.0, tinystr!(4, "M04")); -/// -/// let iso_b = Date::try_new_iso(2012, 5, 23).unwrap(); -/// let dangi_b = iso_b.to_calendar(Dangi::new()); -/// let chinese_b = iso_b.to_calendar(Chinese::new()); -/// -/// assert_eq!(dangi_b.month().standard_code.0, tinystr!(4, "M04")); -/// assert_eq!(chinese_b.month().standard_code.0, tinystr!(4, "M04L")); -/// ``` -/// # Era codes -/// -/// This calendar does not use era codes. -/// -/// # Month codes -/// -/// This calendar is a lunisolar calendar. It supports regular month codes `"M01" - "M12"` as well -/// as leap month codes `"M01L" - "M12L"`. -#[derive(Clone, Debug, Default)] -pub struct Dangi { - data: Option>, -} - -/// The inner date type used for representing [`Date`]s of [`Dangi`]. See [`Date`] and [`Dangi`] for more detail. -#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)] -pub struct DangiDateInner(ArithmeticDate); - -// we want these impls without the `C: Copy/Clone` bounds -impl Copy for DangiDateInner {} -impl Clone for DangiDateInner { - fn clone(&self) -> Self { - *self - } -} - -// These impls just make custom derives on types containing C -// work. They're basically no-ops -impl PartialEq for Dangi { - fn eq(&self, _: &Self) -> bool { - true - } -} -impl Eq for Dangi {} -#[allow(clippy::non_canonical_partial_ord_impl)] // this is intentional -impl PartialOrd for Dangi { - fn partial_cmp(&self, _: &Self) -> Option { - Some(Ordering::Equal) - } -} - -impl Ord for Dangi { - fn cmp(&self, _: &Self) -> Ordering { - Ordering::Equal - } -} - -impl Dangi { - /// Creates a new [`Dangi`] with some precomputed calendrical calculations. - /// - /// ✨ *Enabled with the `compiled_data` Cargo feature.* - /// - /// [📚 Help choosing a constructor](icu_provider::constructors) - #[cfg(feature = "compiled_data")] - pub const fn new() -> Self { - Self { - data: Some(DataPayload::from_static_ref( - crate::provider::Baked::SINGLETON_CALENDAR_DANGI_V1, - )), - } - } - - icu_provider::gen_buffer_data_constructors!(() -> error: DataError, - functions: [ - new: skip, - try_new_with_buffer_provider, - try_new_unstable, - Self, - ]); - - #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new)] - pub fn try_new_unstable + ?Sized>( - provider: &D, - ) -> Result { - Ok(Self { - data: Some(provider.load(Default::default())?.payload), - }) - } - - /// Construct a new [`Dangi`] without any precomputed calendrical calculations. - pub fn new_always_calculating() -> Self { - Dangi { data: None } - } - - pub(crate) const DEBUG_NAME: &'static str = "Dangi"; -} - -impl crate::cal::scaffold::UnstableSealed for Dangi {} -impl Calendar for Dangi { - type DateInner = DangiDateInner; - type Year = CyclicYear; - - fn from_codes( - &self, - era: Option<&str>, - year: i32, - month_code: crate::types::MonthCode, - day: u8, - ) -> Result { - match era { - None => {} - _ => return Err(DateError::UnknownEra), - } - - let year = self.get_precomputed_data().load_or_compute_info(year); - - let Some(month) = year.parse_month_code(month_code) else { - return Err(DateError::UnknownMonthCode(month_code)); - }; - - year.validate_md(month, day)?; - - Ok(DangiDateInner(ArithmeticDate::new_unchecked( - year, month, day, - ))) - } - - fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { - let iso = Iso.from_rata_die(rd); - let y = self - .get_precomputed_data() - .load_or_compute_info_for_rd(rd, iso.0); - let (m, d) = y.md_from_rd(rd); - DangiDateInner(ArithmeticDate::new_unchecked(y, m, d)) - } - - fn to_rata_die(&self, date: &Self::DateInner) -> RataDie { - date.0.year.rd_from_md(date.0.month, date.0.day) - } - - fn from_iso(&self, iso: IsoDateInner) -> Self::DateInner { - let rd = Iso.to_rata_die(&iso); - let y = self - .get_precomputed_data() - .load_or_compute_info_for_rd(rd, iso.0); - let (m, d) = y.md_from_rd(rd); - DangiDateInner(ArithmeticDate::new_unchecked(y, m, d)) - } - - fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { - Iso.from_rata_die(self.to_rata_die(date)) - } - - fn months_in_year(&self, date: &Self::DateInner) -> u8 { - date.0.months_in_year() - } - - fn days_in_year(&self, date: &Self::DateInner) -> u16 { - date.0.days_in_year() - } - - fn days_in_month(&self, date: &Self::DateInner) -> u8 { - date.0.days_in_month() - } - - fn offset_date(&self, date: &mut Self::DateInner, offset: crate::DateDuration) { - date.0.offset_date(offset, &self.get_precomputed_data()); - } - - fn until( - &self, - date1: &Self::DateInner, - date2: &Self::DateInner, - _calendar2: &Self, - largest_unit: crate::DateDurationUnit, - smallest_unit: crate::DateDurationUnit, - ) -> crate::DateDuration { - date1.0.until(date2.0, largest_unit, smallest_unit) - } - - fn debug_name(&self) -> &'static str { - Self::DEBUG_NAME - } - - fn year_info(&self, date: &Self::DateInner) -> Self::Year { - let year = date.0.year; - CyclicYear { - year: (year.related_iso as i64 - 4).rem_euclid(60) as u8 + 1, - related_iso: year.related_iso, - } - } - - fn extended_year(&self, date: &Self::DateInner) -> i32 { - chinese_based::extended_from_iso::(date.0.year.related_iso) - } - - fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { - Self::provided_year_is_leap(date.0.year) - } - - fn month(&self, date: &Self::DateInner) -> crate::types::MonthInfo { - date.0.year.month(date.0.month) - } - - fn day_of_month(&self, date: &Self::DateInner) -> crate::types::DayOfMonth { - date.0.day_of_month() - } - - fn day_of_year(&self, date: &Self::DateInner) -> crate::types::DayOfYear { - types::DayOfYear(date.0.year.day_of_year(date.0.month, date.0.day)) - } - - fn calendar_algorithm(&self) -> Option { - Some(crate::preferences::CalendarAlgorithm::Dangi) - } -} - -impl> Date { - /// Construct a new Dangi date from a `year`, `month`, and `day`. - /// `year` represents the [ISO](crate::Iso) year that roughly matches the Dangi year; - /// `month` represents the month of the year ordinally (ex. if it is a leap year, the last month will be 13, not 12); - /// `day` indicates day of month. - /// - /// This date will not use any precomputed calendrical calculations, - /// one that loads such data from a provider will be added in the future (#3933) - /// - /// ```rust - /// use icu::calendar::cal::Dangi; - /// use icu::calendar::Date; - /// - /// let dangi = Dangi::new(); - /// - /// let date_dangi = Date::try_new_dangi_with_calendar(2023, 6, 18, dangi) - /// .expect("Failed to initialize Dangi Date instance."); - /// - /// assert_eq!(date_dangi.cyclic_year().related_iso, 2023); - /// assert_eq!(date_dangi.cyclic_year().year, 40); - /// assert_eq!(date_dangi.month().ordinal, 6); - /// assert_eq!(date_dangi.day_of_month().0, 18); - /// ``` - pub fn try_new_dangi_with_calendar( - related_iso_year: i32, - month: u8, - day: u8, - calendar: A, - ) -> Result, DateError> { - let year = calendar - .as_calendar() - .get_precomputed_data() - .load_or_compute_info(related_iso_year); - year.validate_md(month, day)?; - Ok(Date::from_raw( - DangiDateInner(ArithmeticDate::new_unchecked(year, month, day)), - calendar, - )) - } -} - -impl ChineseBasedWithDataLoading for Dangi { - type CB = calendrical_calculations::chinese_based::Dangi; - fn get_precomputed_data(&self) -> ChineseBasedPrecomputedData { - ChineseBasedPrecomputedData::new(self.data.as_ref().map(|d| d.get())) - } -} - -#[cfg(test)] -mod test { - - use super::*; - use crate::cal::Chinese; - use calendrical_calculations::rata_die::RataDie; - - /// Run a test twice, with two calendars - fn do_twice( - dangi_calculating: &Dangi, - dangi_cached: &Dangi, - test: impl Fn(crate::Ref, &'static str), - ) { - test(crate::Ref(dangi_calculating), "calculating"); - test(crate::Ref(dangi_cached), "cached"); - } - - fn check_cyclic_and_rel_iso(year: i32) { - let iso = Date::try_new_iso(year, 6, 6).unwrap(); - let chinese = iso.to_calendar(Chinese::new_always_calculating()); - let dangi = iso.to_calendar(Dangi::new_always_calculating()); - let chinese_year = chinese.cyclic_year(); - let korean_year = dangi.cyclic_year(); - assert_eq!( - chinese_year, korean_year, - "Cyclic year failed for year: {year}" - ); - let chinese_rel_iso = chinese_year.related_iso; - let korean_rel_iso = korean_year.related_iso; - assert_eq!( - chinese_rel_iso, korean_rel_iso, - "Rel. ISO year equality failed for year: {year}" - ); - assert_eq!(korean_rel_iso, year, "Dangi Rel. ISO failed!"); - } - - #[test] - fn test_cyclic_same_as_chinese_near_present_day() { - for year in 1923..=2123 { - check_cyclic_and_rel_iso(year); - } - } - - #[test] - fn test_cyclic_same_as_chinese_near_rd_zero() { - for year in -100..=100 { - check_cyclic_and_rel_iso(year); - } - } - - #[test] - fn test_iso_to_dangi_roundtrip() { - let mut rd = -1963020; - let max_rd = 1963020; - let mut iters = 0; - let max_iters = 560; - let dangi_calculating = Dangi::new_always_calculating(); - let dangi_cached = Dangi::new(); - while rd < max_rd && iters < max_iters { - let rata_die = RataDie::new(rd); - let iso = Date::from_rata_die(rata_die, Iso); - do_twice(&dangi_calculating, &dangi_cached, |dangi, calendar_type| { - let korean = iso.to_calendar(dangi); - let result = korean.to_calendar(Iso); - assert_eq!( - iso, result, - "[{calendar_type}] Failed roundtrip ISO -> Dangi -> ISO for RD: {rd}" - ); - }); - - rd += 7043; - iters += 1; - } - } - - #[test] - fn test_dangi_consistent_with_icu() { - // Test cases for this test are derived from existing ICU Intl.DateTimeFormat. If there is a bug in ICU, - // these test cases may be affected, and this calendar's output may not be entirely valid. - - // There are a number of test cases which do not match ICU for dates very far in the past or future, - // see #3709. - - #[derive(Debug)] - struct TestCase { - iso_year: i32, - iso_month: u8, - iso_day: u8, - expected_rel_iso: i32, - expected_cyclic: u8, - expected_month: u8, - expected_day: u8, - } - - let cases = [ - TestCase { - // #3709: This test case fails to match ICU - iso_year: 4321, - iso_month: 1, - iso_day: 23, - expected_rel_iso: 4320, - expected_cyclic: 57, - expected_month: 13, - expected_day: 12, - }, - TestCase { - iso_year: 3649, - iso_month: 9, - iso_day: 20, - expected_rel_iso: 3649, - expected_cyclic: 46, - expected_month: 9, - expected_day: 1, - }, - TestCase { - iso_year: 3333, - iso_month: 3, - iso_day: 3, - expected_rel_iso: 3333, - expected_cyclic: 30, - expected_month: 1, - expected_day: 25, - }, - TestCase { - iso_year: 3000, - iso_month: 3, - iso_day: 30, - expected_rel_iso: 3000, - expected_cyclic: 57, - expected_month: 3, - expected_day: 3, - }, - TestCase { - iso_year: 2772, - iso_month: 7, - iso_day: 27, - expected_rel_iso: 2772, - expected_cyclic: 9, - expected_month: 7, - expected_day: 5, - }, - TestCase { - iso_year: 2525, - iso_month: 2, - iso_day: 25, - expected_rel_iso: 2525, - expected_cyclic: 2, - expected_month: 2, - expected_day: 3, - }, - TestCase { - iso_year: 2345, - iso_month: 3, - iso_day: 21, - expected_rel_iso: 2345, - expected_cyclic: 2, - expected_month: 2, - expected_day: 17, - }, - TestCase { - iso_year: 2222, - iso_month: 2, - iso_day: 22, - expected_rel_iso: 2222, - expected_cyclic: 59, - expected_month: 1, - expected_day: 11, - }, - TestCase { - iso_year: 2167, - iso_month: 6, - iso_day: 22, - expected_rel_iso: 2167, - expected_cyclic: 4, - expected_month: 5, - expected_day: 6, - }, - TestCase { - iso_year: 2121, - iso_month: 2, - iso_day: 12, - expected_rel_iso: 2120, - expected_cyclic: 17, - expected_month: 13, - expected_day: 25, - }, - TestCase { - iso_year: 2080, - iso_month: 12, - iso_day: 31, - expected_rel_iso: 2080, - expected_cyclic: 37, - expected_month: 12, - expected_day: 21, - }, - TestCase { - iso_year: 2030, - iso_month: 3, - iso_day: 20, - expected_rel_iso: 2030, - expected_cyclic: 47, - expected_month: 2, - expected_day: 17, - }, - TestCase { - iso_year: 2027, - iso_month: 2, - iso_day: 7, - expected_rel_iso: 2027, - expected_cyclic: 44, - expected_month: 1, - expected_day: 1, - }, - TestCase { - iso_year: 2023, - iso_month: 7, - iso_day: 1, - expected_rel_iso: 2023, - expected_cyclic: 40, - expected_month: 6, - expected_day: 14, - }, - TestCase { - iso_year: 2022, - iso_month: 3, - iso_day: 1, - expected_rel_iso: 2022, - expected_cyclic: 39, - expected_month: 1, - expected_day: 29, - }, - TestCase { - iso_year: 2021, - iso_month: 2, - iso_day: 1, - expected_rel_iso: 2020, - expected_cyclic: 37, - expected_month: 13, - expected_day: 20, - }, - TestCase { - iso_year: 2016, - iso_month: 3, - iso_day: 30, - expected_rel_iso: 2016, - expected_cyclic: 33, - expected_month: 2, - expected_day: 22, - }, - TestCase { - iso_year: 2016, - iso_month: 7, - iso_day: 30, - expected_rel_iso: 2016, - expected_cyclic: 33, - expected_month: 6, - expected_day: 27, - }, - TestCase { - iso_year: 2015, - iso_month: 9, - iso_day: 22, - expected_rel_iso: 2015, - expected_cyclic: 32, - expected_month: 8, - expected_day: 10, - }, - TestCase { - iso_year: 2013, - iso_month: 10, - iso_day: 1, - expected_rel_iso: 2013, - expected_cyclic: 30, - expected_month: 8, - expected_day: 27, - }, - TestCase { - iso_year: 2010, - iso_month: 2, - iso_day: 1, - expected_rel_iso: 2009, - expected_cyclic: 26, - expected_month: 13, - expected_day: 18, - }, - TestCase { - iso_year: 2000, - iso_month: 8, - iso_day: 30, - expected_rel_iso: 2000, - expected_cyclic: 17, - expected_month: 8, - expected_day: 2, - }, - TestCase { - iso_year: 1990, - iso_month: 11, - iso_day: 11, - expected_rel_iso: 1990, - expected_cyclic: 7, - expected_month: 10, - expected_day: 24, - }, - TestCase { - iso_year: 1970, - iso_month: 6, - iso_day: 10, - expected_rel_iso: 1970, - expected_cyclic: 47, - expected_month: 5, - expected_day: 7, - }, - TestCase { - iso_year: 1970, - iso_month: 1, - iso_day: 1, - expected_rel_iso: 1969, - expected_cyclic: 46, - expected_month: 11, - expected_day: 24, - }, - TestCase { - iso_year: 1941, - iso_month: 12, - iso_day: 7, - expected_rel_iso: 1941, - expected_cyclic: 18, - expected_month: 11, - expected_day: 19, - }, - TestCase { - iso_year: 1812, - iso_month: 5, - iso_day: 4, - expected_rel_iso: 1812, - expected_cyclic: 9, - expected_month: 3, - expected_day: 24, - }, - TestCase { - iso_year: 1655, - iso_month: 6, - iso_day: 15, - expected_rel_iso: 1655, - expected_cyclic: 32, - expected_month: 5, - expected_day: 12, - }, - TestCase { - iso_year: 1333, - iso_month: 3, - iso_day: 10, - expected_rel_iso: 1333, - expected_cyclic: 10, - expected_month: 2, - expected_day: 16, - }, - TestCase { - iso_year: 1000, - iso_month: 10, - iso_day: 10, - expected_rel_iso: 1000, - expected_cyclic: 37, - expected_month: 9, - expected_day: 5, - }, - TestCase { - iso_year: 842, - iso_month: 2, - iso_day: 15, - expected_rel_iso: 841, - expected_cyclic: 58, - expected_month: 13, - expected_day: 28, - }, - TestCase { - iso_year: 101, - iso_month: 1, - iso_day: 10, - expected_rel_iso: 100, - expected_cyclic: 37, - expected_month: 12, - expected_day: 24, - }, - TestCase { - iso_year: -1, - iso_month: 3, - iso_day: 28, - expected_rel_iso: -1, - expected_cyclic: 56, - expected_month: 2, - expected_day: 25, - }, - TestCase { - iso_year: -3, - iso_month: 2, - iso_day: 28, - expected_rel_iso: -3, - expected_cyclic: 54, - expected_month: 2, - expected_day: 5, - }, - TestCase { - iso_year: -365, - iso_month: 7, - iso_day: 24, - expected_rel_iso: -365, - expected_cyclic: 52, - expected_month: 6, - expected_day: 24, - }, - TestCase { - iso_year: -999, - iso_month: 9, - iso_day: 9, - expected_rel_iso: -999, - expected_cyclic: 18, - expected_month: 7, - expected_day: 27, - }, - TestCase { - iso_year: -1500, - iso_month: 1, - iso_day: 5, - expected_rel_iso: -1501, - expected_cyclic: 56, - expected_month: 12, - expected_day: 2, - }, - TestCase { - iso_year: -2332, - iso_month: 3, - iso_day: 1, - expected_rel_iso: -2332, - expected_cyclic: 5, - expected_month: 1, - expected_day: 16, - }, - TestCase { - iso_year: -2332, - iso_month: 2, - iso_day: 15, - expected_rel_iso: -2332, - expected_cyclic: 5, - expected_month: 1, - expected_day: 1, - }, - TestCase { - // #3709: This test case fails to match ICU - iso_year: -2332, - iso_month: 2, - iso_day: 14, - expected_rel_iso: -2333, - expected_cyclic: 4, - expected_month: 13, - expected_day: 30, - }, - TestCase { - // #3709: This test case fails to match ICU - iso_year: -2332, - iso_month: 1, - iso_day: 17, - expected_rel_iso: -2333, - expected_cyclic: 4, - expected_month: 13, - expected_day: 2, - }, - TestCase { - // #3709: This test case fails to match ICU - iso_year: -2332, - iso_month: 1, - iso_day: 16, - expected_rel_iso: -2333, - expected_cyclic: 4, - expected_month: 13, - expected_day: 1, - }, - TestCase { - iso_year: -2332, - iso_month: 1, - iso_day: 15, - expected_rel_iso: -2333, - expected_cyclic: 4, - expected_month: 12, - expected_day: 29, - }, - TestCase { - iso_year: -2332, - iso_month: 1, - iso_day: 1, - expected_rel_iso: -2333, - expected_cyclic: 4, - expected_month: 12, - expected_day: 15, - }, - TestCase { - iso_year: -2333, - iso_month: 1, - iso_day: 16, - expected_rel_iso: -2334, - expected_cyclic: 3, - expected_month: 12, - expected_day: 19, - }, - TestCase { - iso_year: -2333, - iso_month: 1, - iso_day: 27, - expected_rel_iso: -2333, - expected_cyclic: 4, - expected_month: 1, - expected_day: 1, - }, - TestCase { - iso_year: -2333, - iso_month: 1, - iso_day: 26, - expected_rel_iso: -2334, - expected_cyclic: 3, - expected_month: 12, - expected_day: 29, - }, - TestCase { - iso_year: -2600, - iso_month: 9, - iso_day: 16, - expected_rel_iso: -2600, - expected_cyclic: 37, - expected_month: 8, - expected_day: 16, - }, - TestCase { - iso_year: -2855, - iso_month: 2, - iso_day: 3, - expected_rel_iso: -2856, - expected_cyclic: 21, - expected_month: 12, - expected_day: 30, - }, - TestCase { - // #3709: This test case fails to match ICU - iso_year: -3000, - iso_month: 5, - iso_day: 15, - expected_rel_iso: -3000, - expected_cyclic: 57, - expected_month: 4, - expected_day: 1, - }, - TestCase { - // #3709: This test case fails to match ICU - iso_year: -3649, - iso_month: 9, - iso_day: 20, - expected_rel_iso: -3649, - expected_cyclic: 8, - expected_month: 8, - expected_day: 10, - }, - TestCase { - // #3709: This test case fails to match ICU - iso_year: -3649, - iso_month: 3, - iso_day: 30, - expected_rel_iso: -3649, - expected_cyclic: 8, - expected_month: 2, - expected_day: 14, - }, - TestCase { - // #3709: This test case fails to match ICU - iso_year: -3650, - iso_month: 3, - iso_day: 30, - expected_rel_iso: -3650, - expected_cyclic: 7, - expected_month: 3, - expected_day: 3, - }, - ]; - - let dangi_calculating = Dangi::new_always_calculating(); - let dangi_cached = Dangi::new(); - - for case in cases { - let iso = Date::try_new_iso(case.iso_year, case.iso_month, case.iso_day).unwrap(); - do_twice(&dangi_calculating, &dangi_cached, |dangi, calendar_type| { - let dangi = iso.to_calendar(dangi); - let dangi_cyclic = dangi.cyclic_year(); - let dangi_month = dangi.month().ordinal; - let dangi_day = dangi.day_of_month().0; - - assert_eq!( - dangi_cyclic.related_iso, case.expected_rel_iso, - "[{calendar_type}] Related ISO failed for test case: {case:?}" - ); - assert_eq!( - dangi_cyclic.year, case.expected_cyclic, - "[{calendar_type}] Cyclic year failed for test case: {case:?}" - ); - assert_eq!( - dangi_month, case.expected_month, - "[{calendar_type}] Month failed for test case: {case:?}" - ); - assert_eq!( - dangi_day, case.expected_day, - "[{calendar_type}] Day failed for test case: {case:?}" - ); - }); - } - } -} diff --git a/deps/crates/vendor/icu_calendar/src/cal/east_asian_traditional.rs b/deps/crates/vendor/icu_calendar/src/cal/east_asian_traditional.rs new file mode 100644 index 00000000000000..879c4a6f2c8fd9 --- /dev/null +++ b/deps/crates/vendor/icu_calendar/src/cal/east_asian_traditional.rs @@ -0,0 +1,1940 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use crate::cal::iso::Iso; +use crate::calendar_arithmetic::DateFieldsResolver; +use crate::calendar_arithmetic::{ArithmeticDate, ToExtendedYear}; +use crate::error::{ + DateError, DateFromFieldsError, EcmaReferenceYearError, MonthCodeError, UnknownEraError, +}; +use crate::options::{DateAddOptions, DateDifferenceOptions}; +use crate::options::{DateFromFieldsOptions, Overflow}; +use crate::types::ValidMonthCode; +use crate::AsCalendar; +use crate::{types, Calendar, Date}; +use calendrical_calculations::chinese_based::{ + self, ChineseBased, YearBounds, WELL_BEHAVED_ASTRONOMICAL_RANGE, +}; +use calendrical_calculations::rata_die::RataDie; +use icu_locale_core::preferences::extensions::unicode::keywords::CalendarAlgorithm; +use icu_provider::prelude::*; + +#[path = "east_asian_traditional/china_data.rs"] +mod china_data; +#[path = "east_asian_traditional/korea_data.rs"] +mod korea_data; +#[path = "east_asian_traditional/qing_data.rs"] +mod qing_data; +#[path = "east_asian_traditional/simple.rs"] +mod simple; + +/// The traditional East-Asian lunisolar calendar. +/// +/// This calendar used traditionally in China as well as in other countries in East Asia is +/// often used today to track important cultural events and holidays like the Lunar New Year. +/// +/// The type parameter specifies a particular set of calculation rules and local +/// time information, which differs by country and over time. +/// It must implement the currently-unstable `Rules` trait, at the moment this crate exports two stable +/// implementors of `Rules`: [`China`] and [`Korea`]. Please comment on [this issue](https://github.com/unicode-org/icu4x/issues/6962) +/// if you would like to see this trait stabilized. +/// +/// This corresponds to the `"chinese"` and `"dangi"` [CLDR calendars](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier) +/// respectively, when used with the [`China`] and [`Korea`] [`Rules`] types. +/// +/// # Year and Era codes +/// +/// Unlike most calendars, the traditional East-Asian calendar does not traditionally count years in an infinitely +/// increasing sequence. Instead, 10 "celestial stems" and 12 "terrestrial branches" are combined to form a +/// cycle of year names which repeats every 60 years. However, for the purposes of calendar calculations and +/// conversions, this calendar also counts years based on the [`Gregorian`](crate::cal::Gregorian) (ISO) calendar. +/// This "related ISO year" marks the Gregorian year in which a traditional East-Asian year begins. +/// +/// Because the traditional East-Asian calendar does not traditionally count years, era codes are not used in this calendar. +/// +/// For more information, suggested reading materials include: +/// * _Calendrical Calculations_ by Reingold & Dershowitz +/// * _The Mathematics of the Chinese Calendar_ by Helmer Aslaksen +/// * Wikipedia: +/// +/// # Months and days +/// +/// The 12 months (`M01`-`M12`) don't use names in modern usage, instead they are referred to as +/// e.g. 三月 (third month) using Chinese characters. +/// +/// As a lunar calendar, the lengths of the months depend on the lunar cycle (a month starts on the day of +/// local new moon), and will be either 29 or 30 days. As 12 such months fall short of a solar year, a leap +/// month is inserted roughly every 3 years; this can be after any month (e.g. `M02L`). +/// +/// Both the lengths of the months and the occurence of leap months are determined by the +/// concrete [`Rules`] implementation. +/// +/// The length of the year is 353-355 days, and the length of the leap year 383-385 days. +/// +/// # Calendar drift +/// +/// As leap months are determined with respect to the solar year, this calendar stays anchored +/// to the seasons. +#[derive(Clone, Debug, Default, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[allow(clippy::exhaustive_structs)] // newtype +pub struct EastAsianTraditional(pub R); + +/// The rules for the [`EastAsianTraditional`] calendar. +/// +/// The calendar depends on both astronomical calculations and local time. +/// The rules for how to perform these calculations, as well as how local +/// time is determined differ between countries and have changed over time. +/// +/// This crate currently provides [`Rules`] for [`China`] and [`Korea`]. +/// +///
+/// 🚫 This trait is sealed; it should not be implemented by user code. If an API requests an item that implements this +/// trait, please consider using a type from the implementors listed below. +/// +/// It is still possible to implement this trait in userland (since `UnstableSealed` is public), +/// do not do so unless you are prepared for things to occasionally break. +///
+pub trait Rules: Clone + core::fmt::Debug + crate::cal::scaffold::UnstableSealed { + /// Returns data about the given year. + fn year_data(&self, related_iso: i32) -> EastAsianTraditionalYearData; + + /// Returns an ECMA reference year that contains the given month-day combination. + /// + /// If the day is out of range, it will return a year that contains the given month + /// and the maximum day possible for that month. See [the spec][spec] for the + /// precise algorithm used. + /// + /// This API only matters when using [`MissingFieldsStrategy::Ecma`] to compute + /// a date without providing a year in [`Date::try_from_fields()`]. The default impl + /// will just error, and custom calendars who do not care about ECMA/Temporal + /// reference years do not need to override this. + /// + /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal-nonisomonthdaytoisoreferencedate + /// [`MissingFieldsStrategy::Ecma`]: crate::options::MissingFieldsStrategy::Ecma + fn ecma_reference_year( + &self, + // TODO: Consider accepting ValidMonthCode + _month_code: (u8, bool), + _day: u8, + ) -> Result { + Err(EcmaReferenceYearError::Unimplemented) + } + + /// The debug name for the calendar defined by these [`Rules`]. + fn debug_name(&self) -> &'static str { + "Chinese (custom)" + } + + /// The BCP-47 [`CalendarAlgorithm`] for the calendar defined by these [`Rules`], if defined. + fn calendar_algorithm(&self) -> Option { + None + } +} + +/// The [Chinese](https://en.wikipedia.org/wiki/Chinese_calendar) variant of the [`EastAsianTraditional`] calendar. +/// +/// This type agrees with the official data published by the +/// [Purple Mountain Observatory for the years 1900-2025], as well as with +/// the data published by the [Hong Kong Observatory for the years 1901-2100]. +/// +/// For years since 1912, this uses the [GB/T 33661-2017] rules. +/// As accurate computation is computationally expensive, years until +/// 2100 are precomputed, and after that this type regresses to a simplified +/// calculation. If accuracy beyond 2100 is required, clients +/// can implement their own [`Rules`] type containing more precomputed data. +/// We note that the calendar is inherently uncertain for some future dates. +/// +/// Before 1912 [different rules](https://ytliu.epizy.com/Shixian/Shixian_summary.html) +/// were used. This type produces correct data for the years 1900-1912, and +/// falls back to a simplified calculation before 1900. If accuracy is +/// required before 1900, clients can implement their own [`Rules`] type +/// using data such as from the excellent compilation by [Yuk Tung Liu]. +/// +/// The precise behavior of this calendar may change in the future if: +/// - New ground truth is established by published government sources +/// - We decide to tweak the simplified calculation +/// - We decide to expand or reduce the range where we are correctly handling past dates. +/// +/// [Purple Mountain Observatory for the years 1900-2025]: http://www.pmo.cas.cn/xwdt2019/kpdt2019/202203/P020250414456381274062.pdf +/// [Hong Kong Observatory for the years 1901-2100]: https://www.hko.gov.hk/en/gts/time/conversion.htm +/// [GB/T 33661-2017]: China::gb_t_33661_2017 +/// [Yuk Tung Liu]: https://ytliu0.github.io/ChineseCalendar/table.html +pub type ChineseTraditional = EastAsianTraditional; + +/// The [`Rules`] used in China. +/// +/// See [`ChineseTraditional`] for more information. +#[derive(Copy, Clone, Debug, Default)] +#[non_exhaustive] +pub struct China; + +impl China { + /// Computes [`EastAsianTraditionalYearData`] according to [GB/T 33661-2017], + /// as implemented by [`calendrical_calculations::chinese_based::Chinese`]. + /// + /// The rules specified in [GB/T 33661-2017] have only been used + /// since 1912, applying them proleptically to years before 1912 will not + /// necessarily match historical calendars. + /// + /// Note that for future years there is a small degree of uncertainty, as + /// [GB/T 33661-2017] depends on the uncertain future [difference between UT1 + /// and UTC](https://en.wikipedia.org/wiki/Leap_second#Future). + /// As noted by + /// [Yuk Tung Liu](https://ytliu0.github.io/ChineseCalendar/computation.html#modern), + /// years as early as 2057, 2089, and 2097 have lunar events very close to + /// local midnight, which might affect the start of a (single) month if additional + /// leap seconds are introduced. + /// + /// [GB/T 33661-2017]: https://openstd.samr.gov.cn/bzgk/gb/newGbInfo?hcno=E107EA4DE9725EDF819F33C60A44B296 + pub fn gb_t_33661_2017(related_iso: i32) -> EastAsianTraditionalYearData { + EastAsianTraditionalYearData::calendrical_calculations::( + related_iso, + ) + } +} + +impl crate::cal::scaffold::UnstableSealed for China {} +impl Rules for China { + fn year_data(&self, related_iso: i32) -> EastAsianTraditionalYearData { + if let Some(year) = EastAsianTraditionalYearData::lookup( + related_iso, + china_data::STARTING_YEAR, + china_data::DATA, + ) { + year + } else if related_iso > china_data::STARTING_YEAR { + EastAsianTraditionalYearData::simple(simple::UTC_PLUS_8, related_iso) + } else if let Some(year) = EastAsianTraditionalYearData::lookup( + related_iso, + qing_data::STARTING_YEAR, + qing_data::DATA, + ) { + year + } else { + EastAsianTraditionalYearData::simple(simple::BEIJING_UTC_OFFSET, related_iso) + } + } + + fn ecma_reference_year( + &self, + month_code: (u8, bool), + day: u8, + ) -> Result { + let (number, is_leap) = month_code; + // Computed by `generate_reference_years` + let extended_year = match (number, is_leap, day > 29) { + (1, false, false) => 1972, + (1, false, true) => 1970, + (1, true, false) => 1898, + (1, true, true) => 1898, + (2, false, false) => 1972, + (2, false, true) => 1972, + (2, true, false) => 1947, + (2, true, true) => 1830, + (3, false, false) => 1972, + (3, false, true) => 1966, + (3, true, false) => 1966, + (3, true, true) => 1955, + (4, false, false) => 1972, + (4, false, true) => 1970, + (4, true, false) => 1963, + (4, true, true) => 1944, + (5, false, false) => 1972, + (5, false, true) => 1972, + (5, true, false) => 1971, + (5, true, true) => 1952, + (6, false, false) => 1972, + (6, false, true) => 1971, + (6, true, false) => 1960, + (6, true, true) => 1941, + (7, false, false) => 1972, + (7, false, true) => 1972, + (7, true, false) => 1968, + (7, true, true) => 1938, + (8, false, false) => 1972, + (8, false, true) => 1971, + (8, true, false) => 1957, + (8, true, true) => 1691, + (9, false, false) => 1972, + (9, false, true) => 1972, + (9, true, false) => 2014, + (9, true, true) => 1843, + (10, false, false) => 1972, + (10, false, true) => 1972, + (10, true, false) => 1984, + (10, true, true) => 1737, + // Dec 31, 1972 is 1972-M11-26, dates after that + // are in the next year + (11, false, false) if day > 26 => 1971, + (11, false, false) => 1972, + (11, false, true) => 1969, + (11, true, false) => 2033, + (11, true, true) => 1889, + (12, false, false) => 1971, + (12, false, true) => 1971, + (12, true, false) => 1878, + (12, true, true) => 1783, + _ => return Err(EcmaReferenceYearError::MonthCodeNotInCalendar), + }; + Ok(extended_year) + } + + fn calendar_algorithm(&self) -> Option { + Some(CalendarAlgorithm::Chinese) + } + + fn debug_name(&self) -> &'static str { + "Chinese" + } +} + +/// The [Korean](https://en.wikipedia.org/wiki/Korean_calendar) variant of the [`EastAsianTraditional`] calendar. +/// +/// This type agrees with the official data published by the +/// [Korea Astronomy and Space Science Institute for the years 1900-2050]. +/// +/// For years since 1912, this uses [adapted GB/T 33661-2017] rules, +/// using Korea time instead of Beijing Time. +/// As accurate computation is computationally expensive, years until +/// 2100 are precomputed, and after that this type regresses to a simplified +/// calculation. If accuracy beyond 2100 is required, clients +/// can implement their own [`Rules`] type containing more precomputed data. +/// We note that the calendar is inherently uncertain for some future dates. +/// +/// Before 1912 [different rules](https://ytliu.epizy.com/Shixian/Shixian_summary.html) +/// were used (those of Qing-dynasty China). This type produces correct data +/// for the years 1900-1912, and falls back to a simplified calculation +/// before 1900. If accuracy is required before 1900, clients can implement +/// their own [`Rules`] type using data such as from the excellent compilation +/// by [Yuk Tung Liu]. +/// +/// The precise behavior of this calendar may change in the future if: +/// - New ground truth is established by published government sources +/// - We decide to tweak the simplified calculation +/// - We decide to expand or reduce the range where we are correctly handling past dates. +/// +/// [Korea Astronomy and Space Science Institute for the years 1900-2050]: https://astro.kasi.re.kr/life/pageView/5 +/// [adapted GB/T 33661-2017]: Korea::adapted_gb_t_33661_2017 +/// [GB/T 33661-2017]: China::gb_t_33661_2017 +/// [Yuk Tung Liu]: https://ytliu0.github.io/ChineseCalendar/table.html +/// +/// ```rust +/// use icu::calendar::cal::{ChineseTraditional, KoreanTraditional}; +/// use icu::calendar::Date; +/// +/// let iso_a = Date::try_new_iso(2012, 4, 23).unwrap(); +/// let korean_a = iso_a.to_calendar(KoreanTraditional::new()); +/// let chinese_a = iso_a.to_calendar(ChineseTraditional::new()); +/// +/// assert_eq!(korean_a.month().standard_code.0, "M03L"); +/// assert_eq!(chinese_a.month().standard_code.0, "M04"); +/// +/// let iso_b = Date::try_new_iso(2012, 5, 23).unwrap(); +/// let korean_b = iso_b.to_calendar(KoreanTraditional::new()); +/// let chinese_b = iso_b.to_calendar(ChineseTraditional::new()); +/// +/// assert_eq!(korean_b.month().standard_code.0, "M04"); +/// assert_eq!(chinese_b.month().standard_code.0, "M04L"); +/// ``` +pub type KoreanTraditional = EastAsianTraditional; + +/// The [`Rules`] used in Korea. +/// +/// See [`KoreanTraditional`] for more information. +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)] +#[non_exhaustive] +pub struct Korea; + +impl Korea { + /// A version of [`China::gb_t_33661_2017`] adapted for Korean time. + /// + /// See [`China::gb_t_33661_2017`] for caveats. + pub fn adapted_gb_t_33661_2017(related_iso: i32) -> EastAsianTraditionalYearData { + EastAsianTraditionalYearData::calendrical_calculations::(related_iso) + } +} + +impl KoreanTraditional { + /// Creates a new [`KoreanTraditional`] calendar. + pub const fn new() -> Self { + Self(Korea) + } + + /// Use [`Self::new`]. + #[cfg(feature = "serde")] + #[doc = icu_provider::gen_buffer_unstable_docs!(BUFFER,Self::new)] + #[deprecated(since = "2.1.0", note = "use `Self::new()")] + pub fn try_new_with_buffer_provider( + _provider: &(impl icu_provider::buf::BufferProvider + ?Sized), + ) -> Result { + Ok(Self::new()) + } + + /// Use [`Self::new`]. + #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new)] + #[deprecated(since = "2.1.0", note = "use `Self::new()")] + pub fn try_new_unstable(_provider: &D) -> Result { + Ok(Self::new()) + } + + /// Use [`Self::new`]. + #[deprecated(since = "2.1.0", note = "use `Self::new()")] + pub fn new_always_calculating() -> Self { + Self::new() + } +} + +impl crate::cal::scaffold::UnstableSealed for Korea {} +impl Rules for Korea { + fn year_data(&self, related_iso: i32) -> EastAsianTraditionalYearData { + if let Some(year) = EastAsianTraditionalYearData::lookup( + related_iso, + korea_data::STARTING_YEAR, + korea_data::DATA, + ) { + year + } else if related_iso > korea_data::STARTING_YEAR { + EastAsianTraditionalYearData::simple(simple::UTC_PLUS_9, related_iso) + } else if let Some(year) = EastAsianTraditionalYearData::lookup( + related_iso, + qing_data::STARTING_YEAR, + qing_data::DATA, + ) { + // Korea used Qing-dynasty rules before 1912 + // https://github.com/unicode-org/icu4x/issues/6455#issuecomment-3282175550 + year + } else { + EastAsianTraditionalYearData::simple(simple::BEIJING_UTC_OFFSET, related_iso) + } + } + + fn ecma_reference_year( + &self, + month_code: (u8, bool), + day: u8, + ) -> Result { + let (number, is_leap) = month_code; + // Computed by `generate_reference_years` + let extended_year = match (number, is_leap, day > 29) { + (1, false, false) => 1972, + (1, false, true) => 1970, + (1, true, false) => 1898, + (1, true, true) => 1898, + (2, false, false) => 1972, + (2, false, true) => 1972, + (2, true, false) => 1947, + (2, true, true) => 1830, + (3, false, false) => 1972, + (3, false, true) => 1968, + (3, true, false) => 1966, + (3, true, true) => 1955, + (4, false, false) => 1972, + (4, false, true) => 1970, + (4, true, false) => 1963, + (4, true, true) => 1944, + (5, false, false) => 1972, + (5, false, true) => 1972, + (5, true, false) => 1971, + (5, true, true) => 1952, + (6, false, false) => 1972, + (6, false, true) => 1971, + (6, true, false) => 1960, + (6, true, true) => 1941, + (7, false, false) => 1972, + (7, false, true) => 1972, + (7, true, false) => 1968, + (7, true, true) => 1938, + (8, false, false) => 1972, + (8, false, true) => 1971, + (8, true, false) => 1957, + (8, true, true) => 1691, + (9, false, false) => 1972, + (9, false, true) => 1972, + (9, true, false) => 2014, + (9, true, true) => 1843, + (10, false, false) => 1972, + (10, false, true) => 1972, + (10, true, false) => 1984, + (10, true, true) => 1737, + // Dec 31, 1972 is 1972-M11-26, dates after that + // are in the next year + (11, false, false) if day > 26 => 1971, + (11, false, false) => 1972, + (11, false, true) => 1969, + (11, true, false) => 2033, + (11, true, true) => 1889, + (12, false, false) => 1971, + (12, false, true) => 1971, + (12, true, false) => 1878, + (12, true, true) => 1783, + _ => return Err(EcmaReferenceYearError::MonthCodeNotInCalendar), + }; + Ok(extended_year) + } + + fn calendar_algorithm(&self) -> Option { + Some(CalendarAlgorithm::Dangi) + } + fn debug_name(&self) -> &'static str { + "Korean" + } +} + +impl> Date
{ + /// This method uses an ordinal month, which is probably not what you want. + /// + /// Use [`Date::try_new_from_codes`] + #[deprecated(since = "2.1.0", note = "use `Date::try_new_from_codes`")] + pub fn try_new_dangi_with_calendar( + related_iso_year: i32, + ordinal_month: u8, + day: u8, + calendar: A, + ) -> Result, DateError> { + ArithmeticDate::try_from_ymd( + calendar.as_calendar().0.year_data(related_iso_year), + ordinal_month, + day, + ) + .map(ChineseDateInner) + .map(|inner| Date::from_raw(inner, calendar)) + .map_err(Into::into) + } +} + +/// The inner date type used for representing [`Date`]s of [`EastAsianTraditional`]. +#[derive(Debug, Clone)] +pub struct ChineseDateInner(ArithmeticDate>); + +impl Copy for ChineseDateInner {} +impl PartialEq for ChineseDateInner { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} +impl Eq for ChineseDateInner {} +impl PartialOrd for ChineseDateInner { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl Ord for ChineseDateInner { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.0.cmp(&other.0) + } +} + +impl ChineseTraditional { + /// Creates a new [`ChineseTraditional`] calendar. + pub const fn new() -> Self { + EastAsianTraditional(China) + } + + #[cfg(feature = "serde")] + #[doc = icu_provider::gen_buffer_unstable_docs!(BUFFER,Self::new)] + #[deprecated(since = "2.1.0", note = "use `Self::new()")] + pub fn try_new_with_buffer_provider( + _provider: &(impl icu_provider::buf::BufferProvider + ?Sized), + ) -> Result { + Ok(Self::new()) + } + + #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new)] + #[deprecated(since = "2.1.0", note = "use `Self::new()")] + pub fn try_new_unstable(_provider: &D) -> Result { + Ok(Self::new()) + } + + /// Use [`Self::new()`]. + #[deprecated(since = "2.1.0", note = "use `Self::new()")] + pub fn new_always_calculating() -> Self { + Self::new() + } +} + +impl DateFieldsResolver for EastAsianTraditional { + type YearInfo = EastAsianTraditionalYearData; + + fn days_in_provided_month(year: EastAsianTraditionalYearData, month: u8) -> u8 { + 29 + year.packed.month_has_30_days(month) as u8 + } + + /// Returns the number of months in a given year, which is 13 in a leap year, and 12 in a common year. + fn months_in_provided_year(year: EastAsianTraditionalYearData) -> u8 { + 12 + year.packed.leap_month().is_some() as u8 + } + + #[inline] + fn year_info_from_era( + &self, + _era: &[u8], + _era_year: i32, + ) -> Result { + // This calendar has no era codes + Err(UnknownEraError) + } + + #[inline] + fn year_info_from_extended(&self, extended_year: i32) -> Self::YearInfo { + self.0.year_data(extended_year) + } + + #[inline] + fn reference_year_from_month_day( + &self, + month_code: types::ValidMonthCode, + day: u8, + ) -> Result { + self.0 + .ecma_reference_year(month_code.to_tuple(), day) + .map(|y| self.0.year_data(y)) + } + + fn ordinal_month_from_code( + &self, + year: &Self::YearInfo, + month_code: types::ValidMonthCode, + options: DateFromFieldsOptions, + ) -> Result { + // 14 is a sentinel value, greater than all other months, for the purpose of computation only; + // it is impossible to actually have 14 months in a year. + let leap_month = year.packed.leap_month().unwrap_or(14); + + // leap_month identifies the ordinal month number of the leap month, + // so its month number will be leap_month - 1 + if month_code == ValidMonthCode::new_unchecked(leap_month - 1, true) { + return Ok(leap_month); + } + + let (number @ 1..13, leap) = month_code.to_tuple() else { + return Err(MonthCodeError::NotInCalendar); + }; + + if leap && options.overflow != Some(Overflow::Constrain) { + // wrong leap month and not constraining + return Err(MonthCodeError::NotInYear); + } + + // add one if there was a leap month before + Ok(number + (number >= leap_month) as u8) + } + + fn month_code_from_ordinal(&self, year: &Self::YearInfo, ordinal_month: u8) -> ValidMonthCode { + // 14 is a sentinel value, greater than all other months, for the purpose of computation only; + // it is impossible to actually have 14 months in a year. + let leap_month = year.packed.leap_month().unwrap_or(14); + ValidMonthCode::new_unchecked( + // subtract one if there was a leap month before + ordinal_month - (ordinal_month >= leap_month) as u8, + ordinal_month == leap_month, + ) + } +} + +impl crate::cal::scaffold::UnstableSealed for EastAsianTraditional {} +impl Calendar for EastAsianTraditional { + type DateInner = ChineseDateInner; + type Year = types::CyclicYear; + type DifferenceError = core::convert::Infallible; + + fn from_codes( + &self, + era: Option<&str>, + year: i32, + month_code: types::MonthCode, + day: u8, + ) -> Result { + ArithmeticDate::from_codes(era, year, month_code, day, self).map(ChineseDateInner) + } + + #[cfg(feature = "unstable")] + fn from_fields( + &self, + fields: types::DateFields, + options: DateFromFieldsOptions, + ) -> Result { + ArithmeticDate::from_fields(fields, options, self).map(ChineseDateInner) + } + + fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { + let iso = Iso.from_rata_die(rd); + let year = { + let candidate = self.0.year_data(iso.0.year); + + if rd >= candidate.new_year() { + candidate + } else { + self.0.year_data(iso.0.year - 1) + } + }; + + // Clamp the RD to our year + let rd = rd.clamp( + year.new_year(), + year.new_year() + year.packed.days_in_year() as i64, + ); + + let day_of_year = (rd - year.new_year()) as u16; + + // We divide by 30, not 29, to account for the case where all months before this + // were length 30 (possible near the beginning of the year) + let mut month = (day_of_year / 30) as u8 + 1; + let mut last_day_of_month = year.packed.last_day_of_month(month); + let mut last_day_of_prev_month = year.packed.last_day_of_month(month - 1); + + while day_of_year >= last_day_of_month { + month += 1; + last_day_of_prev_month = last_day_of_month; + last_day_of_month = year.packed.last_day_of_month(month); + } + + let day = (day_of_year + 1 - last_day_of_prev_month) as u8; + + ChineseDateInner(ArithmeticDate::new_unchecked(year, month, day)) + } + + fn to_rata_die(&self, date: &Self::DateInner) -> RataDie { + date.0.year.new_year() + + date.0.year.packed.last_day_of_month(date.0.month - 1) as i64 + + (date.0.day - 1) as i64 + } + + fn has_cheap_iso_conversion(&self) -> bool { + false + } + + // Count the number of months in a given year, specified by providing a date + // from that year + fn days_in_year(&self, date: &Self::DateInner) -> u16 { + date.0.year.packed.days_in_year() + } + + fn days_in_month(&self, date: &Self::DateInner) -> u8 { + Self::days_in_provided_month(date.0.year, date.0.month) + } + + #[cfg(feature = "unstable")] + fn add( + &self, + date: &Self::DateInner, + duration: types::DateDuration, + options: DateAddOptions, + ) -> Result { + date.0.added(duration, self, options).map(ChineseDateInner) + } + + #[cfg(feature = "unstable")] + fn until( + &self, + date1: &Self::DateInner, + date2: &Self::DateInner, + options: DateDifferenceOptions, + ) -> Result { + Ok(date1.0.until(&date2.0, self, options)) + } + + /// Obtain a name for the calendar for debug printing + fn debug_name(&self) -> &'static str { + self.0.debug_name() + } + + fn year_info(&self, date: &Self::DateInner) -> Self::Year { + let year = date.0.year; + types::CyclicYear { + year: (year.related_iso - 4).rem_euclid(60) as u8 + 1, + related_iso: year.related_iso, + } + } + + fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { + date.0.year.packed.leap_month().is_some() + } + + /// The calendar-specific month code represented by `date`; + /// since the Chinese calendar has leap months, an "L" is appended to the month code for + /// leap months. For example, in a year where an intercalary month is added after the second + /// month, the month codes for ordinal months 1, 2, 3, 4, 5 would be "M01", "M02", "M02L", "M03", "M04". + fn month(&self, date: &Self::DateInner) -> types::MonthInfo { + types::MonthInfo::for_code_and_ordinal( + self.month_code_from_ordinal(&date.0.year, date.0.month), + date.0.month, + ) + } + + /// The calendar-specific day-of-month represented by `date` + fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { + types::DayOfMonth(date.0.day) + } + + /// Information of the day of the year + fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear { + types::DayOfYear(date.0.year.packed.last_day_of_month(date.0.month - 1) + date.0.day as u16) + } + + fn calendar_algorithm(&self) -> Option { + self.0.calendar_algorithm() + } + + fn months_in_year(&self, date: &Self::DateInner) -> u8 { + Self::months_in_provided_year(date.0.year) + } +} + +impl> Date { + /// This method uses an ordinal month, which is probably not what you want. + /// + /// Use [`Date::try_new_from_codes`] + #[deprecated(since = "2.1.0", note = "use `Date::try_new_from_codes`")] + pub fn try_new_chinese_with_calendar( + related_iso_year: i32, + ordinal_month: u8, + day: u8, + calendar: A, + ) -> Result, DateError> { + ArithmeticDate::try_from_ymd( + calendar.as_calendar().0.year_data(related_iso_year), + ordinal_month, + day, + ) + .map(ChineseDateInner) + .map(|inner| Date::from_raw(inner, calendar)) + .map_err(Into::into) + } +} + +/// Information about a [`EastAsianTraditional`] year. +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] +// TODO(#3933): potentially make this smaller +pub struct EastAsianTraditionalYearData { + /// Contains: + /// - length of each month in the year + /// - whether or not there is a leap month, and which month it is + /// - the date of Chinese New Year in the related ISO year + packed: PackedEastAsianTraditionalYearData, + related_iso: i32, +} + +impl ToExtendedYear for EastAsianTraditionalYearData { + fn to_extended_year(&self) -> i32 { + self.related_iso + } +} + +impl EastAsianTraditionalYearData { + /// Creates [`EastAsianTraditionalYearData`] from the given parts. + /// + /// `start_day` is the date for the first day of the year, see [`Date::to_rata_die`] + /// to obtain a [`RataDie`] from a [`Date`] in an arbitrary calendar. + /// + /// `leap_month` is the ordinal number of the leap month, for example if a year + /// has months 1, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, the `leap_month` + /// would be `Some(4)`. + /// + /// `month_lengths[n - 1]` is true if the nth month has 30 days, and false otherwise. + /// The leap month does not necessarily have the same number of days as the previous + /// month, which is why this has length 13. In non-leap years, the last value is ignored. + pub fn new( + related_iso: i32, + start_day: RataDie, + month_lengths: [bool; 13], + leap_month: Option, + ) -> Self { + Self { + packed: PackedEastAsianTraditionalYearData::new( + related_iso, + month_lengths, + leap_month, + start_day, + ), + related_iso, + } + } + + fn lookup( + related_iso: i32, + starting_year: i32, + data: &[PackedEastAsianTraditionalYearData], + ) -> Option { + Some(related_iso) + .and_then(|e| usize::try_from(e.checked_sub(starting_year)?).ok()) + .and_then(|i| data.get(i)) + .map(|&packed| Self { + related_iso, + packed, + }) + } + + fn calendrical_calculations( + related_iso: i32, + ) -> EastAsianTraditionalYearData { + let mid_year = calendrical_calculations::gregorian::fixed_from_gregorian(related_iso, 7, 1); + let year_bounds = YearBounds::compute::(mid_year); + + let YearBounds { + new_year, + next_new_year, + .. + } = year_bounds; + let (month_lengths, leap_month) = + chinese_based::month_structure_for_year::(new_year, next_new_year); + + EastAsianTraditionalYearData { + packed: PackedEastAsianTraditionalYearData::new( + related_iso, + month_lengths, + leap_month, + new_year, + ), + related_iso, + } + } + + /// Get the new year R.D. + fn new_year(self) -> RataDie { + self.packed.new_year(self.related_iso) + } +} + +/// The struct containing compiled ChineseData +/// +/// Bit structure (little endian: note that shifts go in the opposite direction!) +/// +/// ```text +/// Bit: 0 1 2 3 4 5 6 7 +/// Byte 0: [ month lengths ............. +/// Byte 1: .. month lengths ] | [ leap month index .. +/// Byte 2: ] | [ NY offset ] | unused +/// ``` +/// +/// Where the New Year Offset is the offset from ISO Jan 19 of that year for Chinese New Year, +/// the month lengths are stored as 1 = 30, 0 = 29 for each month including the leap month. +/// The largest possible offset is 33, which requires 6 bits of storage. +/// +///
+/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, +/// including in SemVer minor releases. While the serde representation of data structs is guaranteed +/// to be stable, their Rust representation might not be. Use with caution. +///
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +struct PackedEastAsianTraditionalYearData(u8, u8, u8); + +impl PackedEastAsianTraditionalYearData { + /// The first day on which Chinese New Year may occur + /// + /// According to Reingold & Dershowitz, ch 19.6, Chinese New Year occurs on Jan 21 - Feb 21 inclusive. + /// + /// Our simple approximation sometimes returns Feb 22. + /// + /// We allow it to occur as early as January 19 which is the earliest the second new moon + /// could occur after the Winter Solstice if the solstice is pinned to December 20. + const fn earliest_ny(related_iso: i32) -> RataDie { + calendrical_calculations::gregorian::fixed_from_gregorian(related_iso, 1, 19) + } + + /// It clamps some values to avoid debug assertions on calendrical invariants. + const fn new( + related_iso: i32, + month_lengths: [bool; 13], + leap_month: Option, + new_year: RataDie, + ) -> Self { + // These assertions are API correctness assertions and even bad calendar arithmetic + // should not produce this + if let Some(l) = leap_month { + debug_assert!(2 <= l && l <= 13, "Leap month indices must be 2 <= i <= 13"); + } else { + debug_assert!( + !month_lengths[12], + "Last month length should not be set for non-leap years" + ) + } + + let ny_offset = new_year.since(Self::earliest_ny(related_iso)); + + #[cfg(debug_assertions)] + let out_of_valid_astronomical_range = WELL_BEHAVED_ASTRONOMICAL_RANGE.start.to_i64_date() + > new_year.to_i64_date() + || new_year.to_i64_date() > WELL_BEHAVED_ASTRONOMICAL_RANGE.end.to_i64_date(); + + // Assert the offset is in range, but allow it to be out of + // range when out_of_valid_astronomical_range=true + #[cfg(debug_assertions)] + debug_assert!( + ny_offset >= 0 || out_of_valid_astronomical_range, + "Year offset too small to store" + ); + // The maximum new-year's offset we have found is 34 + #[cfg(debug_assertions)] + debug_assert!( + ny_offset < 35 || out_of_valid_astronomical_range, + "Year offset too big to store" + ); + + // Just clamp to something we can represent when things get of range. + // + // This will typically happen when out_of_valid_astronomical_range + // is true. + // + // We can store up to 6 bytes for ny_offset, even if our + // maximum asserted value is otherwise 33. + let ny_offset = ny_offset & (0x40 - 1); + + let mut all = 0u32; // last byte unused + + let mut month = 0; + while month < month_lengths.len() { + #[allow(clippy::indexing_slicing)] // const iteration + if month_lengths[month] { + all |= 1 << month as u32; + } + month += 1; + } + let leap_month_idx = if let Some(leap_month_idx) = leap_month { + leap_month_idx + } else { + 0 + }; + all |= (leap_month_idx as u32) << (8 + 5); + all |= (ny_offset as u32) << (16 + 1); + let le = all.to_le_bytes(); + Self(le[0], le[1], le[2]) + } + + fn new_year(self, related_iso: i32) -> RataDie { + Self::earliest_ny(related_iso) + (self.2 as i64 >> 1) + } + + fn leap_month(self) -> Option { + let bits = (self.1 >> 5) + ((self.2 & 0b1) << 3); + + (bits != 0).then_some(bits) + } + + // Whether a particular month has 30 days (month is 1-indexed) + fn month_has_30_days(self, month: u8) -> bool { + let months = u16::from_le_bytes([self.0, self.1]); + months & (1 << (month - 1) as u16) != 0 + } + + // month is 1-indexed, but 0 is a valid input, producing 0 + fn last_day_of_month(self, month: u8) -> u16 { + let months = u16::from_le_bytes([self.0, self.1]); + // month is 1-indexed, so `29 * month` includes the current month + let mut prev_month_lengths = 29 * month as u16; + // month is 1-indexed, so `1 << month` is a mask with all zeroes except + // for a 1 at the bit index at the next month. Subtracting 1 from it gets us + // a bitmask for all months up to now + let long_month_bits = months & ((1 << month as u16) - 1); + prev_month_lengths += long_month_bits.count_ones().try_into().unwrap_or(0); + prev_month_lengths + } + + fn days_in_year(self) -> u16 { + self.last_day_of_month(12 + self.leap_month().is_some() as u8) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::options::{DateFromFieldsOptions, Overflow}; + use crate::types::DateFields; + use calendrical_calculations::{gregorian::fixed_from_gregorian, rata_die::RataDie}; + use std::collections::BTreeMap; + + #[test] + fn test_chinese_from_rd() { + #[derive(Debug)] + struct TestCase { + rd: i64, + expected_year: i32, + expected_month: u8, + expected_day: u8, + } + + let cases = [ + TestCase { + rd: -964192, + expected_year: -2639, + expected_month: 1, + expected_day: 1, + }, + TestCase { + rd: -963838, + expected_year: -2638, + expected_month: 1, + expected_day: 1, + }, + TestCase { + rd: -963129, + expected_year: -2637, + expected_month: 13, + expected_day: 1, + }, + TestCase { + rd: -963100, + expected_year: -2637, + expected_month: 13, + expected_day: 30, + }, + TestCase { + rd: -963099, + expected_year: -2636, + expected_month: 1, + expected_day: 1, + }, + TestCase { + rd: 738700, + expected_year: 2023, + expected_month: 6, + expected_day: 12, + }, + TestCase { + rd: fixed_from_gregorian(2319, 2, 20).to_i64_date(), + expected_year: 2318, + expected_month: 13, + expected_day: 30, + }, + TestCase { + rd: fixed_from_gregorian(2319, 2, 21).to_i64_date(), + expected_year: 2319, + expected_month: 1, + expected_day: 1, + }, + TestCase { + rd: 738718, + expected_year: 2023, + expected_month: 6, + expected_day: 30, + }, + TestCase { + rd: 738747, + expected_year: 2023, + expected_month: 7, + expected_day: 29, + }, + TestCase { + rd: 738748, + expected_year: 2023, + expected_month: 8, + expected_day: 1, + }, + TestCase { + rd: 738865, + expected_year: 2023, + expected_month: 11, + expected_day: 29, + }, + TestCase { + rd: 738895, + expected_year: 2023, + expected_month: 12, + expected_day: 29, + }, + TestCase { + rd: 738925, + expected_year: 2023, + expected_month: 13, + expected_day: 30, + }, + TestCase { + rd: 0, + expected_year: 0, + expected_month: 11, + expected_day: 19, + }, + TestCase { + rd: -1, + expected_year: 0, + expected_month: 11, + expected_day: 18, + }, + TestCase { + rd: -365, + expected_year: -1, + expected_month: 12, + expected_day: 9, + }, + TestCase { + rd: 100, + expected_year: 1, + expected_month: 3, + expected_day: 1, + }, + ]; + + for case in cases { + let rata_die = RataDie::new(case.rd); + + let chinese = Date::from_rata_die(rata_die, ChineseTraditional::new()); + assert_eq!( + case.expected_year, + chinese.extended_year(), + "Chinese from RD failed, case: {case:?}" + ); + assert_eq!( + case.expected_month, + chinese.month().ordinal, + "Chinese from RD failed, case: {case:?}" + ); + assert_eq!( + case.expected_day, + chinese.day_of_month().0, + "Chinese from RD failed, case: {case:?}" + ); + } + } + + #[test] + fn test_rd_from_chinese() { + #[derive(Debug)] + struct TestCase { + year: i32, + ordinal_month: u8, + month_code: types::MonthCode, + day: u8, + expected: i64, + } + + let cases = [ + TestCase { + year: 2023, + ordinal_month: 6, + month_code: types::MonthCode::new_normal(5).unwrap(), + day: 6, + // June 23 2023 + expected: 738694, + }, + TestCase { + year: -2636, + ordinal_month: 1, + month_code: types::MonthCode::new_normal(1).unwrap(), + day: 1, + expected: -963099, + }, + ]; + + for case in cases { + let date = Date::try_new_from_codes( + None, + case.year, + case.month_code, + case.day, + ChineseTraditional::new(), + ) + .unwrap(); + #[allow(deprecated)] // should still test + { + assert_eq!( + Date::try_new_chinese_with_calendar( + case.year, + case.ordinal_month, + case.day, + ChineseTraditional::new() + ), + Ok(date) + ); + } + let rd = date.to_rata_die().to_i64_date(); + let expected = case.expected; + assert_eq!(rd, expected, "RD from Chinese failed, with expected: {expected} and calculated: {rd}, for test case: {case:?}"); + } + } + + #[test] + fn test_rd_chinese_roundtrip() { + let mut rd = -1963020; + let max_rd = 1963020; + let mut iters = 0; + let max_iters = 560; + while rd < max_rd && iters < max_iters { + let rata_die = RataDie::new(rd); + + let chinese = Date::from_rata_die(rata_die, ChineseTraditional::new()); + let result = chinese.to_rata_die(); + assert_eq!(result, rata_die, "Failed roundtrip RD -> Chinese -> RD for RD: {rata_die:?}, with calculated: {result:?} from Chinese date:\n{chinese:?}"); + + rd += 7043; + iters += 1; + } + } + + #[test] + fn test_chinese_epoch() { + let iso = Date::try_new_iso(-2636, 2, 15).unwrap(); + + let chinese = iso.to_calendar(ChineseTraditional::new()); + + assert_eq!(chinese.cyclic_year().related_iso, -2636); + assert_eq!(chinese.month().ordinal, 1); + assert_eq!(chinese.month().standard_code.0, "M01"); + assert_eq!(chinese.day_of_month().0, 1); + assert_eq!(chinese.cyclic_year().year, 1); + assert_eq!(chinese.cyclic_year().related_iso, -2636); + } + + #[test] + fn test_iso_to_chinese_negative_years() { + #[derive(Debug)] + struct TestCase { + iso_year: i32, + iso_month: u8, + iso_day: u8, + expected_year: i32, + expected_month: u8, + expected_day: u8, + } + + let cases = [ + TestCase { + iso_year: -2636, + iso_month: 2, + iso_day: 14, + expected_year: -2637, + expected_month: 13, + expected_day: 30, + }, + TestCase { + iso_year: -2636, + iso_month: 1, + iso_day: 15, + expected_year: -2637, + expected_month: 12, + expected_day: 29, + }, + ]; + + for case in cases { + let iso = Date::try_new_iso(case.iso_year, case.iso_month, case.iso_day).unwrap(); + + let chinese = iso.to_calendar(ChineseTraditional::new()); + assert_eq!( + case.expected_year, + chinese.cyclic_year().related_iso, + "ISO to Chinese failed for case: {case:?}" + ); + assert_eq!( + case.expected_month, + chinese.month().ordinal, + "ISO to Chinese failed for case: {case:?}" + ); + assert_eq!( + case.expected_day, + chinese.day_of_month().0, + "ISO to Chinese failed for case: {case:?}" + ); + } + } + + #[test] + fn test_chinese_leap_months() { + let expected = [ + (1933, 6), + (1938, 8), + (1984, 11), + (2009, 6), + (2017, 7), + (2028, 6), + ]; + + for case in expected { + let year = case.0; + let expected_month = case.1; + let iso = Date::try_new_iso(year, 6, 1).unwrap(); + + let chinese_date = iso.to_calendar(ChineseTraditional::new()); + assert!( + chinese_date.is_in_leap_year(), + "{year} should be a leap year" + ); + let new_year = chinese_date.inner.0.year.new_year(); + assert_eq!( + expected_month, + chinese_based::get_leap_month_from_new_year::(new_year), + "{year} have leap month {expected_month}" + ); + } + } + + #[test] + fn test_month_days() { + let year = ChineseTraditional::new().0.year_data(2023); + let cases = [ + (1, 29), + (2, 30), + (3, 29), + (4, 29), + (5, 30), + (6, 30), + (7, 29), + (8, 30), + (9, 30), + (10, 29), + (11, 30), + (12, 29), + (13, 30), + ]; + for case in cases { + let days_in_month = EastAsianTraditional::::days_in_provided_month(year, case.0); + assert_eq!( + case.1, days_in_month, + "month_days test failed for case: {case:?}" + ); + } + } + + #[test] + fn test_ordinal_to_month_code() { + #[derive(Debug)] + struct TestCase { + year: i32, + month: u8, + day: u8, + expected_code: &'static str, + } + + let cases = [ + TestCase { + year: 2023, + month: 1, + day: 9, + expected_code: "M12", + }, + TestCase { + year: 2023, + month: 2, + day: 9, + expected_code: "M01", + }, + TestCase { + year: 2023, + month: 3, + day: 9, + expected_code: "M02", + }, + TestCase { + year: 2023, + month: 4, + day: 9, + expected_code: "M02L", + }, + TestCase { + year: 2023, + month: 5, + day: 9, + expected_code: "M03", + }, + TestCase { + year: 2023, + month: 6, + day: 9, + expected_code: "M04", + }, + TestCase { + year: 2023, + month: 7, + day: 9, + expected_code: "M05", + }, + TestCase { + year: 2023, + month: 8, + day: 9, + expected_code: "M06", + }, + TestCase { + year: 2023, + month: 9, + day: 9, + expected_code: "M07", + }, + TestCase { + year: 2023, + month: 10, + day: 9, + expected_code: "M08", + }, + TestCase { + year: 2023, + month: 11, + day: 9, + expected_code: "M09", + }, + TestCase { + year: 2023, + month: 12, + day: 9, + expected_code: "M10", + }, + TestCase { + year: 2024, + month: 1, + day: 9, + expected_code: "M11", + }, + TestCase { + year: 2024, + month: 2, + day: 9, + expected_code: "M12", + }, + TestCase { + year: 2024, + month: 2, + day: 10, + expected_code: "M01", + }, + ]; + + for case in cases { + let iso = Date::try_new_iso(case.year, case.month, case.day).unwrap(); + let chinese = iso.to_calendar(ChineseTraditional::new()); + let result_code = chinese.month().standard_code.0; + let expected_code = case.expected_code.to_string(); + assert_eq!( + expected_code, result_code, + "Month codes did not match for test case: {case:?}" + ); + } + } + + #[test] + fn test_month_code_to_ordinal() { + let cal = ChineseTraditional::new(); + let reject = DateFromFieldsOptions { + overflow: Some(Overflow::Reject), + ..Default::default() + }; + let year = cal.year_info_from_extended(2023); + let leap_month = year.packed.leap_month().unwrap(); + for ordinal in 1..=13 { + let code = ValidMonthCode::new_unchecked( + ordinal - (ordinal >= leap_month) as u8, + ordinal == leap_month, + ); + assert_eq!( + cal.ordinal_month_from_code(&year, code, reject), + Ok(ordinal), + "Code to ordinal failed for year: {}, code: {ordinal}", + year.related_iso + ); + } + } + + #[test] + fn check_invalid_month_code_to_ordinal() { + let cal = ChineseTraditional::new(); + let reject = DateFromFieldsOptions { + overflow: Some(Overflow::Reject), + ..Default::default() + }; + for year in [4659, 4660] { + let year = cal.year_info_from_extended(year); + for (code, error) in [ + ( + ValidMonthCode::new_unchecked(4, true), + MonthCodeError::NotInYear, + ), + ( + ValidMonthCode::new_unchecked(13, false), + MonthCodeError::NotInCalendar, + ), + ] { + assert_eq!( + cal.ordinal_month_from_code(&year, code, reject), + Err(error), + "Invalid month code failed for year: {}, code: {code:?}", + year.related_iso, + ); + } + } + } + + #[test] + fn test_iso_chinese_roundtrip() { + for i in -1000..=1000 { + let year = i; + let month = i as u8 % 12 + 1; + let day = i as u8 % 28 + 1; + let iso = Date::try_new_iso(year, month, day).unwrap(); + let chinese = iso.to_calendar(ChineseTraditional::new()); + let result = chinese.to_calendar(Iso); + assert_eq!(iso, result, "ISO to Chinese roundtrip failed!\nIso: {iso:?}\nChinese: {chinese:?}\nResult: {result:?}"); + } + } + + fn check_cyclic_and_rel_iso(year: i32) { + let iso = Date::try_new_iso(year, 6, 6).unwrap(); + let chinese = iso.to_calendar(ChineseTraditional::new()); + let korean = iso.to_calendar(KoreanTraditional::new()); + let chinese_year = chinese.cyclic_year(); + let korean_year = korean.cyclic_year(); + assert_eq!( + chinese_year, korean_year, + "Cyclic year failed for year: {year}" + ); + let chinese_rel_iso = chinese_year.related_iso; + let korean_rel_iso = korean_year.related_iso; + assert_eq!( + chinese_rel_iso, korean_rel_iso, + "Rel. ISO year equality failed for year: {year}" + ); + assert_eq!(korean_rel_iso, year, "Korean Rel. ISO failed!"); + } + + #[test] + fn test_cyclic_same_as_chinese_near_present_day() { + for year in 1923..=2123 { + check_cyclic_and_rel_iso(year); + } + } + + #[test] + fn test_cyclic_same_as_chinese_near_rd_zero() { + for year in -100..=100 { + check_cyclic_and_rel_iso(year); + } + } + + #[test] + fn test_iso_to_korean_roundtrip() { + let mut rd = -1963020; + let max_rd = 1963020; + let mut iters = 0; + let max_iters = 560; + while rd < max_rd && iters < max_iters { + let rata_die = RataDie::new(rd); + let iso = Date::from_rata_die(rata_die, Iso); + let korean = iso.to_calendar(KoreanTraditional::new()); + let result = korean.to_calendar(Iso); + assert_eq!( + iso, result, + "Failed roundtrip ISO -> Korean -> ISO for RD: {rd}" + ); + + rd += 7043; + iters += 1; + } + } + + #[test] + fn test_from_fields_constrain() { + let fields = DateFields { + day: Some(31), + month_code: Some(b"M01"), + extended_year: Some(1972), + ..Default::default() + }; + let options = DateFromFieldsOptions { + overflow: Some(Overflow::Constrain), + ..Default::default() + }; + + let cal = ChineseTraditional::new(); + let date = Date::try_from_fields(fields, options, cal).unwrap(); + assert_eq!( + date.day_of_month().0, + 29, + "Day was successfully constrained" + ); + + // 2022 did not have M01L, the month should be constrained back down + let fields = DateFields { + day: Some(1), + month_code: Some(b"M01L"), + extended_year: Some(2022), + ..Default::default() + }; + let date = Date::try_from_fields(fields, options, cal).unwrap(); + assert_eq!( + date.month().standard_code.0, + "M01", + "Month was successfully constrained" + ); + } + + #[test] + fn test_from_fields_regress_7049() { + // We want to make sure that overly large years do not panic + // (we just reject them in Date::try_from_fields) + let fields = DateFields { + extended_year: Some(889192448), + ordinal_month: Some(1), + day: Some(1), + ..Default::default() + }; + let options = DateFromFieldsOptions { + overflow: Some(Overflow::Reject), + ..Default::default() + }; + + let cal = ChineseTraditional::new(); + assert!(matches!( + Date::try_from_fields(fields, options, cal).unwrap_err(), + DateFromFieldsError::Range { .. } + )); + } + + #[test] + #[ignore] // slow, network + fn test_against_hong_kong_observatory_data() { + use crate::{cal::Gregorian, Date}; + + let mut related_iso = 1900; + let mut lunar_month = ValidMonthCode::new_unchecked(11, false); + + for year in 1901..=2100 { + println!("Validating year {year}..."); + + for line in ureq::get(&format!( + "https://www.hko.gov.hk/en/gts/time/calendar/text/files/T{year}e.txt" + )) + .call() + .unwrap() + .body_mut() + .read_to_string() + .unwrap() + .split('\n') + { + if !line.starts_with(['1', '2']) { + // comments or blank lines + continue; + } + + let mut fields = line.split_ascii_whitespace(); + + let mut gregorian = fields.next().unwrap().split('/'); + let gregorian = Date::try_new_gregorian( + gregorian.next().unwrap().parse().unwrap(), + gregorian.next().unwrap().parse().unwrap(), + gregorian.next().unwrap().parse().unwrap(), + ) + .unwrap(); + + let day_or_lunar_month = fields.next().unwrap(); + + let lunar_day = if fields.next().is_some_and(|s| s.contains("Lunar")) { + let new_lunar_month = day_or_lunar_month + // 1st, 2nd, 3rd, nth + .split_once(['s', 'n', 'r', 't']) + .unwrap() + .0 + .parse() + .unwrap(); + lunar_month = ValidMonthCode::new_unchecked( + new_lunar_month, + new_lunar_month == lunar_month.number(), + ); + if new_lunar_month == 1 { + related_iso += 1; + } + 1 + } else { + day_or_lunar_month.parse().unwrap() + }; + + let chinese = Date::try_new_from_codes( + None, + related_iso, + lunar_month.to_month_code(), + lunar_day, + ChineseTraditional::new(), + ) + .unwrap(); + + assert_eq!( + gregorian, + chinese.to_calendar(Gregorian), + "{line}, {chinese:?}" + ); + } + } + } + + #[test] + #[ignore] // network + fn test_against_kasi_data() { + use crate::{cal::Gregorian, types::MonthCode, Date}; + + // TODO: query KASI directly + let uri = "https://gist.githubusercontent.com/Manishearth/d8c94a7df22a9eacefc4472a5805322e/raw/e1ea3b0aa52428686bb3a9cd0f262878515e16c1/resolved.json"; + + #[derive(serde::Deserialize)] + struct Golden(BTreeMap>); + + #[derive(serde::Deserialize)] + struct MonthData { + start_date: String, + } + + let json = ureq::get(uri) + .call() + .unwrap() + .body_mut() + .read_to_string() + .unwrap(); + + let golden = serde_json::from_str::(&json).unwrap(); + + for (&year, months) in &golden.0 { + if year == 1899 || year == 2050 { + continue; + } + for (&month, month_data) in months { + let mut gregorian = month_data.start_date.split('-'); + let gregorian = Date::try_new_gregorian( + gregorian.next().unwrap().parse().unwrap(), + gregorian.next().unwrap().parse().unwrap(), + gregorian.next().unwrap().parse().unwrap(), + ) + .unwrap(); + + assert_eq!( + Date::try_new_from_codes(None, year, month, 1, KoreanTraditional::new()) + .unwrap() + .to_calendar(Gregorian), + gregorian + ); + } + } + } + + #[test] + #[ignore] + fn generate_reference_years() { + generate_reference_years_for(ChineseTraditional::new()); + generate_reference_years_for(KoreanTraditional::new()); + fn generate_reference_years_for(calendar: EastAsianTraditional) { + use crate::Date; + + println!("Reference years for {calendar:?}:"); + let reference_year_end = Date::from_rata_die( + crate::cal::abstract_gregorian::LAST_DAY_OF_REFERENCE_YEAR, + calendar, + ); + let year_1900_start = Date::try_new_gregorian(1900, 1, 1) + .unwrap() + .to_calendar(calendar); + let year_2035_end = Date::try_new_gregorian(2035, 12, 31) + .unwrap() + .to_calendar(calendar); + for month in 1..=12 { + for leap in [false, true] { + 'outer: for long in [false, true] { + for (start_year, start_month, end_year, end_month, by) in [ + ( + reference_year_end.extended_year(), + reference_year_end.month().month_number(), + year_1900_start.extended_year(), + year_1900_start.month().month_number(), + -1, + ), + ( + reference_year_end.extended_year(), + reference_year_end.month().month_number(), + year_2035_end.extended_year(), + year_2035_end.month().month_number(), + 1, + ), + ( + year_1900_start.extended_year(), + year_1900_start.month().month_number(), + -10000, + 1, + -1, + ), + ] { + let mut year = start_year; + while year * by < end_year * by { + if year == start_year + && month as i32 * by <= start_month as i32 * by + || year == end_year + && month as i32 * by >= end_month as i32 * by + { + year += by; + continue; + } + let data = calendar.0.year_data(year); + let leap_month = data.packed.leap_month().unwrap_or(15); + let ordinal_month = if leap && month + 1 == leap_month { + month + 1 + } else { + month + (month + 1 > leap_month) as u8 + }; + if (!long || data.packed.month_has_30_days(ordinal_month)) + && (!leap || month + 1 == leap_month) + { + println!("({month}, {leap:?}, {long:?}) => {year},"); + continue 'outer; + } + year += by; + } + } + println!("({month}, {leap:?}, {long:?}) => todo!(),") + } + } + } + } + } + + #[test] + fn test_roundtrip_packed() { + fn packed_roundtrip_single( + month_lengths: [bool; 13], + leap_month_idx: Option, + ny_offset: i64, + ) { + let ny = + calendrical_calculations::gregorian::fixed_from_gregorian(1000, 1, 1) + ny_offset; + let packed = + PackedEastAsianTraditionalYearData::new(1000, month_lengths, leap_month_idx, ny); + + assert_eq!( + ny, + packed.new_year(1000), + "Roundtrip with {month_lengths:?}, {leap_month_idx:?}, {ny_offset}" + ); + assert_eq!( + leap_month_idx, + packed.leap_month(), + "Roundtrip with {month_lengths:?}, {leap_month_idx:?}, {ny_offset}" + ); + assert_eq!( + month_lengths, + core::array::from_fn(|i| packed.month_has_30_days(i as u8 + 1)), + "Roundtrip with {month_lengths:?}, {leap_month_idx:?}, {ny_offset}" + ); + } + + const SHORT: [bool; 13] = [false; 13]; + const LONG: [bool; 13] = [true; 13]; + const ALTERNATING1: [bool; 13] = [ + false, true, false, true, false, true, false, true, false, true, false, true, false, + ]; + const ALTERNATING2: [bool; 13] = [ + true, false, true, false, true, false, true, false, true, false, true, false, false, + ]; + const RANDOM1: [bool; 13] = [ + true, true, false, false, true, true, false, true, true, true, true, false, false, + ]; + const RANDOM2: [bool; 13] = [ + false, true, true, true, true, false, true, true, true, false, false, true, false, + ]; + packed_roundtrip_single(SHORT, None, 18 + 5); + packed_roundtrip_single(SHORT, None, 18 + 10); + packed_roundtrip_single(SHORT, Some(11), 18 + 15); + packed_roundtrip_single(LONG, Some(12), 18 + 15); + packed_roundtrip_single(ALTERNATING1, None, 18 + 2); + packed_roundtrip_single(ALTERNATING1, Some(3), 18 + 5); + packed_roundtrip_single(ALTERNATING2, None, 18 + 9); + packed_roundtrip_single(ALTERNATING2, Some(7), 18 + 26); + packed_roundtrip_single(RANDOM1, None, 18 + 29); + packed_roundtrip_single(RANDOM1, Some(12), 18 + 29); + packed_roundtrip_single(RANDOM1, Some(2), 18 + 21); + packed_roundtrip_single(RANDOM2, None, 18 + 25); + packed_roundtrip_single(RANDOM2, Some(2), 18 + 19); + packed_roundtrip_single(RANDOM2, Some(5), 18 + 2); + packed_roundtrip_single(RANDOM2, Some(12), 18 + 5); + } +} diff --git a/deps/crates/vendor/icu_calendar/src/cal/east_asian_traditional/china_data.rs b/deps/crates/vendor/icu_calendar/src/cal/east_asian_traditional/china_data.rs new file mode 100644 index 00000000000000..034ca1cedeb535 --- /dev/null +++ b/deps/crates/vendor/icu_calendar/src/cal/east_asian_traditional/china_data.rs @@ -0,0 +1,225 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +//! Data obtained from [`calendrical_calculations`]. + +use super::PackedEastAsianTraditionalYearData; + +pub const STARTING_YEAR: i32 = 1912; + +#[rustfmt::skip] +#[allow(clippy::unwrap_used)] // const +pub const DATA: &[PackedEastAsianTraditionalYearData] = { + use calendrical_calculations::gregorian::fixed_from_gregorian as gregorian; + let l = true; // long + let s = false; // short + &[ + PackedEastAsianTraditionalYearData::new(1912, [l, s, l, s, s, l, s, s, l, l, s, l, s], None, gregorian(1912, 2, 18)), + PackedEastAsianTraditionalYearData::new(1913, [l, l, s, l, s, s, l, s, s, l, s, l, s], None, gregorian(1913, 2, 6)), + PackedEastAsianTraditionalYearData::new(1914, [l, l, s, l, s, l, s, l, s, s, l, s, l], Some(6), gregorian(1914, 1, 26)), + PackedEastAsianTraditionalYearData::new(1915, [l, s, l, l, s, l, s, l, s, l, s, s, s], None, gregorian(1915, 2, 14)), + PackedEastAsianTraditionalYearData::new(1916, [l, l, s, l, s, l, l, s, l, s, l, s, s], None, gregorian(1916, 2, 3)), + PackedEastAsianTraditionalYearData::new(1917, [l, s, s, l, s, l, l, s, l, l, s, l, s], Some(3), gregorian(1917, 1, 23)), + PackedEastAsianTraditionalYearData::new(1918, [l, s, s, l, s, l, s, l, l, s, l, l, s], None, gregorian(1918, 2, 11)), + PackedEastAsianTraditionalYearData::new(1919, [s, l, s, s, l, s, s, l, l, s, l, l, l], Some(8), gregorian(1919, 2, 1)), + PackedEastAsianTraditionalYearData::new(1920, [s, l, s, s, l, s, s, l, s, l, l, l, s], None, gregorian(1920, 2, 20)), + PackedEastAsianTraditionalYearData::new(1921, [l, s, l, s, s, l, s, s, l, s, l, l, s], None, gregorian(1921, 2, 8)), + PackedEastAsianTraditionalYearData::new(1922, [l, s, l, l, s, s, l, s, s, l, s, l, l], Some(6), gregorian(1922, 1, 28)), + PackedEastAsianTraditionalYearData::new(1923, [s, l, l, s, l, s, l, s, s, l, s, l, s], None, gregorian(1923, 2, 16)), + PackedEastAsianTraditionalYearData::new(1924, [s, l, l, s, l, l, s, l, s, l, s, s, s], None, gregorian(1924, 2, 5)), + PackedEastAsianTraditionalYearData::new(1925, [l, s, l, s, l, l, s, l, l, s, l, s, l], Some(5), gregorian(1925, 1, 24)), + PackedEastAsianTraditionalYearData::new(1926, [s, s, l, s, l, s, l, l, s, l, l, s, s], None, gregorian(1926, 2, 13)), + PackedEastAsianTraditionalYearData::new(1927, [l, s, s, l, s, l, s, l, s, l, l, l, s], None, gregorian(1927, 2, 2)), + PackedEastAsianTraditionalYearData::new(1928, [s, l, s, s, l, s, s, l, s, l, l, l, l], Some(3), gregorian(1928, 1, 23)), + PackedEastAsianTraditionalYearData::new(1929, [s, l, s, s, l, s, s, l, s, l, l, l, s], None, gregorian(1929, 2, 10)), + PackedEastAsianTraditionalYearData::new(1930, [s, l, l, s, s, l, s, s, l, s, l, l, s], Some(7), gregorian(1930, 1, 30)), + PackedEastAsianTraditionalYearData::new(1931, [l, l, s, l, s, l, s, s, l, s, l, s, s], None, gregorian(1931, 2, 17)), + PackedEastAsianTraditionalYearData::new(1932, [l, l, l, s, l, s, l, s, s, l, s, l, s], None, gregorian(1932, 2, 6)), + PackedEastAsianTraditionalYearData::new(1933, [s, l, l, s, l, l, s, l, s, l, s, s, l], Some(6), gregorian(1933, 1, 26)), + PackedEastAsianTraditionalYearData::new(1934, [s, l, s, l, l, s, l, s, l, l, s, l, s], None, gregorian(1934, 2, 14)), + PackedEastAsianTraditionalYearData::new(1935, [s, s, l, s, l, s, l, l, s, l, l, s, s], None, gregorian(1935, 2, 4)), + PackedEastAsianTraditionalYearData::new(1936, [l, s, s, l, s, s, l, l, s, l, l, l, s], Some(4), gregorian(1936, 1, 24)), + PackedEastAsianTraditionalYearData::new(1937, [l, s, s, l, s, s, l, s, l, l, l, s, s], None, gregorian(1937, 2, 11)), + PackedEastAsianTraditionalYearData::new(1938, [l, l, s, s, l, s, s, l, s, l, l, s, l], Some(8), gregorian(1938, 1, 31)), + PackedEastAsianTraditionalYearData::new(1939, [l, l, s, s, l, s, s, l, s, l, s, l, s], None, gregorian(1939, 2, 19)), + PackedEastAsianTraditionalYearData::new(1940, [l, l, s, l, s, l, s, s, l, s, l, s, s], None, gregorian(1940, 2, 8)), + PackedEastAsianTraditionalYearData::new(1941, [l, l, s, l, l, s, l, s, s, l, s, l, s], Some(7), gregorian(1941, 1, 27)), + PackedEastAsianTraditionalYearData::new(1942, [l, s, l, l, s, l, s, l, s, l, s, l, s], None, gregorian(1942, 2, 15)), + PackedEastAsianTraditionalYearData::new(1943, [s, l, s, l, s, l, l, s, l, s, l, s, s], None, gregorian(1943, 2, 5)), + PackedEastAsianTraditionalYearData::new(1944, [l, s, l, s, l, s, l, s, l, l, s, l, l], Some(5), gregorian(1944, 1, 25)), + PackedEastAsianTraditionalYearData::new(1945, [s, s, l, s, s, l, s, l, l, l, s, l, s], None, gregorian(1945, 2, 13)), + PackedEastAsianTraditionalYearData::new(1946, [l, s, s, l, s, s, l, s, l, l, s, l, s], None, gregorian(1946, 2, 2)), + PackedEastAsianTraditionalYearData::new(1947, [l, l, s, s, l, s, s, l, s, l, s, l, l], Some(3), gregorian(1947, 1, 22)), + PackedEastAsianTraditionalYearData::new(1948, [l, s, l, s, l, s, s, l, s, l, s, l, s], None, gregorian(1948, 2, 10)), + PackedEastAsianTraditionalYearData::new(1949, [l, s, l, l, s, l, s, s, l, s, l, s, l], Some(8), gregorian(1949, 1, 29)), + PackedEastAsianTraditionalYearData::new(1950, [s, l, l, s, l, l, s, s, l, s, l, s, s], None, gregorian(1950, 2, 17)), + PackedEastAsianTraditionalYearData::new(1951, [l, s, l, l, s, l, s, l, s, l, s, l, s], None, gregorian(1951, 2, 6)), + PackedEastAsianTraditionalYearData::new(1952, [s, l, s, l, s, l, s, l, l, s, l, s, l], Some(6), gregorian(1952, 1, 27)), + PackedEastAsianTraditionalYearData::new(1953, [s, l, s, s, l, l, s, l, l, s, l, s, s], None, gregorian(1953, 2, 14)), + PackedEastAsianTraditionalYearData::new(1954, [l, s, l, s, s, l, s, l, l, s, l, l, s], None, gregorian(1954, 2, 3)), + PackedEastAsianTraditionalYearData::new(1955, [s, l, s, l, s, s, l, s, l, s, l, l, l], Some(4), gregorian(1955, 1, 24)), + PackedEastAsianTraditionalYearData::new(1956, [s, l, s, l, s, s, l, s, l, s, l, l, s], None, gregorian(1956, 2, 12)), + PackedEastAsianTraditionalYearData::new(1957, [l, s, l, s, l, s, s, l, s, l, s, l, s], Some(9), gregorian(1957, 1, 31)), + PackedEastAsianTraditionalYearData::new(1958, [l, l, l, s, l, s, s, l, s, l, s, l, s], None, gregorian(1958, 2, 18)), + PackedEastAsianTraditionalYearData::new(1959, [s, l, l, s, l, s, l, s, l, s, l, s, s], None, gregorian(1959, 2, 8)), + PackedEastAsianTraditionalYearData::new(1960, [l, s, l, s, l, l, s, l, s, l, s, l, s], Some(7), gregorian(1960, 1, 28)), + PackedEastAsianTraditionalYearData::new(1961, [l, s, l, s, l, s, l, l, s, l, s, l, s], None, gregorian(1961, 2, 15)), + PackedEastAsianTraditionalYearData::new(1962, [s, l, s, s, l, s, l, l, s, l, l, s, s], None, gregorian(1962, 2, 5)), + PackedEastAsianTraditionalYearData::new(1963, [l, s, l, s, s, l, s, l, s, l, l, l, s], Some(5), gregorian(1963, 1, 25)), + PackedEastAsianTraditionalYearData::new(1964, [l, s, l, s, s, l, s, l, s, l, l, l, s], None, gregorian(1964, 2, 13)), + PackedEastAsianTraditionalYearData::new(1965, [s, l, s, l, s, s, l, s, s, l, l, s, s], None, gregorian(1965, 2, 2)), + PackedEastAsianTraditionalYearData::new(1966, [l, l, l, s, l, s, s, l, s, s, l, l, s], Some(4), gregorian(1966, 1, 21)), + PackedEastAsianTraditionalYearData::new(1967, [l, l, s, l, l, s, s, l, s, l, s, l, s], None, gregorian(1967, 2, 9)), + PackedEastAsianTraditionalYearData::new(1968, [s, l, s, l, l, s, l, s, l, s, l, s, l], Some(8), gregorian(1968, 1, 30)), + PackedEastAsianTraditionalYearData::new(1969, [s, l, s, l, s, l, l, s, l, s, l, s, s], None, gregorian(1969, 2, 17)), + PackedEastAsianTraditionalYearData::new(1970, [l, s, s, l, s, l, l, s, l, l, s, l, s], None, gregorian(1970, 2, 6)), + PackedEastAsianTraditionalYearData::new(1971, [s, l, s, s, l, s, l, s, l, l, l, s, l], Some(6), gregorian(1971, 1, 27)), + PackedEastAsianTraditionalYearData::new(1972, [s, l, s, s, l, s, l, s, l, l, s, l, s], None, gregorian(1972, 2, 15)), + PackedEastAsianTraditionalYearData::new(1973, [l, s, l, s, s, l, s, s, l, l, s, l, s], None, gregorian(1973, 2, 3)), + PackedEastAsianTraditionalYearData::new(1974, [l, l, s, l, s, s, l, s, s, l, l, s, l], Some(5), gregorian(1974, 1, 23)), + PackedEastAsianTraditionalYearData::new(1975, [l, l, s, l, s, s, l, s, s, l, s, l, s], None, gregorian(1975, 2, 11)), + PackedEastAsianTraditionalYearData::new(1976, [l, l, s, l, s, l, s, l, s, s, l, s, l], Some(9), gregorian(1976, 1, 31)), + PackedEastAsianTraditionalYearData::new(1977, [l, s, l, l, s, l, s, l, s, l, s, s, s], None, gregorian(1977, 2, 18)), + PackedEastAsianTraditionalYearData::new(1978, [l, s, l, l, s, l, l, s, l, s, l, s, s], None, gregorian(1978, 2, 7)), + PackedEastAsianTraditionalYearData::new(1979, [l, s, s, l, s, l, l, s, l, l, s, l, s], Some(7), gregorian(1979, 1, 28)), + PackedEastAsianTraditionalYearData::new(1980, [l, s, s, l, s, l, s, l, l, s, l, l, s], None, gregorian(1980, 2, 16)), + PackedEastAsianTraditionalYearData::new(1981, [s, l, s, s, l, s, s, l, l, s, l, l, s], None, gregorian(1981, 2, 5)), + PackedEastAsianTraditionalYearData::new(1982, [l, s, l, s, s, l, s, s, l, s, l, l, l], Some(5), gregorian(1982, 1, 25)), + PackedEastAsianTraditionalYearData::new(1983, [l, s, l, s, s, l, s, s, l, s, l, l, s], None, gregorian(1983, 2, 13)), + PackedEastAsianTraditionalYearData::new(1984, [l, s, l, l, s, s, l, s, s, l, s, l, l], Some(11), gregorian(1984, 2, 2)), + PackedEastAsianTraditionalYearData::new(1985, [s, l, l, s, l, s, l, s, s, l, s, l, s], None, gregorian(1985, 2, 20)), + PackedEastAsianTraditionalYearData::new(1986, [s, l, l, s, l, l, s, l, s, l, s, s, s], None, gregorian(1986, 2, 9)), + PackedEastAsianTraditionalYearData::new(1987, [l, s, l, s, l, l, s, l, l, s, l, s, s], Some(7), gregorian(1987, 1, 29)), + PackedEastAsianTraditionalYearData::new(1988, [l, s, l, s, l, s, l, l, s, l, l, s, s], None, gregorian(1988, 2, 17)), + PackedEastAsianTraditionalYearData::new(1989, [l, s, s, l, s, l, s, l, s, l, l, l, s], None, gregorian(1989, 2, 6)), + PackedEastAsianTraditionalYearData::new(1990, [s, l, s, s, l, s, s, l, s, l, l, l, l], Some(6), gregorian(1990, 1, 27)), + PackedEastAsianTraditionalYearData::new(1991, [s, l, s, s, l, s, s, l, s, l, l, l, s], None, gregorian(1991, 2, 15)), + PackedEastAsianTraditionalYearData::new(1992, [s, l, l, s, s, l, s, s, l, s, l, l, s], None, gregorian(1992, 2, 4)), + PackedEastAsianTraditionalYearData::new(1993, [s, l, l, s, l, s, l, s, s, l, s, l, s], Some(4), gregorian(1993, 1, 23)), + PackedEastAsianTraditionalYearData::new(1994, [l, l, l, s, l, s, l, s, s, l, s, l, s], None, gregorian(1994, 2, 10)), + PackedEastAsianTraditionalYearData::new(1995, [s, l, l, s, l, s, l, l, s, s, l, s, l], Some(9), gregorian(1995, 1, 31)), + PackedEastAsianTraditionalYearData::new(1996, [s, l, s, l, l, s, l, s, l, l, s, s, s], None, gregorian(1996, 2, 19)), + PackedEastAsianTraditionalYearData::new(1997, [l, s, l, s, l, s, l, l, s, l, l, s, s], None, gregorian(1997, 2, 7)), + PackedEastAsianTraditionalYearData::new(1998, [l, s, s, l, s, s, l, l, s, l, l, s, l], Some(6), gregorian(1998, 1, 28)), + PackedEastAsianTraditionalYearData::new(1999, [l, s, s, l, s, s, l, s, l, l, l, s, s], None, gregorian(1999, 2, 16)), + PackedEastAsianTraditionalYearData::new(2000, [l, l, s, s, l, s, s, l, s, l, l, s, s], None, gregorian(2000, 2, 5)), + PackedEastAsianTraditionalYearData::new(2001, [l, l, s, l, s, l, s, s, l, s, l, s, l], Some(5), gregorian(2001, 1, 24)), + PackedEastAsianTraditionalYearData::new(2002, [l, l, s, l, s, l, s, s, l, s, l, s, s], None, gregorian(2002, 2, 12)), + PackedEastAsianTraditionalYearData::new(2003, [l, l, s, l, l, s, l, s, s, l, s, l, s], None, gregorian(2003, 2, 1)), + PackedEastAsianTraditionalYearData::new(2004, [s, l, s, l, l, s, l, s, l, s, l, s, l], Some(3), gregorian(2004, 1, 22)), + PackedEastAsianTraditionalYearData::new(2005, [s, l, s, l, s, l, l, s, l, s, l, s, s], None, gregorian(2005, 2, 9)), + PackedEastAsianTraditionalYearData::new(2006, [l, s, l, s, l, s, l, s, l, l, s, l, l], Some(8), gregorian(2006, 1, 29)), + PackedEastAsianTraditionalYearData::new(2007, [s, s, l, s, s, l, s, l, l, l, s, l, s], None, gregorian(2007, 2, 18)), + PackedEastAsianTraditionalYearData::new(2008, [l, s, s, l, s, s, l, s, l, l, s, l, s], None, gregorian(2008, 2, 7)), + PackedEastAsianTraditionalYearData::new(2009, [l, l, s, s, l, s, s, l, s, l, s, l, l], Some(6), gregorian(2009, 1, 26)), + PackedEastAsianTraditionalYearData::new(2010, [l, s, l, s, l, s, s, l, s, l, s, l, s], None, gregorian(2010, 2, 14)), + PackedEastAsianTraditionalYearData::new(2011, [l, s, l, l, s, l, s, s, l, s, l, s, s], None, gregorian(2011, 2, 3)), + PackedEastAsianTraditionalYearData::new(2012, [l, s, l, l, s, l, s, l, s, l, s, l, s], Some(5), gregorian(2012, 1, 23)), + PackedEastAsianTraditionalYearData::new(2013, [l, s, l, s, l, l, s, l, s, l, s, l, s], None, gregorian(2013, 2, 10)), + PackedEastAsianTraditionalYearData::new(2014, [s, l, s, l, s, l, s, l, l, s, l, s, l], Some(10), gregorian(2014, 1, 31)), + PackedEastAsianTraditionalYearData::new(2015, [s, l, s, s, l, s, l, l, l, s, l, s, s], None, gregorian(2015, 2, 19)), + PackedEastAsianTraditionalYearData::new(2016, [l, s, l, s, s, l, s, l, l, s, l, l, s], None, gregorian(2016, 2, 8)), + PackedEastAsianTraditionalYearData::new(2017, [s, l, s, l, s, s, l, s, l, s, l, l, l], Some(7), gregorian(2017, 1, 28)), + PackedEastAsianTraditionalYearData::new(2018, [s, l, s, l, s, s, l, s, l, s, l, l, s], None, gregorian(2018, 2, 16)), + PackedEastAsianTraditionalYearData::new(2019, [l, s, l, s, l, s, s, l, s, s, l, l, s], None, gregorian(2019, 2, 5)), + PackedEastAsianTraditionalYearData::new(2020, [s, l, l, l, s, l, s, s, l, s, l, s, l], Some(5), gregorian(2020, 1, 25)), + PackedEastAsianTraditionalYearData::new(2021, [s, l, l, s, l, s, l, s, l, s, l, s, s], None, gregorian(2021, 2, 12)), + PackedEastAsianTraditionalYearData::new(2022, [l, s, l, s, l, l, s, l, s, l, s, l, s], None, gregorian(2022, 2, 1)), + PackedEastAsianTraditionalYearData::new(2023, [s, l, s, s, l, l, s, l, l, s, l, s, l], Some(3), gregorian(2023, 1, 22)), + PackedEastAsianTraditionalYearData::new(2024, [s, l, s, s, l, s, l, l, s, l, l, s, s], None, gregorian(2024, 2, 10)), + PackedEastAsianTraditionalYearData::new(2025, [l, s, l, s, s, l, s, l, s, l, l, l, s], Some(7), gregorian(2025, 1, 29)), + PackedEastAsianTraditionalYearData::new(2026, [l, s, l, s, s, l, s, s, l, l, l, s, s], None, gregorian(2026, 2, 17)), + PackedEastAsianTraditionalYearData::new(2027, [l, l, s, l, s, s, l, s, s, l, l, s, s], None, gregorian(2027, 2, 6)), + PackedEastAsianTraditionalYearData::new(2028, [l, l, l, s, l, s, s, l, s, s, l, l, s], Some(6), gregorian(2028, 1, 26)), + PackedEastAsianTraditionalYearData::new(2029, [l, l, s, l, s, l, s, l, s, s, l, l, s], None, gregorian(2029, 2, 13)), + PackedEastAsianTraditionalYearData::new(2030, [s, l, s, l, l, s, l, s, l, s, l, s, s], None, gregorian(2030, 2, 3)), + PackedEastAsianTraditionalYearData::new(2031, [s, l, l, s, l, s, l, l, s, l, s, l, s], Some(4), gregorian(2031, 1, 23)), + PackedEastAsianTraditionalYearData::new(2032, [l, s, s, l, s, l, l, s, l, l, s, l, s], None, gregorian(2032, 2, 11)), + PackedEastAsianTraditionalYearData::new(2033, [s, l, s, s, l, s, l, s, l, l, l, s, l], Some(12), gregorian(2033, 1, 31)), + PackedEastAsianTraditionalYearData::new(2034, [s, l, s, s, l, s, l, s, l, l, s, l, s], None, gregorian(2034, 2, 19)), + PackedEastAsianTraditionalYearData::new(2035, [l, s, l, s, s, l, s, s, l, l, s, l, s], None, gregorian(2035, 2, 8)), + PackedEastAsianTraditionalYearData::new(2036, [l, l, s, l, s, s, l, s, s, l, s, l, l], Some(7), gregorian(2036, 1, 28)), + PackedEastAsianTraditionalYearData::new(2037, [l, l, s, l, s, s, l, s, s, l, s, l, s], None, gregorian(2037, 2, 15)), + PackedEastAsianTraditionalYearData::new(2038, [l, l, s, l, s, l, s, l, s, s, l, s, s], None, gregorian(2038, 2, 4)), + PackedEastAsianTraditionalYearData::new(2039, [l, l, s, l, l, s, l, s, l, s, l, s, s], Some(6), gregorian(2039, 1, 24)), + PackedEastAsianTraditionalYearData::new(2040, [l, s, l, l, s, l, s, l, l, s, l, s, s], None, gregorian(2040, 2, 12)), + PackedEastAsianTraditionalYearData::new(2041, [s, l, s, l, s, l, l, s, l, l, s, l, s], None, gregorian(2041, 2, 1)), + PackedEastAsianTraditionalYearData::new(2042, [s, l, s, s, l, s, l, s, l, l, s, l, l], Some(3), gregorian(2042, 1, 22)), + PackedEastAsianTraditionalYearData::new(2043, [s, l, s, s, l, s, s, l, l, s, l, l, s], None, gregorian(2043, 2, 10)), + PackedEastAsianTraditionalYearData::new(2044, [l, s, l, s, s, l, s, s, l, s, l, l, l], Some(8), gregorian(2044, 1, 30)), + PackedEastAsianTraditionalYearData::new(2045, [l, s, l, s, s, l, s, s, l, s, l, l, s], None, gregorian(2045, 2, 17)), + PackedEastAsianTraditionalYearData::new(2046, [l, s, l, s, l, s, l, s, s, l, s, l, s], None, gregorian(2046, 2, 6)), + PackedEastAsianTraditionalYearData::new(2047, [l, s, l, l, s, l, s, l, s, s, l, s, l], Some(6), gregorian(2047, 1, 26)), + PackedEastAsianTraditionalYearData::new(2048, [s, l, l, s, l, l, s, l, s, s, l, s, s], None, gregorian(2048, 2, 14)), + PackedEastAsianTraditionalYearData::new(2049, [l, s, l, s, l, l, s, l, l, s, l, s, s], None, gregorian(2049, 2, 2)), + PackedEastAsianTraditionalYearData::new(2050, [s, l, s, l, s, l, s, l, l, s, l, l, s], Some(4), gregorian(2050, 1, 23)), + PackedEastAsianTraditionalYearData::new(2051, [l, s, s, l, s, s, l, l, s, l, l, l, s], None, gregorian(2051, 2, 11)), + PackedEastAsianTraditionalYearData::new(2052, [s, l, s, s, l, s, s, l, s, l, l, l, l], Some(9), gregorian(2052, 2, 1)), + PackedEastAsianTraditionalYearData::new(2053, [s, l, s, s, l, s, s, l, s, l, l, l, s], None, gregorian(2053, 2, 19)), + PackedEastAsianTraditionalYearData::new(2054, [s, l, l, s, s, l, s, s, l, s, l, l, s], None, gregorian(2054, 2, 8)), + PackedEastAsianTraditionalYearData::new(2055, [s, l, l, s, l, s, l, s, s, l, s, l, s], Some(7), gregorian(2055, 1, 28)), + PackedEastAsianTraditionalYearData::new(2056, [l, l, l, s, l, s, l, s, s, l, s, l, s], None, gregorian(2056, 2, 15)), + PackedEastAsianTraditionalYearData::new(2057, [s, l, l, s, l, s, l, s, l, s, l, s, s], None, gregorian(2057, 2, 4)), + PackedEastAsianTraditionalYearData::new(2058, [l, s, l, s, l, s, l, l, s, l, l, s, s], Some(5), gregorian(2058, 1, 24)), + PackedEastAsianTraditionalYearData::new(2059, [l, s, l, s, l, s, l, s, l, l, l, s, s], None, gregorian(2059, 2, 12)), + PackedEastAsianTraditionalYearData::new(2060, [l, s, s, l, s, s, l, s, l, l, l, s, s], None, gregorian(2060, 2, 2)), + PackedEastAsianTraditionalYearData::new(2061, [l, l, s, s, l, s, s, l, s, l, l, l, s], Some(4), gregorian(2061, 1, 21)), + PackedEastAsianTraditionalYearData::new(2062, [l, l, s, s, l, s, s, l, s, l, l, s, s], None, gregorian(2062, 2, 9)), + PackedEastAsianTraditionalYearData::new(2063, [l, l, s, l, s, l, s, s, l, s, l, s, l], Some(8), gregorian(2063, 1, 29)), + PackedEastAsianTraditionalYearData::new(2064, [l, l, s, l, s, l, s, s, l, s, l, s, s], None, gregorian(2064, 2, 17)), + PackedEastAsianTraditionalYearData::new(2065, [l, l, s, l, l, s, l, s, s, l, s, l, s], None, gregorian(2065, 2, 5)), + PackedEastAsianTraditionalYearData::new(2066, [s, l, s, l, l, s, l, s, l, s, l, s, l], Some(6), gregorian(2066, 1, 26)), + PackedEastAsianTraditionalYearData::new(2067, [s, l, s, l, s, l, l, s, l, s, l, s, s], None, gregorian(2067, 2, 14)), + PackedEastAsianTraditionalYearData::new(2068, [l, s, l, s, s, l, l, s, l, l, s, l, s], None, gregorian(2068, 2, 3)), + PackedEastAsianTraditionalYearData::new(2069, [s, l, s, l, s, s, l, s, l, l, l, s, l], Some(5), gregorian(2069, 1, 23)), + PackedEastAsianTraditionalYearData::new(2070, [s, l, s, l, s, s, l, s, l, l, s, l, s], None, gregorian(2070, 2, 11)), + PackedEastAsianTraditionalYearData::new(2071, [l, s, l, s, l, s, s, l, s, l, s, l, l], Some(9), gregorian(2071, 1, 31)), + PackedEastAsianTraditionalYearData::new(2072, [l, s, l, s, l, s, s, l, s, l, s, l, s], None, gregorian(2072, 2, 19)), + PackedEastAsianTraditionalYearData::new(2073, [l, s, l, l, s, l, s, s, l, s, l, s, s], None, gregorian(2073, 2, 7)), + PackedEastAsianTraditionalYearData::new(2074, [l, s, l, l, s, l, s, l, s, l, s, l, s], Some(7), gregorian(2074, 1, 27)), + PackedEastAsianTraditionalYearData::new(2075, [l, s, l, s, l, l, s, l, s, l, s, l, s], None, gregorian(2075, 2, 15)), + PackedEastAsianTraditionalYearData::new(2076, [s, l, s, l, s, l, s, l, l, s, l, s, s], None, gregorian(2076, 2, 5)), + PackedEastAsianTraditionalYearData::new(2077, [l, s, l, s, s, l, s, l, l, l, s, l, s], Some(5), gregorian(2077, 1, 24)), + PackedEastAsianTraditionalYearData::new(2078, [l, s, l, s, s, l, s, l, l, s, l, l, s], None, gregorian(2078, 2, 12)), + PackedEastAsianTraditionalYearData::new(2079, [s, l, s, l, s, s, l, s, l, s, l, l, s], None, gregorian(2079, 2, 2)), + PackedEastAsianTraditionalYearData::new(2080, [l, s, l, s, l, s, s, l, s, s, l, l, l], Some(4), gregorian(2080, 1, 22)), + PackedEastAsianTraditionalYearData::new(2081, [s, l, l, s, l, s, s, l, s, s, l, l, s], None, gregorian(2081, 2, 9)), + PackedEastAsianTraditionalYearData::new(2082, [s, l, l, l, s, s, l, s, l, s, s, l, l], Some(8), gregorian(2082, 1, 29)), + PackedEastAsianTraditionalYearData::new(2083, [s, l, l, s, l, s, l, s, l, s, l, s, s], None, gregorian(2083, 2, 17)), + PackedEastAsianTraditionalYearData::new(2084, [l, s, l, s, l, l, s, l, s, l, s, l, s], None, gregorian(2084, 2, 6)), + PackedEastAsianTraditionalYearData::new(2085, [s, l, s, s, l, l, s, l, l, s, l, s, l], Some(6), gregorian(2085, 1, 26)), + PackedEastAsianTraditionalYearData::new(2086, [s, l, s, s, l, s, l, l, s, l, l, s, s], None, gregorian(2086, 2, 14)), + PackedEastAsianTraditionalYearData::new(2087, [l, s, l, s, s, l, s, l, s, l, l, l, s], None, gregorian(2087, 2, 3)), + PackedEastAsianTraditionalYearData::new(2088, [s, l, s, l, s, s, l, s, s, l, l, l, s], Some(5), gregorian(2088, 1, 24)), + PackedEastAsianTraditionalYearData::new(2089, [l, l, s, l, s, s, s, l, s, l, l, s, s], None, gregorian(2089, 2, 10)), + PackedEastAsianTraditionalYearData::new(2090, [l, l, l, s, l, s, s, l, s, s, l, l, s], Some(9), gregorian(2090, 1, 30)), + PackedEastAsianTraditionalYearData::new(2091, [l, l, s, l, s, l, s, l, s, s, l, s, s], None, gregorian(2091, 2, 18)), + PackedEastAsianTraditionalYearData::new(2092, [l, l, s, l, l, s, l, s, l, s, l, s, s], None, gregorian(2092, 2, 7)), + PackedEastAsianTraditionalYearData::new(2093, [s, l, l, s, l, s, l, l, s, l, s, l, s], Some(7), gregorian(2093, 1, 27)), + PackedEastAsianTraditionalYearData::new(2094, [s, l, s, l, s, l, l, s, l, l, s, l, s], None, gregorian(2094, 2, 15)), + PackedEastAsianTraditionalYearData::new(2095, [s, l, s, s, l, s, l, s, l, l, l, s, s], None, gregorian(2095, 2, 5)), + PackedEastAsianTraditionalYearData::new(2096, [l, s, l, s, s, l, s, s, l, l, l, s, l], Some(5), gregorian(2096, 1, 25)), + PackedEastAsianTraditionalYearData::new(2097, [l, s, l, s, s, s, l, s, l, l, s, l, s], None, gregorian(2097, 2, 12)), + PackedEastAsianTraditionalYearData::new(2098, [l, l, s, l, s, s, s, l, s, l, s, l, s], None, gregorian(2098, 2, 1)), + PackedEastAsianTraditionalYearData::new(2099, [l, l, s, l, l, s, s, l, s, s, l, s, l], Some(3), gregorian(2099, 1, 21)), + PackedEastAsianTraditionalYearData::new(2100, [l, l, s, l, s, l, s, l, s, s, l, s, s], None, gregorian(2100, 2, 9)), + // Extra two years of correct data because the simple calculation lines up at the beginning of 2103 + PackedEastAsianTraditionalYearData::new(2101, [l, l, s, l, l, s, l, s, l, s, s, l, s], Some(8), gregorian(2101, 1, 29)), + PackedEastAsianTraditionalYearData::new(2102, [l, s, l, l, s, l, s, l, l, s, l, s, s], None, gregorian(2102, 2, 17)), + ] +}; + +#[test] +fn test_against_calendrical_calculations() { + use calendrical_calculations::chinese_based::Chinese; + for (i, &data) in DATA.iter().enumerate() { + assert_eq!( + data, + super::EastAsianTraditionalYearData::calendrical_calculations::( + STARTING_YEAR + i as i32 + ) + .packed + ); + } +} diff --git a/deps/crates/vendor/icu_calendar/src/cal/east_asian_traditional/korea_data.rs b/deps/crates/vendor/icu_calendar/src/cal/east_asian_traditional/korea_data.rs new file mode 100644 index 00000000000000..bf4cffc45cb724 --- /dev/null +++ b/deps/crates/vendor/icu_calendar/src/cal/east_asian_traditional/korea_data.rs @@ -0,0 +1,225 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +//! Data obtained from [`calendrical_calculations`]. + +use super::PackedEastAsianTraditionalYearData; + +pub const STARTING_YEAR: i32 = 1912; + +#[rustfmt::skip] +#[allow(clippy::unwrap_used)] // const +pub const DATA: &[PackedEastAsianTraditionalYearData] = { + use calendrical_calculations::gregorian::fixed_from_gregorian as gregorian; + let l = true; // long + let s = false; // short + &[ + PackedEastAsianTraditionalYearData::new(1912, [l, s, l, s, s, l, s, s, l, l, s, l, s], None, gregorian(1912, 2, 18)), + PackedEastAsianTraditionalYearData::new(1913, [l, l, s, l, s, s, l, s, s, l, s, l, s], None, gregorian(1913, 2, 6)), + PackedEastAsianTraditionalYearData::new(1914, [l, l, s, l, l, s, s, l, s, l, s, s, l], Some(6), gregorian(1914, 1, 26)), + PackedEastAsianTraditionalYearData::new(1915, [l, s, l, l, s, l, s, l, s, l, s, l, s], None, gregorian(1915, 2, 14)), + PackedEastAsianTraditionalYearData::new(1916, [s, l, s, l, s, l, l, s, l, s, l, s, s], None, gregorian(1916, 2, 4)), + PackedEastAsianTraditionalYearData::new(1917, [l, s, s, l, s, l, l, s, l, l, s, l, s], Some(3), gregorian(1917, 1, 23)), + PackedEastAsianTraditionalYearData::new(1918, [l, s, s, l, s, l, s, l, l, l, s, l, s], None, gregorian(1918, 2, 11)), + PackedEastAsianTraditionalYearData::new(1919, [s, l, s, s, l, s, l, s, l, l, s, l, l], Some(8), gregorian(1919, 2, 1)), + PackedEastAsianTraditionalYearData::new(1920, [s, l, s, s, l, s, s, l, l, s, l, l, s], None, gregorian(1920, 2, 20)), + PackedEastAsianTraditionalYearData::new(1921, [l, s, l, s, s, l, s, s, l, s, l, l, s], None, gregorian(1921, 2, 8)), + PackedEastAsianTraditionalYearData::new(1922, [l, s, l, l, s, s, l, s, s, l, s, l, l], Some(6), gregorian(1922, 1, 28)), + PackedEastAsianTraditionalYearData::new(1923, [s, l, l, s, l, s, l, s, l, s, s, l, s], None, gregorian(1923, 2, 16)), + PackedEastAsianTraditionalYearData::new(1924, [l, s, l, s, l, l, s, l, s, l, s, s, s], None, gregorian(1924, 2, 5)), + PackedEastAsianTraditionalYearData::new(1925, [l, s, l, l, s, l, s, l, l, s, l, s, l], Some(5), gregorian(1925, 1, 24)), + PackedEastAsianTraditionalYearData::new(1926, [s, s, l, s, l, s, l, l, s, l, l, s, s], None, gregorian(1926, 2, 13)), + PackedEastAsianTraditionalYearData::new(1927, [l, s, s, l, s, l, s, l, l, s, l, l, s], None, gregorian(1927, 2, 2)), + PackedEastAsianTraditionalYearData::new(1928, [s, l, s, s, l, s, s, l, l, s, l, l, l], Some(3), gregorian(1928, 1, 23)), + PackedEastAsianTraditionalYearData::new(1929, [s, l, s, s, l, s, s, l, s, l, l, l, s], None, gregorian(1929, 2, 10)), + PackedEastAsianTraditionalYearData::new(1930, [s, l, l, s, s, l, s, s, l, s, l, l, s], Some(7), gregorian(1930, 1, 30)), + PackedEastAsianTraditionalYearData::new(1931, [l, l, l, s, s, l, s, s, l, s, l, s, s], None, gregorian(1931, 2, 17)), + PackedEastAsianTraditionalYearData::new(1932, [l, l, l, s, l, s, l, s, s, l, s, l, s], None, gregorian(1932, 2, 6)), + PackedEastAsianTraditionalYearData::new(1933, [s, l, l, s, l, l, s, l, s, l, s, s, l], Some(6), gregorian(1933, 1, 26)), + PackedEastAsianTraditionalYearData::new(1934, [s, l, s, l, l, s, l, l, s, l, s, l, s], None, gregorian(1934, 2, 14)), + PackedEastAsianTraditionalYearData::new(1935, [s, s, l, s, l, s, l, l, s, l, l, s, s], None, gregorian(1935, 2, 4)), + PackedEastAsianTraditionalYearData::new(1936, [l, s, s, l, s, l, s, l, s, l, l, l, s], Some(4), gregorian(1936, 1, 24)), + PackedEastAsianTraditionalYearData::new(1937, [l, s, s, l, s, s, l, s, l, l, l, s, s], None, gregorian(1937, 2, 11)), + PackedEastAsianTraditionalYearData::new(1938, [l, l, s, s, l, s, s, l, s, l, l, s, l], Some(8), gregorian(1938, 1, 31)), + PackedEastAsianTraditionalYearData::new(1939, [l, l, s, s, l, s, s, l, s, l, s, l, s], None, gregorian(1939, 2, 19)), + PackedEastAsianTraditionalYearData::new(1940, [l, l, s, l, s, l, s, s, l, s, l, s, s], None, gregorian(1940, 2, 8)), + PackedEastAsianTraditionalYearData::new(1941, [l, l, s, l, l, s, l, s, s, l, s, l, s], Some(7), gregorian(1941, 1, 27)), + PackedEastAsianTraditionalYearData::new(1942, [l, s, l, l, s, l, l, s, l, s, s, l, s], None, gregorian(1942, 2, 15)), + PackedEastAsianTraditionalYearData::new(1943, [s, l, s, l, s, l, l, s, l, l, s, l, s], None, gregorian(1943, 2, 5)), + PackedEastAsianTraditionalYearData::new(1944, [s, s, l, s, l, s, l, s, l, l, s, l, l], Some(5), gregorian(1944, 1, 26)), + PackedEastAsianTraditionalYearData::new(1945, [s, s, l, s, s, l, s, l, l, l, s, l, s], None, gregorian(1945, 2, 13)), + PackedEastAsianTraditionalYearData::new(1946, [l, s, s, l, s, s, l, s, l, l, s, l, s], None, gregorian(1946, 2, 2)), + PackedEastAsianTraditionalYearData::new(1947, [l, l, s, s, l, s, s, l, s, l, s, l, l], Some(3), gregorian(1947, 1, 22)), + PackedEastAsianTraditionalYearData::new(1948, [l, s, l, s, l, s, s, l, s, l, s, l, s], None, gregorian(1948, 2, 10)), + PackedEastAsianTraditionalYearData::new(1949, [l, l, s, l, s, l, s, s, l, s, l, s, l], Some(8), gregorian(1949, 1, 29)), + PackedEastAsianTraditionalYearData::new(1950, [l, s, l, l, s, l, s, s, l, s, l, s, s], None, gregorian(1950, 2, 17)), + PackedEastAsianTraditionalYearData::new(1951, [l, s, l, l, s, l, s, l, s, l, s, l, s], None, gregorian(1951, 2, 6)), + PackedEastAsianTraditionalYearData::new(1952, [s, l, s, l, s, l, l, s, l, s, l, s, l], Some(6), gregorian(1952, 1, 27)), + PackedEastAsianTraditionalYearData::new(1953, [s, l, s, s, l, l, s, l, l, s, l, l, s], None, gregorian(1953, 2, 14)), + PackedEastAsianTraditionalYearData::new(1954, [s, s, l, s, s, l, s, l, l, s, l, l, s], None, gregorian(1954, 2, 4)), + PackedEastAsianTraditionalYearData::new(1955, [l, s, s, l, s, s, l, s, l, s, l, l, l], Some(4), gregorian(1955, 1, 24)), + PackedEastAsianTraditionalYearData::new(1956, [s, l, s, l, s, s, l, s, l, s, l, l, s], None, gregorian(1956, 2, 12)), + PackedEastAsianTraditionalYearData::new(1957, [l, s, l, s, l, s, s, l, s, l, s, l, l], Some(9), gregorian(1957, 1, 31)), + PackedEastAsianTraditionalYearData::new(1958, [s, l, l, s, l, s, s, l, s, l, s, l, s], None, gregorian(1958, 2, 19)), + PackedEastAsianTraditionalYearData::new(1959, [s, l, l, s, l, s, l, s, l, s, l, s, s], None, gregorian(1959, 2, 8)), + PackedEastAsianTraditionalYearData::new(1960, [l, s, l, s, l, l, s, l, s, l, s, l, s], Some(7), gregorian(1960, 1, 28)), + PackedEastAsianTraditionalYearData::new(1961, [l, s, l, s, l, s, l, l, s, l, s, l, s], None, gregorian(1961, 2, 15)), + PackedEastAsianTraditionalYearData::new(1962, [s, l, s, s, l, s, l, l, s, l, l, s, s], None, gregorian(1962, 2, 5)), + PackedEastAsianTraditionalYearData::new(1963, [l, s, l, s, s, l, s, l, s, l, l, l, s], Some(5), gregorian(1963, 1, 25)), + PackedEastAsianTraditionalYearData::new(1964, [l, s, l, s, s, l, s, l, s, l, l, l, s], None, gregorian(1964, 2, 13)), + PackedEastAsianTraditionalYearData::new(1965, [s, l, s, l, s, s, l, s, s, l, l, l, s], None, gregorian(1965, 2, 2)), + PackedEastAsianTraditionalYearData::new(1966, [s, l, l, s, l, s, s, l, s, s, l, l, s], Some(4), gregorian(1966, 1, 22)), + PackedEastAsianTraditionalYearData::new(1967, [l, l, s, l, l, s, s, l, s, l, s, l, s], None, gregorian(1967, 2, 9)), + PackedEastAsianTraditionalYearData::new(1968, [s, l, l, s, l, s, l, s, l, s, l, s, l], Some(8), gregorian(1968, 1, 30)), + PackedEastAsianTraditionalYearData::new(1969, [s, l, s, l, s, l, l, s, l, s, l, s, s], None, gregorian(1969, 2, 17)), + PackedEastAsianTraditionalYearData::new(1970, [l, s, s, l, l, s, l, s, l, l, s, l, s], None, gregorian(1970, 2, 6)), + PackedEastAsianTraditionalYearData::new(1971, [s, l, s, s, l, s, l, s, l, l, l, s, l], Some(6), gregorian(1971, 1, 27)), + PackedEastAsianTraditionalYearData::new(1972, [s, l, s, s, l, s, l, s, l, l, l, s, s], None, gregorian(1972, 2, 15)), + PackedEastAsianTraditionalYearData::new(1973, [l, s, l, s, s, l, s, s, l, l, l, s, s], None, gregorian(1973, 2, 3)), + PackedEastAsianTraditionalYearData::new(1974, [l, l, s, l, s, s, l, s, s, l, l, s, l], Some(5), gregorian(1974, 1, 23)), + PackedEastAsianTraditionalYearData::new(1975, [l, l, s, l, s, s, l, s, s, l, s, l, s], None, gregorian(1975, 2, 11)), + PackedEastAsianTraditionalYearData::new(1976, [l, l, s, l, s, l, s, l, s, l, s, s, l], Some(9), gregorian(1976, 1, 31)), + PackedEastAsianTraditionalYearData::new(1977, [l, s, l, l, s, l, s, l, s, l, s, s, s], None, gregorian(1977, 2, 18)), + PackedEastAsianTraditionalYearData::new(1978, [l, l, s, l, s, l, l, s, l, s, l, s, s], None, gregorian(1978, 2, 7)), + PackedEastAsianTraditionalYearData::new(1979, [l, s, s, l, s, l, l, s, l, l, s, l, s], Some(7), gregorian(1979, 1, 28)), + PackedEastAsianTraditionalYearData::new(1980, [l, s, s, l, s, l, s, l, l, s, l, l, s], None, gregorian(1980, 2, 16)), + PackedEastAsianTraditionalYearData::new(1981, [s, l, s, s, l, s, s, l, l, s, l, l, s], None, gregorian(1981, 2, 5)), + PackedEastAsianTraditionalYearData::new(1982, [l, s, l, s, s, l, s, s, l, l, s, l, l], Some(5), gregorian(1982, 1, 25)), + PackedEastAsianTraditionalYearData::new(1983, [l, s, l, s, s, l, s, s, l, s, l, l, s], None, gregorian(1983, 2, 13)), + PackedEastAsianTraditionalYearData::new(1984, [l, s, l, l, s, s, l, s, s, l, s, l, l], Some(11), gregorian(1984, 2, 2)), + PackedEastAsianTraditionalYearData::new(1985, [s, l, l, s, l, s, l, s, s, l, s, l, s], None, gregorian(1985, 2, 20)), + PackedEastAsianTraditionalYearData::new(1986, [s, l, l, s, l, l, s, l, s, l, s, s, s], None, gregorian(1986, 2, 9)), + PackedEastAsianTraditionalYearData::new(1987, [l, s, l, l, s, l, s, l, l, s, l, s, l], Some(7), gregorian(1987, 1, 29)), + PackedEastAsianTraditionalYearData::new(1988, [s, s, l, s, l, s, l, l, s, l, l, s, s], None, gregorian(1988, 2, 18)), + PackedEastAsianTraditionalYearData::new(1989, [l, s, s, l, s, l, s, l, l, s, l, l, s], None, gregorian(1989, 2, 6)), + PackedEastAsianTraditionalYearData::new(1990, [s, l, s, s, l, s, s, l, l, s, l, l, l], Some(6), gregorian(1990, 1, 27)), + PackedEastAsianTraditionalYearData::new(1991, [s, l, s, s, l, s, s, l, s, l, l, l, s], None, gregorian(1991, 2, 15)), + PackedEastAsianTraditionalYearData::new(1992, [s, l, l, s, s, l, s, s, l, s, l, l, s], None, gregorian(1992, 2, 4)), + PackedEastAsianTraditionalYearData::new(1993, [s, l, l, s, l, s, l, s, s, l, s, l, s], Some(4), gregorian(1993, 1, 23)), + PackedEastAsianTraditionalYearData::new(1994, [l, l, l, s, l, s, l, s, s, l, s, l, s], None, gregorian(1994, 2, 10)), + PackedEastAsianTraditionalYearData::new(1995, [s, l, l, s, l, l, s, l, s, l, s, s, l], Some(9), gregorian(1995, 1, 31)), + PackedEastAsianTraditionalYearData::new(1996, [s, l, s, l, l, s, l, s, l, l, s, l, s], None, gregorian(1996, 2, 19)), + PackedEastAsianTraditionalYearData::new(1997, [s, s, l, s, l, s, l, l, s, l, l, s, s], None, gregorian(1997, 2, 8)), + PackedEastAsianTraditionalYearData::new(1998, [l, s, s, l, s, s, l, l, s, l, l, l, s], Some(6), gregorian(1998, 1, 28)), + PackedEastAsianTraditionalYearData::new(1999, [l, s, s, l, s, s, l, s, l, l, l, s, s], None, gregorian(1999, 2, 16)), + PackedEastAsianTraditionalYearData::new(2000, [l, l, s, s, l, s, s, l, s, l, l, s, s], None, gregorian(2000, 2, 5)), + PackedEastAsianTraditionalYearData::new(2001, [l, l, l, s, s, l, s, s, l, s, l, s, l], Some(5), gregorian(2001, 1, 24)), + PackedEastAsianTraditionalYearData::new(2002, [l, l, s, l, s, l, s, s, l, s, l, s, s], None, gregorian(2002, 2, 12)), + PackedEastAsianTraditionalYearData::new(2003, [l, l, s, l, l, s, l, s, s, l, s, l, s], None, gregorian(2003, 2, 1)), + PackedEastAsianTraditionalYearData::new(2004, [s, l, s, l, l, s, l, s, l, s, l, s, l], Some(3), gregorian(2004, 1, 22)), + PackedEastAsianTraditionalYearData::new(2005, [s, l, s, l, s, l, l, s, l, l, s, s, s], None, gregorian(2005, 2, 9)), + PackedEastAsianTraditionalYearData::new(2006, [l, s, l, s, l, s, l, s, l, l, s, l, l], Some(8), gregorian(2006, 1, 29)), + PackedEastAsianTraditionalYearData::new(2007, [s, s, l, s, s, l, s, l, l, l, s, l, s], None, gregorian(2007, 2, 18)), + PackedEastAsianTraditionalYearData::new(2008, [l, s, s, l, s, s, l, s, l, l, s, l, s], None, gregorian(2008, 2, 7)), + PackedEastAsianTraditionalYearData::new(2009, [l, l, s, s, l, s, s, l, s, l, s, l, l], Some(6), gregorian(2009, 1, 26)), + PackedEastAsianTraditionalYearData::new(2010, [l, s, l, s, l, s, s, l, s, l, s, l, s], None, gregorian(2010, 2, 14)), + PackedEastAsianTraditionalYearData::new(2011, [l, s, l, l, s, l, s, s, l, s, l, s, s], None, gregorian(2011, 2, 3)), + PackedEastAsianTraditionalYearData::new(2012, [l, s, l, l, l, s, l, s, s, l, s, l, s], Some(4), gregorian(2012, 1, 23)), + PackedEastAsianTraditionalYearData::new(2013, [l, s, l, l, s, l, s, l, s, l, s, l, s], None, gregorian(2013, 2, 10)), + PackedEastAsianTraditionalYearData::new(2014, [s, l, s, l, s, l, s, l, l, s, l, s, l], Some(10), gregorian(2014, 1, 31)), + PackedEastAsianTraditionalYearData::new(2015, [s, l, s, s, l, s, l, l, l, s, l, s, s], None, gregorian(2015, 2, 19)), + PackedEastAsianTraditionalYearData::new(2016, [l, s, l, s, s, l, s, l, l, s, l, l, s], None, gregorian(2016, 2, 8)), + PackedEastAsianTraditionalYearData::new(2017, [s, l, s, l, s, s, l, s, l, s, l, l, l], Some(6), gregorian(2017, 1, 28)), + PackedEastAsianTraditionalYearData::new(2018, [s, l, s, l, s, s, l, s, l, s, l, l, s], None, gregorian(2018, 2, 16)), + PackedEastAsianTraditionalYearData::new(2019, [l, s, l, s, l, s, s, l, s, l, s, l, s], None, gregorian(2019, 2, 5)), + PackedEastAsianTraditionalYearData::new(2020, [l, s, l, l, s, l, s, s, l, s, l, s, l], Some(5), gregorian(2020, 1, 25)), + PackedEastAsianTraditionalYearData::new(2021, [s, l, l, s, l, s, l, s, l, s, l, s, s], None, gregorian(2021, 2, 12)), + PackedEastAsianTraditionalYearData::new(2022, [l, s, l, s, l, l, s, l, s, l, s, l, s], None, gregorian(2022, 2, 1)), + PackedEastAsianTraditionalYearData::new(2023, [s, l, s, l, s, l, s, l, l, s, l, s, l], Some(3), gregorian(2023, 1, 22)), + PackedEastAsianTraditionalYearData::new(2024, [s, l, s, s, l, s, l, l, s, l, l, s, s], None, gregorian(2024, 2, 10)), + PackedEastAsianTraditionalYearData::new(2025, [l, s, l, s, s, l, s, l, s, l, l, l, s], Some(7), gregorian(2025, 1, 29)), + PackedEastAsianTraditionalYearData::new(2026, [l, s, l, s, s, l, s, l, s, l, l, l, s], None, gregorian(2026, 2, 17)), + PackedEastAsianTraditionalYearData::new(2027, [s, l, s, l, s, s, l, s, s, l, l, l, s], None, gregorian(2027, 2, 7)), + PackedEastAsianTraditionalYearData::new(2028, [s, l, l, s, l, s, s, l, s, s, l, l, s], Some(6), gregorian(2028, 1, 27)), + PackedEastAsianTraditionalYearData::new(2029, [l, l, s, l, l, s, s, l, s, s, l, l, s], None, gregorian(2029, 2, 13)), + PackedEastAsianTraditionalYearData::new(2030, [s, l, s, l, l, s, l, s, l, s, l, s, s], None, gregorian(2030, 2, 3)), + PackedEastAsianTraditionalYearData::new(2031, [l, s, l, s, l, s, l, l, s, l, s, l, s], Some(4), gregorian(2031, 1, 23)), + PackedEastAsianTraditionalYearData::new(2032, [l, s, s, l, s, l, l, s, l, l, s, l, s], None, gregorian(2032, 2, 11)), + PackedEastAsianTraditionalYearData::new(2033, [s, l, s, s, l, s, l, s, l, l, l, s, l], Some(12), gregorian(2033, 1, 31)), + PackedEastAsianTraditionalYearData::new(2034, [s, l, s, s, l, s, l, s, l, l, l, s, s], None, gregorian(2034, 2, 19)), + PackedEastAsianTraditionalYearData::new(2035, [l, s, l, s, s, l, s, s, l, l, s, l, s], None, gregorian(2035, 2, 8)), + PackedEastAsianTraditionalYearData::new(2036, [l, l, s, l, s, s, l, s, s, l, l, s, l], Some(7), gregorian(2036, 1, 28)), + PackedEastAsianTraditionalYearData::new(2037, [l, l, s, l, s, s, l, s, s, l, s, l, s], None, gregorian(2037, 2, 15)), + PackedEastAsianTraditionalYearData::new(2038, [l, l, s, l, s, l, s, l, s, s, l, s, s], None, gregorian(2038, 2, 4)), + PackedEastAsianTraditionalYearData::new(2039, [l, l, s, l, l, s, l, s, l, s, l, s, s], Some(6), gregorian(2039, 1, 24)), + PackedEastAsianTraditionalYearData::new(2040, [l, s, l, l, s, l, l, s, l, s, l, s, s], None, gregorian(2040, 2, 12)), + PackedEastAsianTraditionalYearData::new(2041, [l, s, s, l, s, l, l, s, l, l, s, l, s], None, gregorian(2041, 2, 1)), + PackedEastAsianTraditionalYearData::new(2042, [s, l, s, s, l, s, l, s, l, l, s, l, l], Some(3), gregorian(2042, 1, 22)), + PackedEastAsianTraditionalYearData::new(2043, [s, l, s, s, l, s, s, l, l, s, l, l, s], None, gregorian(2043, 2, 10)), + PackedEastAsianTraditionalYearData::new(2044, [l, s, l, s, s, l, s, s, l, s, l, l, l], Some(8), gregorian(2044, 1, 30)), + PackedEastAsianTraditionalYearData::new(2045, [l, s, l, s, s, l, s, s, l, s, l, l, s], None, gregorian(2045, 2, 17)), + PackedEastAsianTraditionalYearData::new(2046, [l, s, l, l, s, s, l, s, s, l, s, l, s], None, gregorian(2046, 2, 6)), + PackedEastAsianTraditionalYearData::new(2047, [l, s, l, l, s, l, s, l, s, s, l, s, l], Some(6), gregorian(2047, 1, 26)), + PackedEastAsianTraditionalYearData::new(2048, [s, l, l, s, l, l, s, l, s, l, s, s, s], None, gregorian(2048, 2, 14)), + PackedEastAsianTraditionalYearData::new(2049, [l, s, l, s, l, l, s, l, l, s, l, s, s], None, gregorian(2049, 2, 2)), + PackedEastAsianTraditionalYearData::new(2050, [l, s, s, l, s, l, s, l, l, s, l, l, s], Some(4), gregorian(2050, 1, 23)), + PackedEastAsianTraditionalYearData::new(2051, [l, s, s, l, s, l, s, l, s, l, l, l, s], None, gregorian(2051, 2, 11)), + PackedEastAsianTraditionalYearData::new(2052, [s, l, s, s, l, s, s, l, l, s, l, l, l], Some(9), gregorian(2052, 2, 1)), + PackedEastAsianTraditionalYearData::new(2053, [s, l, s, s, l, s, s, l, s, l, l, l, s], None, gregorian(2053, 2, 19)), + PackedEastAsianTraditionalYearData::new(2054, [s, l, l, s, s, l, s, s, l, s, l, l, s], None, gregorian(2054, 2, 8)), + PackedEastAsianTraditionalYearData::new(2055, [s, l, l, s, l, s, l, s, s, l, s, l, s], Some(7), gregorian(2055, 1, 28)), + PackedEastAsianTraditionalYearData::new(2056, [l, l, l, s, l, s, l, s, s, l, s, l, s], None, gregorian(2056, 2, 15)), + PackedEastAsianTraditionalYearData::new(2057, [s, l, l, s, l, s, l, l, s, s, l, s, s], None, gregorian(2057, 2, 4)), + PackedEastAsianTraditionalYearData::new(2058, [l, s, l, s, l, l, s, l, s, l, l, s, s], Some(5), gregorian(2058, 1, 24)), + PackedEastAsianTraditionalYearData::new(2059, [l, s, l, s, l, s, l, l, s, l, l, s, s], None, gregorian(2059, 2, 12)), + PackedEastAsianTraditionalYearData::new(2060, [l, s, s, l, s, s, l, l, s, l, l, l, s], None, gregorian(2060, 2, 2)), + PackedEastAsianTraditionalYearData::new(2061, [s, l, s, s, l, s, s, l, s, l, l, l, s], Some(4), gregorian(2061, 1, 22)), + PackedEastAsianTraditionalYearData::new(2062, [l, l, s, s, l, s, s, l, s, l, l, s, s], None, gregorian(2062, 2, 9)), + PackedEastAsianTraditionalYearData::new(2063, [l, l, s, l, s, l, s, s, l, s, l, s, l], Some(8), gregorian(2063, 1, 29)), + PackedEastAsianTraditionalYearData::new(2064, [l, l, s, l, s, l, s, s, l, s, l, s, s], None, gregorian(2064, 2, 17)), + PackedEastAsianTraditionalYearData::new(2065, [l, l, s, l, l, s, l, s, s, l, s, l, s], None, gregorian(2065, 2, 5)), + PackedEastAsianTraditionalYearData::new(2066, [s, l, s, l, l, s, l, s, l, s, l, s, l], Some(6), gregorian(2066, 1, 26)), + PackedEastAsianTraditionalYearData::new(2067, [s, l, s, l, s, l, l, s, l, s, l, s, s], None, gregorian(2067, 2, 14)), + PackedEastAsianTraditionalYearData::new(2068, [l, s, l, s, l, s, l, s, l, l, s, l, s], None, gregorian(2068, 2, 3)), + PackedEastAsianTraditionalYearData::new(2069, [l, s, s, l, s, s, l, s, l, l, l, s, l], Some(5), gregorian(2069, 1, 23)), + PackedEastAsianTraditionalYearData::new(2070, [l, s, s, l, s, s, l, s, l, l, s, l, s], None, gregorian(2070, 2, 11)), + PackedEastAsianTraditionalYearData::new(2071, [l, l, s, s, l, s, s, l, s, l, s, l, l], Some(9), gregorian(2071, 1, 31)), + PackedEastAsianTraditionalYearData::new(2072, [l, s, l, s, l, s, s, l, s, l, s, l, s], None, gregorian(2072, 2, 19)), + PackedEastAsianTraditionalYearData::new(2073, [l, s, l, l, s, l, s, s, l, s, l, s, s], None, gregorian(2073, 2, 7)), + PackedEastAsianTraditionalYearData::new(2074, [l, s, l, l, s, l, s, l, s, l, s, l, s], Some(7), gregorian(2074, 1, 27)), + PackedEastAsianTraditionalYearData::new(2075, [l, s, l, s, l, l, s, l, s, l, s, l, s], None, gregorian(2075, 2, 15)), + PackedEastAsianTraditionalYearData::new(2076, [s, l, s, l, s, l, s, l, l, s, l, s, s], None, gregorian(2076, 2, 5)), + PackedEastAsianTraditionalYearData::new(2077, [l, s, l, s, s, l, s, l, l, l, s, l, s], Some(5), gregorian(2077, 1, 24)), + PackedEastAsianTraditionalYearData::new(2078, [l, s, l, s, s, l, s, l, l, s, l, l, s], None, gregorian(2078, 2, 12)), + PackedEastAsianTraditionalYearData::new(2079, [s, l, s, l, s, s, l, s, l, s, l, l, s], None, gregorian(2079, 2, 2)), + PackedEastAsianTraditionalYearData::new(2080, [l, s, l, s, l, s, s, l, s, l, s, l, l], Some(4), gregorian(2080, 1, 22)), + PackedEastAsianTraditionalYearData::new(2081, [l, s, l, s, l, s, s, l, s, s, l, l, s], None, gregorian(2081, 2, 9)), + PackedEastAsianTraditionalYearData::new(2082, [s, l, l, l, s, l, s, s, l, s, l, s, l], Some(8), gregorian(2082, 1, 29)), + PackedEastAsianTraditionalYearData::new(2083, [s, l, l, s, l, s, l, s, l, s, l, s, s], None, gregorian(2083, 2, 17)), + PackedEastAsianTraditionalYearData::new(2084, [l, s, l, s, l, l, s, l, s, l, s, l, s], None, gregorian(2084, 2, 6)), + PackedEastAsianTraditionalYearData::new(2085, [s, l, s, s, l, l, s, l, l, s, l, s, l], Some(6), gregorian(2085, 1, 26)), + PackedEastAsianTraditionalYearData::new(2086, [s, l, s, s, l, s, l, l, s, l, l, s, s], None, gregorian(2086, 2, 14)), + PackedEastAsianTraditionalYearData::new(2087, [l, s, l, s, s, l, s, l, s, l, l, l, s], None, gregorian(2087, 2, 3)), + PackedEastAsianTraditionalYearData::new(2088, [s, l, s, l, s, s, l, s, s, l, l, l, l], Some(5), gregorian(2088, 1, 24)), + PackedEastAsianTraditionalYearData::new(2089, [s, l, s, l, s, s, l, s, s, l, l, s, s], None, gregorian(2089, 2, 11)), + PackedEastAsianTraditionalYearData::new(2090, [l, l, l, s, l, s, s, l, s, s, l, l, s], Some(9), gregorian(2090, 1, 30)), + PackedEastAsianTraditionalYearData::new(2091, [l, l, s, l, s, l, s, l, s, s, l, l, s], None, gregorian(2091, 2, 18)), + PackedEastAsianTraditionalYearData::new(2092, [s, l, s, l, l, s, l, s, l, s, l, s, s], None, gregorian(2092, 2, 8)), + PackedEastAsianTraditionalYearData::new(2093, [l, s, l, s, l, s, l, l, s, l, s, l, s], Some(7), gregorian(2093, 1, 27)), + PackedEastAsianTraditionalYearData::new(2094, [l, s, s, l, s, l, l, s, l, l, s, l, s], None, gregorian(2094, 2, 15)), + PackedEastAsianTraditionalYearData::new(2095, [s, l, s, s, l, s, l, s, l, l, l, s, s], None, gregorian(2095, 2, 5)), + PackedEastAsianTraditionalYearData::new(2096, [l, s, l, s, s, l, s, l, s, l, l, s, l], Some(5), gregorian(2096, 1, 25)), + PackedEastAsianTraditionalYearData::new(2097, [l, s, l, s, s, l, s, s, l, l, s, l, s], None, gregorian(2097, 2, 12)), + PackedEastAsianTraditionalYearData::new(2098, [l, l, s, l, s, s, l, s, s, l, l, s, s], None, gregorian(2098, 2, 1)), + PackedEastAsianTraditionalYearData::new(2099, [l, l, l, s, l, s, s, l, s, s, l, s, l], Some(4), gregorian(2099, 1, 21)), + PackedEastAsianTraditionalYearData::new(2100, [l, l, s, l, s, l, s, l, s, s, l, s, s], None, gregorian(2100, 2, 9)), + // Extra two years of correct data because the simple calculation lines up at the beginning of 2103 + PackedEastAsianTraditionalYearData::new(2101, [l, l, s, l, l, s, l, s, l, s, l, s, s], Some(8), gregorian(2101, 1, 29)), + PackedEastAsianTraditionalYearData::new(2102, [l, s, l, l, s, l, s, l, l, s, l, s, s], None, gregorian(2102, 2, 17)), + ] +}; + +#[test] +fn test_against_calendrical_calculations() { + use calendrical_calculations::chinese_based::Dangi; + for (i, &data) in DATA.iter().enumerate() { + assert_eq!( + data, + super::EastAsianTraditionalYearData::calendrical_calculations::( + STARTING_YEAR + i as i32 + ) + .packed + ); + } +} diff --git a/deps/crates/vendor/icu_calendar/src/cal/east_asian_traditional/qing_data.rs b/deps/crates/vendor/icu_calendar/src/cal/east_asian_traditional/qing_data.rs new file mode 100644 index 00000000000000..c107d7f82118ef --- /dev/null +++ b/deps/crates/vendor/icu_calendar/src/cal/east_asian_traditional/qing_data.rs @@ -0,0 +1,32 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +//! This data is confirmed by both the [Korea Astronomy and Space Science Institute](https://astro.kasi.re.kr/life/pageView/5), +//! as well as the [Hong Kong Observatory](https://www.hko.gov.hk/en/gts/time/conversion.htm). + +use super::PackedEastAsianTraditionalYearData; + +pub const STARTING_YEAR: i32 = 1900; + +#[rustfmt::skip] +#[allow(clippy::unwrap_used)] // const +pub const DATA: &[PackedEastAsianTraditionalYearData] = { + use calendrical_calculations::gregorian::fixed_from_gregorian as gregorian; + let l = true; // long + let s = false; // short + &[ + PackedEastAsianTraditionalYearData::new(1900, [s, l, s, s, l, s, l, l, s, l, l, s, l], Some(9), gregorian(1900, 1, 31)), + PackedEastAsianTraditionalYearData::new(1901, [s, l, s, s, l, s, l, s, l, l, l, s, s], None, gregorian(1901, 2, 19)), + PackedEastAsianTraditionalYearData::new(1902, [l, s, l, s, s, l, s, l, s, l, l, l, s], None, gregorian(1902, 2, 8)), + PackedEastAsianTraditionalYearData::new(1903, [s, l, s, l, s, s, l, s, s, l, l, s, l], Some(6), gregorian(1903, 1, 29)), + PackedEastAsianTraditionalYearData::new(1904, [l, l, s, l, s, s, l, s, s, l, l, s, s], None, gregorian(1904, 2, 16)), + PackedEastAsianTraditionalYearData::new(1905, [l, l, s, l, l, s, s, l, s, l, s, l, s], None, gregorian(1905, 2, 4)), + PackedEastAsianTraditionalYearData::new(1906, [s, l, l, s, l, s, l, s, l, s, l, s, l], Some(5), gregorian(1906, 1, 25)), + PackedEastAsianTraditionalYearData::new(1907, [s, l, s, l, s, l, l, s, l, s, l, s, s], None, gregorian(1907, 2, 13)), + PackedEastAsianTraditionalYearData::new(1908, [l, s, s, l, l, s, l, s, l, l, s, l, s], None, gregorian(1908, 2, 2)), + PackedEastAsianTraditionalYearData::new(1909, [s, l, s, s, l, s, l, s, l, l, l, s, l], Some(3), gregorian(1909, 1, 22)), + PackedEastAsianTraditionalYearData::new(1910, [s, l, s, s, l, s, l, s, l, l, l, s, s], None, gregorian(1910, 2, 10)), + PackedEastAsianTraditionalYearData::new(1911, [l, s, l, s, s, l, s, s, l, l, s, l, l], Some(7), gregorian(1911, 1, 30)), + ] +}; diff --git a/deps/crates/vendor/icu_calendar/src/cal/east_asian_traditional/simple.rs b/deps/crates/vendor/icu_calendar/src/cal/east_asian_traditional/simple.rs new file mode 100644 index 00000000000000..851e7371349a7b --- /dev/null +++ b/deps/crates/vendor/icu_calendar/src/cal/east_asian_traditional/simple.rs @@ -0,0 +1,190 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use super::EastAsianTraditionalYearData; +use calendrical_calculations::{gregorian::DAYS_IN_400_YEAR_CYCLE, rata_die::RataDie}; + +macro_rules! day_fraction_to_ms { + ($n:tt $(/ $d:tt)+) => {{ + Milliseconds((MILLISECONDS_IN_EPHEMERIS_DAY as i128 * $n as i128 $( / $d as i128)+) as i64) + }}; + ($n:tt $(/ $d:tt)+, exact) => {{ + let d = day_fraction_to_ms!($n $(/ $d)+); + assert!((d.0 as i128 $(* $d as i128)+) % MILLISECONDS_IN_EPHEMERIS_DAY as i128 == 0, "inexact"); + d + }}; +} + +pub(super) const UTC_PLUS_8: Milliseconds = day_fraction_to_ms!(8 / 24); +pub(super) const UTC_PLUS_9: Milliseconds = day_fraction_to_ms!(9 / 24); +// Reference time was UTC+(1397/180) +pub(super) const BEIJING_UTC_OFFSET: Milliseconds = day_fraction_to_ms!(1397 / 180 / 24); + +/// The mean year length according to the Gregorian solar cycle. +const MEAN_GREGORIAN_YEAR_LENGTH: Milliseconds = + day_fraction_to_ms!(DAYS_IN_400_YEAR_CYCLE / 400, exact); + +/// The mean solar term length according to the Gregorian solar cycle +const MEAN_GREGORIAN_SOLAR_TERM_LENGTH: Milliseconds = + day_fraction_to_ms!(DAYS_IN_400_YEAR_CYCLE / 400 / 12, exact); + +/// The mean synodic length on Jan 1 2000 according to the [Astronomical Almanac (1992)]. +/// +/// [Astronomical Almanac (1992)]: https://archive.org/details/131123ExplanatorySupplementAstronomicalAlmanac/page/n302/mode/1up +const MEAN_SYNODIC_MONTH_LENGTH: Milliseconds = day_fraction_to_ms!(295305888531 / 10000000000i64); + +/// Number of milliseconds in a day. +const MILLISECONDS_IN_EPHEMERIS_DAY: i64 = 24 * 60 * 60 * 1000; + +// 1999-12-22T07:44, https://aa.usno.navy.mil/calculated/seasons?year=2024&tz=0.00&tz_sign=-1&tz_label=false&dst=false +const UTC_SOLSTICE: LocalMoment = LocalMoment { + rata_die: calendrical_calculations::gregorian::fixed_from_gregorian(1999, 12, 22), + local_milliseconds: ((7 * 60) + 44) * 60 * 1000, +}; + +// 2000-01-06T18:14 https://aa.usno.navy.mil/calculated/moon/phases?date=2000-01-01&nump=1&format=t +const UTC_NEW_MOON: LocalMoment = LocalMoment { + rata_die: calendrical_calculations::gregorian::fixed_from_gregorian(2000, 1, 6), + local_milliseconds: ((18 * 60) + 14) * 60 * 1000, +}; + +#[derive(Debug, Copy, Clone, Default)] +pub(super) struct Milliseconds(i64); + +#[derive(Debug, Copy, Clone)] +struct LocalMoment { + rata_die: RataDie, + local_milliseconds: u32, +} + +impl core::ops::Add for LocalMoment { + type Output = Self; + + fn add(self, Milliseconds(duration): Milliseconds) -> Self::Output { + let temp = self.local_milliseconds as i64 + duration; + Self { + rata_die: self.rata_die + temp.div_euclid(MILLISECONDS_IN_EPHEMERIS_DAY), + local_milliseconds: temp.rem_euclid(MILLISECONDS_IN_EPHEMERIS_DAY) as u32, + } + } +} + +impl super::EastAsianTraditionalYearData { + /// A fast approximation for the Chinese calendar, inspired by the _píngqì_ (平氣) rule + /// used in the Ming dynasty. + /// + /// Stays anchored in the Gregorian calendar, even as the Gregorian calendar drifts + /// from the seasons in the distant future and distant past. + pub(super) fn simple( + utc_offset: Milliseconds, + related_iso: i32, + ) -> EastAsianTraditionalYearData { + /// calculates the largest moment such that moment = base_moment + n * duration lands on rata_die (< rata_die + 1) + fn periodic_duration_on_or_before( + rata_die: RataDie, + base_moment: LocalMoment, + duration: Milliseconds, + ) -> LocalMoment { + let diff_millis = (rata_die - base_moment.rata_die) * MILLISECONDS_IN_EPHEMERIS_DAY + - base_moment.local_milliseconds as i64; + + let num_periods = + (diff_millis + MILLISECONDS_IN_EPHEMERIS_DAY - 1).div_euclid(duration.0); + + let millis = base_moment.rata_die.to_i64_date() * MILLISECONDS_IN_EPHEMERIS_DAY + + base_moment.local_milliseconds as i64 + + num_periods * duration.0; + + // Note: this is Euclidean div/rem, but this more optimized, because + // we know that our divisor is positive + let rata_die = millis / MILLISECONDS_IN_EPHEMERIS_DAY - (millis < 0) as i64; + let local_milliseconds = millis % MILLISECONDS_IN_EPHEMERIS_DAY + + (millis < 0) as i64 * MILLISECONDS_IN_EPHEMERIS_DAY; + + LocalMoment { + rata_die: RataDie::new(rata_die), + local_milliseconds: local_milliseconds as u32, + } + } + + let mut major_solar_term = periodic_duration_on_or_before( + calendrical_calculations::iso::day_before_year(related_iso), + UTC_SOLSTICE + utc_offset, + MEAN_GREGORIAN_YEAR_LENGTH, + ); + + let mut new_moon = periodic_duration_on_or_before( + major_solar_term.rata_die, + UTC_NEW_MOON + utc_offset, + MEAN_SYNODIC_MONTH_LENGTH, + ); + + let mut next_new_moon = new_moon + MEAN_SYNODIC_MONTH_LENGTH; + + // The solstice is in the month of the 11th solar term of the previous year + let mut solar_term = -2; + let mut had_leap_in_sui = false; + + // Skip the months before the year (M11, maybe M11L, M12, maybe M12L) + while solar_term < 0 + || (next_new_moon.rata_die <= major_solar_term.rata_die && !had_leap_in_sui) + { + if next_new_moon.rata_die <= major_solar_term.rata_die && !had_leap_in_sui { + had_leap_in_sui = true; + } else { + solar_term += 1; + major_solar_term = major_solar_term + MEAN_GREGORIAN_SOLAR_TERM_LENGTH; + } + + (new_moon, next_new_moon) = (next_new_moon, next_new_moon + MEAN_SYNODIC_MONTH_LENGTH); + } + + debug_assert_eq!(solar_term, 0); + + let start_day = new_moon.rata_die; + let mut month_lengths = [false; 13]; + let mut leap_month = None; + + // Iterate over the 12 solar terms, producing potentially 13 months + while solar_term < 12 + || (next_new_moon.rata_die <= major_solar_term.rata_die && !had_leap_in_sui) + { + *month_lengths + .get_mut(solar_term as usize + leap_month.is_some() as usize) + .unwrap_or(&mut false) = next_new_moon.rata_die - new_moon.rata_die == 30; + + if next_new_moon.rata_die <= major_solar_term.rata_die && !had_leap_in_sui { + had_leap_in_sui = true; + leap_month = Some(solar_term as u8 + 1); + } else { + solar_term += 1; + major_solar_term = major_solar_term + MEAN_GREGORIAN_SOLAR_TERM_LENGTH; + } + + (new_moon, next_new_moon) = (next_new_moon, next_new_moon + MEAN_SYNODIC_MONTH_LENGTH); + } + + debug_assert_eq!(solar_term, 12); + + EastAsianTraditionalYearData::new(related_iso, start_day, month_lengths, leap_month) + } +} + +#[test] +fn bounds() { + EastAsianTraditionalYearData::simple(UTC_PLUS_9, 292_277_025); + assert!( + std::panic::catch_unwind(|| EastAsianTraditionalYearData::simple(UTC_PLUS_9, 292_277_026)) + .is_err() + ); + + EastAsianTraditionalYearData::simple(BEIJING_UTC_OFFSET, -292_275_024); + assert!( + std::panic::catch_unwind(|| EastAsianTraditionalYearData::simple( + BEIJING_UTC_OFFSET, + -292_275_025 + )) + .is_err() + ); +} diff --git a/deps/crates/vendor/icu_calendar/src/cal/ethiopian.rs b/deps/crates/vendor/icu_calendar/src/cal/ethiopian.rs index 3fd0cb96a07b58..559864e2f765c5 100644 --- a/deps/crates/vendor/icu_calendar/src/cal/ethiopian.rs +++ b/deps/crates/vendor/icu_calendar/src/cal/ethiopian.rs @@ -2,33 +2,27 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -//! This module contains types and implementations for the Ethiopian calendar. -//! -//! ```rust -//! use icu::calendar::{cal::Ethiopian, Date}; -//! -//! let date_iso = Date::try_new_iso(1970, 1, 2) -//! .expect("Failed to initialize ISO Date instance."); -//! let date_ethiopian = Date::new_from_iso(date_iso, Ethiopian::new()); -//! -//! assert_eq!(date_ethiopian.era_year().year, 1962); -//! assert_eq!(date_ethiopian.month().ordinal, 4); -//! assert_eq!(date_ethiopian.day_of_month().0, 24); -//! ``` - -use crate::cal::iso::{Iso, IsoDateInner}; -use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic}; -use crate::error::{year_check, DateError}; -use crate::{types, Calendar, Date, DateDuration, DateDurationUnit, RangeError}; -use calendrical_calculations::helpers::I32CastError; +use crate::cal::coptic::CopticDateInner; +use crate::cal::Coptic; +use crate::calendar_arithmetic::{ArithmeticDate, DateFieldsResolver}; +use crate::error::{ + DateError, DateFromFieldsError, EcmaReferenceYearError, MonthCodeError, UnknownEraError, +}; +use crate::options::DateFromFieldsOptions; +use crate::options::{DateAddOptions, DateDifferenceOptions}; +use crate::types::DateFields; +use crate::{types, Calendar, Date, RangeError}; use calendrical_calculations::rata_die::RataDie; use tinystr::tinystr; -/// The number of years the Amete Alem epoch precedes the Amete Mihret epoch -const INCARNATION_OFFSET: i32 = 5500; +/// The Coptic year of the Amete Mihret epoch +const AMETE_MIHRET_OFFSET: i32 = -276; + +/// The Coptic year of the Amete Alem epoch +const AMETE_ALEM_OFFSET: i32 = -5776; /// Which era style the ethiopian calendar uses -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)] #[non_exhaustive] pub enum EthiopianEraStyle { /// Use the Anno Mundi era, anchored at the date of Creation, followed by the @@ -38,74 +32,110 @@ pub enum EthiopianEraStyle { AmeteAlem, } -/// The [Ethiopian Calendar] +/// The [Ethiopian Calendar](https://en.wikipedia.org/wiki/Ethiopian_calendar) /// -/// The [Ethiopian calendar] is a solar calendar used by the Coptic Orthodox Church, with twelve normal months -/// and a thirteenth small epagomenal month. +/// The Ethiopian calendar is a variant of the [`Coptic`] calendar. It differs +/// from the Coptic calendar by the names of the months as well as the era. /// -/// This type can be used with [`Date`] to represent dates in this calendar. +/// This implementation can be constructed in two modes: using the Amete Alem era +/// scheme, or the Amete Mihret era scheme (the default), see [`EthiopianEraStyle`] +/// for more info. /// -/// It can be constructed in two modes: using the Amete Alem era scheme, or the Amete Mihret era scheme (the default), -/// see [`EthiopianEraStyle`] for more info. +/// This implementation extends proleptically for dates before the calendar's creation. /// -/// [Ethiopian calendar]: https://en.wikipedia.org/wiki/Ethiopian_calendar +/// This corresponds to the `"ethiopic"` and `"ethioaa"` [CLDR calendars](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier), +/// with `"ethiopic"` being for [`EthiopianEraStyle::AmeteMihret`] /// /// # Era codes /// /// This calendar always uses the `aa` era, where 1 Amete Alem is 5493 BCE. Dates before this era use negative years. /// Dates before that use negative year numbers. +/// /// In the Amete Mihret scheme it uses the additional `am` era, 1 Amete Mihret is 9 CE. /// -/// # Month codes +/// # Months and days +/// +/// The 13 months are called Mäskäräm (`M01`, 30 days), Ṭəqəmt (`M02`, 30 days), +/// Ḫədar (`M03`, 30 days), Taḫśaś (`M04`, 30 days), Ṭərr (`M05`, 30 days), Yäkatit (`M06`, 30 days), +/// Mägabit (`M07`, 30 days), Miyazya (`M08`, 30 days), Gənbo (`M09`, 30 days), +/// Säne (`M10`, 30 days), Ḥamle (`M11`, 30 days), Nähase (`M12`, 30 days), Ṗagʷəmen (`M13`, 5 days). +/// +/// In leap years (years divisible by 4), Ṗagʷəmen gains a 6th day. /// -/// This calendar supports 13 solar month codes (`"M01" - "M13"`), with `"M13"` being used for the short epagomenal month -/// at the end of the year. -// The bool specifies whether dates should be in the Amete Alem era scheme -#[derive(Copy, Clone, Debug, Hash, Default, Eq, PartialEq, PartialOrd, Ord)] -pub struct Ethiopian(pub(crate) bool); +/// Standard years thus have 365 days, and leap years 366. +/// +/// # Calendar drift +/// +/// The Ethiopian calendar has the same year lengths and leap year rules as the [`Coptic`] and +/// [`Julian`](crate::cal::Julian) calendars, so it experiences the same drift of 1 day in ~128 +/// years with respect to the seasons. +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] +pub struct Ethiopian(EthiopianEraStyle); -/// The inner date type used for representing [`Date`]s of [`Ethiopian`]. See [`Date`] and [`Ethiopian`] for more details. +impl Default for Ethiopian { + fn default() -> Self { + Self(EthiopianEraStyle::AmeteMihret) + } +} + +#[allow(missing_docs)] // not actually public #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] -pub struct EthiopianDateInner(ArithmeticDate); +pub struct EthiopianDateInner(CopticDateInner); -impl CalendarArithmetic for Ethiopian { +impl DateFieldsResolver for Ethiopian { + // Coptic year type YearInfo = i32; - fn days_in_provided_month(year: i32, month: u8) -> u8 { - if (1..=12).contains(&month) { - 30 - } else if month == 13 { - if Self::provided_year_is_leap(year) { - 6 - } else { - 5 - } - } else { - 0 - } + fn days_in_provided_month(year: Self::YearInfo, month: u8) -> u8 { + Coptic::days_in_provided_month(year, month) } - fn months_in_provided_year(_: i32) -> u8 { - 13 + fn months_in_provided_year(year: Self::YearInfo) -> u8 { + Coptic::months_in_provided_year(year) } - fn provided_year_is_leap(year: i32) -> bool { - year.rem_euclid(4) == 3 + #[inline] + fn year_info_from_era( + &self, + era: &[u8], + era_year: i32, + ) -> Result { + match (self.era_style(), era) { + (EthiopianEraStyle::AmeteMihret, b"am") => Ok(era_year + AMETE_MIHRET_OFFSET), + (_, b"aa") => Ok(era_year + AMETE_ALEM_OFFSET), + (_, _) => Err(UnknownEraError), + } } - fn last_month_day_in_provided_year(year: i32) -> (u8, u8) { - if Self::provided_year_is_leap(year) { - (13, 6) - } else { - (13, 5) - } + #[inline] + fn year_info_from_extended(&self, extended_year: i32) -> Self::YearInfo { + extended_year + + if self.0 == EthiopianEraStyle::AmeteMihret { + AMETE_MIHRET_OFFSET + } else { + AMETE_ALEM_OFFSET + } } - fn days_in_provided_year(year: i32) -> u16 { - if Self::provided_year_is_leap(year) { - 366 - } else { - 365 + #[inline] + fn reference_year_from_month_day( + &self, + month_code: types::ValidMonthCode, + day: u8, + ) -> Result { + crate::cal::Coptic::reference_year_from_month_day(month_code, day) + } + + #[inline] + fn ordinal_month_from_code( + &self, + _year: &Self::YearInfo, + month_code: types::ValidMonthCode, + _options: DateFromFieldsOptions, + ) -> Result { + match month_code.to_tuple() { + (month_number @ 1..=13, false) => Ok(month_number), + _ => Err(MonthCodeError::NotInCalendar), } } } @@ -113,7 +143,9 @@ impl CalendarArithmetic for Ethiopian { impl crate::cal::scaffold::UnstableSealed for Ethiopian {} impl Calendar for Ethiopian { type DateInner = EthiopianDateInner; - type Year = types::EraYear; + type Year = ::Year; + type DifferenceError = ::DifferenceError; + fn from_codes( &self, era: Option<&str>, @@ -121,123 +153,111 @@ impl Calendar for Ethiopian { month_code: types::MonthCode, day: u8, ) -> Result { - let year = match (self.era_style(), era) { - (EthiopianEraStyle::AmeteMihret, Some("am") | None) => { - year_check(year, 1..)? + INCARNATION_OFFSET - } - (EthiopianEraStyle::AmeteMihret, Some("aa")) => { - year_check(year, ..=INCARNATION_OFFSET)? - } - (EthiopianEraStyle::AmeteAlem, Some("aa") | None) => year, - (_, Some(_)) => { - return Err(DateError::UnknownEra); - } - }; - ArithmeticDate::new_from_codes(self, year, month_code, day).map(EthiopianDateInner) + ArithmeticDate::from_codes(era, year, month_code, day, self) + .map(ArithmeticDate::cast) + .map(CopticDateInner) + .map(EthiopianDateInner) } - fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { - EthiopianDateInner( - match calendrical_calculations::ethiopian::ethiopian_from_fixed(rd) { - Err(I32CastError::BelowMin) => ArithmeticDate::min_date(), - Err(I32CastError::AboveMax) => ArithmeticDate::max_date(), - Ok((year, month, day)) => ArithmeticDate::new_unchecked( - // calendrical calculations returns years in the Incarnation era - year + INCARNATION_OFFSET, - month, - day, - ), - }, - ) + #[cfg(feature = "unstable")] + fn from_fields( + &self, + fields: DateFields, + options: DateFromFieldsOptions, + ) -> Result { + ArithmeticDate::from_fields(fields, options, self) + .map(ArithmeticDate::cast) + .map(CopticDateInner) + .map(EthiopianDateInner) } - fn to_rata_die(&self, date: &Self::DateInner) -> RataDie { - // calendrical calculations expects years in the Incarnation era - calendrical_calculations::ethiopian::fixed_from_ethiopian( - date.0.year - INCARNATION_OFFSET, - date.0.month, - date.0.day, - ) + fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { + EthiopianDateInner(Coptic.from_rata_die(rd)) } - fn from_iso(&self, iso: IsoDateInner) -> EthiopianDateInner { - self.from_rata_die(Iso.to_rata_die(&iso)) + fn to_rata_die(&self, date: &Self::DateInner) -> RataDie { + Coptic.to_rata_die(&date.0) } - fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { - Iso.from_rata_die(self.to_rata_die(date)) + fn has_cheap_iso_conversion(&self) -> bool { + false } fn months_in_year(&self, date: &Self::DateInner) -> u8 { - date.0.months_in_year() + Coptic.months_in_year(&date.0) } fn days_in_year(&self, date: &Self::DateInner) -> u16 { - date.0.days_in_year() + Coptic.days_in_year(&date.0) } fn days_in_month(&self, date: &Self::DateInner) -> u8 { - date.0.days_in_month() + Coptic.days_in_month(&date.0) } - fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) { - date.0.offset_date(offset, &()); + #[cfg(feature = "unstable")] + fn add( + &self, + date: &Self::DateInner, + duration: types::DateDuration, + options: DateAddOptions, + ) -> Result { + Coptic + .add(&date.0, duration, options) + .map(EthiopianDateInner) } - #[allow(clippy::field_reassign_with_default)] + #[cfg(feature = "unstable")] fn until( &self, date1: &Self::DateInner, date2: &Self::DateInner, - _calendar2: &Self, - _largest_unit: DateDurationUnit, - _smallest_unit: DateDurationUnit, - ) -> DateDuration { - date1.0.until(date2.0, _largest_unit, _smallest_unit) + options: DateDifferenceOptions, + ) -> Result { + Coptic.until(&date1.0, &date2.0, options) } fn year_info(&self, date: &Self::DateInner) -> Self::Year { - let year = date.0.year; - if self.0 || year <= INCARNATION_OFFSET { + let coptic_year = date.0 .0.year; + let extended_year = if self.0 == EthiopianEraStyle::AmeteAlem { + coptic_year - AMETE_ALEM_OFFSET + } else { + coptic_year - AMETE_MIHRET_OFFSET + }; + + if self.0 == EthiopianEraStyle::AmeteAlem || extended_year <= 0 { types::EraYear { era: tinystr!(16, "aa"), era_index: Some(0), - year, + year: coptic_year - AMETE_ALEM_OFFSET, + extended_year, ambiguity: types::YearAmbiguity::CenturyRequired, } } else { types::EraYear { era: tinystr!(16, "am"), era_index: Some(1), - year: year - INCARNATION_OFFSET, + year: coptic_year - AMETE_MIHRET_OFFSET, + extended_year, ambiguity: types::YearAmbiguity::CenturyRequired, } } } - fn extended_year(&self, date: &Self::DateInner) -> i32 { - let year = date.0.extended_year(); - if self.0 { - year - } else { - year - INCARNATION_OFFSET - } - } - fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { - Self::provided_year_is_leap(date.0.year) + Coptic.is_in_leap_year(&date.0) } fn month(&self, date: &Self::DateInner) -> types::MonthInfo { - date.0.month() + Coptic.month(&date.0) } fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { - date.0.day_of_month() + Coptic.day_of_month(&date.0) } fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear { - date.0.day_of_year() + Coptic.day_of_year(&date.0) } fn debug_name(&self) -> &'static str { @@ -252,20 +272,17 @@ impl Calendar for Ethiopian { impl Ethiopian { /// Construct a new Ethiopian Calendar for the Amete Mihret era naming scheme pub const fn new() -> Self { - Self(false) + Self(EthiopianEraStyle::AmeteMihret) } - /// Construct a new Ethiopian Calendar with a value specifying whether or not it is Amete Alem + + /// Construct a new Ethiopian Calendar with an explicit [`EthiopianEraStyle`]. pub const fn new_with_era_style(era_style: EthiopianEraStyle) -> Self { - Self(matches!(era_style, EthiopianEraStyle::AmeteAlem)) + Self(era_style) } - /// Returns whether this has the Amete Alem era + /// Returns the [`EthiopianEraStyle`] used by this calendar. pub fn era_style(&self) -> EthiopianEraStyle { - if self.0 { - EthiopianEraStyle::AmeteAlem - } else { - EthiopianEraStyle::AmeteMihret - } + self.0 } } @@ -286,16 +303,15 @@ impl Date { /// ``` pub fn try_new_ethiopian( era_style: EthiopianEraStyle, - mut year: i32, + year: i32, month: u8, day: u8, ) -> Result, RangeError> { - if era_style == EthiopianEraStyle::AmeteAlem { - year -= INCARNATION_OFFSET; - } - ArithmeticDate::new_from_ordinals(year, month, day) + let year = Ethiopian(era_style).year_info_from_extended(year); + ArithmeticDate::try_from_ymd(year, month, day) + .map(CopticDateInner) .map(EthiopianDateInner) - .map(|inner| Date::from_raw(inner, Ethiopian::new_with_era_style(era_style))) + .map(|inner| Date::from_raw(inner, Ethiopian(era_style))) } } @@ -331,10 +347,7 @@ mod test { #[test] fn test_iso_to_ethiopian_aa_conversion_and_back() { let iso_date = Date::try_new_iso(1970, 1, 2).unwrap(); - let date_ethiopian = Date::new_from_iso( - iso_date, - Ethiopian::new_with_era_style(EthiopianEraStyle::AmeteAlem), - ); + let date_ethiopian = Date::new_from_iso(iso_date, Ethiopian(EthiopianEraStyle::AmeteAlem)); assert_eq!(date_ethiopian.extended_year(), 7462); assert_eq!(date_ethiopian.month().ordinal, 4); @@ -360,7 +373,7 @@ mod test { assert_eq!( Date::new_from_iso( Date::try_new_iso(-5500 + 9, 1, 1).unwrap(), - Ethiopian::new_with_era_style(EthiopianEraStyle::AmeteAlem) + Ethiopian(EthiopianEraStyle::AmeteAlem) ) .extended_year(), 1 @@ -368,7 +381,7 @@ mod test { assert_eq!( Date::new_from_iso( Date::try_new_iso(9, 1, 1).unwrap(), - Ethiopian::new_with_era_style(EthiopianEraStyle::AmeteAlem) + Ethiopian(EthiopianEraStyle::AmeteAlem) ) .extended_year(), 5501 @@ -377,7 +390,7 @@ mod test { assert_eq!( Date::new_from_iso( Date::try_new_iso(-5500 + 9, 1, 1).unwrap(), - Ethiopian::new_with_era_style(EthiopianEraStyle::AmeteMihret) + Ethiopian(EthiopianEraStyle::AmeteMihret) ) .extended_year(), -5499 @@ -385,7 +398,7 @@ mod test { assert_eq!( Date::new_from_iso( Date::try_new_iso(9, 1, 1).unwrap(), - Ethiopian::new_with_era_style(EthiopianEraStyle::AmeteMihret) + Ethiopian(EthiopianEraStyle::AmeteMihret) ) .extended_year(), 1 diff --git a/deps/crates/vendor/icu_calendar/src/cal/gregorian.rs b/deps/crates/vendor/icu_calendar/src/cal/gregorian.rs index 0466be71743ba5..2475fd562a5c27 100644 --- a/deps/crates/vendor/icu_calendar/src/cal/gregorian.rs +++ b/deps/crates/vendor/icu_calendar/src/cal/gregorian.rs @@ -2,122 +2,39 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -//! This module contains types and implementations for the Gregorian calendar. -//! -//! ```rust -//! use icu::calendar::{cal::Gregorian, Date}; -//! -//! let date_iso = Date::try_new_iso(1970, 1, 2) -//! .expect("Failed to initialize ISO Date instance."); -//! let date_gregorian = Date::new_from_iso(date_iso, Gregorian); -//! -//! assert_eq!(date_gregorian.era_year().year, 1970); -//! assert_eq!(date_gregorian.month().ordinal, 1); -//! assert_eq!(date_gregorian.day_of_month().0, 2); -//! ``` - -use crate::cal::iso::{Iso, IsoDateInner}; +use crate::cal::abstract_gregorian::{impl_with_abstract_gregorian, GregorianYears}; use crate::calendar_arithmetic::ArithmeticDate; -use crate::error::{year_check, DateError}; -use crate::{types, Calendar, Date, DateDuration, DateDurationUnit, RangeError}; -use calendrical_calculations::rata_die::RataDie; +use crate::error::UnknownEraError; +use crate::preferences::CalendarAlgorithm; +use crate::{types, Date, DateError, RangeError}; use tinystr::tinystr; -/// The [(proleptic) Gregorian Calendar](https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar) -/// -/// The Gregorian calendar is a solar calendar used by most of the world, with twelve months. -/// -/// This type can be used with [`Date`] to represent dates in this calendar. -/// -/// # Era codes -/// -/// This calendar uses two era codes: `bce` (alias `bc`), and `ce` (alias `ad`), corresponding to the BCE and CE eras. -/// -/// # Month codes -/// -/// This calendar supports 12 solar month codes (`"M01" - "M12"`) -#[derive(Copy, Clone, Debug, Default)] -#[allow(clippy::exhaustive_structs)] // this type is stable -pub struct Gregorian; +impl_with_abstract_gregorian!(crate::cal::Gregorian, GregorianDateInner, CeBce, _x, CeBce); -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] -/// The inner date type used for representing [`Date`]s of [`Gregorian`]. See [`Date`] and [`Gregorian`] for more details. -pub struct GregorianDateInner(pub(crate) IsoDateInner); +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub(crate) struct CeBce; -impl crate::cal::scaffold::UnstableSealed for Gregorian {} -impl Calendar for Gregorian { - type DateInner = GregorianDateInner; - type Year = types::EraYear; - fn from_codes( +impl GregorianYears for CeBce { + fn extended_from_era_year( &self, - era: Option<&str>, + era: Option<&[u8]>, year: i32, - month_code: types::MonthCode, - day: u8, - ) -> Result { - let year = match era { - Some("bce" | "bc") => 1 - year_check(year, 1..)?, - Some("ad" | "ce") | None => year_check(year, 1..)?, - Some(_) => return Err(DateError::UnknownEra), - }; - - ArithmeticDate::new_from_codes(self, year, month_code, day) - .map(IsoDateInner) - .map(GregorianDateInner) - } - - fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { - GregorianDateInner(Iso.from_rata_die(rd)) - } - - fn to_rata_die(&self, date: &Self::DateInner) -> RataDie { - Iso.to_rata_die(&date.0) - } - - fn from_iso(&self, iso: IsoDateInner) -> GregorianDateInner { - GregorianDateInner(iso) - } - - fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { - date.0 - } - - fn months_in_year(&self, date: &Self::DateInner) -> u8 { - Iso.months_in_year(&date.0) - } - - fn days_in_year(&self, date: &Self::DateInner) -> u16 { - Iso.days_in_year(&date.0) - } - - fn days_in_month(&self, date: &Self::DateInner) -> u8 { - Iso.days_in_month(&date.0) - } - - fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) { - Iso.offset_date(&mut date.0, offset.cast_unit()) + ) -> Result { + match era { + None => Ok(year), + Some(b"ad" | b"ce") => Ok(year), + Some(b"bce" | b"bc") => Ok(1 - year), + Some(_) => Err(UnknownEraError), + } } - #[allow(clippy::field_reassign_with_default)] // it's more clear this way - fn until( - &self, - date1: &Self::DateInner, - date2: &Self::DateInner, - _calendar2: &Self, - largest_unit: DateDurationUnit, - smallest_unit: DateDurationUnit, - ) -> DateDuration { - Iso.until(&date1.0, &date2.0, &Iso, largest_unit, smallest_unit) - .cast_unit() - } - /// The calendar-specific year represented by `date` - fn year_info(&self, date: &Self::DateInner) -> Self::Year { - let extended_year = self.extended_year(date); + fn era_year_from_extended(&self, extended_year: i32, _month: u8, _day: u8) -> types::EraYear { if extended_year > 0 { types::EraYear { era: tinystr!(16, "ce"), era_index: Some(1), year: extended_year, + extended_year, ambiguity: match extended_year { ..=999 => types::YearAmbiguity::EraAndCenturyRequired, 1000..=1949 => types::YearAmbiguity::CenturyRequired, @@ -129,44 +46,77 @@ impl Calendar for Gregorian { types::EraYear { era: tinystr!(16, "bce"), era_index: Some(0), - year: 1_i32.saturating_sub(extended_year), + year: 1 - extended_year, + extended_year, ambiguity: types::YearAmbiguity::EraAndCenturyRequired, } } } - fn extended_year(&self, date: &Self::DateInner) -> i32 { - Iso.extended_year(&date.0) - } - - fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { - Iso.is_in_leap_year(&date.0) - } - - /// The calendar-specific month represented by `date` - fn month(&self, date: &Self::DateInner) -> types::MonthInfo { - Iso.month(&date.0) - } - - /// The calendar-specific day-of-month represented by `date` - fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { - Iso.day_of_month(&date.0) - } - - /// Information of the day of the year - fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear { - date.0 .0.day_of_year() - } - fn debug_name(&self) -> &'static str { "Gregorian" } - fn calendar_algorithm(&self) -> Option { - Some(crate::preferences::CalendarAlgorithm::Gregory) + fn calendar_algorithm(&self) -> Option { + Some(CalendarAlgorithm::Gregory) } } +/// The [Gregorian Calendar](https://en.wikipedia.org/wiki/Gregorian_calendar) +/// +/// The Gregorian calendar is an improvement over the [`Julian`](super::Julian) calendar. +/// It was adopted under Pope Gregory XIII in 1582 CE by much of Roman Catholic Europe, +/// and over the following centuries by all other countries that had been using +/// the Julian calendar. Eventually even countries that had been using other calendars +/// adopted this calendar, and today it is used as the international civil calendar. +/// +/// This implementation extends proleptically for dates before the calendar's creation. +/// +/// This corresponds to the `"gregory"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). +/// +/// # Era codes +/// +/// This calendar uses two era codes: `bce` (alias `bc`), and `ce` (alias `ad`), corresponding to the BCE and CE eras. +/// +/// # Months and days +/// +/// The 12 months are called January (`M01`, 31 days), February (`M02`, 28 days), +/// March (`M03`, 31 days), April (`M04`, 30 days), May (`M05`, 31 days), June (`M06`, 30 days), +/// July (`M07`, 31 days), August (`M08`, 31 days), September (`M09`, 30 days), +/// October (`M10`, 31 days), November (`M11`, 30 days), December (`M12`, 31 days). +/// +/// In leap years (years divisible by 4 but not 100 except when divisble by 400), February gains a 29th day. +/// +/// Standard years thus have 365 days, and leap years 366. +/// +/// # Calendar drift +/// +/// The Gregorian calendar has an average year length of 365.2425, slightly longer than +/// the mean solar year, so this calendar drifts 1 day in ~7700 years with respect +/// to the seasons. +/// +/// # Historical accuracy +/// +/// This type implements the [*proleptic* Gregorian calendar]( +/// https://en.wikipedia.org/wiki/Gregorian_calendar#Proleptic_Gregorian_calendar), +/// with dates before 1582 CE using the rules projected backwards. Care needs to be taken +/// when intepreting historical dates before or during the transition from the Julian to +/// the Gregorian calendar. [Some regions](https://en.wikipedia.org/wiki/Adoption_of_the_Gregorian_calendar) +/// continued using the Julian calendar as late as the 20th century. Sources often +/// mark dates as "New Style" (Gregorian) or "Old Style" (Julian) if there is ambiguity. +/// +/// Historically, the Julian/Gregorian calendars were used with a variety of year reckoning +/// schemes (see [`Julian`](super::Julian) for more detail). The Gregorian calendar has generally +/// been used with the [Anno Domini](https://en.wikipedia.org/wiki/Anno_Domini)/[Common era]( +/// https://en.wikipedia.org/wiki/Common_Era) since its inception. However, some countries +/// that have adopted the Gregorian calendar more recently are still using their traditional +/// year-reckoning schemes. This crate implements some of these as different types, i.e the Thai +/// [`Buddhist`](super::Buddhist) calendar, the [`Japanese`](super::Japanese) calendar, and the +/// Chinese Republican Calendar ([`Roc`](super::Roc)). +#[derive(Copy, Clone, Debug, Default)] +#[allow(clippy::exhaustive_structs)] // this type is stable +pub struct Gregorian; + impl Date { /// Construct a new Gregorian Date. /// @@ -184,12 +134,22 @@ impl Date { /// assert_eq!(date_gregorian.day_of_month().0, 2); /// ``` pub fn try_new_gregorian(year: i32, month: u8, day: u8) -> Result, RangeError> { - Date::try_new_iso(year, month, day).map(|d| Date::new_from_iso(d, Gregorian)) + ArithmeticDate::new_gregorian::(year, month, day) + .map(GregorianDateInner) + .map(|i| Date::from_raw(i, Gregorian)) + } +} + +impl Gregorian { + /// Returns the date of Easter in the given year. + pub fn easter(year: i32) -> Date { + Date::from_rata_die(calendrical_calculations::gregorian::easter(year), Self) } } #[cfg(test)] mod test { + use crate::cal::Iso; use calendrical_calculations::rata_die::RataDie; use super::*; diff --git a/deps/crates/vendor/icu_calendar/src/cal/hebrew.rs b/deps/crates/vendor/icu_calendar/src/cal/hebrew.rs index e0464a2c1af691..e1e43953ca8866 100644 --- a/deps/crates/vendor/icu_calendar/src/cal/hebrew.rs +++ b/deps/crates/vendor/icu_calendar/src/cal/hebrew.rs @@ -2,26 +2,15 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -//! This module contains types and implementations for the Hebrew calendar. -//! -//! ```rust -//! use icu::calendar::Date; -//! -//! let hebrew_date = Date::try_new_hebrew(3425, 10, 11) -//! .expect("Failed to initialize hebrew Date instance."); -//! -//! assert_eq!(hebrew_date.era_year().year, 3425); -//! assert_eq!(hebrew_date.month().ordinal, 10); -//! assert_eq!(hebrew_date.day_of_month().0, 11); -//! ``` - -use crate::cal::iso::{Iso, IsoDateInner}; -use crate::calendar_arithmetic::PrecomputedDataSource; -use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic}; -use crate::error::DateError; -use crate::types::MonthInfo; +use crate::calendar_arithmetic::{ArithmeticDate, DateFieldsResolver, ToExtendedYear}; +use crate::error::{ + DateError, DateFromFieldsError, EcmaReferenceYearError, MonthCodeError, UnknownEraError, +}; +use crate::options::{DateAddOptions, DateDifferenceOptions}; +use crate::options::{DateFromFieldsOptions, Overflow}; +use crate::types::{DateFields, MonthInfo, ValidMonthCode}; use crate::RangeError; -use crate::{types, Calendar, Date, DateDuration, DateDurationUnit}; +use crate::{types, Calendar, Date}; use ::tinystr::tinystr; use calendrical_calculations::hebrew_keviyah::{Keviyah, YearInfo}; use calendrical_calculations::rata_die::RataDie; @@ -31,21 +20,35 @@ use calendrical_calculations::rata_die::RataDie; /// The Hebrew calendar is a lunisolar calendar used as the Jewish liturgical calendar /// as well as an official calendar in Israel. /// -/// This calendar is the _civil_ Hebrew calendar, with the year starting at in the month of Tishrei. +/// This implementation uses civil month numbering, where Tishrei is the first month of the year. +/// +/// The precise algorithm used to calculate the Hebrew Calendar has [changed over time], with +/// the modern one being in place since about 4536 AM (776 CE). This implementation extends +/// proleptically for dates before that. +/// +/// [changed over time]: https://hakirah.org/vol20AjdlerAppendices.pdf +/// +/// This corresponds to the `"hebrew"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). /// /// # Era codes /// /// This calendar uses a single era code `am`, Anno Mundi. Dates before this era use negative years. /// -/// # Month codes +/// # Months and days /// -/// This calendar is a lunisolar calendar and thus has a leap month. It supports codes `"M01"-"M12"` -/// for regular months, and the leap month Adar I being coded as `"M05L"`. +/// The 12 months are called Tishrei (`M01`, 30 days), Ḥešvan (`M02`, 29/30 days), +/// Kīslev (`M03`, 30/29 days), Ṭevet (`M04`, 29 days), Šəvaṭ (`M05`, 30 days), ʾĂdār (`M06`, 29 days), +/// Nīsān (`M07`, 30 days), ʾĪyyar (`M08`, 29 days), Sivan (`M09`, 30 days), Tammūz (`M10`, 29 days), +/// ʾAv (`M11`, 30 days), ʾElūl (`M12`, 29 days). /// -/// [`MonthInfo`] has slightly divergent behavior: because the regular month Adar is formatted -/// as "Adar II" in a leap year, this calendar will produce the special code `"M06L"` in any [`MonthInfo`] -/// objects it creates. -#[derive(Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Default)] +/// Due to Rosh Hashanah postponement rules, Ḥešvan and Kislev vary in length. +/// +/// In leap years (years 3, 6, 8, 11, 17, 19 in a 19-year cycle), the leap month Adar I (`M05L`, 30 days) +/// is inserted before Adar, and Adar is called Adar II (the `formatting_code` returned by [`MonthInfo`] +/// will be `M06L` to mark this, while the `standard_code` remains `M06`). +/// +/// Standard years thus have 353-355 days, and leap years 383-385. +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Default)] #[allow(clippy::exhaustive_structs)] // unit struct pub struct Hebrew; @@ -63,42 +66,29 @@ impl Hebrew { #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub(crate) struct HebrewYearInfo { keviyah: Keviyah, - prev_keviyah: Keviyah, value: i32, } -impl From for i32 { - fn from(value: HebrewYearInfo) -> Self { - value.value +impl ToExtendedYear for HebrewYearInfo { + fn to_extended_year(&self) -> i32 { + self.value } } impl HebrewYearInfo { /// Convenience method to compute for a given year. Don't use this if you actually need /// a YearInfo that you want to call .new_year() on. - /// - /// This can potentially be optimized with adjacent-year knowledge, but it's complex #[inline] - fn compute(h_year: i32) -> Self { - let keviyah = YearInfo::compute_for(h_year).keviyah; - Self::compute_with_keviyah(keviyah, h_year) - } - /// Compute for a given year when the keviyah is already known - #[inline] - fn compute_with_keviyah(keviyah: Keviyah, h_year: i32) -> Self { - let prev_keviyah = YearInfo::compute_for(h_year - 1).keviyah; + fn compute(value: i32) -> Self { Self { - keviyah, - prev_keviyah, - value: h_year, + keviyah: YearInfo::compute_for(value).keviyah, + value, } } } -// HEBREW CALENDAR -impl CalendarArithmetic for Hebrew { +impl DateFieldsResolver for Hebrew { type YearInfo = HebrewYearInfo; - fn days_in_provided_month(info: HebrewYearInfo, ordinal_month: u8) -> u8 { info.keviyah.month_len(ordinal_month) } @@ -111,22 +101,91 @@ impl CalendarArithmetic for Hebrew { } } - fn days_in_provided_year(info: HebrewYearInfo) -> u16 { - info.keviyah.year_length() + #[inline] + fn year_info_from_era( + &self, + era: &[u8], + era_year: i32, + ) -> Result { + match era { + b"am" => Ok(HebrewYearInfo::compute(era_year)), + _ => Err(UnknownEraError), + } + } + + #[inline] + fn year_info_from_extended(&self, extended_year: i32) -> Self::YearInfo { + HebrewYearInfo::compute(extended_year) } - fn provided_year_is_leap(info: HebrewYearInfo) -> bool { - info.keviyah.is_leap() + fn reference_year_from_month_day( + &self, + month_code: types::ValidMonthCode, + day: u8, + ) -> Result { + // December 31, 1972 occurs on 4th month, 26th day, 5733 AM + let hebrew_year = match month_code.to_tuple() { + (1, false) => 5733, + (2, false) => match day { + // There is no day 30 in 5733 (there is in 5732) + ..=29 => 5733, + // Note (here and below): this must be > 29, not just == 30, + // since we have not yet applied a potential Overflow::Constrain. + _ => 5732, + }, + (3, false) => match day { + // There is no day 30 in 5733 (there is in 5732) + ..=29 => 5733, + _ => 5732, + }, + (4, false) => match day { + ..=26 => 5733, + _ => 5732, + }, + (5..=12, false) => 5732, + // Neither 5731 nor 5732 is a leap year + (5, true) => 5730, + _ => { + return Err(EcmaReferenceYearError::MonthCodeNotInCalendar); + } + }; + Ok(HebrewYearInfo::compute(hebrew_year)) } - fn last_month_day_in_provided_year(info: HebrewYearInfo) -> (u8, u8) { - info.keviyah.last_month_day_in_year() + fn ordinal_month_from_code( + &self, + year: &Self::YearInfo, + month_code: types::ValidMonthCode, + options: DateFromFieldsOptions, + ) -> Result { + let is_leap_year = year.keviyah.is_leap(); + let ordinal_month = match month_code.to_tuple() { + (n @ 1..=12, false) => n + (n >= 6 && is_leap_year) as u8, + (5, true) => { + if is_leap_year { + 6 + } else if matches!(options.overflow, Some(Overflow::Constrain)) { + // M05L maps to M06 in a common year + 6 + } else { + return Err(MonthCodeError::NotInYear); + } + } + _ => return Err(MonthCodeError::NotInCalendar), + }; + Ok(ordinal_month) } -} -impl PrecomputedDataSource for () { - fn load_or_compute_info(&self, h_year: i32) -> HebrewYearInfo { - HebrewYearInfo::compute(h_year) + fn month_code_from_ordinal( + &self, + year: &Self::YearInfo, + ordinal_month: u8, + ) -> types::ValidMonthCode { + let is_leap = year.keviyah.is_leap(); + ValidMonthCode::new_unchecked( + ordinal_month - (is_leap && ordinal_month >= 6) as u8, + ordinal_month == 6 && is_leap, + ) } } @@ -134,6 +193,7 @@ impl crate::cal::scaffold::UnstableSealed for Hebrew {} impl Calendar for Hebrew { type DateInner = HebrewDateInner; type Year = types::EraYear; + type DifferenceError = core::convert::Infallible; fn from_codes( &self, @@ -142,118 +202,78 @@ impl Calendar for Hebrew { month_code: types::MonthCode, day: u8, ) -> Result { - match era { - Some("am") | None => {} - _ => return Err(DateError::UnknownEra), - } - - let year = HebrewYearInfo::compute(year); - - let is_leap_year = year.keviyah.is_leap(); - - let month_code_str = month_code.0.as_str(); - - let month_ordinal = if is_leap_year { - match month_code_str { - "M01" => 1, - "M02" => 2, - "M03" => 3, - "M04" => 4, - "M05" => 5, - "M05L" => 6, - // M06L is the formatting era code used for Adar II - "M06" | "M06L" => 7, - "M07" => 8, - "M08" => 9, - "M09" => 10, - "M10" => 11, - "M11" => 12, - "M12" => 13, - _ => { - return Err(DateError::UnknownMonthCode(month_code)); - } - } - } else { - match month_code_str { - "M01" => 1, - "M02" => 2, - "M03" => 3, - "M04" => 4, - "M05" => 5, - "M06" => 6, - "M07" => 7, - "M08" => 8, - "M09" => 9, - "M10" => 10, - "M11" => 11, - "M12" => 12, - _ => { - return Err(DateError::UnknownMonthCode(month_code)); - } - } - }; + ArithmeticDate::from_codes(era, year, month_code, day, self).map(HebrewDateInner) + } - Ok(HebrewDateInner(ArithmeticDate::new_from_ordinals( - year, - month_ordinal, - day, - )?)) + #[cfg(feature = "unstable")] + fn from_fields( + &self, + fields: DateFields, + options: DateFromFieldsOptions, + ) -> Result { + ArithmeticDate::from_fields(fields, options, self).map(HebrewDateInner) } fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { - let (year, h_year) = YearInfo::year_containing_rd(rd); - // Obtaining a 1-indexed day-in-year value - let day = rd - year.new_year() + 1; - let day = u16::try_from(day).unwrap_or(u16::MAX); + let (year_info, year) = YearInfo::year_containing_rd(rd); + let keviyah = year_info.keviyah; - let year = HebrewYearInfo::compute_with_keviyah(year.keviyah, h_year); - let (month, day) = year.keviyah.month_day_for(day); - HebrewDateInner(ArithmeticDate::new_unchecked(year, month, day)) + // Obtaining a 1-indexed day-in-year value + let day_in_year = u16::try_from(rd - year_info.new_year() + 1).unwrap_or(u16::MAX); + let (month, day) = keviyah.month_day_for(day_in_year); + + HebrewDateInner(ArithmeticDate::new_unchecked( + HebrewYearInfo { + keviyah, + value: year, + }, + month, + day, + )) } fn to_rata_die(&self, date: &Self::DateInner) -> RataDie { - let year = date.0.year.keviyah.year_info(date.0.year.value); - - let ny = year.new_year(); - let days_preceding = year.keviyah.days_preceding(date.0.month); + let ny = date.0.year.keviyah.year_info(date.0.year.value).new_year(); + let days_preceding = date.0.year.keviyah.days_preceding(date.0.month); // Need to subtract 1 since the new year is itself in this year ny + i64::from(days_preceding) + i64::from(date.0.day) - 1 } - fn from_iso(&self, iso: IsoDateInner) -> Self::DateInner { - self.from_rata_die(Iso.to_rata_die(&iso)) - } - - fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { - Iso.from_rata_die(self.to_rata_die(date)) + fn has_cheap_iso_conversion(&self) -> bool { + false } fn months_in_year(&self, date: &Self::DateInner) -> u8 { - date.0.months_in_year() + Self::months_in_provided_year(date.0.year) } fn days_in_year(&self, date: &Self::DateInner) -> u16 { - date.0.days_in_year() + date.0.year.keviyah.year_length() } fn days_in_month(&self, date: &Self::DateInner) -> u8 { - date.0.days_in_month() + Self::days_in_provided_month(date.0.year, date.0.month) } - fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) { - date.0.offset_date(offset, &()) + #[cfg(feature = "unstable")] + fn add( + &self, + date: &Self::DateInner, + duration: types::DateDuration, + options: DateAddOptions, + ) -> Result { + date.0.added(duration, self, options).map(HebrewDateInner) } + #[cfg(feature = "unstable")] fn until( &self, date1: &Self::DateInner, date2: &Self::DateInner, - _calendar2: &Self, - _largest_unit: DateDurationUnit, - _smallest_unit: DateDurationUnit, - ) -> DateDuration { - date1.0.until(date2.0, _largest_unit, _smallest_unit) + options: DateDifferenceOptions, + ) -> Result { + Ok(date1.0.until(&date2.0, self, options)) } fn debug_name(&self) -> &'static str { @@ -261,76 +281,44 @@ impl Calendar for Hebrew { } fn year_info(&self, date: &Self::DateInner) -> Self::Year { + let extended_year = date.0.year.value; types::EraYear { era_index: Some(0), era: tinystr!(16, "am"), - year: self.extended_year(date), + year: extended_year, + extended_year, ambiguity: types::YearAmbiguity::CenturyRequired, } } - fn extended_year(&self, date: &Self::DateInner) -> i32 { - date.0.extended_year() - } - fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { - Self::provided_year_is_leap(date.0.year) + date.0.year.keviyah.is_leap() } fn month(&self, date: &Self::DateInner) -> MonthInfo { - let mut ordinal = date.0.month; - let is_leap_year = Self::provided_year_is_leap(date.0.year); - - if is_leap_year { - if ordinal == 6 { - return types::MonthInfo { - ordinal, - standard_code: types::MonthCode(tinystr!(4, "M05L")), - formatting_code: types::MonthCode(tinystr!(4, "M05L")), - }; - } else if ordinal == 7 { - return types::MonthInfo { - ordinal, - // Adar II is the same as Adar and has the same code - standard_code: types::MonthCode(tinystr!(4, "M06")), - formatting_code: types::MonthCode(tinystr!(4, "M06L")), - }; - } - } + let valid_standard_code = self.month_code_from_ordinal(&date.0.year, date.0.month); - if is_leap_year && ordinal > 6 { - ordinal -= 1; - } - - let code = match ordinal { - 1 => tinystr!(4, "M01"), - 2 => tinystr!(4, "M02"), - 3 => tinystr!(4, "M03"), - 4 => tinystr!(4, "M04"), - 5 => tinystr!(4, "M05"), - 6 => tinystr!(4, "M06"), - 7 => tinystr!(4, "M07"), - 8 => tinystr!(4, "M08"), - 9 => tinystr!(4, "M09"), - 10 => tinystr!(4, "M10"), - 11 => tinystr!(4, "M11"), - 12 => tinystr!(4, "M12"), - _ => tinystr!(4, "und"), + let valid_formatting_code = if valid_standard_code.number() == 6 && date.0.month == 7 { + ValidMonthCode::new_unchecked(6, true) // M06L + } else { + valid_standard_code }; types::MonthInfo { ordinal: date.0.month, - standard_code: types::MonthCode(code), - formatting_code: types::MonthCode(code), + standard_code: valid_standard_code.to_month_code(), + valid_standard_code, + formatting_code: valid_formatting_code.to_month_code(), + valid_formatting_code, } } fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { - date.0.day_of_month() + types::DayOfMonth(date.0.day) } fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear { - date.0.day_of_year() + types::DayOfYear(date.0.year.keviyah.days_preceding(date.0.month) + date.0.day as u16) } fn calendar_algorithm(&self) -> Option { @@ -339,26 +327,18 @@ impl Calendar for Hebrew { } impl Date { - /// Construct new Hebrew Date. - /// - /// This date will not use any precomputed calendrical calculations, - /// one that loads such data from a provider will be added in the future (#3933) - /// + /// This method uses an ordinal month, which is probably not what you want. /// - /// ```rust - /// use icu::calendar::Date; - /// - /// let date_hebrew = Date::try_new_hebrew(3425, 4, 25) - /// .expect("Failed to initialize Hebrew Date instance."); - /// - /// assert_eq!(date_hebrew.era_year().year, 3425); - /// assert_eq!(date_hebrew.month().ordinal, 4); - /// assert_eq!(date_hebrew.day_of_month().0, 25); - /// ``` - pub fn try_new_hebrew(year: i32, month: u8, day: u8) -> Result, RangeError> { + /// Use [`Date::try_new_from_codes`] + #[deprecated(since = "2.1.0", note = "use `Date::try_new_from_codes`")] + pub fn try_new_hebrew( + year: i32, + ordinal_month: u8, + day: u8, + ) -> Result, RangeError> { let year = HebrewYearInfo::compute(year); - ArithmeticDate::new_from_ordinals(year, month, day) + ArithmeticDate::try_from_ymd(year, ordinal_month, day) .map(HebrewDateInner) .map(|inner| Date::from_raw(inner, Hebrew)) } @@ -369,21 +349,28 @@ mod tests { use super::*; use crate::types::MonthCode; - use calendrical_calculations::hebrew_keviyah::*; - // Sentinel value for Adar I - // We're using normalized month values here so that we can use constants. These do not - // distinguish between the different Adars. We add an out-of-range sentinel value of 13 to - // specifically talk about Adar I in a leap year - const ADARI: u8 = 13; + pub const TISHREI: ValidMonthCode = ValidMonthCode::new_unchecked(1, false); + pub const ḤESHVAN: ValidMonthCode = ValidMonthCode::new_unchecked(2, false); + pub const KISLEV: ValidMonthCode = ValidMonthCode::new_unchecked(3, false); + pub const TEVET: ValidMonthCode = ValidMonthCode::new_unchecked(4, false); + pub const SHEVAT: ValidMonthCode = ValidMonthCode::new_unchecked(5, false); + pub const ADARI: ValidMonthCode = ValidMonthCode::new_unchecked(5, true); + pub const ADAR: ValidMonthCode = ValidMonthCode::new_unchecked(6, false); + pub const NISAN: ValidMonthCode = ValidMonthCode::new_unchecked(7, false); + pub const IYYAR: ValidMonthCode = ValidMonthCode::new_unchecked(8, false); + pub const SIVAN: ValidMonthCode = ValidMonthCode::new_unchecked(9, false); + pub const TAMMUZ: ValidMonthCode = ValidMonthCode::new_unchecked(10, false); + pub const AV: ValidMonthCode = ValidMonthCode::new_unchecked(11, false); + pub const ELUL: ValidMonthCode = ValidMonthCode::new_unchecked(12, false); /// The leap years used in the tests below const LEAP_YEARS_IN_TESTS: [i32; 1] = [5782]; /// (iso, hebrew) pairs of testcases. If any of the years here /// are leap years please add them to LEAP_YEARS_IN_TESTS (we have this manually /// so we don't end up exercising potentially buggy codepaths to test this) - #[allow(clippy::type_complexity)] - const ISO_HEBREW_DATE_PAIRS: [((i32, u8, u8), (i32, u8, u8)); 48] = [ + #[expect(clippy::type_complexity)] + const ISO_HEBREW_DATE_PAIRS: [((i32, u8, u8), (i32, ValidMonthCode, u8)); 48] = [ ((2021, 1, 10), (5781, TEVET, 26)), ((2021, 1, 25), (5781, SHEVAT, 12)), ((2021, 2, 10), (5781, SHEVAT, 28)), @@ -438,17 +425,12 @@ mod tests { fn test_conversions() { for ((iso_y, iso_m, iso_d), (y, m, d)) in ISO_HEBREW_DATE_PAIRS.into_iter() { let iso_date = Date::try_new_iso(iso_y, iso_m, iso_d).unwrap(); - let month_code = if m == ADARI { - MonthCode(tinystr!(4, "M05L")) - } else { - MonthCode::new_normal(m).unwrap() - }; - let hebrew_date = Date::try_new_from_codes(Some("am"), y, month_code, d, Hebrew) + let hebrew_date = Date::try_new_from_codes(Some("am"), y, m.to_month_code(), d, Hebrew) .expect("Date should parse"); let iso_to_hebrew = iso_date.to_calendar(Hebrew); - let hebrew_to_iso = hebrew_date.to_calendar(Iso); + let hebrew_to_iso = hebrew_date.to_iso(); assert_eq!( hebrew_to_iso, iso_date, @@ -459,19 +441,16 @@ mod tests { "Failed comparing to-hebrew value for {iso_date:?} => {hebrew_date:?}" ); - let ordinal_month = if LEAP_YEARS_IN_TESTS.contains(&y) { - if m == ADARI { - ADAR - } else if m >= ADAR { - m + 1 - } else { - m - } + let ordinal_month = if (m == ADARI || m.number() >= ADAR.number()) + && LEAP_YEARS_IN_TESTS.contains(&y) + { + m.number() + 1 } else { assert!(m != ADARI); - m + m.number() }; + #[allow(deprecated)] // should still test let ordinal_hebrew_date = Date::try_new_hebrew(y, ordinal_month, d) .expect("Construction of date must succeed"); @@ -489,7 +468,7 @@ mod tests { fn test_negative_era_years() { let greg_date = Date::try_new_gregorian(-5000, 1, 1).unwrap(); let greg_year = greg_date.era_year(); - assert_eq!(greg_date.inner.0 .0.year, -5000); + assert_eq!(greg_date.inner.0.year, -5000); assert_eq!(greg_year.era, "bce"); // In Gregorian, era year is 1 - extended year assert_eq!(greg_year.year, 5001); @@ -506,7 +485,7 @@ mod tests { // https://github.com/unicode-org/icu4x/issues/4893 let cal = Hebrew::new(); let era = "am"; - let month_code = MonthCode(tinystr!(4, "M01")); + let month_code = MonthCode::new_normal(1).unwrap(); let dt = Date::try_new_from_codes(Some(era), 3760, month_code, 1, cal).unwrap(); // Should be Saturday per: diff --git a/deps/crates/vendor/icu_calendar/src/cal/hijri.rs b/deps/crates/vendor/icu_calendar/src/cal/hijri.rs index 02a5d920269fa7..cd445acd34067a 100644 --- a/deps/crates/vendor/icu_calendar/src/cal/hijri.rs +++ b/deps/crates/vendor/icu_calendar/src/cal/hijri.rs @@ -2,533 +2,191 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -//! This module contains types and implementations for the Hijri calendars. -//! -//! ```rust -//! use icu::calendar::cal::HijriSimulated; -//! use icu::calendar::Date; -//! -//! let hijri = HijriSimulated::new_mecca_always_calculating(); -//! let hijri_date = -//! Date::try_new_simulated_hijri_with_calendar(1348, 10, 11, hijri) -//! .expect("Failed to initialize Hijri Date instance."); -//! -//! assert_eq!(hijri_date.era_year().year, 1348); -//! assert_eq!(hijri_date.month().ordinal, 10); -//! assert_eq!(hijri_date.day_of_month().0, 11); -//! ``` - -use crate::cal::iso::{Iso, IsoDateInner}; -use crate::calendar_arithmetic::PrecomputedDataSource; -use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic}; -use crate::error::{year_check, DateError}; -use crate::provider::hijri::PackedHijriYearInfo; -use crate::provider::hijri::{CalendarHijriSimulatedMeccaV1, HijriData}; -use crate::types::EraYear; -use crate::{types, Calendar, Date, DateDuration, DateDurationUnit}; +use crate::calendar_arithmetic::ArithmeticDate; +use crate::calendar_arithmetic::DateFieldsResolver; +use crate::calendar_arithmetic::ToExtendedYear; +use crate::error::{DateError, DateFromFieldsError, EcmaReferenceYearError, UnknownEraError}; +use crate::options::DateFromFieldsOptions; +use crate::options::{DateAddOptions, DateDifferenceOptions}; +use crate::types::DateFields; +use crate::{types, Calendar, Date}; use crate::{AsCalendar, RangeError}; -use calendrical_calculations::islamic::{ISLAMIC_EPOCH_FRIDAY, ISLAMIC_EPOCH_THURSDAY}; +use calendrical_calculations::islamic::{ + ISLAMIC_EPOCH_FRIDAY, ISLAMIC_EPOCH_THURSDAY, WELL_BEHAVED_ASTRONOMICAL_RANGE, +}; use calendrical_calculations::rata_die::RataDie; -use icu_provider::marker::ErasedMarker; +use core::fmt::Debug; +use icu_locale_core::preferences::extensions::unicode::keywords::{ + CalendarAlgorithm, HijriCalendarAlgorithm, +}; use icu_provider::prelude::*; use tinystr::tinystr; -use ummalqura_data::{UMMALQURA_DATA, UMMALQURA_DATA_STARTING_YEAR}; +#[path = "hijri/simulated_mecca_data.rs"] +mod simulated_mecca_data; +#[path = "hijri/ummalqura_data.rs"] mod ummalqura_data; -fn era_year(year: i32) -> EraYear { - if year > 0 { - types::EraYear { - era: tinystr!(16, "ah"), - era_index: Some(0), - year, - ambiguity: types::YearAmbiguity::CenturyRequired, - } - } else { - types::EraYear { - era: tinystr!(16, "bh"), - era_index: Some(1), - year: 1 - year, - ambiguity: types::YearAmbiguity::CenturyRequired, - } - } -} - -/// The [simulated Hijri Calendar](https://en.wikipedia.org/wiki/Islamic_calendar) -/// -/// # Era codes -/// -/// This calendar uses two era codes: `ah`, and `bh`, corresponding to the Anno Hegirae and Before Hijrah eras +/// The [Hijri Calendar](https://en.wikipedia.org/wiki/Islamic_calendar) /// -/// # Month codes +/// There are many variants of this calendar, using different lunar observations or calculations +/// (see [`Rules`]). Currently, [`Rules`] is an unstable trait, but some of its implementors +/// are stable, and can be constructed via the various `Hijri::new_*` constructors. Please comment +/// on [this issue](https://github.com/unicode-org/icu4x/issues/6962) +/// if you would like to see this the ability to implement custom [`Rules`] stabilized. /// -/// This calendar is a pure lunar calendar with no leap months. It uses month codes -/// `"M01" - "M12"`. -#[derive(Clone, Debug)] -pub struct HijriSimulated { - pub(crate) location: HijriSimulatedLocation, - data: Option>>>, -} - -#[derive(Clone, Debug, Copy, PartialEq)] -pub(crate) enum HijriSimulatedLocation { - Mecca, -} - -impl HijriSimulatedLocation { - fn location(self) -> calendrical_calculations::islamic::Location { - match self { - Self::Mecca => calendrical_calculations::islamic::MECCA, - } - } -} - -/// The [Umm al-Qura Hijri Calendar](https://en.wikipedia.org/wiki/Islamic_calendar#Saudi_Arabia's_Umm_al-Qura_calendar) +/// This implementation supports only variants where months are either 29 or 30 days. /// -/// This calendar is the official calendar in Saudi Arabia. +/// This corresponds to various `"islamic-*"` [CLDR calendars](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier), +/// see the individual implementors of [`Rules`] ([`TabularAlgorithm`], [`UmmAlQura`], [`AstronomicalSimulation`]) for more information. /// /// # Era codes /// /// This calendar uses two era codes: `ah`, and `bh`, corresponding to the Anno Hegirae and Before Hijrah eras /// -/// # Month codes +/// # Months and days /// -/// This calendar is a pure lunar calendar with no leap months. It uses month codes -/// `"M01" - "M12"`. -#[derive(Clone, Debug, Default)] -#[non_exhaustive] -pub struct HijriUmmAlQura; - -/// The [tabular Hijri Calendar](https://en.wikipedia.org/wiki/Tabular_Islamic_calendar). +/// The 12 months are called al-Muḥarram (`M01`), Ṣafar (`M02`), Rabīʿ al-ʾAwwal (`M03`), +/// Rabīʿ ath-Thānī or Rabīʿ al-ʾĀkhir (`M04`), Jumādā al-ʾŪlā (`M05`), Jumādā ath-Thāniyah +/// or Jumādā al-ʾĀkhirah (`M06`), Rajab (`M07`), Shaʿbān (`M08`), Ramaḍān (`M09`), Shawwāl (`M10`), +/// Ḏū al-Qaʿdah (`M11`), Ḏū al-Ḥijjah (`M12`). /// -/// See [`HijriTabularEpoch`] and [`HijriTabularLeapYears`] for customization. +/// As a true lunar calendar, the lengths of the months depend on the lunar cycle (a month starts on the day +/// where the waxing crescent is first observed), and will be either 29 or 30 days. /// -/// The most common version of this calendar uses [`HijriTabularEpoch::Friday`] and [`HijriTabularLeapYears::TypeII`]. +/// The lengths of the months are determined by the concrete [`Rules`] implementation. /// -/// # Era codes -/// -/// This calendar uses two era codes: `ah`, and `bh`, corresponding to the Anno Hegirae and Before Hijrah eras +/// There are either 6 or 7 30-day months, so the length of the year is 354 or 355 days. /// -/// # Month codes +/// # Calendar drift /// -/// This calendar is a pure lunar calendar with no leap months. It uses month codes -/// `"M01" - "M12"`. -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] -pub struct HijriTabular { - pub(crate) leap_years: HijriTabularLeapYears, - pub(crate) epoch: HijriTabularEpoch, -} +/// As a lunar calendar, this calendar does not intend to follow the solar year, and drifts more +/// than 10 days per year with respect to the seasons. +#[derive(Clone, Debug, Default, Copy)] +#[allow(clippy::exhaustive_structs)] // newtype +pub struct Hijri(pub S); -impl HijriSimulated { - /// Creates a new [`HijriSimulated`] for reference location Mecca, with some compiled data containing precomputed calendrical calculations. +/// Defines a variant of the [`Hijri`] calendar. +/// +/// This crate includes the [`UmmAlQura`], [`AstronomicalSimulation`], and [`TabularAlgorithm`] +/// rules, other rules can be implemented by users. +/// +///
+/// 🚫 This trait is sealed; it should not be implemented by user code. If an API requests an item that implements this +/// trait, please consider using a type from the implementors listed below. +/// +/// It is still possible to implement this trait in userland (since `UnstableSealed` is public), +/// do not do so unless you are prepared for things to occasionally break. +///
+pub trait Rules: Clone + Debug + crate::cal::scaffold::UnstableSealed { + /// Returns data about the given year. + fn year_data(&self, extended_year: i32) -> HijriYearData; + + /// Returns an ECMA reference year that contains the given month-day combination. /// - /// ✨ *Enabled with the `compiled_data` Cargo feature.* + /// If the day is out of range, it will return a year that contains the given month + /// and the maximum day possible for that month. See [the spec][spec] for the + /// precise algorithm used. /// - /// [📚 Help choosing a constructor](icu_provider::constructors) - #[cfg(feature = "compiled_data")] - pub const fn new_mecca() -> Self { - Self { - location: HijriSimulatedLocation::Mecca, - data: Some(DataPayload::from_static_ref( - crate::provider::Baked::SINGLETON_CALENDAR_HIJRI_SIMULATED_MECCA_V1, - )), - } - } - - icu_provider::gen_buffer_data_constructors!(() -> error: DataError, - functions: [ - new: skip, - try_new_mecca_with_buffer_provider, - try_new_mecca_unstable, - Self, - ]); - - #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_mecca)] - pub fn try_new_mecca_unstable + ?Sized>( - provider: &D, - ) -> Result { - Ok(Self { - location: HijriSimulatedLocation::Mecca, - data: Some(provider.load(Default::default())?.payload.cast()), - }) - } - - /// Construct a new [`HijriSimulated`] for reference location Mecca, without any precomputed calendrical calculations. - pub const fn new_mecca_always_calculating() -> Self { - Self { - location: HijriSimulatedLocation::Mecca, - data: None, - } - } - - /// Compute a cache for this calendar - #[cfg(feature = "datagen")] - pub fn build_cache(&self, extended_years: core::ops::Range) -> HijriData<'static> { - let data = extended_years - .clone() - .map(|year| self.location.compute_year_info(year).pack()) - .collect(); - HijriData { - first_extended_year: extended_years.start, - data, - } + /// This API only matters when using [`MissingFieldsStrategy::Ecma`] to compute + /// a date without providing a year in [`Date::try_from_fields()`]. The default impl + /// will just error, and custom calendars who do not care about ECMA/Temporal + /// reference years do not need to override this. + /// + /// [spec]: https://tc39.es/proposal-temporal/#sec-temporal-nonisomonthdaytoisoreferencedate + /// [`MissingFieldsStrategy::Ecma`]: crate::options::MissingFieldsStrategy::Ecma + fn ecma_reference_year( + &self, + // TODO: Consider accepting ValidMonthCode + _month_code: (u8, bool), + _day: u8, + ) -> Result { + Err(EcmaReferenceYearError::Unimplemented) } -} -impl HijriUmmAlQura { - /// Creates a new [`HijriUmmAlQura`]. - pub const fn new() -> Self { - Self + /// The BCP-47 [`CalendarAlgorithm`] for the Hijri calendar using these rules, if defined. + fn calendar_algorithm(&self) -> Option { + None } -} -/// The epoch for the [`HijriTabular`] calendar. -#[non_exhaustive] -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] -pub enum HijriTabularEpoch { - /// Thusday July 15, 622 AD (0622-07-18 ISO) - Thursday, - /// Friday July 16, 622 AD (0622-07-19 ISO) - Friday, -} - -impl HijriTabularEpoch { - fn rata_die(self) -> RataDie { - match self { - Self::Thursday => ISLAMIC_EPOCH_THURSDAY, - Self::Friday => ISLAMIC_EPOCH_FRIDAY, - } + /// The debug name for these rules. + fn debug_name(&self) -> &'static str { + "Hijri (custom rules)" } } -/// The leap year rule for the [`HijriTabular`] calendar. +/// [`Hijri`] [`Rules`] based on an astronomical simulation for a particular location. /// -/// This specifies which years of a 30-year cycle have an additional day at -/// the end of the year. -#[non_exhaustive] -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] -pub enum HijriTabularLeapYears { - /// Leap years 2, 5, 7, 10, 13, 16, 18, 21, 24, 26, 29 - TypeII, -} - -impl HijriTabular { - /// Construct a new [`HijriTabular`] with the given leap year rule and epoch. - pub const fn new(leap_years: HijriTabularLeapYears, epoch: HijriTabularEpoch) -> Self { - Self { epoch, leap_years } - } -} - -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub(crate) struct HijriYearInfo { - month_lengths: [bool; 12], - start_day: RataDie, - value: i32, -} - -impl From for i32 { - fn from(value: HijriYearInfo) -> Self { - value.value - } +/// These simulations are unofficial and are known to not necessarily match sightings +/// on the ground. Unless you know otherwise for sure, instead of this variant, use +/// [`UmmAlQura`], which uses the results of KACST's Mecca-based calculations. +/// +/// As floating point arithmetic degenerates for far-away dates, this falls back to +/// the tabular calendar at some point. +/// +/// The precise behavior of this calendar may change in the future if: +/// - We decide to tweak the precise astronomical simulation used +/// - We decide to expand or reduce the range where we are using the astronomical simulation. +/// +/// This corresponds to the `"islamic-rgsa"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier) +/// if constructed with [`Hijri::new_simulated_mecca()`]. +#[derive(Copy, Clone, Debug)] +pub struct AstronomicalSimulation { + pub(crate) location: SimulatedLocation, } -impl HijriData<'_> { - /// Get the cached data for a given extended year - fn get(&self, extended_year: i32) -> Option { - Some(HijriYearInfo::unpack( - extended_year, - self.data - .get(usize::try_from(extended_year - self.first_extended_year).ok()?)?, - )) - } +#[derive(Clone, Debug, Copy, PartialEq)] +pub(crate) enum SimulatedLocation { + Mecca, } -const LONG_YEAR_LEN: u16 = 355; -const SHORT_YEAR_LEN: u16 = 354; - -impl HijriYearInfo { - #[cfg(feature = "datagen")] - fn pack(&self) -> PackedHijriYearInfo { - PackedHijriYearInfo::new(self.value, self.month_lengths, self.start_day) - } - - fn unpack(extended_year: i32, packed: PackedHijriYearInfo) -> Self { - let (month_lengths, start_day) = packed.unpack(extended_year); - - HijriYearInfo { - month_lengths, - start_day, - value: extended_year, - } - } - - /// The number of days in a given 1-indexed month - fn days_in_month(self, month: u8) -> u8 { - let Some(zero_month) = month.checked_sub(1) else { - return 29; - }; - - if self.month_lengths.get(zero_month as usize) == Some(&true) { - 30 - } else { - 29 +impl crate::cal::scaffold::UnstableSealed for AstronomicalSimulation {} +impl Rules for AstronomicalSimulation { + fn debug_name(&self) -> &'static str { + match self.location { + SimulatedLocation::Mecca => "Hijri (simulated, Mecca)", } } - fn days_in_year(self) -> u16 { - self.last_day_of_month(12) - } - - /// Get the date's R.D. given (m, d) in this info's year - fn md_to_rd(self, month: u8, day: u8) -> RataDie { - let month_offset = if month == 1 { - 0 - } else { - self.last_day_of_month(month - 1) - }; - self.start_day + month_offset as i64 + (day - 1) as i64 - } - - fn md_from_rd(self, rd: RataDie) -> (u8, u8) { - let day_of_year = (rd - self.start_day) as u16; - debug_assert!(day_of_year < 360); - // We divide by 30, not 29, to account for the case where all months before this - // were length 30 (possible near the beginning of the year) - let mut month = (day_of_year / 30) as u8 + 1; - - let day_of_year = day_of_year + 1; - let mut last_day_of_month = self.last_day_of_month(month); - let mut last_day_of_prev_month = if month == 1 { - 0 - } else { - self.last_day_of_month(month - 1) - }; - - while day_of_year > last_day_of_month && month <= 12 { - month += 1; - last_day_of_prev_month = last_day_of_month; - last_day_of_month = self.last_day_of_month(month); + fn year_data(&self, extended_year: i32) -> HijriYearData { + if let Some(data) = HijriYearData::lookup( + extended_year, + simulated_mecca_data::STARTING_YEAR, + simulated_mecca_data::DATA, + ) { + return data; } - debug_assert!( - day_of_year - last_day_of_prev_month <= 30, - "Found day {} that doesn't fit in month!", - day_of_year - last_day_of_prev_month - ); - let day = (day_of_year - last_day_of_prev_month) as u8; - (month, day) - } - - // Which day of year is the last day of a month (month is 1-indexed) - fn last_day_of_month(self, month: u8) -> u16 { - 29 * month as u16 - + self - .month_lengths - .get(..month as usize) - .unwrap_or_default() - .iter() - .filter(|&&x| x) - .count() as u16 - } -} - -impl PrecomputedDataSource for HijriSimulated { - fn load_or_compute_info(&self, extended_year: i32) -> HijriYearInfo { - self.data - .as_ref() - .and_then(|d| d.get().get(extended_year)) - .unwrap_or_else(|| self.location.compute_year_info(extended_year)) - } -} - -/// The inner date type used for representing [`Date`]s of [`HijriSimulated`]. See [`Date`] and [`HijriSimulated`] for more details. - -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] -pub struct HijriSimulatedDateInner(ArithmeticDate); - -impl CalendarArithmetic for HijriSimulated { - type YearInfo = HijriYearInfo; - - fn days_in_provided_month(year: Self::YearInfo, month: u8) -> u8 { - year.days_in_month(month) - } - - fn months_in_provided_year(_year: Self::YearInfo) -> u8 { - 12 - } - - fn days_in_provided_year(year: Self::YearInfo) -> u16 { - year.days_in_year() - } - - // As an true lunar calendar, it does not have leap years. - fn provided_year_is_leap(year: Self::YearInfo) -> bool { - year.days_in_year() != SHORT_YEAR_LEN - } - - fn last_month_day_in_provided_year(year: Self::YearInfo) -> (u8, u8) { - let days = Self::days_in_provided_month(year, 12); - - (12, days) - } -} - -impl crate::cal::scaffold::UnstableSealed for HijriSimulated {} -impl Calendar for HijriSimulated { - type DateInner = HijriSimulatedDateInner; - type Year = types::EraYear; - fn from_codes( - &self, - era: Option<&str>, - year: i32, - month_code: types::MonthCode, - day: u8, - ) -> Result { - let year = match era { - Some("ah") | None => year_check(year, 1..)?, - Some("bh") => 1 - year_check(year, 1..)?, - Some(_) => return Err(DateError::UnknownEra), - }; - let Some((month, false)) = month_code.parsed() else { - return Err(DateError::UnknownMonthCode(month_code)); - }; - Ok(HijriSimulatedDateInner(ArithmeticDate::new_from_ordinals( - self.load_or_compute_info(year), - month, - day, - )?)) - } - fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { - // +1 because the epoch is new year of year 1 - // truncating instead of flooring does not matter, as this is well-defined for - // positive years only - let extended_year = ((rd - calendrical_calculations::islamic::ISLAMIC_EPOCH_FRIDAY) as f64 - / calendrical_calculations::islamic::MEAN_YEAR_LENGTH) - as i32 - + 1; - - let year = self.load_or_compute_info(extended_year); - - let y = if rd < year.start_day { - self.load_or_compute_info(extended_year - 1) - } else { - let next_year = self.load_or_compute_info(extended_year + 1); - if rd < next_year.start_day { - year - } else { - next_year - } + let location = match self.location { + SimulatedLocation::Mecca => calendrical_calculations::islamic::MECCA, }; - let (m, d) = y.md_from_rd(rd); - HijriSimulatedDateInner(ArithmeticDate::new_unchecked(y, m, d)) - } - - fn to_rata_die(&self, date: &Self::DateInner) -> RataDie { - date.0.year.md_to_rd(date.0.month, date.0.day) - } - - fn from_iso(&self, iso: IsoDateInner) -> Self::DateInner { - self.from_rata_die(Iso.to_rata_die(&iso)) - } - fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { - Iso.from_rata_die(self.to_rata_die(date)) - } - - fn months_in_year(&self, date: &Self::DateInner) -> u8 { - date.0.months_in_year() - } - - fn days_in_year(&self, date: &Self::DateInner) -> u16 { - date.0.days_in_year() - } - - fn days_in_month(&self, date: &Self::DateInner) -> u8 { - date.0.days_in_month() - } - - fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) { - date.0.offset_date(offset, self) - } - - fn until( - &self, - date1: &Self::DateInner, - date2: &Self::DateInner, - _calendar2: &Self, - _largest_unit: DateDurationUnit, - _smallest_unit: DateDurationUnit, - ) -> DateDuration { - date1.0.until(date2.0, _largest_unit, _smallest_unit) - } - - fn debug_name(&self) -> &'static str { - Self::DEBUG_NAME - } - - fn year_info(&self, date: &Self::DateInner) -> Self::Year { - era_year(self.extended_year(date)) - } - - fn extended_year(&self, date: &Self::DateInner) -> i32 { - date.0.extended_year() - } - - fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { - Self::provided_year_is_leap(date.0.year) - } - - fn month(&self, date: &Self::DateInner) -> types::MonthInfo { - date.0.month() - } - - fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { - date.0.day_of_month() - } - - fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear { - date.0.day_of_year() - } - - fn calendar_algorithm(&self) -> Option { - Some(match self.location { - crate::cal::hijri::HijriSimulatedLocation::Mecca => { - crate::preferences::CalendarAlgorithm::Hijri(Some( - crate::preferences::HijriCalendarAlgorithm::Rgsa, - )) - } - }) - } -} - -impl HijriSimulatedLocation { - fn compute_year_info(self, extended_year: i32) -> HijriYearInfo { let start_day = calendrical_calculations::islamic::fixed_from_observational_islamic( extended_year, 1, 1, - self.location(), + location, ); let next_start_day = calendrical_calculations::islamic::fixed_from_observational_islamic( extended_year + 1, 1, 1, - self.location(), + location, ); match (next_start_day - start_day) as u16 { - LONG_YEAR_LEN | SHORT_YEAR_LEN => (), + 355 | 354 => (), 353 => { icu_provider::log::trace!( "({}) Found year {extended_year} AH with length {}. See ", - HijriSimulated::DEBUG_NAME, + self.debug_name(), next_start_day - start_day ); } other => { debug_assert!( - false, + !WELL_BEHAVED_ASTRONOMICAL_RANGE.contains(&start_day), "({}) Found year {extended_year} AH with length {}!", - HijriSimulated::DEBUG_NAME, + self.debug_name(), other ) } @@ -541,7 +199,7 @@ impl HijriSimulatedLocation { calendrical_calculations::islamic::observational_islamic_month_days( extended_year, month_idx as u8 + 1, - self.location(), + location, ); match days_in_month { 29 => false, @@ -549,7 +207,7 @@ impl HijriSimulatedLocation { 31 => { icu_provider::log::trace!( "({}) Found year {extended_year} AH with month length {days_in_month} for month {}.", - HijriSimulated::DEBUG_NAME, + self.debug_name(), month_idx + 1 ); excess_days += 1; @@ -557,9 +215,9 @@ impl HijriSimulatedLocation { } _ => { debug_assert!( - false, + !WELL_BEHAVED_ASTRONOMICAL_RANGE.contains(&start_day), "({}) Found year {extended_year} AH with month length {days_in_month} for month {}!", - HijriSimulated::DEBUG_NAME, + self.debug_name(), month_idx + 1 ); false @@ -570,11 +228,10 @@ impl HijriSimulatedLocation { // a 31-day month, "move" the day to the first 29-day month in the // same year to maintain all months at 29 or 30 days. if excess_days != 0 { - debug_assert_eq!( - excess_days, - 1, + debug_assert!( + excess_days == 1 || !WELL_BEHAVED_ASTRONOMICAL_RANGE.contains(&start_day), "({}) Found year {extended_year} AH with more than one excess day!", - HijriSimulated::DEBUG_NAME + self.debug_name() ); if let Some(l) = month_lengths.iter_mut().find(|l| !(**l)) { *l = true; @@ -582,307 +239,627 @@ impl HijriSimulatedLocation { } month_lengths }; - HijriYearInfo { - month_lengths, - start_day, - value: extended_year, + HijriYearData::try_new(extended_year, start_day, month_lengths) + .unwrap_or_else(|| UmmAlQura.year_data(extended_year)) + } +} + +/// [`Hijri`] [`Rules`] for the [Umm al-Qura](https://en.wikipedia.org/wiki/Islamic_calendar#Saudi_Arabia's_Umm_al-Qura_calendar) calendar. +/// +/// From the start of 1300 AH (1882-11-12 ISO) to the end of 1600 AH (2174-11-25 ISO), this +/// `Rules` implementation uses Umm al-Qura month lengths obtained from +/// [KACST](https://kacst.gov.sa/). Outside this range, this implementation falls back to +/// [`TabularAlgorithm`] with [`TabularAlgorithmLeapYears::TypeII`] and [`TabularAlgorithmEpoch::Friday`]. +/// +/// The precise behavior of this calendar may change in the future if: +/// - New ground truth is established by published government sources +/// - We decide to use a different algorithm outside the KACST range +/// - We decide to expand or reduce the range where we are correctly handling past dates. +/// +/// This corresponds to the `"islamic-umalqura"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). +#[derive(Copy, Clone, Debug, Default)] +#[non_exhaustive] +pub struct UmmAlQura; + +impl crate::cal::scaffold::UnstableSealed for UmmAlQura {} +impl Rules for UmmAlQura { + fn calendar_algorithm(&self) -> Option { + Some(CalendarAlgorithm::Hijri(Some( + HijriCalendarAlgorithm::Umalqura, + ))) + } + + fn ecma_reference_year( + &self, + month_code: (u8, bool), + day: u8, + ) -> Result { + let (ordinal_month, false) = month_code else { + return Err(EcmaReferenceYearError::MonthCodeNotInCalendar); + }; + + let extended_year = match (ordinal_month, day) { + (1, _) => 1392, + (2, 30..) => 1390, + (2, _) => 1392, + (3, 30..) => 1391, + (3, _) => 1392, + (4, _) => 1392, + (5, 30..) => 1391, + (5, _) => 1392, + (6, _) => 1392, + (7, 30..) => 1389, + (7, _) => 1392, + (8, _) => 1392, + (9, _) => 1392, + (10, 30..) => 1390, + (10, _) => 1392, + (11, ..=25) => 1392, + (11, _) => 1391, + (12, 30..) => 1390, + (12, _) => 1391, + _ => return Err(EcmaReferenceYearError::MonthCodeNotInCalendar), + }; + Ok(extended_year) + } + + fn debug_name(&self) -> &'static str { + "Hijri (Umm al-Qura)" + } + + fn year_data(&self, extended_year: i32) -> HijriYearData { + if let Some(data) = HijriYearData::lookup( + extended_year, + ummalqura_data::STARTING_YEAR, + ummalqura_data::DATA, + ) { + data + } else { + TabularAlgorithm { + leap_years: TabularAlgorithmLeapYears::TypeII, + epoch: TabularAlgorithmEpoch::Friday, + } + .year_data(extended_year) + } + } +} + +/// [`Hijri`] [`Rules`] for the [Tabular Hijri Algorithm](https://en.wikipedia.org/wiki/Tabular_Islamic_calendar). +/// +/// See [`TabularAlgorithmEpoch`] and [`TabularAlgorithmLeapYears`] for customization. +/// +/// The most common version of these rules uses [`TabularAlgorithmEpoch::Friday`] and [`TabularAlgorithmLeapYears::TypeII`]. +/// +/// When constructed with [`TabularAlgorithmLeapYears::TypeII`], and either [`TabularAlgorithmEpoch::Friday`] or [`TabularAlgorithmEpoch::Thursday`], +/// this corresponds to the `"islamic-civil"` and `"islamic-tbla"` [CLDR calendars](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier) respectively. +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] +pub struct TabularAlgorithm { + pub(crate) leap_years: TabularAlgorithmLeapYears, + pub(crate) epoch: TabularAlgorithmEpoch, +} + +impl TabularAlgorithm { + /// Construct a new [`TabularAlgorithm`] with the given leap year rule and epoch. + pub const fn new(leap_years: TabularAlgorithmLeapYears, epoch: TabularAlgorithmEpoch) -> Self { + Self { epoch, leap_years } + } +} + +impl crate::cal::scaffold::UnstableSealed for TabularAlgorithm {} +impl Rules for TabularAlgorithm { + fn calendar_algorithm(&self) -> Option { + Some(match (self.epoch, self.leap_years) { + (TabularAlgorithmEpoch::Friday, TabularAlgorithmLeapYears::TypeII) => { + CalendarAlgorithm::Hijri(Some(HijriCalendarAlgorithm::Civil)) + } + (TabularAlgorithmEpoch::Thursday, TabularAlgorithmLeapYears::TypeII) => { + CalendarAlgorithm::Hijri(Some(HijriCalendarAlgorithm::Tbla)) + } + }) + } + + fn ecma_reference_year( + &self, + month_code: (u8, bool), + day: u8, + ) -> Result { + let (ordinal_month, false) = month_code else { + return Err(EcmaReferenceYearError::MonthCodeNotInCalendar); + }; + + Ok(match (ordinal_month, day) { + (1, _) => 1392, + (2, 30..) => 1389, + (2, _) => 1392, + (3, _) => 1392, + (4, 30..) => 1389, + (4, _) => 1392, + (5, _) => 1392, + (6, 30..) => 1389, + (6, _) => 1392, + (7, _) => 1392, + (8, 30..) => 1389, + (8, _) => 1392, + (9, _) => 1392, + (10, 30..) => 1389, + (10, _) => 1392, + (11, ..=26) if self.epoch == TabularAlgorithmEpoch::Thursday => 1392, + (11, ..=25) if self.epoch == TabularAlgorithmEpoch::Friday => 1392, + (11, _) => 1391, + (12, 30..) => 1390, + (12, _) => 1391, + _ => return Err(EcmaReferenceYearError::MonthCodeNotInCalendar), + }) + } + + fn debug_name(&self) -> &'static str { + match self.epoch { + TabularAlgorithmEpoch::Friday => "Hijri (civil)", + TabularAlgorithmEpoch::Thursday => "Hijri (astronomical)", + } + } + + fn year_data(&self, extended_year: i32) -> HijriYearData { + let start_day = calendrical_calculations::islamic::fixed_from_tabular_islamic( + extended_year, + 1, + 1, + self.epoch.rata_die(), + ); + let month_lengths = core::array::from_fn(|m| { + m % 2 == 0 + || m == 11 + && match self.leap_years { + TabularAlgorithmLeapYears::TypeII => { + (14 + 11 * extended_year as i64).rem_euclid(30) < 11 + } + } + }); + HijriYearData { + // start_day is within 5 days of the tabular start day (trivial), and month lengths + // has either 6 or 7 long months. + packed: PackedHijriYearData::new_unchecked(extended_year, month_lengths, start_day), + extended_year, } } } -impl HijriSimulated { - pub(crate) const DEBUG_NAME: &'static str = "Hijri (simulated)"; -} +impl Hijri { + /// Use [`Self::new_simulated_mecca`]. + #[cfg(feature = "compiled_data")] + #[deprecated(since = "2.1.0", note = "use `Hijri::new_simulated_mecca`")] + pub const fn new_mecca() -> Self { + Self::new_simulated_mecca() + } -impl> Date
{ - /// Construct new simulated Hijri Date. - /// - /// ```rust - /// use icu::calendar::cal::HijriSimulated; - /// use icu::calendar::Date; + /// Creates a [`Hijri`] calendar using simulated sightings at Mecca. /// - /// let hijri = HijriSimulated::new_mecca_always_calculating(); - /// - /// let date_hijri = - /// Date::try_new_simulated_hijri_with_calendar(1392, 4, 25, hijri) - /// .expect("Failed to initialize Hijri Date instance."); - /// - /// assert_eq!(date_hijri.era_year().year, 1392); - /// assert_eq!(date_hijri.month().ordinal, 4); - /// assert_eq!(date_hijri.day_of_month().0, 25); - /// ``` - pub fn try_new_simulated_hijri_with_calendar( - year: i32, - month: u8, - day: u8, - calendar: A, - ) -> Result, RangeError> { - let y = calendar.as_calendar().load_or_compute_info(year); - ArithmeticDate::new_from_ordinals(y, month, day) - .map(HijriSimulatedDateInner) - .map(|inner| Date::from_raw(inner, calendar)) + /// These simulations are unofficial and are known to not necessarily match sightings + /// on the ground. Unless you know otherwise for sure, instead of this variant, use + /// [`Hijri::new_umm_al_qura`], which uses the results of KACST's Mecca-based calculations. + pub const fn new_simulated_mecca() -> Self { + Self(AstronomicalSimulation { + location: SimulatedLocation::Mecca, + }) } -} - -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] -/// The inner date type used for representing [`Date`]s of [`HijriUmmAlQura`]. See [`Date`] and [`HijriUmmAlQura`] for more details. -pub struct HijriUmmAlQuraDateInner(ArithmeticDate); -impl CalendarArithmetic for HijriUmmAlQura { - type YearInfo = HijriYearInfo; + #[cfg(feature = "serde")] + #[doc = icu_provider::gen_buffer_unstable_docs!(BUFFER,Self::new)] + #[deprecated(since = "2.1.0", note = "use `Hijri::new_simulated_mecca`")] + pub fn try_new_mecca_with_buffer_provider( + _provider: &(impl icu_provider::buf::BufferProvider + ?Sized), + ) -> Result { + Ok(Self::new_simulated_mecca()) + } - fn days_in_provided_month(year: Self::YearInfo, month: u8) -> u8 { - year.days_in_month(month) + #[doc = icu_provider::gen_buffer_unstable_docs!(UNSTABLE, Self::new_mecca)] + #[deprecated(since = "2.1.0", note = "use `Hijri::new_simulated_mecca`")] + pub fn try_new_mecca_unstable(_provider: &D) -> Result { + Ok(Self::new_simulated_mecca()) } - fn months_in_provided_year(_year: HijriYearInfo) -> u8 { - 12 + /// Use [`Self::new_simulated_mecca`]. + #[deprecated(since = "2.1.0", note = "use `Hijri::new_simulated_mecca`")] + pub const fn new_mecca_always_calculating() -> Self { + Self::new_simulated_mecca() } +} - fn days_in_provided_year(year: Self::YearInfo) -> u16 { - year.days_in_year() +impl Hijri { + /// Use [`Self::new_umm_al_qura`] + #[deprecated(since = "2.1.0", note = "use `Self::new_umm_al_qura`")] + pub const fn new() -> Self { + Self(UmmAlQura) } - // As an true lunar calendar, it does not have leap years. - fn provided_year_is_leap(year: Self::YearInfo) -> bool { - year.days_in_year() != SHORT_YEAR_LEN + /// Creates a [`Hijri`] calendar using [`UmmAlQura`] rules. + pub const fn new_umm_al_qura() -> Self { + Self(UmmAlQura) } +} - fn last_month_day_in_provided_year(year: HijriYearInfo) -> (u8, u8) { - let days = Self::days_in_provided_month(year, 12); +/// The epoch for the [`TabularAlgorithm`] rules. +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] +pub enum TabularAlgorithmEpoch { + /// Thusday July 15, 622 AD Julian (0622-07-18 ISO) + Thursday, + /// Friday July 16, 622 AD Julian (0622-07-19 ISO) + Friday, +} - (12, days) +impl TabularAlgorithmEpoch { + fn rata_die(self) -> RataDie { + match self { + Self::Thursday => ISLAMIC_EPOCH_THURSDAY, + Self::Friday => ISLAMIC_EPOCH_FRIDAY, + } } } -impl crate::cal::scaffold::UnstableSealed for HijriUmmAlQura {} -impl Calendar for HijriUmmAlQura { - type DateInner = HijriUmmAlQuraDateInner; - type Year = types::EraYear; - fn from_codes( - &self, - era: Option<&str>, - year: i32, - month_code: types::MonthCode, - day: u8, - ) -> Result { - let year = match era { - Some("ah") | None => year_check(year, 1..)?, - Some("bh") => 1 - year_check(year, 1..)?, - Some(_) => return Err(DateError::UnknownEra), - }; - let Some((month, false)) = month_code.parsed() else { - return Err(DateError::UnknownMonthCode(month_code)); - }; - Ok(HijriUmmAlQuraDateInner(ArithmeticDate::new_from_ordinals( - self.load_or_compute_info(year), - month, - day, - )?)) +/// The leap year rule for the [`TabularAlgorithm`] rules. +/// +/// This specifies which years of a 30-year cycle have an additional day at +/// the end of the year. +#[non_exhaustive] +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] +pub enum TabularAlgorithmLeapYears { + /// Leap years 2, 5, 7, 10, 13, 16, 18, 21, 24, 26, 29 + TypeII, +} + +impl Hijri { + /// Use [`Self::new_tabular`] + #[deprecated(since = "2.1.0", note = "use `Hijri::new_tabular`")] + pub const fn new(leap_years: TabularAlgorithmLeapYears, epoch: TabularAlgorithmEpoch) -> Self { + Hijri::new_tabular(leap_years, epoch) } - fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { - // +1 because the epoch is new year of year 1 - // truncating instead of flooring does not matter, as this is well-defined for - // positive years only - let extended_year = ((rd - calendrical_calculations::islamic::ISLAMIC_EPOCH_FRIDAY) as f64 - / calendrical_calculations::islamic::MEAN_YEAR_LENGTH) - as i32 - + 1; + /// Creates a [`Hijri`] calendar with tabular rules and the given leap year rule and epoch. + pub const fn new_tabular( + leap_years: TabularAlgorithmLeapYears, + epoch: TabularAlgorithmEpoch, + ) -> Self { + Self(TabularAlgorithm::new(leap_years, epoch)) + } +} - let year = self.load_or_compute_info(extended_year); +/// Information about a Hijri year. +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +pub struct HijriYearData { + packed: PackedHijriYearData, + extended_year: i32, +} - let y = if rd < year.start_day { - self.load_or_compute_info(extended_year - 1) - } else { - let next_year = self.load_or_compute_info(extended_year + 1); - if rd < next_year.start_day { - year - } else { - next_year - } - }; - let (m, d) = y.md_from_rd(rd); - HijriUmmAlQuraDateInner(ArithmeticDate::new_unchecked(y, m, d)) +impl ToExtendedYear for HijriYearData { + fn to_extended_year(&self) -> i32 { + self.extended_year } +} - fn to_rata_die(&self, date: &Self::DateInner) -> RataDie { - date.0.year.md_to_rd(date.0.month, date.0.day) +impl HijriYearData { + /// Creates [`HijriYearData`] from the given parts. + /// + /// `start_day` is the date for the first day of the year, see [`Date::to_rata_die`] + /// to obtain a [`RataDie`] from a [`Date`] in an arbitrary calendar. `start_day` has + /// to be within 5 days of the start of the year of the [`TabularAlgorithm`]. + /// + /// `month_lengths[n - 1]` is true if the nth month has 30 days, and false otherwise. + /// Either 6 or 7 months need to have 30 days. + pub fn try_new( + extended_year: i32, + start_day: RataDie, + month_lengths: [bool; 12], + ) -> Option { + Some(Self { + packed: PackedHijriYearData::try_new(extended_year, month_lengths, start_day)?, + extended_year, + }) } - fn from_iso(&self, iso: IsoDateInner) -> Self::DateInner { - self.from_rata_die(Iso.to_rata_die(&iso)) + fn lookup( + extended_year: i32, + starting_year: i32, + data: &[PackedHijriYearData], + ) -> Option { + Some(extended_year) + .and_then(|e| usize::try_from(e.checked_sub(starting_year)?).ok()) + .and_then(|i| data.get(i)) + .map(|&packed| Self { + extended_year, + packed, + }) } - fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { - Iso.from_rata_die(self.to_rata_die(date)) + fn new_year(self) -> RataDie { + self.packed.new_year(self.extended_year) } +} - fn months_in_year(&self, date: &Self::DateInner) -> u8 { - date.0.months_in_year() - } +/// The struct containing compiled Hijri YearInfo +/// +/// * `start_day` has to be within 5 days of the start of the year of the [`TabularAlgorithm`]. +/// * `month_lengths[n - 1]` has either 6 or 7 long months. +/// +/// Bit structure +/// +/// ```text +/// Bit: F.........C B.............0 +/// Value: [ start day ][ month lengths ] +/// ``` +/// +/// The start day is encoded as a signed offset from `Self::mean_tabular_start_day`. This number does not +/// appear to be less than 2, however we use all remaining bits for it in case of drift in the math. +/// The month lengths are stored as 1 = 30, 0 = 29 for each month including the leap month. +/// +///
+/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, +/// including in SemVer minor releases. While the serde representation of data structs is guaranteed +/// to be stable, their Rust representation might not be. Use with caution. +///
+#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +struct PackedHijriYearData(u16); + +impl PackedHijriYearData { + const fn try_new( + extended_year: i32, + month_lengths: [bool; 12], + start_day: RataDie, + ) -> Option { + let start_offset = start_day.since(Self::mean_tabular_start_day(extended_year)); + + if !(-8 < start_offset && start_offset < 8 + || calendrical_calculations::islamic::WELL_BEHAVED_ASTRONOMICAL_RANGE + .start + .to_i64_date() + > start_day.to_i64_date() + || calendrical_calculations::islamic::WELL_BEHAVED_ASTRONOMICAL_RANGE + .end + .to_i64_date() + < start_day.to_i64_date()) + { + return None; + } + let start_offset = start_offset as i8 & 0b1000_0111u8 as i8; - fn days_in_year(&self, date: &Self::DateInner) -> u16 { - date.0.days_in_year() - } + let mut all = 0u16; - fn days_in_month(&self, date: &Self::DateInner) -> u8 { - date.0.days_in_month() - } + let mut num_days = 29 * 12; - fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) { - date.0.offset_date(offset, &HijriUmmAlQura) - } + let mut i = 0; + while i < 12 { + #[expect(clippy::indexing_slicing)] + if month_lengths[i] { + all |= 1 << i; + num_days += 1; + } + i += 1; + } - fn until( - &self, - date1: &Self::DateInner, - date2: &Self::DateInner, - _calendar2: &Self, - _largest_unit: DateDurationUnit, - _smallest_unit: DateDurationUnit, - ) -> DateDuration { - date1.0.until(date2.0, _largest_unit, _smallest_unit) + if !matches!(num_days, 354 | 355) { + return None; + } + + if start_offset < 0 { + all |= 1 << 12; + } + all |= (start_offset.unsigned_abs() as u16) << 13; + Some(Self(all)) } - fn debug_name(&self) -> &'static str { - Self::DEBUG_NAME + const fn new_unchecked( + extended_year: i32, + month_lengths: [bool; 12], + start_day: RataDie, + ) -> Self { + let start_offset = start_day.since(Self::mean_tabular_start_day(extended_year)); + + let start_offset = start_offset as i8 & 0b1000_0111u8 as i8; + + let mut all = 0u16; + + let mut i = 0; + while i < 12 { + #[expect(clippy::indexing_slicing)] + if month_lengths[i] { + all |= 1 << i; + } + i += 1; + } + + if start_offset < 0 { + all |= 1 << 12; + } + all |= (start_offset.unsigned_abs() as u16) << 13; + Self(all) } - fn year_info(&self, date: &Self::DateInner) -> Self::Year { - era_year(self.extended_year(date)) + fn new_year(self, extended_year: i32) -> RataDie { + let start_offset = if (self.0 & 0b1_0000_0000_0000) != 0 { + -((self.0 >> 13) as i64) + } else { + (self.0 >> 13) as i64 + }; + Self::mean_tabular_start_day(extended_year) + start_offset } - fn extended_year(&self, date: &Self::DateInner) -> i32 { - date.0.extended_year() + fn month_has_30_days(self, month: u8) -> bool { + self.0 & (1 << (month - 1) as u16) != 0 } - fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { - Self::provided_year_is_leap(date.0.year) + fn is_leap(self) -> bool { + (self.0 & ((1 << 12) - 1)).count_ones() == 7 } - fn month(&self, date: &Self::DateInner) -> types::MonthInfo { - date.0.month() + // month is 1-indexed, but 0 is a valid input, producing 0 + fn last_day_of_month(self, month: u8) -> u16 { + // month is 1-indexed, so `29 * month` includes the current month + let mut prev_month_lengths = 29 * month as u16; + // month is 1-indexed, so `1 << month` is a mask with all zeroes except + // for a 1 at the bit index at the next month. Subtracting 1 from it gets us + // a bitmask for all months up to now + let long_month_bits = self.0 & ((1 << month as u16) - 1); + prev_month_lengths += long_month_bits.count_ones().try_into().unwrap_or(0); + prev_month_lengths } - fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { - date.0.day_of_month() + fn days_in_year(self) -> u16 { + self.last_day_of_month(12) } - fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear { - date.0.day_of_year() + const fn mean_tabular_start_day(extended_year: i32) -> RataDie { + // -1 because the epoch is new year of year 1 + calendrical_calculations::islamic::ISLAMIC_EPOCH_FRIDAY + .add((extended_year as i64 - 1) * (354 * 30 + 11) / 30) } +} - fn calendar_algorithm(&self) -> Option { - let expected_calendar = crate::preferences::CalendarAlgorithm::Hijri(Some( - crate::preferences::HijriCalendarAlgorithm::Umalqura, - )); - Some(expected_calendar) +impl>> Date
{ + /// Deprecated + #[deprecated(since = "2.1.0", note = "use `Date::try_new_hijri_with_calendar`")] + pub fn try_new_simulated_hijri_with_calendar( + year: i32, + month: u8, + day: u8, + calendar: A, + ) -> Result, RangeError> { + Date::try_new_hijri_with_calendar(year, month, day, calendar) } } -impl PrecomputedDataSource for HijriUmmAlQura { - fn load_or_compute_info(&self, year: i32) -> HijriYearInfo { - if let Some(&packed) = usize::try_from(year - UMMALQURA_DATA_STARTING_YEAR) - .ok() - .and_then(|i| UMMALQURA_DATA.get(i)) - { - HijriYearInfo::unpack(year, packed) - } else { - HijriYearInfo { - value: year, - month_lengths: core::array::from_fn(|i| { - HijriTabular::days_in_provided_month(year, i as u8 + 1) == 30 - }), - start_day: calendrical_calculations::islamic::fixed_from_tabular_islamic( - year, - 1, - 1, - ISLAMIC_EPOCH_FRIDAY, - ), +#[test] +fn computer_reference_years() { + let rules = UmmAlQura; + + fn compute_hijri_reference_year( + ordinal_month: u8, + day: u8, + cal: &C, + year_info_from_extended: impl Fn(i32) -> C::YearInfo, + ) -> Result + where + C: DateFieldsResolver, + { + let dec_31 = Date::from_rata_die( + crate::cal::abstract_gregorian::LAST_DAY_OF_REFERENCE_YEAR, + crate::Ref(cal), + ); + // December 31, 1972 occurs in the 11th month, 1392 AH, but the day could vary + debug_assert_eq!(dec_31.month().ordinal, 11); + let (y0, y1, y2, y3) = + if ordinal_month < 11 || (ordinal_month == 11 && day <= dec_31.day_of_month().0) { + (1389, 1390, 1391, 1392) + } else { + (1388, 1389, 1390, 1391) + }; + let year_info = year_info_from_extended(y3); + if day <= C::days_in_provided_month(year_info, ordinal_month) { + return Ok(year_info); + } + let year_info = year_info_from_extended(y2); + if day <= C::days_in_provided_month(year_info, ordinal_month) { + return Ok(year_info); + } + let year_info = year_info_from_extended(y1); + if day <= C::days_in_provided_month(year_info, ordinal_month) { + return Ok(year_info); + } + let year_info = year_info_from_extended(y0); + // This function might be called with out-of-range days that are handled later. + // Some calendars don't have day 30s in every month so we don't check those. + if day <= 29 { + debug_assert!( + day <= C::days_in_provided_month(year_info, ordinal_month), + "{ordinal_month}/{day}" + ); + } + Ok(year_info) + } + for month in 1..=12 { + for day in [30, 29] { + let y = compute_hijri_reference_year(month, day, &Hijri(rules), |e| rules.year_data(e)) + .unwrap() + .extended_year; + + if day == 30 { + println!("({month}, {day}) => {y},") + } else { + println!("({month}, _) => {y},") } } } } -impl HijriUmmAlQura { - pub(crate) const DEBUG_NAME: &'static str = "Hijri (Umm al-Qura)"; -} +#[allow(clippy::derived_hash_with_manual_eq)] // bounds +#[derive(Clone, Debug, Hash)] +/// The inner date type used for representing [`Date`]s of [`Hijri`]. See [`Date`] and [`Hijri`] for more details. +pub struct HijriDateInner(ArithmeticDate>); -impl Date { - /// Construct new Hijri Umm al-Qura Date. - /// - /// ```rust - /// use icu::calendar::cal::HijriUmmAlQura; - /// use icu::calendar::Date; - /// - /// let date_hijri = Date::try_new_ummalqura(1392, 4, 25) - /// .expect("Failed to initialize Hijri Date instance."); - /// - /// assert_eq!(date_hijri.era_year().year, 1392); - /// assert_eq!(date_hijri.month().ordinal, 4); - /// assert_eq!(date_hijri.day_of_month().0, 25); - /// ``` - pub fn try_new_ummalqura( - year: i32, - month: u8, - day: u8, - ) -> Result, RangeError> { - let y = HijriUmmAlQura.load_or_compute_info(year); - Ok(Date::from_raw( - HijriUmmAlQuraDateInner(ArithmeticDate::new_from_ordinals(y, month, day)?), - HijriUmmAlQura, - )) +impl Copy for HijriDateInner {} +impl PartialEq for HijriDateInner { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} +impl Eq for HijriDateInner {} +impl PartialOrd for HijriDateInner { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl Ord for HijriDateInner { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.0.cmp(&other.0) } } -/// The inner date type used for representing [`Date`]s of [`HijriTabular`]. See [`Date`] and [`HijriTabular`] for more details. +impl DateFieldsResolver for Hijri { + type YearInfo = HijriYearData; -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] -pub struct HijriTabularDateInner(ArithmeticDate); - -impl CalendarArithmetic for HijriTabular { - type YearInfo = i32; - - fn days_in_provided_month(year: i32, month: u8) -> u8 { - match month { - 1 | 3 | 5 | 7 | 9 | 11 => 30, - 2 | 4 | 6 | 8 | 10 => 29, - 12 if Self::provided_year_is_leap(year) => 30, - 12 => 29, - _ => 0, - } + fn days_in_provided_month(year: Self::YearInfo, month: u8) -> u8 { + 29 + year.packed.month_has_30_days(month) as u8 } fn months_in_provided_year(_year: Self::YearInfo) -> u8 { 12 } - fn days_in_provided_year(year: i32) -> u16 { - if Self::provided_year_is_leap(year) { - LONG_YEAR_LEN - } else { - SHORT_YEAR_LEN - } + #[inline] + fn year_info_from_era( + &self, + era: &[u8], + era_year: i32, + ) -> Result { + let extended_year = match era { + b"ah" => era_year, + b"bh" => 1 - era_year, + _ => return Err(UnknownEraError), + }; + Ok(self.year_info_from_extended(extended_year)) } - fn provided_year_is_leap(year: i32) -> bool { - (14 + 11 * year).rem_euclid(30) < 11 + #[inline] + fn year_info_from_extended(&self, extended_year: i32) -> Self::YearInfo { + self.0.year_data(extended_year) } - fn last_month_day_in_provided_year(year: i32) -> (u8, u8) { - if Self::provided_year_is_leap(year) { - (12, 30) - } else { - (12, 29) - } + #[inline] + fn reference_year_from_month_day( + &self, + month_code: types::ValidMonthCode, + day: u8, + ) -> Result { + self.0 + .ecma_reference_year(month_code.to_tuple(), day) + .map(|y| self.0.year_data(y)) } } -impl crate::cal::scaffold::UnstableSealed for HijriTabular {} -impl Calendar for HijriTabular { - type DateInner = HijriTabularDateInner; +impl crate::cal::scaffold::UnstableSealed for Hijri {} +impl Calendar for Hijri { + type DateInner = HijriDateInner; type Year = types::EraYear; + type DifferenceError = core::convert::Infallible; fn from_codes( &self, @@ -891,157 +868,200 @@ impl Calendar for HijriTabular { month_code: types::MonthCode, day: u8, ) -> Result { - let year = match era { - Some("ah") | None => year_check(year, 1..)?, - Some("bh") => 1 - year_check(year, 1..)?, - Some(_) => return Err(DateError::UnknownEra), - }; + ArithmeticDate::from_codes(era, year, month_code, day, self).map(HijriDateInner) + } - ArithmeticDate::new_from_codes(self, year, month_code, day).map(HijriTabularDateInner) + #[cfg(feature = "unstable")] + fn from_fields( + &self, + fields: DateFields, + options: DateFromFieldsOptions, + ) -> Result { + ArithmeticDate::from_fields(fields, options, self).map(HijriDateInner) } fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { - let (y, m, d) = match self.leap_years { - HijriTabularLeapYears::TypeII => { - calendrical_calculations::islamic::tabular_islamic_from_fixed( - rd, - self.epoch.rata_die(), - ) - } - }; + // (354 * 30 + 11) / 30 is the mean year length for a tabular year + // This is slightly different from the `calendrical_calculations::islamic::MEAN_YEAR_LENGTH`, which is based on + // the (current) synodic month length. + // + // +1 because the epoch is new year of year 1 + // Before the epoch the division will round up (towards 0), so we need to + // subtract 1, which is the same as not adding the 1. + let extended_year = (rd - calendrical_calculations::islamic::ISLAMIC_EPOCH_FRIDAY) * 30 + / (354 * 30 + 11) + + (rd >= calendrical_calculations::islamic::ISLAMIC_EPOCH_FRIDAY) as i64; - debug_assert!(Date::try_new_hijri_tabular_with_calendar(y, m, d, crate::Ref(self)).is_ok()); - HijriTabularDateInner(ArithmeticDate::new_unchecked(y, m, d)) - } + let extended_year = extended_year.clamp(i32::MIN as i64, i32::MAX as i64) as i32; - fn to_rata_die(&self, date: &Self::DateInner) -> RataDie { - match self.leap_years { - HijriTabularLeapYears::TypeII => { - calendrical_calculations::islamic::fixed_from_tabular_islamic( - date.0.year, - date.0.month, - date.0.day, - self.epoch.rata_die(), - ) - } + let mut year = self.0.year_data(extended_year); + + // We rounded the extended year down, so we might need to use the next year + if rd >= year.new_year() + year.packed.days_in_year() as i64 && extended_year < i32::MAX { + year = self.0.year_data(year.extended_year + 1) + } + + // Clamp the RD to our year + let rd = rd.clamp( + year.new_year(), + year.new_year() + year.packed.days_in_year() as i64, + ); + + let day_of_year = (rd - year.new_year()) as u16; + + // We divide by 30, not 29, to account for the case where all months before this + // were length 30 (possible near the beginning of the year) + let mut month = (day_of_year / 30) as u8 + 1; + let mut last_day_of_month = year.packed.last_day_of_month(month); + let mut last_day_of_prev_month = year.packed.last_day_of_month(month - 1); + + while day_of_year >= last_day_of_month { + month += 1; + last_day_of_prev_month = last_day_of_month; + last_day_of_month = year.packed.last_day_of_month(month); } + + let day = (day_of_year + 1 - last_day_of_prev_month) as u8; + + HijriDateInner(ArithmeticDate::new_unchecked(year, month, day)) } - fn from_iso(&self, iso: IsoDateInner) -> Self::DateInner { - self.from_rata_die(Iso.to_rata_die(&iso)) + fn to_rata_die(&self, date: &Self::DateInner) -> RataDie { + date.0.year.new_year() + + date.0.year.packed.last_day_of_month(date.0.month - 1) as i64 + + (date.0.day - 1) as i64 } - fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { - Iso.from_rata_die(self.to_rata_die(date)) + fn has_cheap_iso_conversion(&self) -> bool { + false } fn months_in_year(&self, date: &Self::DateInner) -> u8 { - date.0.months_in_year() + Self::months_in_provided_year(date.0.year) } fn days_in_year(&self, date: &Self::DateInner) -> u16 { - date.0.days_in_year() + date.0.year.packed.days_in_year() } fn days_in_month(&self, date: &Self::DateInner) -> u8 { - date.0.days_in_month() + Self::days_in_provided_month(date.0.year, date.0.month) } - fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) { - date.0.offset_date(offset, &()) + #[cfg(feature = "unstable")] + fn add( + &self, + date: &Self::DateInner, + duration: types::DateDuration, + options: DateAddOptions, + ) -> Result { + date.0.added(duration, self, options).map(HijriDateInner) } + #[cfg(feature = "unstable")] fn until( &self, date1: &Self::DateInner, date2: &Self::DateInner, - _calendar2: &Self, - _largest_unit: DateDurationUnit, - _smallest_unit: DateDurationUnit, - ) -> DateDuration { - date1.0.until(date2.0, _largest_unit, _smallest_unit) + options: DateDifferenceOptions, + ) -> Result { + Ok(date1.0.until(&date2.0, self, options)) } fn debug_name(&self) -> &'static str { - match self.epoch { - HijriTabularEpoch::Friday => "Hijri (civil)", - HijriTabularEpoch::Thursday => "Hijri (astronomical)", - } + self.0.debug_name() } fn year_info(&self, date: &Self::DateInner) -> Self::Year { - era_year(self.extended_year(date)) - } - - fn extended_year(&self, date: &Self::DateInner) -> i32 { - date.0.extended_year() + let extended_year = date.0.year.extended_year; + if extended_year > 0 { + types::EraYear { + era: tinystr!(16, "ah"), + era_index: Some(0), + year: extended_year, + extended_year, + ambiguity: types::YearAmbiguity::CenturyRequired, + } + } else { + types::EraYear { + era: tinystr!(16, "bh"), + era_index: Some(1), + year: 1 - extended_year, + extended_year, + ambiguity: types::YearAmbiguity::CenturyRequired, + } + } } fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { - Self::provided_year_is_leap(date.0.year) + date.0.year.packed.is_leap() } fn month(&self, date: &Self::DateInner) -> types::MonthInfo { - date.0.month() + types::MonthInfo::non_lunisolar(date.0.month) } fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { - date.0.day_of_month() + types::DayOfMonth(date.0.day) } fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear { - date.0.day_of_year() + types::DayOfYear(date.0.year.packed.last_day_of_month(date.0.month - 1) + date.0.day as u16) } fn calendar_algorithm(&self) -> Option { - let expected_calendar = match (self.epoch, self.leap_years) { - (crate::cal::HijriTabularEpoch::Friday, crate::cal::HijriTabularLeapYears::TypeII) => { - crate::preferences::CalendarAlgorithm::Hijri(Some( - crate::preferences::HijriCalendarAlgorithm::Civil, - )) - } - ( - crate::cal::HijriTabularEpoch::Thursday, - crate::cal::HijriTabularLeapYears::TypeII, - ) => crate::preferences::CalendarAlgorithm::Hijri(Some( - crate::preferences::HijriCalendarAlgorithm::Tbla, - )), - }; - Some(expected_calendar) + self.0.calendar_algorithm() } } -impl> Date { - /// Construct new Tabular Hijri Date. +impl>, R: Rules> Date { + /// Construct new Hijri Date. /// /// ```rust - /// use icu::calendar::cal::{ - /// HijriTabular, HijriTabularEpoch, HijriTabularLeapYears, - /// }; + /// use icu::calendar::cal::Hijri; /// use icu::calendar::Date; /// - /// let hijri = HijriTabular::new( - /// HijriTabularLeapYears::TypeII, - /// HijriTabularEpoch::Thursday, - /// ); + /// let hijri = Hijri::new_simulated_mecca(); /// - /// let date_hijri = - /// Date::try_new_hijri_tabular_with_calendar(1392, 4, 25, hijri) - /// .expect("Failed to initialize Hijri Date instance."); + /// let date_hijri = Date::try_new_hijri_with_calendar(1392, 4, 25, hijri) + /// .expect("Failed to initialize Hijri Date instance."); /// /// assert_eq!(date_hijri.era_year().year, 1392); /// assert_eq!(date_hijri.month().ordinal, 4); /// assert_eq!(date_hijri.day_of_month().0, 25); /// ``` + pub fn try_new_hijri_with_calendar( + year: i32, + month: u8, + day: u8, + calendar: A, + ) -> Result { + let y = calendar.as_calendar().0.year_data(year); + Ok(Date::from_raw( + HijriDateInner(ArithmeticDate::try_from_ymd(y, month, day)?), + calendar, + )) + } +} + +impl Date> { + /// Deprecated + #[deprecated(since = "2.1.0", note = "use `Date::try_new_hijri_with_calendar")] + pub fn try_new_ummalqura(year: i32, month: u8, day: u8) -> Result { + Date::try_new_hijri_with_calendar(year, month, day, Hijri::new_umm_al_qura()) + } +} + +impl>> Date { + /// Deprecated + #[deprecated(since = "2.1.0", note = "use `Date::try_new_hijri_with_calendar")] pub fn try_new_hijri_tabular_with_calendar( year: i32, month: u8, day: u8, calendar: A, ) -> Result, RangeError> { - ArithmeticDate::new_from_ordinals(year, month, day) - .map(HijriTabularDateInner) - .map(|inner| Date::from_raw(inner, calendar)) + Date::try_new_hijri_with_calendar(year, month, day, calendar) } } @@ -1050,7 +1070,6 @@ mod test { use types::MonthCode; use super::*; - use crate::Ref; const START_YEAR: i32 = -1245; const END_YEAR: i32 = 1518; @@ -1742,14 +1761,11 @@ mod test { #[test] fn test_simulated_hijri_from_rd() { - let calendar = HijriSimulated::new_mecca(); - let calendar = Ref(&calendar); + let calendar = Hijri::new_simulated_mecca(); for (case, f_date) in SIMULATED_CASES.iter().zip(TEST_RD.iter()) { - let date = Date::try_new_simulated_hijri_with_calendar( - case.year, case.month, case.day, calendar, - ) - .unwrap(); - let iso = Date::from_rata_die(RataDie::new(*f_date), Iso); + let date = Date::try_new_hijri_with_calendar(case.year, case.month, case.day, calendar) + .unwrap(); + let iso = Date::from_rata_die(RataDie::new(*f_date), crate::Iso); assert_eq!(iso.to_calendar(calendar).inner, date.inner, "{case:?}"); } @@ -1757,39 +1773,36 @@ mod test { #[test] fn test_rd_from_simulated_hijri() { - let calendar = HijriSimulated::new_mecca(); - let calendar = Ref(&calendar); + let calendar = Hijri::new_simulated_mecca(); for (case, f_date) in SIMULATED_CASES.iter().zip(TEST_RD.iter()) { - let date = Date::try_new_simulated_hijri_with_calendar( - case.year, case.month, case.day, calendar, - ) - .unwrap(); + let date = Date::try_new_hijri_with_calendar(case.year, case.month, case.day, calendar) + .unwrap(); assert_eq!(date.to_rata_die(), RataDie::new(*f_date), "{case:?}"); } } #[test] fn test_rd_from_hijri() { - let calendar = HijriTabular::new(HijriTabularLeapYears::TypeII, HijriTabularEpoch::Friday); - let calendar = Ref(&calendar); + let calendar = Hijri::new_tabular( + TabularAlgorithmLeapYears::TypeII, + TabularAlgorithmEpoch::Friday, + ); for (case, f_date) in ARITHMETIC_CASES.iter().zip(TEST_RD.iter()) { - let date = Date::try_new_hijri_tabular_with_calendar( - case.year, case.month, case.day, calendar, - ) - .unwrap(); + let date = Date::try_new_hijri_with_calendar(case.year, case.month, case.day, calendar) + .unwrap(); assert_eq!(date.to_rata_die(), RataDie::new(*f_date), "{case:?}"); } } #[test] fn test_hijri_from_rd() { - let calendar = HijriTabular::new(HijriTabularLeapYears::TypeII, HijriTabularEpoch::Friday); - let calendar = Ref(&calendar); + let calendar = Hijri::new_tabular( + TabularAlgorithmLeapYears::TypeII, + TabularAlgorithmEpoch::Friday, + ); for (case, f_date) in ARITHMETIC_CASES.iter().zip(TEST_RD.iter()) { - let date = Date::try_new_hijri_tabular_with_calendar( - case.year, case.month, case.day, calendar, - ) - .unwrap(); + let date = Date::try_new_hijri_with_calendar(case.year, case.month, case.day, calendar) + .unwrap(); let date_rd = Date::from_rata_die(RataDie::new(*f_date), calendar); assert_eq!(date, date_rd, "{case:?}"); @@ -1798,28 +1811,26 @@ mod test { #[test] fn test_rd_from_hijri_tbla() { - let calendar = - HijriTabular::new(HijriTabularLeapYears::TypeII, HijriTabularEpoch::Thursday); - let calendar = Ref(&calendar); + let calendar = Hijri::new_tabular( + TabularAlgorithmLeapYears::TypeII, + TabularAlgorithmEpoch::Thursday, + ); for (case, f_date) in ASTRONOMICAL_CASES.iter().zip(TEST_RD.iter()) { - let date = Date::try_new_hijri_tabular_with_calendar( - case.year, case.month, case.day, calendar, - ) - .unwrap(); + let date = Date::try_new_hijri_with_calendar(case.year, case.month, case.day, calendar) + .unwrap(); assert_eq!(date.to_rata_die(), RataDie::new(*f_date), "{case:?}"); } } #[test] fn test_hijri_tbla_from_rd() { - let calendar = - HijriTabular::new(HijriTabularLeapYears::TypeII, HijriTabularEpoch::Thursday); - let calendar = Ref(&calendar); + let calendar = Hijri::new_tabular( + TabularAlgorithmLeapYears::TypeII, + TabularAlgorithmEpoch::Thursday, + ); for (case, f_date) in ASTRONOMICAL_CASES.iter().zip(TEST_RD.iter()) { - let date = Date::try_new_hijri_tabular_with_calendar( - case.year, case.month, case.day, calendar, - ) - .unwrap(); + let date = Date::try_new_hijri_with_calendar(case.year, case.month, case.day, calendar) + .unwrap(); let date_rd = Date::from_rata_die(RataDie::new(*f_date), calendar); assert_eq!(date, date_rd, "{case:?}"); @@ -1828,10 +1839,10 @@ mod test { #[test] fn test_saudi_hijri_from_rd() { - let calendar = HijriUmmAlQura::new(); - let calendar = Ref(&calendar); + let calendar = Hijri::new_umm_al_qura(); for (case, f_date) in UMMALQURA_CASES.iter().zip(TEST_RD.iter()) { - let date = Date::try_new_ummalqura(case.year, case.month, case.day).unwrap(); + let date = Date::try_new_hijri_with_calendar(case.year, case.month, case.day, calendar) + .unwrap(); let date_rd = Date::from_rata_die(RataDie::new(*f_date), calendar); assert_eq!(date, date_rd, "{case:?}"); @@ -1840,8 +1851,10 @@ mod test { #[test] fn test_rd_from_saudi_hijri() { + let calendar = Hijri::new_umm_al_qura(); for (case, f_date) in UMMALQURA_CASES.iter().zip(TEST_RD.iter()) { - let date = Date::try_new_ummalqura(case.year, case.month, case.day).unwrap(); + let date = Date::try_new_hijri_with_calendar(case.year, case.month, case.day, calendar) + .unwrap(); assert_eq!(date.to_rata_die(), RataDie::new(*f_date), "{case:?}"); } } @@ -1849,24 +1862,24 @@ mod test { #[ignore] // slow #[test] fn test_days_in_provided_year_simulated() { - let calendar = HijriSimulated::new_mecca(); - let calendar = Ref(&calendar); + let calendar = Hijri::new_simulated_mecca(); // -1245 1 1 = -214526 (R.D Date) // 1518 1 1 = 764589 (R.D Date) let sum_days_in_year: i64 = (START_YEAR..END_YEAR) .map(|year| { - HijriSimulated::days_in_provided_year( - HijriSimulatedLocation::Mecca.compute_year_info(year), - ) as i64 + Hijri::new_simulated_mecca() + .0 + .year_data(year) + .packed + .days_in_year() as i64 }) .sum(); - let expected_number_of_days = - Date::try_new_simulated_hijri_with_calendar(END_YEAR, 1, 1, calendar) + let expected_number_of_days = Date::try_new_hijri_with_calendar(END_YEAR, 1, 1, calendar) + .unwrap() + .to_rata_die() + - Date::try_new_hijri_with_calendar(START_YEAR, 1, 1, calendar) .unwrap() - .to_rata_die() - - Date::try_new_simulated_hijri_with_calendar(START_YEAR, 1, 1, calendar) - .unwrap() - .to_rata_die(); // The number of days between Hijri years -1245 and 1518 + .to_rata_die(); // The number of days between Hijri years -1245 and 1518 let tolerance = 1; // One day tolerance (See Astronomical::month_length for more context) assert!( @@ -1878,18 +1891,17 @@ mod test { #[ignore] // slow #[test] fn test_days_in_provided_year_ummalqura() { + let calendar = Hijri::new_umm_al_qura(); // -1245 1 1 = -214528 (R.D Date) // 1518 1 1 = 764588 (R.D Date) let sum_days_in_year: i64 = (START_YEAR..END_YEAR) - .map(|year| { - HijriUmmAlQura::days_in_provided_year(HijriUmmAlQura.load_or_compute_info(year)) - as i64 - }) + .map(|year| calendar.0.year_data(year).packed.days_in_year() as i64) .sum(); - let expected_number_of_days = Date::try_new_ummalqura(END_YEAR, 1, 1) + let expected_number_of_days = Date::try_new_hijri_with_calendar(END_YEAR, 1, 1, calendar) .unwrap() .to_rata_die() - - (Date::try_new_ummalqura(START_YEAR, 1, 1).unwrap()).to_rata_die(); // The number of days between Umm al-Qura Hijri years -1245 and 1518 + - (Date::try_new_hijri_with_calendar(START_YEAR, 1, 1, calendar).unwrap()) + .to_rata_die(); // The number of days between Umm al-Qura Hijri years -1245 and 1518 assert_eq!(sum_days_in_year, expected_number_of_days); } @@ -1898,7 +1910,7 @@ mod test { fn test_regression_3868() { // This date used to panic on creation let iso = Date::try_new_iso(2011, 4, 4).unwrap(); - let hijri = iso.to_calendar(HijriUmmAlQura::new()); + let hijri = iso.to_calendar(Hijri::new_umm_al_qura()); // Data from https://www.ummulqura.org.sa/Index.aspx assert_eq!(hijri.day_of_month().0, 30); assert_eq!(hijri.month().ordinal, 4); @@ -1908,143 +1920,96 @@ mod test { #[test] fn test_regression_4914() { // https://github.com/unicode-org/icu4x/issues/4914 - let dt = HijriUmmAlQura::new() + let dt = Hijri::new_umm_al_qura() .from_codes(Some("bh"), 6824, MonthCode::new_normal(1).unwrap(), 1) .unwrap(); assert_eq!(dt.0.day, 1); assert_eq!(dt.0.month, 1); - assert_eq!(dt.0.year.value, -6823); + assert_eq!(dt.0.year.extended_year, -6823); } #[test] - fn test_regression_5069_uaq() { - let cached = HijriUmmAlQura::new(); + fn test_regression_7056() { + // https://github.com/unicode-org/icu4x/issues/7056 + let calendar = Hijri::new_tabular( + TabularAlgorithmLeapYears::TypeII, + TabularAlgorithmEpoch::Friday, + ); + let iso = Date::try_new_iso(-62971, 3, 19).unwrap(); + let _dt = iso.to_calendar(calendar); + let _dt = iso.to_calendar(Hijri::new_umm_al_qura()); + } - let cached = crate::Ref(&cached); + #[test] + fn test_regression_5069_uaq() { + let calendar = Hijri::new_umm_al_qura(); - let dt_cached = Date::try_new_ummalqura(1391, 1, 29).unwrap(); + let dt = Date::try_new_hijri_with_calendar(1391, 1, 29, calendar).unwrap(); - assert_eq!(dt_cached.to_iso().to_calendar(cached), dt_cached); + assert_eq!(dt.to_iso().to_calendar(calendar), dt); } #[test] fn test_regression_5069_obs() { - let cached = HijriSimulated::new_mecca(); - let comp = HijriSimulated::new_mecca_always_calculating(); - - let cached = crate::Ref(&cached); - let comp = crate::Ref(&comp); + let cal = Hijri::new_simulated_mecca(); - let dt_cached = Date::try_new_simulated_hijri_with_calendar(1390, 1, 30, cached).unwrap(); - let dt_comp = Date::try_new_simulated_hijri_with_calendar(1390, 1, 30, comp).unwrap(); + let dt = Date::try_new_hijri_with_calendar(1390, 1, 30, cal).unwrap(); - assert_eq!(dt_cached.to_iso(), dt_comp.to_iso()); - - assert_eq!(dt_comp.to_iso().to_calendar(comp), dt_comp); - assert_eq!(dt_cached.to_iso().to_calendar(cached), dt_cached); + assert_eq!(dt.to_iso().to_calendar(cal), dt); let dt = Date::try_new_iso(2000, 5, 5).unwrap(); - assert!(dt.to_calendar(comp).day_of_month().0 > 0); - assert!(dt.to_calendar(cached).day_of_month().0 > 0); + assert!(dt.to_calendar(cal).day_of_month().0 > 0); } #[test] fn test_regression_6197() { - let cached = HijriUmmAlQura::new(); - - let cached = crate::Ref(&cached); + let calendar = Hijri::new_umm_al_qura(); let iso = Date::try_new_iso(2025, 2, 26).unwrap(); - let cached = iso.to_calendar(cached); + let date = iso.to_calendar(calendar); // Data from https://www.ummulqura.org.sa/ assert_eq!( ( - cached.day_of_month().0, - cached.month().ordinal, - cached.era_year().year + date.day_of_month().0, + date.month().ordinal, + date.era_year().year ), (27, 8, 1446) ); } #[test] - fn test_uaq_icu4c_agreement() { - // From https://github.com/unicode-org/icu/blob/1bf6bf774dbc8c6c2051963a81100ea1114b497f/icu4c/source/i18n/islamcal.cpp#L87 - const ICU4C_ENCODED_MONTH_LENGTHS: [u16; 1601 - 1300] = [ - 0x0AAA, 0x0D54, 0x0EC9, 0x06D4, 0x06EA, 0x036C, 0x0AAD, 0x0555, 0x06A9, 0x0792, 0x0BA9, - 0x05D4, 0x0ADA, 0x055C, 0x0D2D, 0x0695, 0x074A, 0x0B54, 0x0B6A, 0x05AD, 0x04AE, 0x0A4F, - 0x0517, 0x068B, 0x06A5, 0x0AD5, 0x02D6, 0x095B, 0x049D, 0x0A4D, 0x0D26, 0x0D95, 0x05AC, - 0x09B6, 0x02BA, 0x0A5B, 0x052B, 0x0A95, 0x06CA, 0x0AE9, 0x02F4, 0x0976, 0x02B6, 0x0956, - 0x0ACA, 0x0BA4, 0x0BD2, 0x05D9, 0x02DC, 0x096D, 0x054D, 0x0AA5, 0x0B52, 0x0BA5, 0x05B4, - 0x09B6, 0x0557, 0x0297, 0x054B, 0x06A3, 0x0752, 0x0B65, 0x056A, 0x0AAB, 0x052B, 0x0C95, - 0x0D4A, 0x0DA5, 0x05CA, 0x0AD6, 0x0957, 0x04AB, 0x094B, 0x0AA5, 0x0B52, 0x0B6A, 0x0575, - 0x0276, 0x08B7, 0x045B, 0x0555, 0x05A9, 0x05B4, 0x09DA, 0x04DD, 0x026E, 0x0936, 0x0AAA, - 0x0D54, 0x0DB2, 0x05D5, 0x02DA, 0x095B, 0x04AB, 0x0A55, 0x0B49, 0x0B64, 0x0B71, 0x05B4, - 0x0AB5, 0x0A55, 0x0D25, 0x0E92, 0x0EC9, 0x06D4, 0x0AE9, 0x096B, 0x04AB, 0x0A93, 0x0D49, - 0x0DA4, 0x0DB2, 0x0AB9, 0x04BA, 0x0A5B, 0x052B, 0x0A95, 0x0B2A, 0x0B55, 0x055C, 0x04BD, - 0x023D, 0x091D, 0x0A95, 0x0B4A, 0x0B5A, 0x056D, 0x02B6, 0x093B, 0x049B, 0x0655, 0x06A9, - 0x0754, 0x0B6A, 0x056C, 0x0AAD, 0x0555, 0x0B29, 0x0B92, 0x0BA9, 0x05D4, 0x0ADA, 0x055A, - 0x0AAB, 0x0595, 0x0749, 0x0764, 0x0BAA, 0x05B5, 0x02B6, 0x0A56, 0x0E4D, 0x0B25, 0x0B52, - 0x0B6A, 0x05AD, 0x02AE, 0x092F, 0x0497, 0x064B, 0x06A5, 0x06AC, 0x0AD6, 0x055D, 0x049D, - 0x0A4D, 0x0D16, 0x0D95, 0x05AA, 0x05B5, 0x02DA, 0x095B, 0x04AD, 0x0595, 0x06CA, 0x06E4, - 0x0AEA, 0x04F5, 0x02B6, 0x0956, 0x0AAA, 0x0B54, 0x0BD2, 0x05D9, 0x02EA, 0x096D, 0x04AD, - 0x0A95, 0x0B4A, 0x0BA5, 0x05B2, 0x09B5, 0x04D6, 0x0A97, 0x0547, 0x0693, 0x0749, 0x0B55, - 0x056A, 0x0A6B, 0x052B, 0x0A8B, 0x0D46, 0x0DA3, 0x05CA, 0x0AD6, 0x04DB, 0x026B, 0x094B, - 0x0AA5, 0x0B52, 0x0B69, 0x0575, 0x0176, 0x08B7, 0x025B, 0x052B, 0x0565, 0x05B4, 0x09DA, - 0x04ED, 0x016D, 0x08B6, 0x0AA6, 0x0D52, 0x0DA9, 0x05D4, 0x0ADA, 0x095B, 0x04AB, 0x0653, - 0x0729, 0x0762, 0x0BA9, 0x05B2, 0x0AB5, 0x0555, 0x0B25, 0x0D92, 0x0EC9, 0x06D2, 0x0AE9, - 0x056B, 0x04AB, 0x0A55, 0x0D29, 0x0D54, 0x0DAA, 0x09B5, 0x04BA, 0x0A3B, 0x049B, 0x0A4D, - 0x0AAA, 0x0AD5, 0x02DA, 0x095D, 0x045E, 0x0A2E, 0x0C9A, 0x0D55, 0x06B2, 0x06B9, 0x04BA, - 0x0A5D, 0x052D, 0x0A95, 0x0B52, 0x0BA8, 0x0BB4, 0x05B9, 0x02DA, 0x095A, 0x0B4A, 0x0DA4, - 0x0ED1, 0x06E8, 0x0B6A, 0x056D, 0x0535, 0x0695, 0x0D4A, 0x0DA8, 0x0DD4, 0x06DA, 0x055B, - 0x029D, 0x062B, 0x0B15, 0x0B4A, 0x0B95, 0x05AA, 0x0AAE, 0x092E, 0x0C8F, 0x0527, 0x0695, - 0x06AA, 0x0AD6, 0x055D, 0x029D, - ]; - - // From https://github.com/unicode-org/icu/blob/1bf6bf774dbc8c6c2051963a81100ea1114b497f/icu4c/source/i18n/islamcal.cpp#L264 - const ICU4C_YEAR_START_ESTIMATE_FIX: [i64; 1601 - 1300] = [ - 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 1, 1, 0, 0, 0, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, -1, 0, 0, 0, 1, 0, 0, -1, 0, 0, - 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 1, 0, 0, -1, 0, 1, 0, 1, 1, 0, 0, -1, - 0, 1, 0, 0, 0, -1, 0, 1, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, -1, -1, 0, -1, 0, 1, 0, 0, 0, - -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, -1, 0, 0, 0, 1, 0, 0, -1, -1, 0, -1, 0, 0, - -1, -1, 0, -1, 0, -1, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 1, 1, 0, 0, -1, 0, - 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, -1, 0, 1, 0, 0, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, 0, -1, 0, 1, 0, 1, 1, 0, 0, 0, - 0, 1, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, -1, 0, -1, 0, 1, 0, 0, 0, - -1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, -1, - -1, 0, -1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 1, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, - ]; - - let icu4c = ICU4C_ENCODED_MONTH_LENGTHS - .into_iter() - .zip(ICU4C_YEAR_START_ESTIMATE_FIX) - .enumerate() - .map( - |(years_since_1300, (encoded_months_lengths, year_start_estimate_fix))| { - // https://github.com/unicode-org/icu/blob/1bf6bf774dbc8c6c2051963a81100ea1114b497f/icu4c/source/i18n/islamcal.cpp#L858 - let month_lengths = - core::array::from_fn(|i| (1 << (11 - i)) & encoded_months_lengths != 0); - // From https://github.com/unicode-org/icu/blob/1bf6bf774dbc8c6c2051963a81100ea1114b497f/icu4c/source/i18n/islamcal.cpp#L813 - let year_start = ((354.36720 * years_since_1300 as f64) + 460322.05 + 0.5) - as i64 - + year_start_estimate_fix; - HijriYearInfo { - value: 1300 + years_since_1300 as i32, - month_lengths, - start_day: ISLAMIC_EPOCH_FRIDAY + year_start, - } - }, - ) - .collect::>(); - - let icu4x = (1300..=1600) - .map(|y| HijriUmmAlQura.load_or_compute_info(y)) - .collect::>(); + fn test_hijri_packed_roundtrip() { + fn single_roundtrip(month_lengths: [bool; 12], start_day: RataDie) -> Option<()> { + let packed = PackedHijriYearData::try_new(1600, month_lengths, start_day)?; + for i in 0..12 { + assert_eq!(packed.month_has_30_days(i + 1), month_lengths[i as usize]); + } + assert_eq!(packed.new_year(1600), start_day); + Some(()) + } - assert_eq!(icu4x, icu4c); + let l = true; + let s = false; + let all_short = [s; 12]; + let all_long = [l; 12]; + let mixed1 = [l, s, l, s, l, s, l, s, l, s, l, s]; + let mixed2 = [s, s, l, l, l, s, l, s, s, s, l, l]; + + let start_1600 = PackedHijriYearData::mean_tabular_start_day(1600); + assert_eq!(single_roundtrip(all_short, start_1600), None); + assert_eq!(single_roundtrip(all_long, start_1600), None); + single_roundtrip(mixed1, start_1600).unwrap(); + single_roundtrip(mixed2, start_1600).unwrap(); + + single_roundtrip(mixed1, start_1600 - 7).unwrap(); + single_roundtrip(mixed2, start_1600 + 7).unwrap(); + single_roundtrip(mixed2, start_1600 + 4).unwrap(); + single_roundtrip(mixed2, start_1600 + 1).unwrap(); + single_roundtrip(mixed2, start_1600 - 1).unwrap(); + single_roundtrip(mixed2, start_1600 - 4).unwrap(); } } diff --git a/deps/crates/vendor/icu_calendar/src/cal/hijri/simulated_mecca_data.rs b/deps/crates/vendor/icu_calendar/src/cal/hijri/simulated_mecca_data.rs new file mode 100644 index 00000000000000..895ffd46eb9c89 --- /dev/null +++ b/deps/crates/vendor/icu_calendar/src/cal/hijri/simulated_mecca_data.rs @@ -0,0 +1,269 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +//! Data obtained from [`calendrical_calculations`]. + +use super::PackedHijriYearData; + +pub const STARTING_YEAR: i32 = 1317; + +#[rustfmt::skip] +#[allow(clippy::unwrap_used)] // const +pub const DATA: &[PackedHijriYearData] = { + use calendrical_calculations::gregorian::fixed_from_gregorian as gregorian; + let l = true; // long + let s = false; // short + &[ + PackedHijriYearData::try_new(1317, [l, l, l, l, s, s, l, s, l, s, s, l], gregorian(1899, 5, 11)).unwrap(), + PackedHijriYearData::try_new(1318, [s, l, l, l, s, l, s, l, s, l, s, s], gregorian(1900, 5, 1)).unwrap(), + PackedHijriYearData::try_new(1319, [l, s, l, l, s, l, s, l, l, s, l, s], gregorian(1901, 4, 20)).unwrap(), + PackedHijriYearData::try_new(1320, [l, s, s, l, s, l, s, l, l, s, l, l], gregorian(1902, 4, 10)).unwrap(), + PackedHijriYearData::try_new(1321, [s, l, s, s, l, s, s, l, l, s, l, l], gregorian(1903, 3, 31)).unwrap(), + PackedHijriYearData::try_new(1322, [l, s, l, s, s, s, l, s, l, s, l, l], gregorian(1904, 3, 19)).unwrap(), + PackedHijriYearData::try_new(1323, [l, s, l, l, s, s, s, l, s, l, s, l], gregorian(1905, 3, 8)).unwrap(), + PackedHijriYearData::try_new(1324, [l, s, l, l, s, l, s, s, l, s, l, s], gregorian(1906, 2, 25)).unwrap(), + PackedHijriYearData::try_new(1325, [l, s, l, l, s, l, l, s, l, s, l, s], gregorian(1907, 2, 14)).unwrap(), + PackedHijriYearData::try_new(1326, [s, l, s, l, s, l, l, s, l, l, s, l], gregorian(1908, 2, 4)).unwrap(), + PackedHijriYearData::try_new(1327, [s, s, l, s, l, s, l, s, l, l, l, s], gregorian(1909, 1, 24)).unwrap(), + PackedHijriYearData::try_new(1328, [l, s, s, l, s, s, l, s, l, l, l, s], gregorian(1910, 1, 13)).unwrap(), + PackedHijriYearData::try_new(1329, [l, l, s, l, s, s, s, l, s, l, l, l], gregorian(1911, 1, 2)).unwrap(), + PackedHijriYearData::try_new(1330, [s, l, l, s, s, l, s, s, l, s, l, l], gregorian(1911, 12, 23)).unwrap(), + PackedHijriYearData::try_new(1331, [s, l, l, s, l, s, l, s, l, s, l, s], gregorian(1912, 12, 11)).unwrap(), + PackedHijriYearData::try_new(1332, [s, l, l, l, s, l, s, l, s, l, s, l], gregorian(1913, 11, 30)).unwrap(), + PackedHijriYearData::try_new(1333, [s, s, l, l, s, l, l, s, l, l, s, s], gregorian(1914, 11, 20)).unwrap(), + PackedHijriYearData::try_new(1334, [s, l, s, l, s, l, l, s, l, l, l, s], gregorian(1915, 11, 9)).unwrap(), + PackedHijriYearData::try_new(1335, [s, s, l, s, l, s, l, s, l, l, l, s], gregorian(1916, 10, 29)).unwrap(), + PackedHijriYearData::try_new(1336, [l, s, l, s, s, l, s, l, s, l, l, s], gregorian(1917, 10, 18)).unwrap(), + PackedHijriYearData::try_new(1337, [l, s, l, l, s, s, l, s, l, s, l, s], gregorian(1918, 10, 7)).unwrap(), + PackedHijriYearData::try_new(1338, [l, s, l, l, l, s, l, s, s, l, s, l], gregorian(1919, 9, 26)).unwrap(), + PackedHijriYearData::try_new(1339, [s, s, l, l, l, s, l, s, l, s, l, s], gregorian(1920, 9, 15)).unwrap(), + PackedHijriYearData::try_new(1340, [s, l, s, l, l, l, s, l, s, l, s, l], gregorian(1921, 9, 4)).unwrap(), + PackedHijriYearData::try_new(1341, [s, s, l, s, l, l, s, l, l, s, l, s], gregorian(1922, 8, 25)).unwrap(), + PackedHijriYearData::try_new(1342, [s, l, s, l, s, l, s, l, l, s, l, l], gregorian(1923, 8, 14)).unwrap(), + PackedHijriYearData::try_new(1343, [s, s, l, s, l, s, l, s, l, s, l, l], gregorian(1924, 8, 3)).unwrap(), + PackedHijriYearData::try_new(1344, [s, l, s, l, s, l, s, l, s, l, s, l], gregorian(1925, 7, 23)).unwrap(), + PackedHijriYearData::try_new(1345, [s, l, l, s, l, l, s, s, l, s, s, l], gregorian(1926, 7, 12)).unwrap(), + PackedHijriYearData::try_new(1346, [s, l, l, s, l, l, s, l, s, l, s, s], gregorian(1927, 7, 1)).unwrap(), + PackedHijriYearData::try_new(1347, [l, s, l, s, l, l, l, s, l, s, l, s], gregorian(1928, 6, 19)).unwrap(), + PackedHijriYearData::try_new(1348, [s, l, s, l, s, l, l, l, s, l, s, l], gregorian(1929, 6, 9)).unwrap(), + PackedHijriYearData::try_new(1349, [s, s, l, s, l, s, l, s, l, l, l, s], gregorian(1930, 5, 30)).unwrap(), + PackedHijriYearData::try_new(1350, [l, s, s, l, s, l, s, l, s, l, l, s], gregorian(1931, 5, 19)).unwrap(), + PackedHijriYearData::try_new(1351, [l, l, s, l, s, l, s, s, l, s, l, s], gregorian(1932, 5, 7)).unwrap(), + PackedHijriYearData::try_new(1352, [l, l, s, l, l, s, l, s, s, l, s, l], gregorian(1933, 4, 26)).unwrap(), + PackedHijriYearData::try_new(1353, [s, l, l, s, l, l, s, s, l, s, l, s], gregorian(1934, 4, 16)).unwrap(), + PackedHijriYearData::try_new(1354, [s, l, l, s, l, l, l, s, s, l, s, l], gregorian(1935, 4, 5)).unwrap(), + PackedHijriYearData::try_new(1355, [s, s, l, l, s, l, l, s, l, s, l, s], gregorian(1936, 3, 25)).unwrap(), + PackedHijriYearData::try_new(1356, [l, s, s, l, l, s, l, s, l, l, s, l], gregorian(1937, 3, 14)).unwrap(), + PackedHijriYearData::try_new(1357, [s, l, s, l, s, s, l, s, l, l, s, l], gregorian(1938, 3, 4)).unwrap(), + PackedHijriYearData::try_new(1358, [l, s, l, s, l, s, s, l, s, l, s, l], gregorian(1939, 2, 21)).unwrap(), + PackedHijriYearData::try_new(1359, [l, l, s, l, s, l, s, s, l, s, s, l], gregorian(1940, 2, 10)).unwrap(), + PackedHijriYearData::try_new(1360, [l, l, s, l, l, s, l, s, s, l, s, l], gregorian(1941, 1, 29)).unwrap(), + PackedHijriYearData::try_new(1361, [s, l, s, l, l, s, l, s, l, s, l, s], gregorian(1942, 1, 19)).unwrap(), + PackedHijriYearData::try_new(1362, [l, s, l, s, l, s, l, l, s, l, s, l], gregorian(1943, 1, 8)).unwrap(), + PackedHijriYearData::try_new(1363, [s, l, s, s, l, s, l, l, s, l, l, s], gregorian(1943, 12, 29)).unwrap(), + PackedHijriYearData::try_new(1364, [l, s, l, s, s, l, s, l, s, l, l, l], gregorian(1944, 12, 17)).unwrap(), + PackedHijriYearData::try_new(1365, [s, l, s, l, s, s, l, s, s, l, l, l], gregorian(1945, 12, 7)).unwrap(), + PackedHijriYearData::try_new(1366, [s, l, l, s, l, s, s, l, s, s, l, l], gregorian(1946, 11, 26)).unwrap(), + PackedHijriYearData::try_new(1367, [s, l, l, l, s, l, s, s, l, s, s, l], gregorian(1947, 11, 15)).unwrap(), + PackedHijriYearData::try_new(1368, [l, s, l, l, s, l, l, s, s, l, s, l], gregorian(1948, 11, 3)).unwrap(), + PackedHijriYearData::try_new(1369, [s, l, s, l, s, l, l, s, l, s, l, s], gregorian(1949, 10, 24)).unwrap(), + PackedHijriYearData::try_new(1370, [l, s, s, l, l, s, l, s, l, l, s, l], gregorian(1950, 10, 13)).unwrap(), + PackedHijriYearData::try_new(1371, [l, s, s, l, s, s, l, s, l, l, l, l], gregorian(1951, 10, 3)).unwrap(), + PackedHijriYearData::try_new(1372, [s, s, l, s, l, s, s, l, s, l, l, l], gregorian(1952, 9, 22)).unwrap(), + PackedHijriYearData::try_new(1373, [s, l, s, l, s, l, s, s, l, s, l, l], gregorian(1953, 9, 11)).unwrap(), + PackedHijriYearData::try_new(1374, [s, l, s, l, l, s, l, s, s, l, s, l], gregorian(1954, 8, 31)).unwrap(), + PackedHijriYearData::try_new(1375, [s, l, s, l, l, l, s, l, s, s, l, s], gregorian(1955, 8, 20)).unwrap(), + PackedHijriYearData::try_new(1376, [l, s, l, s, l, l, s, l, l, s, l, s], gregorian(1956, 8, 8)).unwrap(), + PackedHijriYearData::try_new(1377, [s, l, s, s, l, l, s, l, l, l, s, l], gregorian(1957, 7, 29)).unwrap(), + PackedHijriYearData::try_new(1378, [s, s, l, s, s, l, s, l, l, l, s, l], gregorian(1958, 7, 19)).unwrap(), + PackedHijriYearData::try_new(1379, [l, s, s, l, s, s, l, s, l, l, s, l], gregorian(1959, 7, 8)).unwrap(), + PackedHijriYearData::try_new(1380, [l, s, l, s, l, s, s, l, s, l, s, l], gregorian(1960, 6, 26)).unwrap(), + PackedHijriYearData::try_new(1381, [l, s, l, s, l, l, s, l, s, s, l, s], gregorian(1961, 6, 15)).unwrap(), + PackedHijriYearData::try_new(1382, [l, s, l, l, s, l, l, s, l, s, s, l], gregorian(1962, 6, 4)).unwrap(), + PackedHijriYearData::try_new(1383, [s, l, s, l, s, l, l, l, s, l, s, s], gregorian(1963, 5, 25)).unwrap(), + PackedHijriYearData::try_new(1384, [l, s, s, l, s, l, l, l, s, l, l, s], gregorian(1964, 5, 13)).unwrap(), + PackedHijriYearData::try_new(1385, [s, l, s, s, l, s, l, l, s, l, l, l], gregorian(1965, 5, 3)).unwrap(), + PackedHijriYearData::try_new(1386, [s, s, l, s, s, l, s, l, s, l, l, l], gregorian(1966, 4, 23)).unwrap(), + PackedHijriYearData::try_new(1387, [s, l, s, l, s, l, s, s, l, s, l, l], gregorian(1967, 4, 12)).unwrap(), + PackedHijriYearData::try_new(1388, [s, l, l, s, l, s, l, s, s, l, s, l], gregorian(1968, 3, 31)).unwrap(), + PackedHijriYearData::try_new(1389, [s, l, l, s, l, l, s, l, s, s, l, s], gregorian(1969, 3, 20)).unwrap(), + PackedHijriYearData::try_new(1390, [l, s, l, s, l, l, l, s, l, s, l, s], gregorian(1970, 3, 9)).unwrap(), + PackedHijriYearData::try_new(1391, [s, l, s, l, s, l, l, l, s, l, s, l], gregorian(1971, 2, 27)).unwrap(), + PackedHijriYearData::try_new(1392, [s, s, l, s, s, l, l, l, s, l, s, l], gregorian(1972, 2, 17)).unwrap(), + PackedHijriYearData::try_new(1393, [l, s, s, l, s, l, s, l, s, l, s, l], gregorian(1973, 2, 5)).unwrap(), + PackedHijriYearData::try_new(1394, [l, l, s, s, l, s, l, s, s, l, s, l], gregorian(1974, 1, 25)).unwrap(), + PackedHijriYearData::try_new(1395, [l, l, s, l, s, l, s, l, s, s, l, s], gregorian(1975, 1, 14)).unwrap(), + PackedHijriYearData::try_new(1396, [l, l, l, s, l, s, l, s, l, s, s, l], gregorian(1976, 1, 3)).unwrap(), + PackedHijriYearData::try_new(1397, [s, l, l, s, l, l, s, l, s, l, s, s], gregorian(1976, 12, 23)).unwrap(), + PackedHijriYearData::try_new(1398, [l, s, l, s, l, l, s, l, l, s, s, l], gregorian(1977, 12, 12)).unwrap(), + PackedHijriYearData::try_new(1399, [s, l, s, l, s, l, s, l, l, s, l, s], gregorian(1978, 12, 2)).unwrap(), + PackedHijriYearData::try_new(1400, [l, l, s, s, l, s, l, s, l, s, l, l], gregorian(1979, 11, 21)).unwrap(), + PackedHijriYearData::try_new(1401, [s, l, l, s, s, l, s, s, l, s, l, l], gregorian(1980, 11, 10)).unwrap(), + PackedHijriYearData::try_new(1402, [s, l, l, l, s, s, l, s, s, l, s, l], gregorian(1981, 10, 30)).unwrap(), + PackedHijriYearData::try_new(1403, [s, l, l, l, s, l, s, l, s, s, l, s], gregorian(1982, 10, 19)).unwrap(), + PackedHijriYearData::try_new(1404, [l, s, l, l, s, l, l, s, l, s, s, l], gregorian(1983, 10, 8)).unwrap(), + PackedHijriYearData::try_new(1405, [s, l, s, l, s, l, l, l, s, l, s, s], gregorian(1984, 9, 27)).unwrap(), + PackedHijriYearData::try_new(1406, [l, s, l, s, l, s, l, l, s, l, s, l], gregorian(1985, 9, 16)).unwrap(), + PackedHijriYearData::try_new(1407, [l, s, s, l, s, l, s, l, s, l, l, s], gregorian(1986, 9, 6)).unwrap(), + PackedHijriYearData::try_new(1408, [l, l, s, s, l, s, l, s, l, s, l, s], gregorian(1987, 8, 26)).unwrap(), + PackedHijriYearData::try_new(1409, [l, l, l, s, s, l, s, l, s, s, l, s], gregorian(1988, 8, 14)).unwrap(), + PackedHijriYearData::try_new(1410, [l, l, l, s, l, l, s, s, l, s, s, l], gregorian(1989, 8, 3)).unwrap(), + PackedHijriYearData::try_new(1411, [l, s, l, s, l, l, s, l, s, l, s, s], gregorian(1990, 7, 24)).unwrap(), + PackedHijriYearData::try_new(1412, [l, l, s, l, s, l, l, s, l, s, l, s], gregorian(1991, 7, 13)).unwrap(), + PackedHijriYearData::try_new(1413, [l, s, s, l, s, l, l, s, l, l, s, l], gregorian(1992, 7, 2)).unwrap(), + PackedHijriYearData::try_new(1414, [s, l, s, s, l, s, l, s, l, l, l, s], gregorian(1993, 6, 22)).unwrap(), + PackedHijriYearData::try_new(1415, [l, s, l, s, s, l, s, l, s, l, l, s], gregorian(1994, 6, 11)).unwrap(), + PackedHijriYearData::try_new(1416, [l, l, s, l, s, s, l, s, l, s, l, s], gregorian(1995, 5, 31)).unwrap(), + PackedHijriYearData::try_new(1417, [l, l, s, l, s, l, s, l, s, l, s, s], gregorian(1996, 5, 19)).unwrap(), + PackedHijriYearData::try_new(1418, [l, l, s, l, l, s, l, s, l, s, l, s], gregorian(1997, 5, 8)).unwrap(), + PackedHijriYearData::try_new(1419, [s, l, s, l, s, l, l, l, s, l, s, l], gregorian(1998, 4, 28)).unwrap(), + PackedHijriYearData::try_new(1420, [s, s, l, s, l, s, l, l, l, s, l, s], gregorian(1999, 4, 18)).unwrap(), + PackedHijriYearData::try_new(1421, [l, s, s, l, s, s, l, l, l, s, l, l], gregorian(2000, 4, 6)).unwrap(), + PackedHijriYearData::try_new(1422, [s, l, s, s, l, s, s, l, l, s, l, l], gregorian(2001, 3, 27)).unwrap(), + PackedHijriYearData::try_new(1423, [l, s, l, s, s, l, s, s, l, l, s, l], gregorian(2002, 3, 16)).unwrap(), + PackedHijriYearData::try_new(1424, [l, s, l, s, l, s, l, s, l, s, s, l], gregorian(2003, 3, 5)).unwrap(), + PackedHijriYearData::try_new(1425, [l, s, l, l, s, l, s, l, s, l, s, s], gregorian(2004, 2, 22)).unwrap(), + PackedHijriYearData::try_new(1426, [l, l, s, l, s, l, l, s, l, s, l, s], gregorian(2005, 2, 10)).unwrap(), + PackedHijriYearData::try_new(1427, [l, s, s, l, s, l, l, l, s, l, s, l], gregorian(2006, 1, 31)).unwrap(), + PackedHijriYearData::try_new(1428, [s, l, s, s, l, s, l, l, l, s, l, s], gregorian(2007, 1, 21)).unwrap(), + PackedHijriYearData::try_new(1429, [l, s, l, s, s, l, s, l, l, s, l, s], gregorian(2008, 1, 10)).unwrap(), + PackedHijriYearData::try_new(1430, [l, l, s, l, s, s, l, s, l, s, l, s], gregorian(2008, 12, 29)).unwrap(), + PackedHijriYearData::try_new(1431, [l, l, l, s, l, s, s, l, s, l, s, s], gregorian(2009, 12, 18)).unwrap(), + PackedHijriYearData::try_new(1432, [l, l, l, s, l, l, s, l, s, s, l, s], gregorian(2010, 12, 7)).unwrap(), + PackedHijriYearData::try_new(1433, [s, l, l, s, l, l, s, l, l, s, s, l], gregorian(2011, 11, 27)).unwrap(), + PackedHijriYearData::try_new(1434, [s, s, l, s, l, l, s, l, l, l, s, s], gregorian(2012, 11, 16)).unwrap(), + PackedHijriYearData::try_new(1435, [l, s, s, l, s, l, s, l, l, l, s, l], gregorian(2013, 11, 5)).unwrap(), + PackedHijriYearData::try_new(1436, [s, l, s, l, s, s, l, s, l, l, s, l], gregorian(2014, 10, 26)).unwrap(), + PackedHijriYearData::try_new(1437, [s, l, l, s, l, s, s, l, s, l, s, l], gregorian(2015, 10, 15)).unwrap(), + PackedHijriYearData::try_new(1438, [s, l, l, l, s, l, s, s, l, s, s, l], gregorian(2016, 10, 3)).unwrap(), + PackedHijriYearData::try_new(1439, [s, l, l, l, l, s, l, s, s, l, s, s], gregorian(2017, 9, 22)).unwrap(), + PackedHijriYearData::try_new(1440, [l, s, l, l, l, s, l, l, s, s, l, s], gregorian(2018, 9, 11)).unwrap(), + PackedHijriYearData::try_new(1441, [s, l, s, l, l, s, l, l, s, l, s, l], gregorian(2019, 9, 1)).unwrap(), + PackedHijriYearData::try_new(1442, [s, s, l, s, l, s, l, l, l, s, l, s], gregorian(2020, 8, 21)).unwrap(), + PackedHijriYearData::try_new(1443, [l, s, l, s, s, l, s, l, l, s, l, s], gregorian(2021, 8, 10)).unwrap(), + PackedHijriYearData::try_new(1444, [l, l, s, l, s, s, l, s, l, s, l, s], gregorian(2022, 7, 30)).unwrap(), + PackedHijriYearData::try_new(1445, [l, l, l, s, l, s, l, s, s, l, s, l], gregorian(2023, 7, 19)).unwrap(), + PackedHijriYearData::try_new(1446, [s, l, l, l, s, l, s, l, s, s, l, s], gregorian(2024, 7, 8)).unwrap(), + PackedHijriYearData::try_new(1447, [s, l, l, l, s, l, l, s, l, s, s, l], gregorian(2025, 6, 27)).unwrap(), + PackedHijriYearData::try_new(1448, [s, s, l, l, s, l, l, s, l, l, s, s], gregorian(2026, 6, 17)).unwrap(), + PackedHijriYearData::try_new(1449, [l, s, l, s, l, s, l, s, l, l, s, l], gregorian(2027, 6, 6)).unwrap(), + PackedHijriYearData::try_new(1450, [s, l, s, l, s, s, l, s, l, l, l, s], gregorian(2028, 5, 26)).unwrap(), + PackedHijriYearData::try_new(1451, [l, s, l, l, s, s, s, l, s, l, l, s], gregorian(2029, 5, 15)).unwrap(), + PackedHijriYearData::try_new(1452, [l, l, l, s, s, l, s, s, l, s, l, s], gregorian(2030, 5, 4)).unwrap(), + PackedHijriYearData::try_new(1453, [l, l, l, s, l, s, l, s, s, l, s, l], gregorian(2031, 4, 23)).unwrap(), + PackedHijriYearData::try_new(1454, [s, l, l, s, l, l, s, l, s, s, l, s], gregorian(2032, 4, 12)).unwrap(), + PackedHijriYearData::try_new(1455, [l, s, l, s, l, l, s, l, s, l, l, s], gregorian(2033, 4, 1)).unwrap(), + PackedHijriYearData::try_new(1456, [s, l, s, l, s, l, s, l, l, s, l, l], gregorian(2034, 3, 22)).unwrap(), + PackedHijriYearData::try_new(1457, [s, s, l, s, s, l, s, l, l, s, l, l], gregorian(2035, 3, 12)).unwrap(), + PackedHijriYearData::try_new(1458, [l, s, s, l, s, s, l, s, l, s, l, l], gregorian(2036, 2, 29)).unwrap(), + PackedHijriYearData::try_new(1459, [l, s, l, s, l, s, s, l, s, l, s, l], gregorian(2037, 2, 17)).unwrap(), + PackedHijriYearData::try_new(1460, [l, s, l, l, s, l, s, s, l, s, l, s], gregorian(2038, 2, 6)).unwrap(), + PackedHijriYearData::try_new(1461, [l, s, l, l, s, l, s, l, s, l, s, l], gregorian(2039, 1, 26)).unwrap(), + PackedHijriYearData::try_new(1462, [s, l, s, l, l, s, l, s, l, l, s, s], gregorian(2040, 1, 16)).unwrap(), + PackedHijriYearData::try_new(1463, [l, s, l, s, l, s, l, s, l, l, l, s], gregorian(2041, 1, 4)).unwrap(), + PackedHijriYearData::try_new(1464, [s, l, s, l, s, s, l, s, l, l, l, l], gregorian(2041, 12, 25)).unwrap(), + PackedHijriYearData::try_new(1465, [s, l, s, s, l, s, s, l, s, l, l, l], gregorian(2042, 12, 15)).unwrap(), + PackedHijriYearData::try_new(1466, [s, l, l, s, s, l, s, s, l, l, s, l], gregorian(2043, 12, 4)).unwrap(), + PackedHijriYearData::try_new(1467, [s, l, l, s, l, s, l, s, s, l, l, s], gregorian(2044, 11, 22)).unwrap(), + PackedHijriYearData::try_new(1468, [s, l, l, l, s, l, s, l, s, l, s, s], gregorian(2045, 11, 11)).unwrap(), + PackedHijriYearData::try_new(1469, [l, s, l, s, l, l, l, s, l, s, l, s], gregorian(2046, 10, 31)).unwrap(), + PackedHijriYearData::try_new(1470, [s, l, s, l, s, l, l, s, l, l, s, l], gregorian(2047, 10, 21)).unwrap(), + PackedHijriYearData::try_new(1471, [s, s, l, s, l, s, l, s, l, l, l, s], gregorian(2048, 10, 10)).unwrap(), + PackedHijriYearData::try_new(1472, [l, s, s, l, s, l, s, l, s, l, l, s], gregorian(2049, 9, 29)).unwrap(), + PackedHijriYearData::try_new(1473, [l, s, l, s, l, s, l, s, s, l, l, s], gregorian(2050, 9, 18)).unwrap(), + PackedHijriYearData::try_new(1474, [l, s, l, l, s, l, s, l, s, s, l, s], gregorian(2051, 9, 7)).unwrap(), + PackedHijriYearData::try_new(1475, [l, s, l, l, l, s, l, s, l, s, s, l], gregorian(2052, 8, 26)).unwrap(), + PackedHijriYearData::try_new(1476, [s, l, s, l, l, l, s, l, s, l, s, s], gregorian(2053, 8, 16)).unwrap(), + PackedHijriYearData::try_new(1477, [l, s, s, l, l, l, s, l, l, s, l, s], gregorian(2054, 8, 5)).unwrap(), + PackedHijriYearData::try_new(1478, [s, l, s, s, l, l, s, l, l, s, l, l], gregorian(2055, 7, 26)).unwrap(), + PackedHijriYearData::try_new(1479, [s, s, l, s, l, s, l, s, l, s, l, l], gregorian(2056, 7, 15)).unwrap(), + PackedHijriYearData::try_new(1480, [s, l, s, l, s, l, s, s, l, l, s, l], gregorian(2057, 7, 4)).unwrap(), + PackedHijriYearData::try_new(1481, [s, l, l, s, l, s, l, s, l, s, s, l], gregorian(2058, 6, 23)).unwrap(), + PackedHijriYearData::try_new(1482, [s, l, l, s, l, l, s, l, s, l, s, s], gregorian(2059, 6, 12)).unwrap(), + PackedHijriYearData::try_new(1483, [l, s, l, s, l, l, l, s, l, s, l, s], gregorian(2060, 5, 31)).unwrap(), + PackedHijriYearData::try_new(1484, [s, l, s, l, l, s, l, s, l, l, s, l], gregorian(2061, 5, 21)).unwrap(), + PackedHijriYearData::try_new(1485, [s, s, l, s, l, s, l, l, s, l, l, s], gregorian(2062, 5, 11)).unwrap(), + PackedHijriYearData::try_new(1486, [l, s, s, l, s, l, s, l, s, l, l, s], gregorian(2063, 4, 30)).unwrap(), + PackedHijriYearData::try_new(1487, [l, l, s, l, s, s, l, s, l, s, l, s], gregorian(2064, 4, 18)).unwrap(), + PackedHijriYearData::try_new(1488, [l, l, s, l, l, s, s, l, s, s, l, l], gregorian(2065, 4, 7)).unwrap(), + PackedHijriYearData::try_new(1489, [s, l, l, s, l, l, s, s, l, s, s, l], gregorian(2066, 3, 28)).unwrap(), + PackedHijriYearData::try_new(1490, [s, l, l, s, l, l, l, s, s, l, s, s], gregorian(2067, 3, 17)).unwrap(), + PackedHijriYearData::try_new(1491, [l, s, l, s, l, l, l, s, l, s, l, s], gregorian(2068, 3, 5)).unwrap(), + PackedHijriYearData::try_new(1492, [l, s, s, l, s, l, l, s, l, s, l, l], gregorian(2069, 2, 23)).unwrap(), + PackedHijriYearData::try_new(1493, [s, l, s, s, l, s, l, s, l, s, l, l], gregorian(2070, 2, 13)).unwrap(), + PackedHijriYearData::try_new(1494, [l, s, l, s, s, l, s, s, l, s, l, l], gregorian(2071, 2, 2)).unwrap(), + PackedHijriYearData::try_new(1495, [l, l, s, l, s, s, l, s, s, l, s, l], gregorian(2072, 1, 22)).unwrap(), + PackedHijriYearData::try_new(1496, [l, l, s, l, l, s, s, l, s, s, l, s], gregorian(2073, 1, 10)).unwrap(), + PackedHijriYearData::try_new(1497, [l, l, s, l, l, s, l, s, l, s, s, l], gregorian(2073, 12, 30)).unwrap(), + PackedHijriYearData::try_new(1498, [s, l, s, l, l, s, l, l, s, l, s, l], gregorian(2074, 12, 20)).unwrap(), + PackedHijriYearData::try_new(1499, [s, s, l, s, l, s, l, l, s, l, l, s], gregorian(2075, 12, 10)).unwrap(), + PackedHijriYearData::try_new(1500, [l, s, s, l, s, l, s, l, s, l, l, l], gregorian(2076, 11, 28)).unwrap(), + PackedHijriYearData::try_new(1501, [s, l, s, l, s, s, l, s, s, l, l, l], gregorian(2077, 11, 18)).unwrap(), + PackedHijriYearData::try_new(1502, [s, l, l, s, l, s, s, l, s, s, l, l], gregorian(2078, 11, 7)).unwrap(), + PackedHijriYearData::try_new(1503, [l, s, l, l, s, l, s, s, l, s, s, l], gregorian(2079, 10, 27)).unwrap(), + PackedHijriYearData::try_new(1504, [l, s, l, l, s, l, l, s, s, l, s, l], gregorian(2080, 10, 15)).unwrap(), + PackedHijriYearData::try_new(1505, [s, s, l, l, s, l, l, s, l, s, l, s], gregorian(2081, 10, 5)).unwrap(), + PackedHijriYearData::try_new(1506, [l, s, s, l, s, l, l, s, l, l, s, l], gregorian(2082, 9, 24)).unwrap(), + PackedHijriYearData::try_new(1507, [l, s, s, s, l, s, l, s, l, l, l, l], gregorian(2083, 9, 14)).unwrap(), + PackedHijriYearData::try_new(1508, [s, s, l, s, s, l, s, l, s, l, l, l], gregorian(2084, 9, 3)).unwrap(), + PackedHijriYearData::try_new(1509, [s, l, s, l, s, s, l, s, l, s, l, l], gregorian(2085, 8, 23)).unwrap(), + PackedHijriYearData::try_new(1510, [s, l, s, l, l, s, l, s, s, l, s, l], gregorian(2086, 8, 12)).unwrap(), + PackedHijriYearData::try_new(1511, [s, l, s, l, l, s, l, l, s, s, l, s], gregorian(2087, 8, 1)).unwrap(), + PackedHijriYearData::try_new(1512, [l, s, s, l, l, l, s, l, l, s, s, l], gregorian(2088, 7, 20)).unwrap(), + PackedHijriYearData::try_new(1513, [s, s, l, s, l, l, s, l, l, s, l, s], gregorian(2089, 7, 10)).unwrap(), + PackedHijriYearData::try_new(1514, [l, s, s, l, s, l, s, l, l, l, s, l], gregorian(2090, 6, 29)).unwrap(), + PackedHijriYearData::try_new(1515, [s, l, s, s, l, s, l, s, l, l, s, l], gregorian(2091, 6, 19)).unwrap(), + PackedHijriYearData::try_new(1516, [l, s, l, s, s, l, s, l, s, l, s, l], gregorian(2092, 6, 7)).unwrap(), + PackedHijriYearData::try_new(1517, [l, s, l, s, l, s, l, s, l, s, l, s], gregorian(2093, 5, 27)).unwrap(), + PackedHijriYearData::try_new(1518, [l, s, l, l, s, l, l, s, s, l, s, l], gregorian(2094, 5, 16)).unwrap(), + PackedHijriYearData::try_new(1519, [s, s, l, l, s, l, l, s, l, s, l, s], gregorian(2095, 5, 6)).unwrap(), + PackedHijriYearData::try_new(1520, [l, s, s, l, s, l, l, l, s, l, l, s], gregorian(2096, 4, 24)).unwrap(), + PackedHijriYearData::try_new(1521, [s, l, s, s, l, s, l, l, s, l, l, l], gregorian(2097, 4, 14)).unwrap(), + PackedHijriYearData::try_new(1522, [s, s, l, s, s, l, s, l, s, l, l, l], gregorian(2098, 4, 4)).unwrap(), + PackedHijriYearData::try_new(1523, [s, l, s, l, s, s, l, s, l, s, l, l], gregorian(2099, 3, 24)).unwrap(), + PackedHijriYearData::try_new(1524, [s, l, l, s, l, s, l, s, s, l, s, l], gregorian(2100, 3, 13)).unwrap(), + PackedHijriYearData::try_new(1525, [s, l, l, s, l, l, s, l, s, s, l, s], gregorian(2101, 3, 2)).unwrap(), + PackedHijriYearData::try_new(1526, [l, s, l, s, l, l, l, s, l, s, s, l], gregorian(2102, 2, 19)).unwrap(), + PackedHijriYearData::try_new(1527, [s, l, s, l, s, l, l, l, s, s, l, s], gregorian(2103, 2, 9)).unwrap(), + PackedHijriYearData::try_new(1528, [l, s, l, s, s, l, l, l, s, l, s, l], gregorian(2104, 1, 29)).unwrap(), + PackedHijriYearData::try_new(1529, [s, l, s, l, s, l, s, l, s, l, s, l], gregorian(2105, 1, 18)).unwrap(), + PackedHijriYearData::try_new(1530, [l, s, l, s, l, s, l, s, s, l, s, l], gregorian(2106, 1, 7)).unwrap(), + PackedHijriYearData::try_new(1531, [l, l, s, l, s, l, s, l, s, s, l, s], gregorian(2106, 12, 27)).unwrap(), + PackedHijriYearData::try_new(1532, [l, l, l, s, l, s, l, s, s, l, s, s], gregorian(2107, 12, 16)).unwrap(), + PackedHijriYearData::try_new(1533, [l, l, l, s, l, l, s, l, s, s, l, s], gregorian(2108, 12, 4)).unwrap(), + PackedHijriYearData::try_new(1534, [l, s, l, s, l, l, s, l, s, l, s, l], gregorian(2109, 11, 24)).unwrap(), + PackedHijriYearData::try_new(1535, [s, l, s, l, s, l, s, l, l, s, l, s], gregorian(2110, 11, 14)).unwrap(), + PackedHijriYearData::try_new(1536, [l, s, l, s, l, s, s, l, l, s, l, l], gregorian(2111, 11, 3)).unwrap(), + PackedHijriYearData::try_new(1537, [s, l, s, l, s, l, s, s, l, s, l, l], gregorian(2112, 10, 23)).unwrap(), + PackedHijriYearData::try_new(1538, [s, l, l, s, l, s, l, s, s, l, s, l], gregorian(2113, 10, 12)).unwrap(), + PackedHijriYearData::try_new(1539, [s, l, l, l, s, l, s, l, s, s, s, l], gregorian(2114, 10, 1)).unwrap(), + PackedHijriYearData::try_new(1540, [l, s, l, l, s, l, l, s, l, s, s, l], gregorian(2115, 9, 20)).unwrap(), + PackedHijriYearData::try_new(1541, [s, l, s, l, s, l, l, l, s, l, s, s], gregorian(2116, 9, 9)).unwrap(), + PackedHijriYearData::try_new(1542, [l, s, l, s, l, s, l, l, s, l, s, l], gregorian(2117, 8, 29)).unwrap(), + PackedHijriYearData::try_new(1543, [l, s, s, l, s, l, s, l, s, l, l, s], gregorian(2118, 8, 19)).unwrap(), + PackedHijriYearData::try_new(1544, [l, l, s, s, l, s, l, s, s, l, l, s], gregorian(2119, 8, 8)).unwrap(), + PackedHijriYearData::try_new(1545, [l, l, l, s, s, l, s, s, l, s, l, s], gregorian(2120, 7, 27)).unwrap(), + PackedHijriYearData::try_new(1546, [l, l, l, s, l, s, l, s, l, s, s, l], gregorian(2121, 7, 16)).unwrap(), + PackedHijriYearData::try_new(1547, [l, s, l, s, l, l, s, l, s, l, s, s], gregorian(2122, 7, 6)).unwrap(), + PackedHijriYearData::try_new(1548, [l, s, l, s, l, l, s, l, l, s, l, s], gregorian(2123, 6, 25)).unwrap(), + PackedHijriYearData::try_new(1549, [s, l, s, l, s, l, s, l, l, l, s, l], gregorian(2124, 6, 14)).unwrap(), + PackedHijriYearData::try_new(1550, [s, l, s, s, s, l, s, l, l, l, l, s], gregorian(2125, 6, 4)).unwrap(), + PackedHijriYearData::try_new(1551, [l, s, l, s, s, s, l, s, l, l, l, s], gregorian(2126, 5, 24)).unwrap(), + PackedHijriYearData::try_new(1552, [l, l, s, s, l, s, s, l, s, l, l, s], gregorian(2127, 5, 13)).unwrap(), + PackedHijriYearData::try_new(1553, [l, l, s, l, s, l, s, l, s, s, l, s], gregorian(2128, 5, 1)).unwrap(), + PackedHijriYearData::try_new(1554, [l, l, s, l, s, l, l, s, l, s, s, l], gregorian(2129, 4, 20)).unwrap(), + PackedHijriYearData::try_new(1555, [s, l, s, l, s, l, l, l, s, l, s, l], gregorian(2130, 4, 10)).unwrap(), + PackedHijriYearData::try_new(1556, [s, s, l, s, l, s, l, l, l, s, l, s], gregorian(2131, 3, 31)).unwrap(), + PackedHijriYearData::try_new(1557, [l, s, s, l, s, s, l, l, l, s, l, l], gregorian(2132, 3, 19)).unwrap(), + PackedHijriYearData::try_new(1558, [s, l, s, s, s, l, s, l, l, s, l, l], gregorian(2133, 3, 9)).unwrap(), + PackedHijriYearData::try_new(1559, [l, s, l, s, s, l, s, s, l, s, l, l], gregorian(2134, 2, 26)).unwrap(), + PackedHijriYearData::try_new(1560, [l, s, l, s, l, s, l, s, l, s, s, l], gregorian(2135, 2, 15)).unwrap(), + PackedHijriYearData::try_new(1561, [l, s, l, l, s, l, s, l, s, l, s, s], gregorian(2136, 2, 4)).unwrap(), + PackedHijriYearData::try_new(1562, [l, s, l, l, s, l, l, s, l, s, l, s], gregorian(2137, 1, 23)).unwrap(), + PackedHijriYearData::try_new(1563, [s, l, s, l, s, l, l, l, l, s, s, l], gregorian(2138, 1, 13)).unwrap(), + PackedHijriYearData::try_new(1564, [s, s, l, s, l, s, l, l, l, s, l, s], gregorian(2139, 1, 3)).unwrap(), + PackedHijriYearData::try_new(1565, [l, s, l, s, s, l, s, l, l, s, l, s], gregorian(2139, 12, 23)).unwrap(), + PackedHijriYearData::try_new(1566, [l, l, s, l, s, s, l, s, l, s, l, s], gregorian(2140, 12, 11)).unwrap(), + ] +}; diff --git a/deps/crates/vendor/icu_calendar/src/cal/hijri/ummalqura_data.rs b/deps/crates/vendor/icu_calendar/src/cal/hijri/ummalqura_data.rs index 718286a8c1f830..884d851795d8da 100644 --- a/deps/crates/vendor/icu_calendar/src/cal/hijri/ummalqura_data.rs +++ b/deps/crates/vendor/icu_calendar/src/cal/hijri/ummalqura_data.rs @@ -2,316 +2,401 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -use crate::provider::hijri::PackedHijriYearInfo; +//! Data obtained from ICU4C: +//! -pub const UMMALQURA_DATA_STARTING_YEAR: i32 = 1300; +use super::PackedHijriYearData; + +pub const STARTING_YEAR: i32 = 1300; #[rustfmt::skip] -pub const UMMALQURA_DATA: [PackedHijriYearInfo; 1601 - UMMALQURA_DATA_STARTING_YEAR as usize] = { - use calendrical_calculations::iso::const_fixed_from_iso as iso; +#[allow(clippy::unwrap_used)] // const +pub const DATA: &[PackedHijriYearData] = { + use calendrical_calculations::gregorian::fixed_from_gregorian as gregorian; let l = true; // long let s = false; // short - [ - PackedHijriYearInfo::new(UMMALQURA_DATA_STARTING_YEAR, [l, s, l, s, l, s, l, s, l, s, l, s], iso(1882, 11, 12)), - PackedHijriYearInfo::new(1301, [l, l, s, l, s, l, s, l, s, l, s, s], iso(1883, 11, 1)), - PackedHijriYearInfo::new(1302, [l, l, l, s, l, l, s, s, l, s, s, l], iso(1884, 10, 20)), - PackedHijriYearInfo::new(1303, [s, l, l, s, l, l, s, l, s, l, s, s], iso(1885, 10, 10)), - PackedHijriYearInfo::new(1304, [s, l, l, s, l, l, l, s, l, s, l, s], iso(1886, 9, 29)), - PackedHijriYearInfo::new(1305, [s, s, l, l, s, l, l, s, l, l, s, s], iso(1887, 9, 19)), - PackedHijriYearInfo::new(1306, [l, s, l, s, l, s, l, s, l, l, s, l], iso(1888, 9, 7)), - PackedHijriYearInfo::new(1307, [s, l, s, l, s, l, s, l, s, l, s, l], iso(1889, 8, 28)), - PackedHijriYearInfo::new(1308, [s, l, l, s, l, s, l, s, l, s, s, l], iso(1890, 8, 17)), - PackedHijriYearInfo::new(1309, [s, l, l, l, l, s, s, l, s, s, l, s], iso(1891, 8, 6)), - PackedHijriYearInfo::new(1310, [l, s, l, l, l, s, l, s, l, s, s, l], iso(1892, 7, 25)), - PackedHijriYearInfo::new(1311, [s, l, s, l, l, l, s, l, s, l, s, s], iso(1893, 7, 15)), - PackedHijriYearInfo::new(1312, [l, s, l, s, l, l, s, l, l, s, l, s], iso(1894, 7, 4)), - PackedHijriYearInfo::new(1313, [s, l, s, l, s, l, s, l, l, l, s, s], iso(1895, 6, 24)), - PackedHijriYearInfo::new(1314, [l, l, s, l, s, s, l, s, l, l, s, l], iso(1896, 6, 12)), - PackedHijriYearInfo::new(1315, [s, l, l, s, l, s, s, l, s, l, s, l], iso(1897, 6, 2)), - PackedHijriYearInfo::new(1316, [s, l, l, l, s, l, s, s, l, s, l, s], iso(1898, 5, 22)), - PackedHijriYearInfo::new(1317, [l, s, l, l, s, l, s, l, s, l, s, s], iso(1899, 5, 11)), - PackedHijriYearInfo::new(1318, [l, s, l, l, s, l, l, s, l, s, l, s], iso(1900, 4, 30)), - PackedHijriYearInfo::new(1319, [s, l, s, l, l, s, l, s, l, l, s, l], iso(1901, 4, 20)), - PackedHijriYearInfo::new(1320, [s, l, s, s, l, s, l, s, l, l, l, s], iso(1902, 4, 10)), - PackedHijriYearInfo::new(1321, [l, s, l, s, s, l, s, s, l, l, l, l], iso(1903, 3, 30)), - PackedHijriYearInfo::new(1322, [s, l, s, l, s, s, s, l, s, l, l, l], iso(1904, 3, 19)), - PackedHijriYearInfo::new(1323, [s, l, l, s, l, s, s, s, l, s, l, l], iso(1905, 3, 8)), - PackedHijriYearInfo::new(1324, [s, l, l, s, l, s, l, s, s, l, s, l], iso(1906, 2, 25)), - PackedHijriYearInfo::new(1325, [l, s, l, s, l, l, s, l, s, l, s, l], iso(1907, 2, 14)), - PackedHijriYearInfo::new(1326, [s, s, l, s, l, l, s, l, s, l, l, s], iso(1908, 2, 4)), - PackedHijriYearInfo::new(1327, [l, s, s, l, s, l, s, l, l, s, l, l], iso(1909, 1, 23)), - PackedHijriYearInfo::new(1328, [s, l, s, s, l, s, s, l, l, l, s, l], iso(1910, 1, 13)), - PackedHijriYearInfo::new(1329, [l, s, l, s, s, l, s, s, l, l, s, l], iso(1911, 1, 2)), - PackedHijriYearInfo::new(1330, [l, l, s, l, s, s, l, s, s, l, l, s], iso(1911, 12, 22)), - PackedHijriYearInfo::new(1331, [l, l, s, l, l, s, s, l, s, l, s, l], iso(1912, 12, 10)), - PackedHijriYearInfo::new(1332, [s, l, s, l, l, s, l, s, l, l, s, s], iso(1913, 11, 30)), - PackedHijriYearInfo::new(1333, [l, s, s, l, l, s, l, l, s, l, l, s], iso(1914, 11, 19)), - PackedHijriYearInfo::new(1334, [s, s, l, s, l, s, l, l, l, s, l, s], iso(1915, 11, 9)), - PackedHijriYearInfo::new(1335, [l, s, l, s, s, l, s, l, l, s, l, l], iso(1916, 10, 28)), - PackedHijriYearInfo::new(1336, [s, l, s, l, s, s, l, s, l, s, l, l], iso(1917, 10, 18)), - PackedHijriYearInfo::new(1337, [l, s, l, s, l, s, s, l, s, l, s, l], iso(1918, 10, 7)), - PackedHijriYearInfo::new(1338, [s, l, l, s, l, l, s, s, l, s, l, s], iso(1919, 9, 26)), - PackedHijriYearInfo::new(1339, [l, s, l, s, l, l, l, s, l, s, s, l], iso(1920, 9, 14)), - PackedHijriYearInfo::new(1340, [s, s, l, s, l, l, l, l, s, l, s, s], iso(1921, 9, 4)), - PackedHijriYearInfo::new(1341, [l, s, s, l, s, l, l, l, s, l, l, s], iso(1922, 8, 24)), - PackedHijriYearInfo::new(1342, [s, s, l, s, l, s, l, l, s, l, l, s], iso(1923, 8, 14)), - PackedHijriYearInfo::new(1343, [l, s, s, l, s, l, s, l, s, l, l, s], iso(1924, 8, 2)), - PackedHijriYearInfo::new(1344, [l, s, l, s, l, l, s, s, l, s, l, s], iso(1925, 7, 22)), - PackedHijriYearInfo::new(1345, [l, s, l, l, l, s, l, s, s, l, s, s], iso(1926, 7, 11)), - PackedHijriYearInfo::new(1346, [l, s, l, l, l, l, s, l, s, s, l, s], iso(1927, 6, 30)), - PackedHijriYearInfo::new(1347, [s, l, s, l, l, l, s, l, l, s, s, l], iso(1928, 6, 19)), - PackedHijriYearInfo::new(1348, [s, s, l, s, l, l, s, l, l, l, s, s], iso(1929, 6, 9)), - PackedHijriYearInfo::new(1349, [l, s, s, l, s, l, l, s, l, l, s, l], iso(1930, 5, 29)), - PackedHijriYearInfo::new(1350, [s, l, s, l, s, l, s, s, l, l, s, l], iso(1931, 5, 19)), - PackedHijriYearInfo::new(1351, [l, s, l, s, l, s, l, s, s, l, s, l], iso(1932, 5, 7)), - PackedHijriYearInfo::new(1352, [l, s, l, l, s, l, s, l, s, s, l, s], iso(1933, 4, 26)), - PackedHijriYearInfo::new(1353, [l, s, l, l, l, s, l, s, s, l, s, l], iso(1934, 4, 15)), - PackedHijriYearInfo::new(1354, [s, l, s, l, l, s, l, l, s, l, s, s], iso(1935, 4, 5)), - PackedHijriYearInfo::new(1355, [l, s, s, l, l, s, l, l, s, l, l, s], iso(1936, 3, 24)), - PackedHijriYearInfo::new(1356, [s, l, s, l, s, l, s, l, s, l, l, l], iso(1937, 3, 14)), - PackedHijriYearInfo::new(1357, [s, s, l, s, l, s, s, l, s, l, l, l], iso(1938, 3, 4)), - PackedHijriYearInfo::new(1358, [s, l, s, l, s, l, s, s, l, s, l, l], iso(1939, 2, 21)), - PackedHijriYearInfo::new(1359, [s, l, l, s, l, s, l, s, s, s, l, l], iso(1940, 2, 10)), - PackedHijriYearInfo::new(1360, [s, l, l, l, s, l, s, l, s, s, l, s], iso(1941, 1, 29)), - PackedHijriYearInfo::new(1361, [l, s, l, l, s, l, l, s, s, l, s, l], iso(1942, 1, 18)), - PackedHijriYearInfo::new(1362, [s, l, s, l, s, l, l, s, l, s, l, s], iso(1943, 1, 8)), - PackedHijriYearInfo::new(1363, [l, s, l, s, l, s, l, s, l, s, l, l], iso(1943, 12, 28)), - PackedHijriYearInfo::new(1364, [s, l, s, l, s, s, l, s, l, s, l, l], iso(1944, 12, 17)), - PackedHijriYearInfo::new(1365, [l, l, s, s, l, s, s, l, s, l, s, l], iso(1945, 12, 6)), - PackedHijriYearInfo::new(1366, [l, l, s, l, s, l, s, s, l, s, l, s], iso(1946, 11, 25)), - PackedHijriYearInfo::new(1367, [l, l, s, l, l, s, l, s, s, l, s, l], iso(1947, 11, 14)), - PackedHijriYearInfo::new(1368, [s, l, s, l, l, l, s, s, l, s, l, s], iso(1948, 11, 3)), - PackedHijriYearInfo::new(1369, [l, s, l, s, l, l, s, l, s, l, l, s], iso(1949, 10, 23)), - PackedHijriYearInfo::new(1370, [l, s, s, l, s, l, s, l, s, l, l, l], iso(1950, 10, 13)), - PackedHijriYearInfo::new(1371, [s, l, s, s, l, s, l, s, l, s, l, l], iso(1951, 10, 3)), - PackedHijriYearInfo::new(1372, [l, s, s, l, s, l, s, s, l, s, l, l], iso(1952, 9, 21)), - PackedHijriYearInfo::new(1373, [l, s, l, s, l, s, l, s, s, l, s, l], iso(1953, 9, 10)), - PackedHijriYearInfo::new(1374, [l, s, l, l, s, l, s, l, s, s, l, s], iso(1954, 8, 30)), - PackedHijriYearInfo::new(1375, [l, s, l, l, s, l, l, s, l, s, l, s], iso(1955, 8, 19)), - PackedHijriYearInfo::new(1376, [s, l, s, l, s, l, l, l, s, l, s, l], iso(1956, 8, 8)), - PackedHijriYearInfo::new(1377, [s, s, l, s, s, l, l, l, s, l, l, s], iso(1957, 7, 29)), - PackedHijriYearInfo::new(1378, [l, s, s, s, l, s, l, l, s, l, l, l], iso(1958, 7, 18)), - PackedHijriYearInfo::new(1379, [s, l, s, s, s, l, s, l, l, s, l, l], iso(1959, 7, 8)), - PackedHijriYearInfo::new(1380, [s, l, s, l, s, l, s, l, s, l, s, l], iso(1960, 6, 26)), - PackedHijriYearInfo::new(1381, [s, l, s, l, l, s, l, s, l, s, s, l], iso(1961, 6, 15)), - PackedHijriYearInfo::new(1382, [s, l, s, l, l, s, l, l, s, l, s, s], iso(1962, 6, 4)), - PackedHijriYearInfo::new(1383, [l, s, s, l, l, l, s, l, l, s, l, s], iso(1963, 5, 24)), - PackedHijriYearInfo::new(1384, [s, l, s, s, l, l, s, l, l, l, s, l], iso(1964, 5, 13)), - PackedHijriYearInfo::new(1385, [s, s, l, s, s, l, l, s, l, l, l, s], iso(1965, 5, 3)), - PackedHijriYearInfo::new(1386, [l, s, s, l, s, s, l, l, s, l, l, s], iso(1966, 4, 22)), - PackedHijriYearInfo::new(1387, [l, s, l, s, l, s, l, s, l, s, l, s], iso(1967, 4, 11)), - PackedHijriYearInfo::new(1388, [l, l, s, l, s, l, s, l, s, l, s, s], iso(1968, 3, 30)), - PackedHijriYearInfo::new(1389, [l, l, s, l, l, s, l, l, s, s, l, s], iso(1969, 3, 19)), - PackedHijriYearInfo::new(1390, [s, l, s, l, l, l, s, l, s, l, s, l], iso(1970, 3, 9)), - PackedHijriYearInfo::new(1391, [s, s, l, s, l, l, s, l, l, s, l, s], iso(1971, 2, 27)), - PackedHijriYearInfo::new(1392, [l, s, s, l, s, l, s, l, l, s, l, l], iso(1972, 2, 16)), - PackedHijriYearInfo::new(1393, [s, l, s, s, l, s, l, s, l, s, l, l], iso(1973, 2, 5)), - PackedHijriYearInfo::new(1394, [l, s, l, s, s, l, s, l, s, l, s, l], iso(1974, 1, 25)), - PackedHijriYearInfo::new(1395, [l, s, l, l, s, l, s, s, l, s, s, l], iso(1975, 1, 14)), - PackedHijriYearInfo::new(1396, [l, s, l, l, s, l, l, s, s, l, s, s], iso(1976, 1, 3)), - PackedHijriYearInfo::new(1397, [l, s, l, l, s, l, l, l, s, s, s, l], iso(1976, 12, 22)), - PackedHijriYearInfo::new(1398, [s, l, s, l, l, s, l, l, s, l, s, s], iso(1977, 12, 12)), - PackedHijriYearInfo::new(1399, [l, s, l, s, l, s, l, l, s, l, s, l], iso(1978, 12, 1)), - PackedHijriYearInfo::new(1400, [l, s, l, s, s, l, s, l, s, l, s, l], iso(1979, 11, 21)), - PackedHijriYearInfo::new(1401, [l, l, s, l, s, s, l, s, s, l, s, l], iso(1980, 11, 9)), - PackedHijriYearInfo::new(1402, [l, l, l, s, l, s, s, l, s, s, l, s], iso(1981, 10, 29)), - PackedHijriYearInfo::new(1403, [l, l, l, s, l, l, s, s, l, s, s, l], iso(1982, 10, 18)), - PackedHijriYearInfo::new(1404, [s, l, l, s, l, l, s, l, s, l, s, s], iso(1983, 10, 8)), - PackedHijriYearInfo::new(1405, [l, s, l, s, l, l, l, s, l, s, s, l], iso(1984, 9, 26)), - PackedHijriYearInfo::new(1406, [l, s, s, l, s, l, l, s, l, s, l, l], iso(1985, 9, 16)), - PackedHijriYearInfo::new(1407, [s, l, s, s, l, s, l, s, l, s, l, l], iso(1986, 9, 6)), - PackedHijriYearInfo::new(1408, [l, s, l, s, l, s, s, l, s, s, l, l], iso(1987, 8, 26)), - PackedHijriYearInfo::new(1409, [l, l, s, l, s, l, s, s, l, s, s, l], iso(1988, 8, 14)), - PackedHijriYearInfo::new(1410, [l, l, s, l, l, s, l, s, s, l, s, s], iso(1989, 8, 3)), - PackedHijriYearInfo::new(1411, [l, l, s, l, l, s, l, l, s, s, l, s], iso(1990, 7, 23)), - PackedHijriYearInfo::new(1412, [l, s, l, s, l, s, l, l, l, s, s, l], iso(1991, 7, 13)), - PackedHijriYearInfo::new(1413, [s, l, s, s, l, s, l, l, l, s, l, s], iso(1992, 7, 2)), - PackedHijriYearInfo::new(1414, [l, s, l, s, s, l, s, l, l, s, l, l], iso(1993, 6, 21)), - PackedHijriYearInfo::new(1415, [s, l, s, l, s, s, l, s, l, s, l, l], iso(1994, 6, 11)), - PackedHijriYearInfo::new(1416, [l, s, l, s, l, s, s, l, s, l, s, l], iso(1995, 5, 31)), - PackedHijriYearInfo::new(1417, [l, s, l, l, s, s, l, s, l, s, l, s], iso(1996, 5, 19)), - PackedHijriYearInfo::new(1418, [l, s, l, l, s, l, s, l, s, l, s, l], iso(1997, 5, 8)), - PackedHijriYearInfo::new(1419, [s, l, s, l, s, l, s, l, l, l, s, s], iso(1998, 4, 28)), - PackedHijriYearInfo::new(1420, [s, l, s, s, l, s, l, l, l, l, s, l], iso(1999, 4, 17)), - PackedHijriYearInfo::new(1421, [s, s, l, s, s, s, l, l, l, l, s, l], iso(2000, 4, 6)), - PackedHijriYearInfo::new(1422, [l, s, s, l, s, s, s, l, l, l, s, l], iso(2001, 3, 26)), - PackedHijriYearInfo::new(1423, [l, s, l, s, l, s, s, l, s, l, s, l], iso(2002, 3, 15)), - PackedHijriYearInfo::new(1424, [l, s, l, l, s, l, s, s, l, s, l, s], iso(2003, 3, 4)), - PackedHijriYearInfo::new(1425, [l, s, l, l, s, l, s, l, l, s, l, s], iso(2004, 2, 21)), - PackedHijriYearInfo::new(1426, [s, l, s, l, s, l, l, s, l, l, s, l], iso(2005, 2, 10)), - PackedHijriYearInfo::new(1427, [s, s, l, s, l, s, l, l, s, l, l, s], iso(2006, 1, 31)), - PackedHijriYearInfo::new(1428, [l, s, s, l, s, s, l, l, l, s, l, l], iso(2007, 1, 20)), - PackedHijriYearInfo::new(1429, [s, l, s, s, l, s, s, l, l, s, l, l], iso(2008, 1, 10)), - PackedHijriYearInfo::new(1430, [s, l, l, s, s, l, s, l, s, l, s, l], iso(2008, 12, 29)), - PackedHijriYearInfo::new(1431, [s, l, l, s, l, s, l, s, l, s, s, l], iso(2009, 12, 18)), - PackedHijriYearInfo::new(1432, [s, l, l, l, s, l, s, l, s, l, s, s], iso(2010, 12, 7)), - PackedHijriYearInfo::new(1433, [l, s, l, l, s, l, l, s, l, s, l, s], iso(2011, 11, 26)), - PackedHijriYearInfo::new(1434, [s, l, s, l, s, l, l, s, l, l, s, s], iso(2012, 11, 15)), - PackedHijriYearInfo::new(1435, [l, s, l, s, l, s, l, s, l, l, s, l], iso(2013, 11, 4)), - PackedHijriYearInfo::new(1436, [s, l, s, l, s, l, s, l, s, l, s, l], iso(2014, 10, 25)), - PackedHijriYearInfo::new(1437, [l, s, l, l, s, s, l, s, l, s, s, l], iso(2015, 10, 14)), - PackedHijriYearInfo::new(1438, [l, s, l, l, l, s, s, l, s, s, l, s], iso(2016, 10, 2)), - PackedHijriYearInfo::new(1439, [l, s, l, l, l, s, l, s, l, s, s, l], iso(2017, 9, 21)), - PackedHijriYearInfo::new(1440, [s, l, s, l, l, l, s, l, s, l, s, s], iso(2018, 9, 11)), - PackedHijriYearInfo::new(1441, [l, s, l, s, l, l, s, l, l, s, l, s], iso(2019, 8, 31)), - PackedHijriYearInfo::new(1442, [s, l, s, l, s, l, s, l, l, s, l, s], iso(2020, 8, 20)), - PackedHijriYearInfo::new(1443, [l, s, l, s, l, s, l, s, l, s, l, l], iso(2021, 8, 9)), - PackedHijriYearInfo::new(1444, [s, l, s, l, l, s, s, l, s, l, s, l], iso(2022, 7, 30)), - PackedHijriYearInfo::new(1445, [s, l, l, l, s, l, s, s, l, s, s, l], iso(2023, 7, 19)), - PackedHijriYearInfo::new(1446, [s, l, l, l, s, l, l, s, s, l, s, s], iso(2024, 7, 7)), - PackedHijriYearInfo::new(1447, [l, s, l, l, l, s, l, s, l, s, l, s], iso(2025, 6, 26)), - PackedHijriYearInfo::new(1448, [s, l, s, l, l, s, l, l, s, l, s, l], iso(2026, 6, 16)), - PackedHijriYearInfo::new(1449, [s, s, l, s, l, s, l, l, s, l, l, s], iso(2027, 6, 6)), - PackedHijriYearInfo::new(1450, [l, s, l, s, s, l, s, l, s, l, l, s], iso(2028, 5, 25)), - PackedHijriYearInfo::new(1451, [l, l, l, s, s, l, s, s, l, l, s, l], iso(2029, 5, 14)), - PackedHijriYearInfo::new(1452, [l, s, l, l, s, s, l, s, s, l, s, l], iso(2030, 5, 4)), - PackedHijriYearInfo::new(1453, [l, s, l, l, s, l, s, l, s, s, l, s], iso(2031, 4, 23)), - PackedHijriYearInfo::new(1454, [l, s, l, l, s, l, l, s, l, s, l, s], iso(2032, 4, 11)), - PackedHijriYearInfo::new(1455, [s, l, s, l, l, s, l, s, l, l, s, l], iso(2033, 4, 1)), - PackedHijriYearInfo::new(1456, [s, s, l, s, l, s, l, s, l, l, l, s], iso(2034, 3, 22)), - PackedHijriYearInfo::new(1457, [l, s, s, l, s, s, l, s, l, l, l, l], iso(2035, 3, 11)), - PackedHijriYearInfo::new(1458, [s, l, s, s, l, s, s, l, s, l, l, l], iso(2036, 2, 29)), - PackedHijriYearInfo::new(1459, [s, l, l, s, s, l, s, s, l, s, l, l], iso(2037, 2, 17)), - PackedHijriYearInfo::new(1460, [s, l, l, s, l, s, l, s, s, l, s, l], iso(2038, 2, 6)), - PackedHijriYearInfo::new(1461, [s, l, l, s, l, s, l, s, l, l, s, s], iso(2039, 1, 26)), - PackedHijriYearInfo::new(1462, [l, s, l, s, l, l, s, l, s, l, l, s], iso(2040, 1, 15)), - PackedHijriYearInfo::new(1463, [s, l, s, l, s, l, s, l, l, l, s, l], iso(2041, 1, 4)), - PackedHijriYearInfo::new(1464, [s, l, s, s, l, s, s, l, l, l, s, l], iso(2041, 12, 25)), - PackedHijriYearInfo::new(1465, [l, s, l, s, s, l, s, s, l, l, s, l], iso(2042, 12, 14)), - PackedHijriYearInfo::new(1466, [l, l, s, l, s, s, s, l, s, l, l, s], iso(2043, 12, 3)), - PackedHijriYearInfo::new(1467, [l, l, s, l, l, s, s, l, s, l, s, l], iso(2044, 11, 21)), - PackedHijriYearInfo::new(1468, [s, l, s, l, l, s, l, s, l, s, l, s], iso(2045, 11, 11)), - PackedHijriYearInfo::new(1469, [s, l, s, l, l, s, l, l, s, l, s, l], iso(2046, 10, 31)), - PackedHijriYearInfo::new(1470, [s, s, l, s, l, l, s, l, l, s, l, s], iso(2047, 10, 21)), - PackedHijriYearInfo::new(1471, [l, s, s, l, s, l, s, l, l, s, l, l], iso(2048, 10, 9)), - PackedHijriYearInfo::new(1472, [s, l, s, s, l, s, l, s, l, l, s, l], iso(2049, 9, 29)), - PackedHijriYearInfo::new(1473, [s, l, s, l, l, s, s, l, s, l, s, l], iso(2050, 9, 18)), - PackedHijriYearInfo::new(1474, [s, l, l, s, l, l, s, s, l, s, l, s], iso(2051, 9, 7)), - PackedHijriYearInfo::new(1475, [s, l, l, s, l, l, l, s, s, l, s, s], iso(2052, 8, 26)), - PackedHijriYearInfo::new(1476, [l, s, l, s, l, l, l, s, l, s, l, s], iso(2053, 8, 15)), - PackedHijriYearInfo::new(1477, [s, l, s, s, l, l, l, l, s, l, s, l], iso(2054, 8, 5)), - PackedHijriYearInfo::new(1478, [s, s, l, s, l, s, l, l, s, l, l, s], iso(2055, 7, 26)), - PackedHijriYearInfo::new(1479, [l, s, s, l, s, l, s, l, s, l, l, s], iso(2056, 7, 14)), - PackedHijriYearInfo::new(1480, [l, s, l, s, l, s, l, s, l, s, l, s], iso(2057, 7, 3)), - PackedHijriYearInfo::new(1481, [l, s, l, l, s, l, s, l, s, l, s, s], iso(2058, 6, 22)), - PackedHijriYearInfo::new(1482, [l, s, l, l, l, l, s, l, s, s, l, s], iso(2059, 6, 11)), - PackedHijriYearInfo::new(1483, [s, l, s, l, l, l, s, l, l, s, s, l], iso(2060, 5, 31)), - PackedHijriYearInfo::new(1484, [s, s, l, s, l, l, l, s, l, s, l, s], iso(2061, 5, 21)), - PackedHijriYearInfo::new(1485, [l, s, s, l, s, l, l, s, l, l, s, l], iso(2062, 5, 10)), - PackedHijriYearInfo::new(1486, [s, l, s, s, l, s, l, s, l, l, s, l], iso(2063, 4, 30)), - PackedHijriYearInfo::new(1487, [l, s, l, s, l, s, s, l, s, l, s, l], iso(2064, 4, 18)), - PackedHijriYearInfo::new(1488, [l, s, l, l, s, l, s, s, l, s, l, s], iso(2065, 4, 7)), - PackedHijriYearInfo::new(1489, [l, s, l, l, l, s, l, s, s, l, s, l], iso(2066, 3, 27)), - PackedHijriYearInfo::new(1490, [s, l, s, l, l, s, l, l, s, s, l, s], iso(2067, 3, 17)), - PackedHijriYearInfo::new(1491, [l, s, s, l, l, s, l, l, s, l, s, l], iso(2068, 3, 5)), - PackedHijriYearInfo::new(1492, [s, l, s, s, l, l, s, l, s, l, l, s], iso(2069, 2, 23)), - PackedHijriYearInfo::new(1493, [l, s, l, s, l, s, s, l, s, l, l, l], iso(2070, 2, 12)), - PackedHijriYearInfo::new(1494, [s, l, s, l, s, l, s, s, s, l, l, l], iso(2071, 2, 2)), - PackedHijriYearInfo::new(1495, [s, l, l, s, l, s, s, l, s, s, l, l], iso(2072, 1, 22)), - PackedHijriYearInfo::new(1496, [s, l, l, l, s, l, s, s, l, s, s, l], iso(2073, 1, 10)), - PackedHijriYearInfo::new(1497, [l, s, l, l, s, l, s, l, s, l, s, l], iso(2073, 12, 30)), - PackedHijriYearInfo::new(1498, [s, l, s, l, s, l, l, s, l, s, l, s], iso(2074, 12, 20)), - PackedHijriYearInfo::new(1499, [l, s, l, s, s, l, l, s, l, s, l, l], iso(2075, 12, 9)), - PackedHijriYearInfo::new(1500, [s, l, s, l, s, s, l, s, l, s, l, l], iso(2076, 11, 28)), - PackedHijriYearInfo::new(1501, [l, s, l, s, l, s, s, s, l, s, l, l], iso(2077, 11, 17)), - PackedHijriYearInfo::new(1502, [l, l, s, l, s, l, s, s, s, l, l, s], iso(2078, 11, 6)), - PackedHijriYearInfo::new(1503, [l, l, s, l, l, s, l, s, s, s, l, l], iso(2079, 10, 26)), - PackedHijriYearInfo::new(1504, [s, l, s, l, l, l, s, s, l, s, l, s], iso(2080, 10, 15)), - PackedHijriYearInfo::new(1505, [l, s, l, s, l, l, s, l, s, l, l, s], iso(2081, 10, 4)), - PackedHijriYearInfo::new(1506, [s, l, s, s, l, l, s, l, l, s, l, l], iso(2082, 9, 24)), - PackedHijriYearInfo::new(1507, [s, s, l, s, s, l, l, s, l, s, l, l], iso(2083, 9, 14)), - PackedHijriYearInfo::new(1508, [l, s, s, l, s, l, s, s, l, s, l, l], iso(2084, 9, 2)), - PackedHijriYearInfo::new(1509, [l, s, l, s, l, s, l, s, s, l, s, l], iso(2085, 8, 22)), - PackedHijriYearInfo::new(1510, [l, s, l, l, s, l, s, l, s, s, l, s], iso(2086, 8, 11)), - PackedHijriYearInfo::new(1511, [l, s, l, l, s, l, l, s, l, s, s, l], iso(2087, 7, 31)), - PackedHijriYearInfo::new(1512, [s, l, s, l, s, l, l, l, s, l, s, l], iso(2088, 7, 20)), - PackedHijriYearInfo::new(1513, [s, s, s, l, s, l, l, l, s, l, l, s], iso(2089, 7, 10)), - PackedHijriYearInfo::new(1514, [l, s, s, s, l, s, l, l, s, l, l, l], iso(2090, 6, 29)), - PackedHijriYearInfo::new(1515, [s, s, l, s, s, l, s, l, l, s, l, l], iso(2091, 6, 19)), - PackedHijriYearInfo::new(1516, [s, l, s, l, s, s, l, s, l, s, l, l], iso(2092, 6, 7)), - PackedHijriYearInfo::new(1517, [s, l, s, l, s, l, l, s, s, l, s, l], iso(2093, 5, 27)), - PackedHijriYearInfo::new(1518, [s, l, s, l, l, s, l, l, s, l, s, s], iso(2094, 5, 16)), - PackedHijriYearInfo::new(1519, [l, s, s, l, l, l, s, l, l, s, l, s], iso(2095, 5, 5)), - PackedHijriYearInfo::new(1520, [s, l, s, s, l, l, l, s, l, l, s, l], iso(2096, 4, 24)), - PackedHijriYearInfo::new(1521, [s, s, s, l, s, l, l, s, l, l, s, l], iso(2097, 4, 14)), - PackedHijriYearInfo::new(1522, [l, s, s, s, l, s, l, l, s, l, l, s], iso(2098, 4, 3)), - PackedHijriYearInfo::new(1523, [l, s, l, s, l, s, l, s, s, l, l, s], iso(2099, 3, 23)), - PackedHijriYearInfo::new(1524, [l, l, s, l, s, l, s, l, s, s, l, s], iso(2100, 3, 12)), - PackedHijriYearInfo::new(1525, [l, l, s, l, l, s, l, s, l, s, s, l], iso(2101, 3, 1)), - PackedHijriYearInfo::new(1526, [s, l, s, l, l, l, s, l, s, l, s, s], iso(2102, 2, 19)), - PackedHijriYearInfo::new(1527, [l, s, l, s, l, l, s, l, l, s, l, s], iso(2103, 2, 8)), - PackedHijriYearInfo::new(1528, [l, s, s, l, s, l, s, l, l, s, l, l], iso(2104, 1, 29)), - PackedHijriYearInfo::new(1529, [s, l, s, s, l, s, l, s, l, s, l, l], iso(2105, 1, 18)), - PackedHijriYearInfo::new(1530, [s, l, l, s, s, l, s, l, s, s, l, l], iso(2106, 1, 7)), - PackedHijriYearInfo::new(1531, [s, l, l, l, s, s, l, s, l, s, s, l], iso(2106, 12, 27)), - PackedHijriYearInfo::new(1532, [s, l, l, l, s, l, l, s, s, s, l, s], iso(2107, 12, 16)), - PackedHijriYearInfo::new(1533, [l, s, l, l, l, s, l, s, l, s, s, l], iso(2108, 12, 4)), - PackedHijriYearInfo::new(1534, [s, l, s, l, l, s, l, l, s, s, l, s], iso(2109, 11, 24)), - PackedHijriYearInfo::new(1535, [l, s, l, s, l, s, l, l, s, l, s, l], iso(2110, 11, 13)), - PackedHijriYearInfo::new(1536, [s, l, s, l, s, l, s, l, s, l, s, l], iso(2111, 11, 3)), - PackedHijriYearInfo::new(1537, [l, s, l, l, s, s, l, s, s, l, s, l], iso(2112, 10, 22)), - PackedHijriYearInfo::new(1538, [l, l, s, l, l, s, s, l, s, s, l, s], iso(2113, 10, 11)), - PackedHijriYearInfo::new(1539, [l, l, l, s, l, l, s, s, l, s, s, l], iso(2114, 9, 30)), - PackedHijriYearInfo::new(1540, [s, l, l, s, l, l, s, l, s, s, l, s], iso(2115, 9, 20)), - PackedHijriYearInfo::new(1541, [l, s, l, s, l, l, l, s, l, s, s, l], iso(2116, 9, 8)), - PackedHijriYearInfo::new(1542, [s, l, s, l, s, l, l, s, l, s, l, l], iso(2117, 8, 29)), - PackedHijriYearInfo::new(1543, [s, l, s, s, l, s, l, s, l, s, l, l], iso(2118, 8, 19)), - PackedHijriYearInfo::new(1544, [l, s, l, s, s, l, s, l, s, l, s, l], iso(2119, 8, 8)), - PackedHijriYearInfo::new(1545, [l, l, s, l, s, s, l, s, l, s, s, l], iso(2120, 7, 27)), - PackedHijriYearInfo::new(1546, [l, l, s, l, s, l, s, l, s, l, s, s], iso(2121, 7, 16)), - PackedHijriYearInfo::new(1547, [l, l, s, l, l, s, l, s, l, s, l, s], iso(2122, 7, 5)), - PackedHijriYearInfo::new(1548, [l, s, s, l, l, s, l, l, s, l, s, l], iso(2123, 6, 25)), - PackedHijriYearInfo::new(1549, [s, l, s, s, l, s, l, l, l, s, l, s], iso(2124, 6, 14)), - PackedHijriYearInfo::new(1550, [l, s, l, s, s, s, l, l, l, s, l, l], iso(2125, 6, 3)), - PackedHijriYearInfo::new(1551, [s, l, s, s, l, s, s, l, l, s, l, l], iso(2126, 5, 24)), - PackedHijriYearInfo::new(1552, [l, s, l, s, s, l, s, s, l, l, s, l], iso(2127, 5, 13)), - PackedHijriYearInfo::new(1553, [l, s, l, s, l, s, l, s, l, s, l, s], iso(2128, 5, 1)), - PackedHijriYearInfo::new(1554, [l, s, l, s, l, l, s, l, s, l, s, l], iso(2129, 4, 20)), - PackedHijriYearInfo::new(1555, [s, s, l, s, l, l, s, l, l, s, l, s], iso(2130, 4, 10)), - PackedHijriYearInfo::new(1556, [l, s, s, l, s, l, s, l, l, l, s, l], iso(2131, 3, 30)), - PackedHijriYearInfo::new(1557, [s, l, s, s, s, l, s, l, l, l, l, s], iso(2132, 3, 19)), - PackedHijriYearInfo::new(1558, [l, s, l, s, s, s, l, s, l, l, l, s], iso(2133, 3, 8)), - PackedHijriYearInfo::new(1559, [l, l, s, s, l, s, s, l, l, s, l, s], iso(2134, 2, 25)), - PackedHijriYearInfo::new(1560, [l, l, s, l, s, l, s, l, s, l, s, l], iso(2135, 2, 14)), - PackedHijriYearInfo::new(1561, [s, l, l, s, l, s, l, l, s, s, l, s], iso(2136, 2, 4)), - PackedHijriYearInfo::new(1562, [s, l, l, s, l, s, l, l, l, s, s, l], iso(2137, 1, 23)), - PackedHijriYearInfo::new(1563, [s, l, s, s, l, s, l, l, l, s, l, s], iso(2138, 1, 13)), - PackedHijriYearInfo::new(1564, [l, s, l, s, s, l, s, l, l, l, s, l], iso(2139, 1, 2)), - PackedHijriYearInfo::new(1565, [s, l, s, l, s, s, l, s, l, l, s, l], iso(2139, 12, 23)), - PackedHijriYearInfo::new(1566, [l, s, l, s, l, s, s, l, s, l, s, l], iso(2140, 12, 11)), - PackedHijriYearInfo::new(1567, [l, s, l, l, s, l, s, l, s, s, l, s], iso(2141, 11, 30)), - PackedHijriYearInfo::new(1568, [l, s, l, l, l, s, l, s, l, s, s, s], iso(2142, 11, 19)), - PackedHijriYearInfo::new(1569, [l, s, l, l, l, s, l, l, s, l, s, s], iso(2143, 11, 8)), - PackedHijriYearInfo::new(1570, [s, l, s, l, l, s, l, l, l, s, s, l], iso(2144, 10, 28)), - PackedHijriYearInfo::new(1571, [s, s, l, s, l, l, s, l, l, s, l, s], iso(2145, 10, 18)), - PackedHijriYearInfo::new(1572, [l, s, s, l, s, l, s, l, l, s, l, s], iso(2146, 10, 7)), - PackedHijriYearInfo::new(1573, [l, s, l, l, s, l, s, s, l, s, l, s], iso(2147, 9, 26)), - PackedHijriYearInfo::new(1574, [l, l, s, l, l, s, l, s, s, l, s, s], iso(2148, 9, 14)), - PackedHijriYearInfo::new(1575, [l, l, l, s, l, l, s, l, s, s, s, l], iso(2149, 9, 3)), - PackedHijriYearInfo::new(1576, [s, l, l, s, l, l, l, s, l, s, s, s], iso(2150, 8, 24)), - PackedHijriYearInfo::new(1577, [l, s, l, l, s, l, l, s, l, s, l, s], iso(2151, 8, 13)), - PackedHijriYearInfo::new(1578, [s, l, s, l, s, l, l, s, l, l, s, l], iso(2152, 8, 2)), - PackedHijriYearInfo::new(1579, [s, l, s, l, s, s, l, l, s, l, s, l], iso(2153, 7, 23)), - PackedHijriYearInfo::new(1580, [s, l, l, s, l, s, s, l, s, l, s, l], iso(2154, 7, 12)), - PackedHijriYearInfo::new(1581, [l, l, s, l, s, l, s, s, l, s, l, s], iso(2155, 7, 1)), - PackedHijriYearInfo::new(1582, [l, l, s, l, l, s, l, s, l, s, s, s], iso(2156, 6, 19)), - PackedHijriYearInfo::new(1583, [l, l, s, l, l, l, s, l, s, l, s, s], iso(2157, 6, 8)), - PackedHijriYearInfo::new(1584, [s, l, l, s, l, l, s, l, l, s, l, s], iso(2158, 5, 29)), - PackedHijriYearInfo::new(1585, [s, l, s, l, s, l, s, l, l, s, l, l], iso(2159, 5, 19)), - PackedHijriYearInfo::new(1586, [s, s, l, s, l, s, s, l, l, l, s, l], iso(2160, 5, 8)), - PackedHijriYearInfo::new(1587, [s, l, l, s, s, s, l, s, l, s, l, l], iso(2161, 4, 27)), - PackedHijriYearInfo::new(1588, [l, s, l, l, s, s, s, l, s, l, s, l], iso(2162, 4, 16)), - PackedHijriYearInfo::new(1589, [l, s, l, l, s, l, s, s, l, s, l, s], iso(2163, 4, 5)), - PackedHijriYearInfo::new(1590, [l, s, l, l, l, s, s, l, s, l, s, l], iso(2164, 3, 24)), - PackedHijriYearInfo::new(1591, [s, l, s, l, l, s, l, s, l, s, l, s], iso(2165, 3, 14)), - PackedHijriYearInfo::new(1592, [l, s, l, s, l, s, l, s, l, l, l, s], iso(2166, 3, 3)), - PackedHijriYearInfo::new(1593, [l, s, s, l, s, s, l, s, l, l, l, s], iso(2167, 2, 21)), - PackedHijriYearInfo::new(1594, [l, l, s, s, l, s, s, s, l, l, l, l], iso(2168, 2, 10)), - PackedHijriYearInfo::new(1595, [s, l, s, l, s, s, l, s, s, l, l, l], iso(2169, 1, 30)), - PackedHijriYearInfo::new(1596, [s, l, l, s, l, s, s, l, s, l, s, l], iso(2170, 1, 19)), - PackedHijriYearInfo::new(1597, [s, l, l, s, l, s, l, s, l, s, l, s], iso(2171, 1, 8)), - PackedHijriYearInfo::new(1598, [l, s, l, s, l, l, s, l, s, l, l, s], iso(2171, 12, 28)), - PackedHijriYearInfo::new(1599, [s, l, s, l, s, l, s, l, l, l, s, l], iso(2172, 12, 17)), - PackedHijriYearInfo::new(1600, [s, s, l, s, l, s, s, l, l, l, s, l], iso(2173, 12, 7)), + &[ + PackedHijriYearData::try_new(1300, [l, s, l, s, l, s, l, s, l, s, l, s], gregorian(1882, 11, 12)).unwrap(), + PackedHijriYearData::try_new(1301, [l, l, s, l, s, l, s, l, s, l, s, s], gregorian(1883, 11, 1)).unwrap(), + PackedHijriYearData::try_new(1302, [l, l, l, s, l, l, s, s, l, s, s, l], gregorian(1884, 10, 20)).unwrap(), + PackedHijriYearData::try_new(1303, [s, l, l, s, l, l, s, l, s, l, s, s], gregorian(1885, 10, 10)).unwrap(), + PackedHijriYearData::try_new(1304, [s, l, l, s, l, l, l, s, l, s, l, s], gregorian(1886, 9, 29)).unwrap(), + PackedHijriYearData::try_new(1305, [s, s, l, l, s, l, l, s, l, l, s, s], gregorian(1887, 9, 19)).unwrap(), + PackedHijriYearData::try_new(1306, [l, s, l, s, l, s, l, s, l, l, s, l], gregorian(1888, 9, 7)).unwrap(), + PackedHijriYearData::try_new(1307, [s, l, s, l, s, l, s, l, s, l, s, l], gregorian(1889, 8, 28)).unwrap(), + PackedHijriYearData::try_new(1308, [s, l, l, s, l, s, l, s, l, s, s, l], gregorian(1890, 8, 17)).unwrap(), + PackedHijriYearData::try_new(1309, [s, l, l, l, l, s, s, l, s, s, l, s], gregorian(1891, 8, 6)).unwrap(), + PackedHijriYearData::try_new(1310, [l, s, l, l, l, s, l, s, l, s, s, l], gregorian(1892, 7, 25)).unwrap(), + PackedHijriYearData::try_new(1311, [s, l, s, l, l, l, s, l, s, l, s, s], gregorian(1893, 7, 15)).unwrap(), + PackedHijriYearData::try_new(1312, [l, s, l, s, l, l, s, l, l, s, l, s], gregorian(1894, 7, 4)).unwrap(), + PackedHijriYearData::try_new(1313, [s, l, s, l, s, l, s, l, l, l, s, s], gregorian(1895, 6, 24)).unwrap(), + PackedHijriYearData::try_new(1314, [l, l, s, l, s, s, l, s, l, l, s, l], gregorian(1896, 6, 12)).unwrap(), + PackedHijriYearData::try_new(1315, [s, l, l, s, l, s, s, l, s, l, s, l], gregorian(1897, 6, 2)).unwrap(), + PackedHijriYearData::try_new(1316, [s, l, l, l, s, l, s, s, l, s, l, s], gregorian(1898, 5, 22)).unwrap(), + PackedHijriYearData::try_new(1317, [l, s, l, l, s, l, s, l, s, l, s, s], gregorian(1899, 5, 11)).unwrap(), + PackedHijriYearData::try_new(1318, [l, s, l, l, s, l, l, s, l, s, l, s], gregorian(1900, 4, 30)).unwrap(), + PackedHijriYearData::try_new(1319, [s, l, s, l, l, s, l, s, l, l, s, l], gregorian(1901, 4, 20)).unwrap(), + PackedHijriYearData::try_new(1320, [s, l, s, s, l, s, l, s, l, l, l, s], gregorian(1902, 4, 10)).unwrap(), + PackedHijriYearData::try_new(1321, [l, s, l, s, s, l, s, s, l, l, l, l], gregorian(1903, 3, 30)).unwrap(), + PackedHijriYearData::try_new(1322, [s, l, s, l, s, s, s, l, s, l, l, l], gregorian(1904, 3, 19)).unwrap(), + PackedHijriYearData::try_new(1323, [s, l, l, s, l, s, s, s, l, s, l, l], gregorian(1905, 3, 8)).unwrap(), + PackedHijriYearData::try_new(1324, [s, l, l, s, l, s, l, s, s, l, s, l], gregorian(1906, 2, 25)).unwrap(), + PackedHijriYearData::try_new(1325, [l, s, l, s, l, l, s, l, s, l, s, l], gregorian(1907, 2, 14)).unwrap(), + PackedHijriYearData::try_new(1326, [s, s, l, s, l, l, s, l, s, l, l, s], gregorian(1908, 2, 4)).unwrap(), + PackedHijriYearData::try_new(1327, [l, s, s, l, s, l, s, l, l, s, l, l], gregorian(1909, 1, 23)).unwrap(), + PackedHijriYearData::try_new(1328, [s, l, s, s, l, s, s, l, l, l, s, l], gregorian(1910, 1, 13)).unwrap(), + PackedHijriYearData::try_new(1329, [l, s, l, s, s, l, s, s, l, l, s, l], gregorian(1911, 1, 2)).unwrap(), + PackedHijriYearData::try_new(1330, [l, l, s, l, s, s, l, s, s, l, l, s], gregorian(1911, 12, 22)).unwrap(), + PackedHijriYearData::try_new(1331, [l, l, s, l, l, s, s, l, s, l, s, l], gregorian(1912, 12, 10)).unwrap(), + PackedHijriYearData::try_new(1332, [s, l, s, l, l, s, l, s, l, l, s, s], gregorian(1913, 11, 30)).unwrap(), + PackedHijriYearData::try_new(1333, [l, s, s, l, l, s, l, l, s, l, l, s], gregorian(1914, 11, 19)).unwrap(), + PackedHijriYearData::try_new(1334, [s, s, l, s, l, s, l, l, l, s, l, s], gregorian(1915, 11, 9)).unwrap(), + PackedHijriYearData::try_new(1335, [l, s, l, s, s, l, s, l, l, s, l, l], gregorian(1916, 10, 28)).unwrap(), + PackedHijriYearData::try_new(1336, [s, l, s, l, s, s, l, s, l, s, l, l], gregorian(1917, 10, 18)).unwrap(), + PackedHijriYearData::try_new(1337, [l, s, l, s, l, s, s, l, s, l, s, l], gregorian(1918, 10, 7)).unwrap(), + PackedHijriYearData::try_new(1338, [s, l, l, s, l, l, s, s, l, s, l, s], gregorian(1919, 9, 26)).unwrap(), + PackedHijriYearData::try_new(1339, [l, s, l, s, l, l, l, s, l, s, s, l], gregorian(1920, 9, 14)).unwrap(), + PackedHijriYearData::try_new(1340, [s, s, l, s, l, l, l, l, s, l, s, s], gregorian(1921, 9, 4)).unwrap(), + PackedHijriYearData::try_new(1341, [l, s, s, l, s, l, l, l, s, l, l, s], gregorian(1922, 8, 24)).unwrap(), + PackedHijriYearData::try_new(1342, [s, s, l, s, l, s, l, l, s, l, l, s], gregorian(1923, 8, 14)).unwrap(), + PackedHijriYearData::try_new(1343, [l, s, s, l, s, l, s, l, s, l, l, s], gregorian(1924, 8, 2)).unwrap(), + PackedHijriYearData::try_new(1344, [l, s, l, s, l, l, s, s, l, s, l, s], gregorian(1925, 7, 22)).unwrap(), + PackedHijriYearData::try_new(1345, [l, s, l, l, l, s, l, s, s, l, s, s], gregorian(1926, 7, 11)).unwrap(), + PackedHijriYearData::try_new(1346, [l, s, l, l, l, l, s, l, s, s, l, s], gregorian(1927, 6, 30)).unwrap(), + PackedHijriYearData::try_new(1347, [s, l, s, l, l, l, s, l, l, s, s, l], gregorian(1928, 6, 19)).unwrap(), + PackedHijriYearData::try_new(1348, [s, s, l, s, l, l, s, l, l, l, s, s], gregorian(1929, 6, 9)).unwrap(), + PackedHijriYearData::try_new(1349, [l, s, s, l, s, l, l, s, l, l, s, l], gregorian(1930, 5, 29)).unwrap(), + PackedHijriYearData::try_new(1350, [s, l, s, l, s, l, s, s, l, l, s, l], gregorian(1931, 5, 19)).unwrap(), + PackedHijriYearData::try_new(1351, [l, s, l, s, l, s, l, s, s, l, s, l], gregorian(1932, 5, 7)).unwrap(), + PackedHijriYearData::try_new(1352, [l, s, l, l, s, l, s, l, s, s, l, s], gregorian(1933, 4, 26)).unwrap(), + PackedHijriYearData::try_new(1353, [l, s, l, l, l, s, l, s, s, l, s, l], gregorian(1934, 4, 15)).unwrap(), + PackedHijriYearData::try_new(1354, [s, l, s, l, l, s, l, l, s, l, s, s], gregorian(1935, 4, 5)).unwrap(), + PackedHijriYearData::try_new(1355, [l, s, s, l, l, s, l, l, s, l, l, s], gregorian(1936, 3, 24)).unwrap(), + PackedHijriYearData::try_new(1356, [s, l, s, l, s, l, s, l, s, l, l, l], gregorian(1937, 3, 14)).unwrap(), + PackedHijriYearData::try_new(1357, [s, s, l, s, l, s, s, l, s, l, l, l], gregorian(1938, 3, 4)).unwrap(), + PackedHijriYearData::try_new(1358, [s, l, s, l, s, l, s, s, l, s, l, l], gregorian(1939, 2, 21)).unwrap(), + PackedHijriYearData::try_new(1359, [s, l, l, s, l, s, l, s, s, s, l, l], gregorian(1940, 2, 10)).unwrap(), + PackedHijriYearData::try_new(1360, [s, l, l, l, s, l, s, l, s, s, l, s], gregorian(1941, 1, 29)).unwrap(), + PackedHijriYearData::try_new(1361, [l, s, l, l, s, l, l, s, s, l, s, l], gregorian(1942, 1, 18)).unwrap(), + PackedHijriYearData::try_new(1362, [s, l, s, l, s, l, l, s, l, s, l, s], gregorian(1943, 1, 8)).unwrap(), + PackedHijriYearData::try_new(1363, [l, s, l, s, l, s, l, s, l, s, l, l], gregorian(1943, 12, 28)).unwrap(), + PackedHijriYearData::try_new(1364, [s, l, s, l, s, s, l, s, l, s, l, l], gregorian(1944, 12, 17)).unwrap(), + PackedHijriYearData::try_new(1365, [l, l, s, s, l, s, s, l, s, l, s, l], gregorian(1945, 12, 6)).unwrap(), + PackedHijriYearData::try_new(1366, [l, l, s, l, s, l, s, s, l, s, l, s], gregorian(1946, 11, 25)).unwrap(), + PackedHijriYearData::try_new(1367, [l, l, s, l, l, s, l, s, s, l, s, l], gregorian(1947, 11, 14)).unwrap(), + PackedHijriYearData::try_new(1368, [s, l, s, l, l, l, s, s, l, s, l, s], gregorian(1948, 11, 3)).unwrap(), + PackedHijriYearData::try_new(1369, [l, s, l, s, l, l, s, l, s, l, l, s], gregorian(1949, 10, 23)).unwrap(), + PackedHijriYearData::try_new(1370, [l, s, s, l, s, l, s, l, s, l, l, l], gregorian(1950, 10, 13)).unwrap(), + PackedHijriYearData::try_new(1371, [s, l, s, s, l, s, l, s, l, s, l, l], gregorian(1951, 10, 3)).unwrap(), + PackedHijriYearData::try_new(1372, [l, s, s, l, s, l, s, s, l, s, l, l], gregorian(1952, 9, 21)).unwrap(), + PackedHijriYearData::try_new(1373, [l, s, l, s, l, s, l, s, s, l, s, l], gregorian(1953, 9, 10)).unwrap(), + PackedHijriYearData::try_new(1374, [l, s, l, l, s, l, s, l, s, s, l, s], gregorian(1954, 8, 30)).unwrap(), + PackedHijriYearData::try_new(1375, [l, s, l, l, s, l, l, s, l, s, l, s], gregorian(1955, 8, 19)).unwrap(), + PackedHijriYearData::try_new(1376, [s, l, s, l, s, l, l, l, s, l, s, l], gregorian(1956, 8, 8)).unwrap(), + PackedHijriYearData::try_new(1377, [s, s, l, s, s, l, l, l, s, l, l, s], gregorian(1957, 7, 29)).unwrap(), + PackedHijriYearData::try_new(1378, [l, s, s, s, l, s, l, l, s, l, l, l], gregorian(1958, 7, 18)).unwrap(), + PackedHijriYearData::try_new(1379, [s, l, s, s, s, l, s, l, l, s, l, l], gregorian(1959, 7, 8)).unwrap(), + PackedHijriYearData::try_new(1380, [s, l, s, l, s, l, s, l, s, l, s, l], gregorian(1960, 6, 26)).unwrap(), + PackedHijriYearData::try_new(1381, [s, l, s, l, l, s, l, s, l, s, s, l], gregorian(1961, 6, 15)).unwrap(), + PackedHijriYearData::try_new(1382, [s, l, s, l, l, s, l, l, s, l, s, s], gregorian(1962, 6, 4)).unwrap(), + PackedHijriYearData::try_new(1383, [l, s, s, l, l, l, s, l, l, s, l, s], gregorian(1963, 5, 24)).unwrap(), + PackedHijriYearData::try_new(1384, [s, l, s, s, l, l, s, l, l, l, s, l], gregorian(1964, 5, 13)).unwrap(), + PackedHijriYearData::try_new(1385, [s, s, l, s, s, l, l, s, l, l, l, s], gregorian(1965, 5, 3)).unwrap(), + PackedHijriYearData::try_new(1386, [l, s, s, l, s, s, l, l, s, l, l, s], gregorian(1966, 4, 22)).unwrap(), + PackedHijriYearData::try_new(1387, [l, s, l, s, l, s, l, s, l, s, l, s], gregorian(1967, 4, 11)).unwrap(), + PackedHijriYearData::try_new(1388, [l, l, s, l, s, l, s, l, s, l, s, s], gregorian(1968, 3, 30)).unwrap(), + PackedHijriYearData::try_new(1389, [l, l, s, l, l, s, l, l, s, s, l, s], gregorian(1969, 3, 19)).unwrap(), + PackedHijriYearData::try_new(1390, [s, l, s, l, l, l, s, l, s, l, s, l], gregorian(1970, 3, 9)).unwrap(), + PackedHijriYearData::try_new(1391, [s, s, l, s, l, l, s, l, l, s, l, s], gregorian(1971, 2, 27)).unwrap(), + PackedHijriYearData::try_new(1392, [l, s, s, l, s, l, s, l, l, s, l, l], gregorian(1972, 2, 16)).unwrap(), + PackedHijriYearData::try_new(1393, [s, l, s, s, l, s, l, s, l, s, l, l], gregorian(1973, 2, 5)).unwrap(), + PackedHijriYearData::try_new(1394, [l, s, l, s, s, l, s, l, s, l, s, l], gregorian(1974, 1, 25)).unwrap(), + PackedHijriYearData::try_new(1395, [l, s, l, l, s, l, s, s, l, s, s, l], gregorian(1975, 1, 14)).unwrap(), + PackedHijriYearData::try_new(1396, [l, s, l, l, s, l, l, s, s, l, s, s], gregorian(1976, 1, 3)).unwrap(), + PackedHijriYearData::try_new(1397, [l, s, l, l, s, l, l, l, s, s, s, l], gregorian(1976, 12, 22)).unwrap(), + PackedHijriYearData::try_new(1398, [s, l, s, l, l, s, l, l, s, l, s, s], gregorian(1977, 12, 12)).unwrap(), + PackedHijriYearData::try_new(1399, [l, s, l, s, l, s, l, l, s, l, s, l], gregorian(1978, 12, 1)).unwrap(), + PackedHijriYearData::try_new(1400, [l, s, l, s, s, l, s, l, s, l, s, l], gregorian(1979, 11, 21)).unwrap(), + PackedHijriYearData::try_new(1401, [l, l, s, l, s, s, l, s, s, l, s, l], gregorian(1980, 11, 9)).unwrap(), + PackedHijriYearData::try_new(1402, [l, l, l, s, l, s, s, l, s, s, l, s], gregorian(1981, 10, 29)).unwrap(), + PackedHijriYearData::try_new(1403, [l, l, l, s, l, l, s, s, l, s, s, l], gregorian(1982, 10, 18)).unwrap(), + PackedHijriYearData::try_new(1404, [s, l, l, s, l, l, s, l, s, l, s, s], gregorian(1983, 10, 8)).unwrap(), + PackedHijriYearData::try_new(1405, [l, s, l, s, l, l, l, s, l, s, s, l], gregorian(1984, 9, 26)).unwrap(), + PackedHijriYearData::try_new(1406, [l, s, s, l, s, l, l, s, l, s, l, l], gregorian(1985, 9, 16)).unwrap(), + PackedHijriYearData::try_new(1407, [s, l, s, s, l, s, l, s, l, s, l, l], gregorian(1986, 9, 6)).unwrap(), + PackedHijriYearData::try_new(1408, [l, s, l, s, l, s, s, l, s, s, l, l], gregorian(1987, 8, 26)).unwrap(), + PackedHijriYearData::try_new(1409, [l, l, s, l, s, l, s, s, l, s, s, l], gregorian(1988, 8, 14)).unwrap(), + PackedHijriYearData::try_new(1410, [l, l, s, l, l, s, l, s, s, l, s, s], gregorian(1989, 8, 3)).unwrap(), + PackedHijriYearData::try_new(1411, [l, l, s, l, l, s, l, l, s, s, l, s], gregorian(1990, 7, 23)).unwrap(), + PackedHijriYearData::try_new(1412, [l, s, l, s, l, s, l, l, l, s, s, l], gregorian(1991, 7, 13)).unwrap(), + PackedHijriYearData::try_new(1413, [s, l, s, s, l, s, l, l, l, s, l, s], gregorian(1992, 7, 2)).unwrap(), + PackedHijriYearData::try_new(1414, [l, s, l, s, s, l, s, l, l, s, l, l], gregorian(1993, 6, 21)).unwrap(), + PackedHijriYearData::try_new(1415, [s, l, s, l, s, s, l, s, l, s, l, l], gregorian(1994, 6, 11)).unwrap(), + PackedHijriYearData::try_new(1416, [l, s, l, s, l, s, s, l, s, l, s, l], gregorian(1995, 5, 31)).unwrap(), + PackedHijriYearData::try_new(1417, [l, s, l, l, s, s, l, s, l, s, l, s], gregorian(1996, 5, 19)).unwrap(), + PackedHijriYearData::try_new(1418, [l, s, l, l, s, l, s, l, s, l, s, l], gregorian(1997, 5, 8)).unwrap(), + PackedHijriYearData::try_new(1419, [s, l, s, l, s, l, s, l, l, l, s, s], gregorian(1998, 4, 28)).unwrap(), + PackedHijriYearData::try_new(1420, [s, l, s, s, l, s, l, l, l, l, s, l], gregorian(1999, 4, 17)).unwrap(), + PackedHijriYearData::try_new(1421, [s, s, l, s, s, s, l, l, l, l, s, l], gregorian(2000, 4, 6)).unwrap(), + PackedHijriYearData::try_new(1422, [l, s, s, l, s, s, s, l, l, l, s, l], gregorian(2001, 3, 26)).unwrap(), + PackedHijriYearData::try_new(1423, [l, s, l, s, l, s, s, l, s, l, s, l], gregorian(2002, 3, 15)).unwrap(), + PackedHijriYearData::try_new(1424, [l, s, l, l, s, l, s, s, l, s, l, s], gregorian(2003, 3, 4)).unwrap(), + PackedHijriYearData::try_new(1425, [l, s, l, l, s, l, s, l, l, s, l, s], gregorian(2004, 2, 21)).unwrap(), + PackedHijriYearData::try_new(1426, [s, l, s, l, s, l, l, s, l, l, s, l], gregorian(2005, 2, 10)).unwrap(), + PackedHijriYearData::try_new(1427, [s, s, l, s, l, s, l, l, s, l, l, s], gregorian(2006, 1, 31)).unwrap(), + PackedHijriYearData::try_new(1428, [l, s, s, l, s, s, l, l, l, s, l, l], gregorian(2007, 1, 20)).unwrap(), + PackedHijriYearData::try_new(1429, [s, l, s, s, l, s, s, l, l, s, l, l], gregorian(2008, 1, 10)).unwrap(), + PackedHijriYearData::try_new(1430, [s, l, l, s, s, l, s, l, s, l, s, l], gregorian(2008, 12, 29)).unwrap(), + PackedHijriYearData::try_new(1431, [s, l, l, s, l, s, l, s, l, s, s, l], gregorian(2009, 12, 18)).unwrap(), + PackedHijriYearData::try_new(1432, [s, l, l, l, s, l, s, l, s, l, s, s], gregorian(2010, 12, 7)).unwrap(), + PackedHijriYearData::try_new(1433, [l, s, l, l, s, l, l, s, l, s, l, s], gregorian(2011, 11, 26)).unwrap(), + PackedHijriYearData::try_new(1434, [s, l, s, l, s, l, l, s, l, l, s, s], gregorian(2012, 11, 15)).unwrap(), + PackedHijriYearData::try_new(1435, [l, s, l, s, l, s, l, s, l, l, s, l], gregorian(2013, 11, 4)).unwrap(), + PackedHijriYearData::try_new(1436, [s, l, s, l, s, l, s, l, s, l, s, l], gregorian(2014, 10, 25)).unwrap(), + PackedHijriYearData::try_new(1437, [l, s, l, l, s, s, l, s, l, s, s, l], gregorian(2015, 10, 14)).unwrap(), + PackedHijriYearData::try_new(1438, [l, s, l, l, l, s, s, l, s, s, l, s], gregorian(2016, 10, 2)).unwrap(), + PackedHijriYearData::try_new(1439, [l, s, l, l, l, s, l, s, l, s, s, l], gregorian(2017, 9, 21)).unwrap(), + PackedHijriYearData::try_new(1440, [s, l, s, l, l, l, s, l, s, l, s, s], gregorian(2018, 9, 11)).unwrap(), + PackedHijriYearData::try_new(1441, [l, s, l, s, l, l, s, l, l, s, l, s], gregorian(2019, 8, 31)).unwrap(), + PackedHijriYearData::try_new(1442, [s, l, s, l, s, l, s, l, l, s, l, s], gregorian(2020, 8, 20)).unwrap(), + PackedHijriYearData::try_new(1443, [l, s, l, s, l, s, l, s, l, s, l, l], gregorian(2021, 8, 9)).unwrap(), + PackedHijriYearData::try_new(1444, [s, l, s, l, l, s, s, l, s, l, s, l], gregorian(2022, 7, 30)).unwrap(), + PackedHijriYearData::try_new(1445, [s, l, l, l, s, l, s, s, l, s, s, l], gregorian(2023, 7, 19)).unwrap(), + PackedHijriYearData::try_new(1446, [s, l, l, l, s, l, l, s, s, l, s, s], gregorian(2024, 7, 7)).unwrap(), + PackedHijriYearData::try_new(1447, [l, s, l, l, l, s, l, s, l, s, l, s], gregorian(2025, 6, 26)).unwrap(), + PackedHijriYearData::try_new(1448, [s, l, s, l, l, s, l, l, s, l, s, l], gregorian(2026, 6, 16)).unwrap(), + PackedHijriYearData::try_new(1449, [s, s, l, s, l, s, l, l, s, l, l, s], gregorian(2027, 6, 6)).unwrap(), + PackedHijriYearData::try_new(1450, [l, s, l, s, s, l, s, l, s, l, l, s], gregorian(2028, 5, 25)).unwrap(), + PackedHijriYearData::try_new(1451, [l, l, l, s, s, l, s, s, l, l, s, l], gregorian(2029, 5, 14)).unwrap(), + PackedHijriYearData::try_new(1452, [l, s, l, l, s, s, l, s, s, l, s, l], gregorian(2030, 5, 4)).unwrap(), + PackedHijriYearData::try_new(1453, [l, s, l, l, s, l, s, l, s, s, l, s], gregorian(2031, 4, 23)).unwrap(), + PackedHijriYearData::try_new(1454, [l, s, l, l, s, l, l, s, l, s, l, s], gregorian(2032, 4, 11)).unwrap(), + PackedHijriYearData::try_new(1455, [s, l, s, l, l, s, l, s, l, l, s, l], gregorian(2033, 4, 1)).unwrap(), + PackedHijriYearData::try_new(1456, [s, s, l, s, l, s, l, s, l, l, l, s], gregorian(2034, 3, 22)).unwrap(), + PackedHijriYearData::try_new(1457, [l, s, s, l, s, s, l, s, l, l, l, l], gregorian(2035, 3, 11)).unwrap(), + PackedHijriYearData::try_new(1458, [s, l, s, s, l, s, s, l, s, l, l, l], gregorian(2036, 2, 29)).unwrap(), + PackedHijriYearData::try_new(1459, [s, l, l, s, s, l, s, s, l, s, l, l], gregorian(2037, 2, 17)).unwrap(), + PackedHijriYearData::try_new(1460, [s, l, l, s, l, s, l, s, s, l, s, l], gregorian(2038, 2, 6)).unwrap(), + PackedHijriYearData::try_new(1461, [s, l, l, s, l, s, l, s, l, l, s, s], gregorian(2039, 1, 26)).unwrap(), + PackedHijriYearData::try_new(1462, [l, s, l, s, l, l, s, l, s, l, l, s], gregorian(2040, 1, 15)).unwrap(), + PackedHijriYearData::try_new(1463, [s, l, s, l, s, l, s, l, l, l, s, l], gregorian(2041, 1, 4)).unwrap(), + PackedHijriYearData::try_new(1464, [s, l, s, s, l, s, s, l, l, l, s, l], gregorian(2041, 12, 25)).unwrap(), + PackedHijriYearData::try_new(1465, [l, s, l, s, s, l, s, s, l, l, s, l], gregorian(2042, 12, 14)).unwrap(), + PackedHijriYearData::try_new(1466, [l, l, s, l, s, s, s, l, s, l, l, s], gregorian(2043, 12, 3)).unwrap(), + PackedHijriYearData::try_new(1467, [l, l, s, l, l, s, s, l, s, l, s, l], gregorian(2044, 11, 21)).unwrap(), + PackedHijriYearData::try_new(1468, [s, l, s, l, l, s, l, s, l, s, l, s], gregorian(2045, 11, 11)).unwrap(), + PackedHijriYearData::try_new(1469, [s, l, s, l, l, s, l, l, s, l, s, l], gregorian(2046, 10, 31)).unwrap(), + PackedHijriYearData::try_new(1470, [s, s, l, s, l, l, s, l, l, s, l, s], gregorian(2047, 10, 21)).unwrap(), + PackedHijriYearData::try_new(1471, [l, s, s, l, s, l, s, l, l, s, l, l], gregorian(2048, 10, 9)).unwrap(), + PackedHijriYearData::try_new(1472, [s, l, s, s, l, s, l, s, l, l, s, l], gregorian(2049, 9, 29)).unwrap(), + PackedHijriYearData::try_new(1473, [s, l, s, l, l, s, s, l, s, l, s, l], gregorian(2050, 9, 18)).unwrap(), + PackedHijriYearData::try_new(1474, [s, l, l, s, l, l, s, s, l, s, l, s], gregorian(2051, 9, 7)).unwrap(), + PackedHijriYearData::try_new(1475, [s, l, l, s, l, l, l, s, s, l, s, s], gregorian(2052, 8, 26)).unwrap(), + PackedHijriYearData::try_new(1476, [l, s, l, s, l, l, l, s, l, s, l, s], gregorian(2053, 8, 15)).unwrap(), + PackedHijriYearData::try_new(1477, [s, l, s, s, l, l, l, l, s, l, s, l], gregorian(2054, 8, 5)).unwrap(), + PackedHijriYearData::try_new(1478, [s, s, l, s, l, s, l, l, s, l, l, s], gregorian(2055, 7, 26)).unwrap(), + PackedHijriYearData::try_new(1479, [l, s, s, l, s, l, s, l, s, l, l, s], gregorian(2056, 7, 14)).unwrap(), + PackedHijriYearData::try_new(1480, [l, s, l, s, l, s, l, s, l, s, l, s], gregorian(2057, 7, 3)).unwrap(), + PackedHijriYearData::try_new(1481, [l, s, l, l, s, l, s, l, s, l, s, s], gregorian(2058, 6, 22)).unwrap(), + PackedHijriYearData::try_new(1482, [l, s, l, l, l, l, s, l, s, s, l, s], gregorian(2059, 6, 11)).unwrap(), + PackedHijriYearData::try_new(1483, [s, l, s, l, l, l, s, l, l, s, s, l], gregorian(2060, 5, 31)).unwrap(), + PackedHijriYearData::try_new(1484, [s, s, l, s, l, l, l, s, l, s, l, s], gregorian(2061, 5, 21)).unwrap(), + PackedHijriYearData::try_new(1485, [l, s, s, l, s, l, l, s, l, l, s, l], gregorian(2062, 5, 10)).unwrap(), + PackedHijriYearData::try_new(1486, [s, l, s, s, l, s, l, s, l, l, s, l], gregorian(2063, 4, 30)).unwrap(), + PackedHijriYearData::try_new(1487, [l, s, l, s, l, s, s, l, s, l, s, l], gregorian(2064, 4, 18)).unwrap(), + PackedHijriYearData::try_new(1488, [l, s, l, l, s, l, s, s, l, s, l, s], gregorian(2065, 4, 7)).unwrap(), + PackedHijriYearData::try_new(1489, [l, s, l, l, l, s, l, s, s, l, s, l], gregorian(2066, 3, 27)).unwrap(), + PackedHijriYearData::try_new(1490, [s, l, s, l, l, s, l, l, s, s, l, s], gregorian(2067, 3, 17)).unwrap(), + PackedHijriYearData::try_new(1491, [l, s, s, l, l, s, l, l, s, l, s, l], gregorian(2068, 3, 5)).unwrap(), + PackedHijriYearData::try_new(1492, [s, l, s, s, l, l, s, l, s, l, l, s], gregorian(2069, 2, 23)).unwrap(), + PackedHijriYearData::try_new(1493, [l, s, l, s, l, s, s, l, s, l, l, l], gregorian(2070, 2, 12)).unwrap(), + PackedHijriYearData::try_new(1494, [s, l, s, l, s, l, s, s, s, l, l, l], gregorian(2071, 2, 2)).unwrap(), + PackedHijriYearData::try_new(1495, [s, l, l, s, l, s, s, l, s, s, l, l], gregorian(2072, 1, 22)).unwrap(), + PackedHijriYearData::try_new(1496, [s, l, l, l, s, l, s, s, l, s, s, l], gregorian(2073, 1, 10)).unwrap(), + PackedHijriYearData::try_new(1497, [l, s, l, l, s, l, s, l, s, l, s, l], gregorian(2073, 12, 30)).unwrap(), + PackedHijriYearData::try_new(1498, [s, l, s, l, s, l, l, s, l, s, l, s], gregorian(2074, 12, 20)).unwrap(), + PackedHijriYearData::try_new(1499, [l, s, l, s, s, l, l, s, l, s, l, l], gregorian(2075, 12, 9)).unwrap(), + PackedHijriYearData::try_new(1500, [s, l, s, l, s, s, l, s, l, s, l, l], gregorian(2076, 11, 28)).unwrap(), + PackedHijriYearData::try_new(1501, [l, s, l, s, l, s, s, s, l, s, l, l], gregorian(2077, 11, 17)).unwrap(), + PackedHijriYearData::try_new(1502, [l, l, s, l, s, l, s, s, s, l, l, s], gregorian(2078, 11, 6)).unwrap(), + PackedHijriYearData::try_new(1503, [l, l, s, l, l, s, l, s, s, s, l, l], gregorian(2079, 10, 26)).unwrap(), + PackedHijriYearData::try_new(1504, [s, l, s, l, l, l, s, s, l, s, l, s], gregorian(2080, 10, 15)).unwrap(), + PackedHijriYearData::try_new(1505, [l, s, l, s, l, l, s, l, s, l, l, s], gregorian(2081, 10, 4)).unwrap(), + PackedHijriYearData::try_new(1506, [s, l, s, s, l, l, s, l, l, s, l, l], gregorian(2082, 9, 24)).unwrap(), + PackedHijriYearData::try_new(1507, [s, s, l, s, s, l, l, s, l, s, l, l], gregorian(2083, 9, 14)).unwrap(), + PackedHijriYearData::try_new(1508, [l, s, s, l, s, l, s, s, l, s, l, l], gregorian(2084, 9, 2)).unwrap(), + PackedHijriYearData::try_new(1509, [l, s, l, s, l, s, l, s, s, l, s, l], gregorian(2085, 8, 22)).unwrap(), + PackedHijriYearData::try_new(1510, [l, s, l, l, s, l, s, l, s, s, l, s], gregorian(2086, 8, 11)).unwrap(), + PackedHijriYearData::try_new(1511, [l, s, l, l, s, l, l, s, l, s, s, l], gregorian(2087, 7, 31)).unwrap(), + PackedHijriYearData::try_new(1512, [s, l, s, l, s, l, l, l, s, l, s, l], gregorian(2088, 7, 20)).unwrap(), + PackedHijriYearData::try_new(1513, [s, s, s, l, s, l, l, l, s, l, l, s], gregorian(2089, 7, 10)).unwrap(), + PackedHijriYearData::try_new(1514, [l, s, s, s, l, s, l, l, s, l, l, l], gregorian(2090, 6, 29)).unwrap(), + PackedHijriYearData::try_new(1515, [s, s, l, s, s, l, s, l, l, s, l, l], gregorian(2091, 6, 19)).unwrap(), + PackedHijriYearData::try_new(1516, [s, l, s, l, s, s, l, s, l, s, l, l], gregorian(2092, 6, 7)).unwrap(), + PackedHijriYearData::try_new(1517, [s, l, s, l, s, l, l, s, s, l, s, l], gregorian(2093, 5, 27)).unwrap(), + PackedHijriYearData::try_new(1518, [s, l, s, l, l, s, l, l, s, l, s, s], gregorian(2094, 5, 16)).unwrap(), + PackedHijriYearData::try_new(1519, [l, s, s, l, l, l, s, l, l, s, l, s], gregorian(2095, 5, 5)).unwrap(), + PackedHijriYearData::try_new(1520, [s, l, s, s, l, l, l, s, l, l, s, l], gregorian(2096, 4, 24)).unwrap(), + PackedHijriYearData::try_new(1521, [s, s, s, l, s, l, l, s, l, l, s, l], gregorian(2097, 4, 14)).unwrap(), + PackedHijriYearData::try_new(1522, [l, s, s, s, l, s, l, l, s, l, l, s], gregorian(2098, 4, 3)).unwrap(), + PackedHijriYearData::try_new(1523, [l, s, l, s, l, s, l, s, s, l, l, s], gregorian(2099, 3, 23)).unwrap(), + PackedHijriYearData::try_new(1524, [l, l, s, l, s, l, s, l, s, s, l, s], gregorian(2100, 3, 12)).unwrap(), + PackedHijriYearData::try_new(1525, [l, l, s, l, l, s, l, s, l, s, s, l], gregorian(2101, 3, 1)).unwrap(), + PackedHijriYearData::try_new(1526, [s, l, s, l, l, l, s, l, s, l, s, s], gregorian(2102, 2, 19)).unwrap(), + PackedHijriYearData::try_new(1527, [l, s, l, s, l, l, s, l, l, s, l, s], gregorian(2103, 2, 8)).unwrap(), + PackedHijriYearData::try_new(1528, [l, s, s, l, s, l, s, l, l, s, l, l], gregorian(2104, 1, 29)).unwrap(), + PackedHijriYearData::try_new(1529, [s, l, s, s, l, s, l, s, l, s, l, l], gregorian(2105, 1, 18)).unwrap(), + PackedHijriYearData::try_new(1530, [s, l, l, s, s, l, s, l, s, s, l, l], gregorian(2106, 1, 7)).unwrap(), + PackedHijriYearData::try_new(1531, [s, l, l, l, s, s, l, s, l, s, s, l], gregorian(2106, 12, 27)).unwrap(), + PackedHijriYearData::try_new(1532, [s, l, l, l, s, l, l, s, s, s, l, s], gregorian(2107, 12, 16)).unwrap(), + PackedHijriYearData::try_new(1533, [l, s, l, l, l, s, l, s, l, s, s, l], gregorian(2108, 12, 4)).unwrap(), + PackedHijriYearData::try_new(1534, [s, l, s, l, l, s, l, l, s, s, l, s], gregorian(2109, 11, 24)).unwrap(), + PackedHijriYearData::try_new(1535, [l, s, l, s, l, s, l, l, s, l, s, l], gregorian(2110, 11, 13)).unwrap(), + PackedHijriYearData::try_new(1536, [s, l, s, l, s, l, s, l, s, l, s, l], gregorian(2111, 11, 3)).unwrap(), + PackedHijriYearData::try_new(1537, [l, s, l, l, s, s, l, s, s, l, s, l], gregorian(2112, 10, 22)).unwrap(), + PackedHijriYearData::try_new(1538, [l, l, s, l, l, s, s, l, s, s, l, s], gregorian(2113, 10, 11)).unwrap(), + PackedHijriYearData::try_new(1539, [l, l, l, s, l, l, s, s, l, s, s, l], gregorian(2114, 9, 30)).unwrap(), + PackedHijriYearData::try_new(1540, [s, l, l, s, l, l, s, l, s, s, l, s], gregorian(2115, 9, 20)).unwrap(), + PackedHijriYearData::try_new(1541, [l, s, l, s, l, l, l, s, l, s, s, l], gregorian(2116, 9, 8)).unwrap(), + PackedHijriYearData::try_new(1542, [s, l, s, l, s, l, l, s, l, s, l, l], gregorian(2117, 8, 29)).unwrap(), + PackedHijriYearData::try_new(1543, [s, l, s, s, l, s, l, s, l, s, l, l], gregorian(2118, 8, 19)).unwrap(), + PackedHijriYearData::try_new(1544, [l, s, l, s, s, l, s, l, s, l, s, l], gregorian(2119, 8, 8)).unwrap(), + PackedHijriYearData::try_new(1545, [l, l, s, l, s, s, l, s, l, s, s, l], gregorian(2120, 7, 27)).unwrap(), + PackedHijriYearData::try_new(1546, [l, l, s, l, s, l, s, l, s, l, s, s], gregorian(2121, 7, 16)).unwrap(), + PackedHijriYearData::try_new(1547, [l, l, s, l, l, s, l, s, l, s, l, s], gregorian(2122, 7, 5)).unwrap(), + PackedHijriYearData::try_new(1548, [l, s, s, l, l, s, l, l, s, l, s, l], gregorian(2123, 6, 25)).unwrap(), + PackedHijriYearData::try_new(1549, [s, l, s, s, l, s, l, l, l, s, l, s], gregorian(2124, 6, 14)).unwrap(), + PackedHijriYearData::try_new(1550, [l, s, l, s, s, s, l, l, l, s, l, l], gregorian(2125, 6, 3)).unwrap(), + PackedHijriYearData::try_new(1551, [s, l, s, s, l, s, s, l, l, s, l, l], gregorian(2126, 5, 24)).unwrap(), + PackedHijriYearData::try_new(1552, [l, s, l, s, s, l, s, s, l, l, s, l], gregorian(2127, 5, 13)).unwrap(), + PackedHijriYearData::try_new(1553, [l, s, l, s, l, s, l, s, l, s, l, s], gregorian(2128, 5, 1)).unwrap(), + PackedHijriYearData::try_new(1554, [l, s, l, s, l, l, s, l, s, l, s, l], gregorian(2129, 4, 20)).unwrap(), + PackedHijriYearData::try_new(1555, [s, s, l, s, l, l, s, l, l, s, l, s], gregorian(2130, 4, 10)).unwrap(), + PackedHijriYearData::try_new(1556, [l, s, s, l, s, l, s, l, l, l, s, l], gregorian(2131, 3, 30)).unwrap(), + PackedHijriYearData::try_new(1557, [s, l, s, s, s, l, s, l, l, l, l, s], gregorian(2132, 3, 19)).unwrap(), + PackedHijriYearData::try_new(1558, [l, s, l, s, s, s, l, s, l, l, l, s], gregorian(2133, 3, 8)).unwrap(), + PackedHijriYearData::try_new(1559, [l, l, s, s, l, s, s, l, l, s, l, s], gregorian(2134, 2, 25)).unwrap(), + PackedHijriYearData::try_new(1560, [l, l, s, l, s, l, s, l, s, l, s, l], gregorian(2135, 2, 14)).unwrap(), + PackedHijriYearData::try_new(1561, [s, l, l, s, l, s, l, l, s, s, l, s], gregorian(2136, 2, 4)).unwrap(), + PackedHijriYearData::try_new(1562, [s, l, l, s, l, s, l, l, l, s, s, l], gregorian(2137, 1, 23)).unwrap(), + PackedHijriYearData::try_new(1563, [s, l, s, s, l, s, l, l, l, s, l, s], gregorian(2138, 1, 13)).unwrap(), + PackedHijriYearData::try_new(1564, [l, s, l, s, s, l, s, l, l, l, s, l], gregorian(2139, 1, 2)).unwrap(), + PackedHijriYearData::try_new(1565, [s, l, s, l, s, s, l, s, l, l, s, l], gregorian(2139, 12, 23)).unwrap(), + PackedHijriYearData::try_new(1566, [l, s, l, s, l, s, s, l, s, l, s, l], gregorian(2140, 12, 11)).unwrap(), + PackedHijriYearData::try_new(1567, [l, s, l, l, s, l, s, l, s, s, l, s], gregorian(2141, 11, 30)).unwrap(), + PackedHijriYearData::try_new(1568, [l, s, l, l, l, s, l, s, l, s, s, s], gregorian(2142, 11, 19)).unwrap(), + PackedHijriYearData::try_new(1569, [l, s, l, l, l, s, l, l, s, l, s, s], gregorian(2143, 11, 8)).unwrap(), + PackedHijriYearData::try_new(1570, [s, l, s, l, l, s, l, l, l, s, s, l], gregorian(2144, 10, 28)).unwrap(), + PackedHijriYearData::try_new(1571, [s, s, l, s, l, l, s, l, l, s, l, s], gregorian(2145, 10, 18)).unwrap(), + PackedHijriYearData::try_new(1572, [l, s, s, l, s, l, s, l, l, s, l, s], gregorian(2146, 10, 7)).unwrap(), + PackedHijriYearData::try_new(1573, [l, s, l, l, s, l, s, s, l, s, l, s], gregorian(2147, 9, 26)).unwrap(), + PackedHijriYearData::try_new(1574, [l, l, s, l, l, s, l, s, s, l, s, s], gregorian(2148, 9, 14)).unwrap(), + PackedHijriYearData::try_new(1575, [l, l, l, s, l, l, s, l, s, s, s, l], gregorian(2149, 9, 3)).unwrap(), + PackedHijriYearData::try_new(1576, [s, l, l, s, l, l, l, s, l, s, s, s], gregorian(2150, 8, 24)).unwrap(), + PackedHijriYearData::try_new(1577, [l, s, l, l, s, l, l, s, l, s, l, s], gregorian(2151, 8, 13)).unwrap(), + PackedHijriYearData::try_new(1578, [s, l, s, l, s, l, l, s, l, l, s, l], gregorian(2152, 8, 2)).unwrap(), + PackedHijriYearData::try_new(1579, [s, l, s, l, s, s, l, l, s, l, s, l], gregorian(2153, 7, 23)).unwrap(), + PackedHijriYearData::try_new(1580, [s, l, l, s, l, s, s, l, s, l, s, l], gregorian(2154, 7, 12)).unwrap(), + PackedHijriYearData::try_new(1581, [l, l, s, l, s, l, s, s, l, s, l, s], gregorian(2155, 7, 1)).unwrap(), + PackedHijriYearData::try_new(1582, [l, l, s, l, l, s, l, s, l, s, s, s], gregorian(2156, 6, 19)).unwrap(), + PackedHijriYearData::try_new(1583, [l, l, s, l, l, l, s, l, s, l, s, s], gregorian(2157, 6, 8)).unwrap(), + PackedHijriYearData::try_new(1584, [s, l, l, s, l, l, s, l, l, s, l, s], gregorian(2158, 5, 29)).unwrap(), + PackedHijriYearData::try_new(1585, [s, l, s, l, s, l, s, l, l, s, l, l], gregorian(2159, 5, 19)).unwrap(), + PackedHijriYearData::try_new(1586, [s, s, l, s, l, s, s, l, l, l, s, l], gregorian(2160, 5, 8)).unwrap(), + PackedHijriYearData::try_new(1587, [s, l, l, s, s, s, l, s, l, s, l, l], gregorian(2161, 4, 27)).unwrap(), + PackedHijriYearData::try_new(1588, [l, s, l, l, s, s, s, l, s, l, s, l], gregorian(2162, 4, 16)).unwrap(), + PackedHijriYearData::try_new(1589, [l, s, l, l, s, l, s, s, l, s, l, s], gregorian(2163, 4, 5)).unwrap(), + PackedHijriYearData::try_new(1590, [l, s, l, l, l, s, s, l, s, l, s, l], gregorian(2164, 3, 24)).unwrap(), + PackedHijriYearData::try_new(1591, [s, l, s, l, l, s, l, s, l, s, l, s], gregorian(2165, 3, 14)).unwrap(), + PackedHijriYearData::try_new(1592, [l, s, l, s, l, s, l, s, l, l, l, s], gregorian(2166, 3, 3)).unwrap(), + PackedHijriYearData::try_new(1593, [l, s, s, l, s, s, l, s, l, l, l, s], gregorian(2167, 2, 21)).unwrap(), + PackedHijriYearData::try_new(1594, [l, l, s, s, l, s, s, s, l, l, l, l], gregorian(2168, 2, 10)).unwrap(), + PackedHijriYearData::try_new(1595, [s, l, s, l, s, s, l, s, s, l, l, l], gregorian(2169, 1, 30)).unwrap(), + PackedHijriYearData::try_new(1596, [s, l, l, s, l, s, s, l, s, l, s, l], gregorian(2170, 1, 19)).unwrap(), + PackedHijriYearData::try_new(1597, [s, l, l, s, l, s, l, s, l, s, l, s], gregorian(2171, 1, 8)).unwrap(), + PackedHijriYearData::try_new(1598, [l, s, l, s, l, l, s, l, s, l, l, s], gregorian(2171, 12, 28)).unwrap(), + PackedHijriYearData::try_new(1599, [s, l, s, l, s, l, s, l, l, l, s, l], gregorian(2172, 12, 17)).unwrap(), + PackedHijriYearData::try_new(1600, [s, s, l, s, l, s, s, l, l, l, s, l], gregorian(2173, 12, 7)).unwrap(), ] }; + +#[test] +fn test_icu4c_agreement() { + use calendrical_calculations::islamic::ISLAMIC_EPOCH_FRIDAY; + + // From https://github.com/unicode-org/icu/blob/1bf6bf774dbc8c6c2051963a81100ea1114b497f/icu4c/source/i18n/islamcal.cpp#L87 + const ICU4C_ENCODED_MONTH_LENGTHS: [u16; 1601 - 1300] = [ + 0x0AAA, 0x0D54, 0x0EC9, 0x06D4, 0x06EA, 0x036C, 0x0AAD, 0x0555, 0x06A9, 0x0792, 0x0BA9, + 0x05D4, 0x0ADA, 0x055C, 0x0D2D, 0x0695, 0x074A, 0x0B54, 0x0B6A, 0x05AD, 0x04AE, 0x0A4F, + 0x0517, 0x068B, 0x06A5, 0x0AD5, 0x02D6, 0x095B, 0x049D, 0x0A4D, 0x0D26, 0x0D95, 0x05AC, + 0x09B6, 0x02BA, 0x0A5B, 0x052B, 0x0A95, 0x06CA, 0x0AE9, 0x02F4, 0x0976, 0x02B6, 0x0956, + 0x0ACA, 0x0BA4, 0x0BD2, 0x05D9, 0x02DC, 0x096D, 0x054D, 0x0AA5, 0x0B52, 0x0BA5, 0x05B4, + 0x09B6, 0x0557, 0x0297, 0x054B, 0x06A3, 0x0752, 0x0B65, 0x056A, 0x0AAB, 0x052B, 0x0C95, + 0x0D4A, 0x0DA5, 0x05CA, 0x0AD6, 0x0957, 0x04AB, 0x094B, 0x0AA5, 0x0B52, 0x0B6A, 0x0575, + 0x0276, 0x08B7, 0x045B, 0x0555, 0x05A9, 0x05B4, 0x09DA, 0x04DD, 0x026E, 0x0936, 0x0AAA, + 0x0D54, 0x0DB2, 0x05D5, 0x02DA, 0x095B, 0x04AB, 0x0A55, 0x0B49, 0x0B64, 0x0B71, 0x05B4, + 0x0AB5, 0x0A55, 0x0D25, 0x0E92, 0x0EC9, 0x06D4, 0x0AE9, 0x096B, 0x04AB, 0x0A93, 0x0D49, + 0x0DA4, 0x0DB2, 0x0AB9, 0x04BA, 0x0A5B, 0x052B, 0x0A95, 0x0B2A, 0x0B55, 0x055C, 0x04BD, + 0x023D, 0x091D, 0x0A95, 0x0B4A, 0x0B5A, 0x056D, 0x02B6, 0x093B, 0x049B, 0x0655, 0x06A9, + 0x0754, 0x0B6A, 0x056C, 0x0AAD, 0x0555, 0x0B29, 0x0B92, 0x0BA9, 0x05D4, 0x0ADA, 0x055A, + 0x0AAB, 0x0595, 0x0749, 0x0764, 0x0BAA, 0x05B5, 0x02B6, 0x0A56, 0x0E4D, 0x0B25, 0x0B52, + 0x0B6A, 0x05AD, 0x02AE, 0x092F, 0x0497, 0x064B, 0x06A5, 0x06AC, 0x0AD6, 0x055D, 0x049D, + 0x0A4D, 0x0D16, 0x0D95, 0x05AA, 0x05B5, 0x02DA, 0x095B, 0x04AD, 0x0595, 0x06CA, 0x06E4, + 0x0AEA, 0x04F5, 0x02B6, 0x0956, 0x0AAA, 0x0B54, 0x0BD2, 0x05D9, 0x02EA, 0x096D, 0x04AD, + 0x0A95, 0x0B4A, 0x0BA5, 0x05B2, 0x09B5, 0x04D6, 0x0A97, 0x0547, 0x0693, 0x0749, 0x0B55, + 0x056A, 0x0A6B, 0x052B, 0x0A8B, 0x0D46, 0x0DA3, 0x05CA, 0x0AD6, 0x04DB, 0x026B, 0x094B, + 0x0AA5, 0x0B52, 0x0B69, 0x0575, 0x0176, 0x08B7, 0x025B, 0x052B, 0x0565, 0x05B4, 0x09DA, + 0x04ED, 0x016D, 0x08B6, 0x0AA6, 0x0D52, 0x0DA9, 0x05D4, 0x0ADA, 0x095B, 0x04AB, 0x0653, + 0x0729, 0x0762, 0x0BA9, 0x05B2, 0x0AB5, 0x0555, 0x0B25, 0x0D92, 0x0EC9, 0x06D2, 0x0AE9, + 0x056B, 0x04AB, 0x0A55, 0x0D29, 0x0D54, 0x0DAA, 0x09B5, 0x04BA, 0x0A3B, 0x049B, 0x0A4D, + 0x0AAA, 0x0AD5, 0x02DA, 0x095D, 0x045E, 0x0A2E, 0x0C9A, 0x0D55, 0x06B2, 0x06B9, 0x04BA, + 0x0A5D, 0x052D, 0x0A95, 0x0B52, 0x0BA8, 0x0BB4, 0x05B9, 0x02DA, 0x095A, 0x0B4A, 0x0DA4, + 0x0ED1, 0x06E8, 0x0B6A, 0x056D, 0x0535, 0x0695, 0x0D4A, 0x0DA8, 0x0DD4, 0x06DA, 0x055B, + 0x029D, 0x062B, 0x0B15, 0x0B4A, 0x0B95, 0x05AA, 0x0AAE, 0x092E, 0x0C8F, 0x0527, 0x0695, + 0x06AA, 0x0AD6, 0x055D, 0x029D, + ]; + + // From https://github.com/unicode-org/icu/blob/1bf6bf774dbc8c6c2051963a81100ea1114b497f/icu4c/source/i18n/islamcal.cpp#L264 + const ICU4C_YEAR_START_ESTIMATE_FIX: [i64; 1601 - 1300] = [ + 0, 0, -1, 0, -1, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, -1, 0, 0, 0, 1, 0, 0, -1, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 1, 0, 0, -1, 0, 1, 0, 1, 1, 0, 0, -1, 0, 1, 0, + 0, 0, -1, 0, 1, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, -1, -1, 0, -1, 0, 1, 0, 0, 0, -1, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 1, 0, 0, -1, -1, 0, 0, 0, 1, 0, 0, -1, -1, 0, -1, 0, 0, -1, -1, 0, -1, 0, + -1, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 1, 1, 0, 0, -1, 0, 1, 0, 0, 0, 0, 0, 1, 0, + 1, 0, 0, 0, -1, 0, 1, 0, 0, -1, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, + 0, 0, -1, 0, 0, 0, 1, 1, 0, 0, -1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, 1, + 0, 0, 0, -1, 0, 0, 0, 0, 0, -1, 0, -1, 0, 1, 0, 0, 0, -1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, + 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, -1, 0, 0, 0, 0, -1, -1, 0, -1, 0, 1, 0, 0, -1, -1, 0, 0, 1, + 1, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, + ]; + + let icu4c = ICU4C_ENCODED_MONTH_LENGTHS + .into_iter() + .zip(ICU4C_YEAR_START_ESTIMATE_FIX) + .enumerate() + .map( + |(years_since_1300, (encoded_months_lengths, year_start_estimate_fix))| { + // https://github.com/unicode-org/icu/blob/1bf6bf774dbc8c6c2051963a81100ea1114b497f/icu4c/source/i18n/islamcal.cpp#L858 + let month_lengths = + core::array::from_fn(|i| (1 << (11 - i)) & encoded_months_lengths != 0); + // From https://github.com/unicode-org/icu/blob/1bf6bf774dbc8c6c2051963a81100ea1114b497f/icu4c/source/i18n/islamcal.cpp#L813 + let year_start = ((354.36720 * years_since_1300 as f64) + 460322.05 + 0.5) as i64 + + year_start_estimate_fix; + ( + 1300 + years_since_1300 as i32, + PackedHijriYearData::try_new( + 1300 + years_since_1300 as i32, + month_lengths, + ISLAMIC_EPOCH_FRIDAY + year_start, + ) + .unwrap(), + ) + }, + ) + .collect::>(); + + let icu4x = (1300..=1600).zip(DATA.iter().copied()).collect::>(); + + assert_eq!(icu4x, icu4c); +} diff --git a/deps/crates/vendor/icu_calendar/src/cal/indian.rs b/deps/crates/vendor/icu_calendar/src/cal/indian.rs index 608e85e2ead8c2..0b021d41970d93 100644 --- a/deps/crates/vendor/icu_calendar/src/cal/indian.rs +++ b/deps/crates/vendor/icu_calendar/src/cal/indian.rs @@ -2,40 +2,46 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -//! This module contains types and implementations for the Indian national calendar. -//! -//! ```rust -//! use icu::calendar::{cal::Indian, Date}; -//! -//! let date_iso = Date::try_new_iso(1970, 1, 2) -//! .expect("Failed to initialize ISO Date instance."); -//! let date_indian = Date::new_from_iso(date_iso, Indian); -//! -//! assert_eq!(date_indian.era_year().year, 1891); -//! assert_eq!(date_indian.month().ordinal, 10); -//! assert_eq!(date_indian.day_of_month().0, 12); -//! ``` - -use crate::cal::iso::{Iso, IsoDateInner}; -use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic}; -use crate::error::DateError; -use crate::{types, Calendar, Date, DateDuration, DateDurationUnit, RangeError}; +use crate::calendar_arithmetic::ArithmeticDate; +use crate::calendar_arithmetic::DateFieldsResolver; +use crate::error::{DateError, DateFromFieldsError, EcmaReferenceYearError, UnknownEraError}; +use crate::options::DateFromFieldsOptions; +use crate::options::{DateAddOptions, DateDifferenceOptions}; +use crate::types::DateFields; +use crate::{types, Calendar, Date, RangeError}; use calendrical_calculations::rata_die::RataDie; use tinystr::tinystr; /// The [Indian National (Śaka) Calendar](https://en.wikipedia.org/wiki/Indian_national_calendar) /// -/// The Indian National calendar is a solar calendar used by the Indian government, with twelve months. +/// The Indian National calendar is a solar calendar created by the Indian government. /// -/// This type can be used with [`Date`] to represent dates in this calendar. +/// This implementation extends proleptically for dates before the calendar's creation +/// in 1879 Śaka (1957 CE). +/// +/// This corresponds to the `"indian"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). /// /// # Era codes /// /// This calendar uses a single era code: `shaka`, with Śaka 0 being 78 CE. Dates before this era use negative years. /// -/// # Month codes +/// # Months and days +/// +/// The 12 months are called Chaitra (`M01`, 30 days), Vaisakha (`M02`, 31 days), +/// Jyaishtha (`M03`, 31 days), Ashadha (`M04`, 31 days), Sravana (`M05`, 31 days), +/// Bhadra (`M06`, 31 days), Asvina (`M07`, 30 days), Kartika (`M08`, 30 days), +/// Agrahayana or Margasirsha (`M09`, 30 days), Pausha (`M10`, 30 days), Magha (`M11`, 30 days), +/// Phalguna (`M12`, 30 days). +/// +/// In leap years (years where the concurrent [`Gregorian`](crate::cal::Gregorian) year (`year + 78`) is leap), +/// Chaitra gains a 31st day. +/// +/// Standard years thus have 365 days, and leap years 366. /// -/// This calendar supports 12 solar month codes (`"M01" - "M12"`) +/// # Calendar drift +/// +/// The Indian calendar has the same year lengths and leap year rules as the Gregorian calendar, +/// so it experiences the same drift of 1 day in ~7700 years with respect to the seasons. #[derive(Copy, Clone, Debug, Hash, Default, Eq, PartialEq, PartialOrd, Ord)] #[allow(clippy::exhaustive_structs)] // this type is stable pub struct Indian; @@ -44,16 +50,18 @@ pub struct Indian; #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] pub struct IndianDateInner(ArithmeticDate); -impl CalendarArithmetic for Indian { +/// The Śaka era starts on the 81st day of the Gregorian year (March 22 or 21) +/// which is an 80 day offset. This number should be subtracted from Gregorian dates +const DAY_OFFSET: u16 = 80; +/// The Śaka era is 78 years behind Gregorian. This number should be added to Gregorian dates +const YEAR_OFFSET: i32 = 78; + +impl DateFieldsResolver for Indian { type YearInfo = i32; fn days_in_provided_month(year: i32, month: u8) -> u8 { if month == 1 { - if Self::provided_year_is_leap(year) { - 31 - } else { - 30 - } + 30 + calendrical_calculations::gregorian::is_leap_year(year + YEAR_OFFSET) as u8 } else if (2..=6).contains(&month) { 31 } else if (7..=12).contains(&month) { @@ -67,33 +75,49 @@ impl CalendarArithmetic for Indian { 12 } - fn provided_year_is_leap(year: i32) -> bool { - Iso::provided_year_is_leap(year + 78) + #[inline] + fn year_info_from_era( + &self, + era: &[u8], + era_year: i32, + ) -> Result { + match era { + b"shaka" => Ok(era_year), + _ => Err(UnknownEraError), + } } - fn last_month_day_in_provided_year(_year: i32) -> (u8, u8) { - (12, 30) + #[inline] + fn year_info_from_extended(&self, extended_year: i32) -> Self::YearInfo { + extended_year } - fn days_in_provided_year(year: i32) -> u16 { - if Self::provided_year_is_leap(year) { - 366 + #[inline] + fn reference_year_from_month_day( + &self, + month_code: types::ValidMonthCode, + day: u8, + ) -> Result { + let (ordinal_month, false) = month_code.to_tuple() else { + return Err(EcmaReferenceYearError::MonthCodeNotInCalendar); + }; + // December 31, 1972 occurs on 10th month, 10th day, 1894 Shaka + // Note: 1894 Shaka is also a leap year + let shaka_year = if ordinal_month < 10 || (ordinal_month == 10 && day <= 10) { + 1894 } else { - 365 - } + 1893 + }; + Ok(shaka_year) } } -/// The Śaka era starts on the 81st day of the Gregorian year (March 22 or 21) -/// which is an 80 day offset. This number should be subtracted from Gregorian dates -const DAY_OFFSET: u16 = 80; -/// The Śaka era is 78 years behind Gregorian. This number should be added to Gregorian dates -const YEAR_OFFSET: i32 = 78; - impl crate::cal::scaffold::UnstableSealed for Indian {} impl Calendar for Indian { type DateInner = IndianDateInner; type Year = types::EraYear; + type DifferenceError = core::convert::Infallible; + fn from_codes( &self, era: Option<&str>, @@ -101,115 +125,147 @@ impl Calendar for Indian { month_code: types::MonthCode, day: u8, ) -> Result { - let year = match era { - Some("shaka") | None => year, - Some(_) => return Err(DateError::UnknownEra), - }; - ArithmeticDate::new_from_codes(self, year, month_code, day).map(IndianDateInner) + ArithmeticDate::from_codes(era, year, month_code, day, self).map(IndianDateInner) } - fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { - self.from_iso(Iso.from_rata_die(rd)) - } - - fn to_rata_die(&self, date: &Self::DateInner) -> RataDie { - Iso.to_rata_die(&self.to_iso(date)) + #[cfg(feature = "unstable")] + fn from_fields( + &self, + fields: DateFields, + options: DateFromFieldsOptions, + ) -> Result { + ArithmeticDate::from_fields(fields, options, self).map(IndianDateInner) } // Algorithms directly implemented in icu_calendar since they're not from the book - fn from_iso(&self, iso: IsoDateInner) -> IndianDateInner { + fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { + let iso_year = calendrical_calculations::gregorian::year_from_fixed(rd) + .unwrap_or_else(|e| e.saturate()); // Get day number in year (1 indexed) - let day_of_year_iso = Iso::day_of_year(iso); + let day_of_year_iso = + (rd - calendrical_calculations::gregorian::day_before_year(iso_year)) as u16; // Convert to Śaka year - let mut year = iso.0.year - YEAR_OFFSET; + let mut year = iso_year - YEAR_OFFSET; // This is in the previous Indian year let day_of_year_indian = if day_of_year_iso <= DAY_OFFSET { year -= 1; - let n_days = Self::days_in_provided_year(year); + let n_days = if calendrical_calculations::gregorian::is_leap_year(year + YEAR_OFFSET) { + 366 + } else { + 365 + }; // calculate day of year in previous year n_days + day_of_year_iso - DAY_OFFSET } else { day_of_year_iso - DAY_OFFSET }; - IndianDateInner(ArithmeticDate::date_from_year_day( - year, - day_of_year_indian as u32, - )) + let mut month = 1; + let mut day = day_of_year_indian as i32; + while month <= 12 { + let month_days = Self::days_in_provided_month(year, month) as i32; + if day <= month_days { + break; + } else { + day -= month_days; + month += 1; + } + } + + debug_assert!(day <= Self::days_in_provided_month(year, month) as i32); + let day = day.try_into().unwrap_or(1); + + IndianDateInner(ArithmeticDate::new_unchecked(year, month, day)) } // Algorithms directly implemented in icu_calendar since they're not from the book - fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { - let day_of_year_indian = date.0.day_of_year().0; // 1-indexed - let days_in_year = date.0.days_in_year(); + fn to_rata_die(&self, date: &Self::DateInner) -> RataDie { + let day_of_year_indian = self.day_of_year(date).0; // 1-indexed + let days_in_year = self.days_in_year(date); - let mut year = date.0.year + YEAR_OFFSET; + let mut year_iso = date.0.year + YEAR_OFFSET; // days_in_year is a valid day of the year, so we check > not >= let day_of_year_iso = if day_of_year_indian + DAY_OFFSET > days_in_year { - year += 1; + year_iso += 1; // calculate day of year in next year day_of_year_indian + DAY_OFFSET - days_in_year } else { day_of_year_indian + DAY_OFFSET }; - Iso::iso_from_year_day(year, day_of_year_iso) + + calendrical_calculations::gregorian::day_before_year(year_iso) + day_of_year_iso as i64 + } + + fn has_cheap_iso_conversion(&self) -> bool { + false } fn months_in_year(&self, date: &Self::DateInner) -> u8 { - date.0.months_in_year() + Self::months_in_provided_year(date.0.year) } fn days_in_year(&self, date: &Self::DateInner) -> u16 { - date.0.days_in_year() + if self.is_in_leap_year(date) { + 366 + } else { + 365 + } } fn days_in_month(&self, date: &Self::DateInner) -> u8 { - date.0.days_in_month() + Self::days_in_provided_month(date.0.year, date.0.month) } - fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) { - date.0.offset_date(offset, &()); + #[cfg(feature = "unstable")] + fn add( + &self, + date: &Self::DateInner, + duration: types::DateDuration, + options: DateAddOptions, + ) -> Result { + date.0.added(duration, self, options).map(IndianDateInner) } - #[allow(clippy::field_reassign_with_default)] + #[cfg(feature = "unstable")] fn until( &self, date1: &Self::DateInner, date2: &Self::DateInner, - _calendar2: &Self, - _largest_unit: DateDurationUnit, - _smallest_unit: DateDurationUnit, - ) -> DateDuration { - date1.0.until(date2.0, _largest_unit, _smallest_unit) + options: DateDifferenceOptions, + ) -> Result { + Ok(date1.0.until(&date2.0, self, options)) } fn year_info(&self, date: &Self::DateInner) -> Self::Year { + let extended_year = date.0.year; types::EraYear { era_index: Some(0), era: tinystr!(16, "shaka"), - year: self.extended_year(date), + year: extended_year, + extended_year, ambiguity: types::YearAmbiguity::CenturyRequired, } } - fn extended_year(&self, date: &Self::DateInner) -> i32 { - date.0.extended_year() - } - fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { - Self::provided_year_is_leap(date.0.year) + calendrical_calculations::gregorian::is_leap_year(date.0.year + YEAR_OFFSET) } fn month(&self, date: &Self::DateInner) -> types::MonthInfo { - date.0.month() + types::MonthInfo::non_lunisolar(date.0.month) } fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { - date.0.day_of_month() + types::DayOfMonth(date.0.day) } fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear { - date.0.day_of_year() + types::DayOfYear( + (1..date.0.month) + .map(|m| Self::days_in_provided_month(date.0.year, m) as u16) + .sum::() + + date.0.day as u16, + ) } fn debug_name(&self) -> &'static str { @@ -242,7 +298,7 @@ impl Date { /// assert_eq!(date_indian.day_of_month().0, 12); /// ``` pub fn try_new_indian(year: i32, month: u8, day: u8) -> Result, RangeError> { - ArithmeticDate::new_from_ordinals(year, month, day) + ArithmeticDate::try_from_ymd(year, month, day) .map(IndianDateInner) .map(|inner| Date::from_raw(inner, Indian)) } @@ -450,10 +506,7 @@ mod tests { fn test_roundtrip_near_rd_zero() { for i in -1000..=1000 { let initial = RataDie::new(i); - let result = Date::from_rata_die(initial, Iso) - .to_calendar(Indian) - .to_iso() - .to_rata_die(); + let result = Date::from_rata_die(initial, Indian).to_rata_die(); assert_eq!( initial, result, "Roundtrip failed for initial: {initial:?}, result: {result:?}" @@ -466,10 +519,7 @@ mod tests { // Epoch start: RD 28570 for i in 27570..=29570 { let initial = RataDie::new(i); - let result = Date::from_rata_die(initial, Iso) - .to_calendar(Indian) - .to_iso() - .to_rata_die(); + let result = Date::from_rata_die(initial, Indian).to_rata_die(); assert_eq!( initial, result, "Roundtrip failed for initial: {initial:?}, result: {result:?}" diff --git a/deps/crates/vendor/icu_calendar/src/cal/iso.rs b/deps/crates/vendor/icu_calendar/src/cal/iso.rs index 989485dc7a1733..ebb361817d70a6 100644 --- a/deps/crates/vendor/icu_calendar/src/cal/iso.rs +++ b/deps/crates/vendor/icu_calendar/src/cal/iso.rs @@ -2,186 +2,56 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -//! This module contains types and implementations for the ISO calendar. -//! -//! ```rust -//! use icu::calendar::Date; -//! -//! let date_iso = Date::try_new_iso(1970, 1, 2) -//! .expect("Failed to initialize ISO Date instance."); -//! -//! assert_eq!(date_iso.era_year().year, 1970); -//! assert_eq!(date_iso.month().ordinal, 1); -//! assert_eq!(date_iso.day_of_month().0, 2); -//! ``` - -use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic}; -use crate::error::DateError; -use crate::{types, Calendar, Date, DateDuration, DateDurationUnit, RangeError}; -use calendrical_calculations::helpers::I32CastError; -use calendrical_calculations::rata_die::RataDie; +use crate::cal::abstract_gregorian::{impl_with_abstract_gregorian, GregorianYears}; +use crate::calendar_arithmetic::ArithmeticDate; +use crate::error::UnknownEraError; +use crate::{types, Date, DateError, RangeError}; use tinystr::tinystr; /// The [ISO-8601 Calendar](https://en.wikipedia.org/wiki/ISO_8601#Dates) /// -/// The ISO-8601 Calendar is a standardized solar calendar with twelve months. -/// It is identical to the [`Gregorian`](super::Gregorian) calendar, except it uses -/// negative years for years before 1 CE, and may have differing formatting data for a given locale. +/// This calendar is identical to the [`Gregorian`](super::Gregorian) calendar, +/// except that it uses a single `default` era instead of `bce` and `ce`. /// -/// This type can be used with [`Date`] to represent dates in this calendar. +/// This corresponds to the `"iso8601"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). /// /// # Era codes /// /// This calendar uses a single era: `default` - #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[allow(clippy::exhaustive_structs)] // this type is stable pub struct Iso; -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] -/// The inner date type used for representing [`Date`]s of [`Iso`]. See [`Date`] and [`Iso`] for more details. -pub struct IsoDateInner(pub(crate) ArithmeticDate); - -impl CalendarArithmetic for Iso { - type YearInfo = i32; - - fn days_in_provided_month(year: i32, month: u8) -> u8 { - match month { - 4 | 6 | 9 | 11 => 30, - 2 if Self::provided_year_is_leap(year) => 29, - 2 => 28, - 1 | 3 | 5 | 7 | 8 | 10 | 12 => 31, - _ => 0, - } - } - - fn months_in_provided_year(_: i32) -> u8 { - 12 - } +impl_with_abstract_gregorian!(crate::cal::Iso, IsoDateInner, IsoEra, _x, IsoEra); - fn provided_year_is_leap(year: i32) -> bool { - calendrical_calculations::iso::is_leap_year(year) - } - - fn last_month_day_in_provided_year(_year: i32) -> (u8, u8) { - (12, 31) - } - - fn days_in_provided_year(year: i32) -> u16 { - if Self::provided_year_is_leap(year) { - 366 - } else { - 365 - } - } -} +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub(crate) struct IsoEra; -impl crate::cal::scaffold::UnstableSealed for Iso {} -impl Calendar for Iso { - type DateInner = IsoDateInner; - type Year = types::EraYear; - /// Construct a date from era/month codes and fields - fn from_codes( +impl GregorianYears for IsoEra { + fn extended_from_era_year( &self, - era: Option<&str>, + era: Option<&[u8]>, year: i32, - month_code: types::MonthCode, - day: u8, - ) -> Result { - let year = match era { - Some("default") | None => year, - Some(_) => return Err(DateError::UnknownEra), - }; - - ArithmeticDate::new_from_codes(self, year, month_code, day).map(IsoDateInner) - } - - fn from_rata_die(&self, date: RataDie) -> IsoDateInner { - IsoDateInner(match calendrical_calculations::iso::iso_from_fixed(date) { - Err(I32CastError::BelowMin) => ArithmeticDate::min_date(), - Err(I32CastError::AboveMax) => ArithmeticDate::max_date(), - Ok((year, month, day)) => ArithmeticDate::new_unchecked(year, month, day), - }) - } - - fn to_rata_die(&self, date: &IsoDateInner) -> RataDie { - calendrical_calculations::iso::fixed_from_iso(date.0.year, date.0.month, date.0.day) - } - - fn from_iso(&self, iso: IsoDateInner) -> IsoDateInner { - iso - } - - fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { - *date - } - - fn months_in_year(&self, date: &Self::DateInner) -> u8 { - date.0.months_in_year() - } - - fn days_in_year(&self, date: &Self::DateInner) -> u16 { - date.0.days_in_year() - } - - fn days_in_month(&self, date: &Self::DateInner) -> u8 { - date.0.days_in_month() - } - - fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) { - date.0.offset_date(offset, &()); - } - - #[allow(clippy::field_reassign_with_default)] - fn until( - &self, - date1: &Self::DateInner, - date2: &Self::DateInner, - _calendar2: &Self, - _largest_unit: DateDurationUnit, - _smallest_unit: DateDurationUnit, - ) -> DateDuration { - date1.0.until(date2.0, _largest_unit, _smallest_unit) + ) -> Result { + match era { + Some(b"default") | None => Ok(year), + Some(_) => Err(UnknownEraError), + } } - fn year_info(&self, date: &Self::DateInner) -> Self::Year { + fn era_year_from_extended(&self, extended_year: i32, _month: u8, _day: u8) -> types::EraYear { types::EraYear { era_index: Some(0), era: tinystr!(16, "default"), - year: self.extended_year(date), + year: extended_year, + extended_year, ambiguity: types::YearAmbiguity::Unambiguous, } } - fn extended_year(&self, date: &Self::DateInner) -> i32 { - date.0.extended_year() - } - - fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { - Self::provided_year_is_leap(date.0.year) - } - - /// The calendar-specific month represented by `date` - fn month(&self, date: &Self::DateInner) -> types::MonthInfo { - date.0.month() - } - - /// The calendar-specific day-of-month represented by `date` - fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { - date.0.day_of_month() - } - - fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear { - date.0.day_of_year() - } - fn debug_name(&self) -> &'static str { "ISO" } - - fn calendar_algorithm(&self) -> Option { - None - } } impl Date { @@ -198,9 +68,9 @@ impl Date { /// assert_eq!(date_iso.day_of_month().0, 2); /// ``` pub fn try_new_iso(year: i32, month: u8, day: u8) -> Result, RangeError> { - ArithmeticDate::new_from_ordinals(year, month, day) + ArithmeticDate::new_gregorian::(year, month, day) .map(IsoDateInner) - .map(|inner| Date::from_raw(inner, Iso)) + .map(|i| Date::from_raw(i, Iso)) } } @@ -209,46 +79,13 @@ impl Iso { pub fn new() -> Self { Self } - - pub(crate) fn iso_from_year_day(year: i32, year_day: u16) -> IsoDateInner { - let mut month = 1; - let mut day = year_day as i32; - while month <= 12 { - let month_days = Self::days_in_provided_month(year, month) as i32; - if day <= month_days { - break; - } else { - debug_assert!(month < 12); // don't try going to month 13 - day -= month_days; - month += 1; - } - } - let day = day as u8; // day <= month_days < u8::MAX - - // month in 1..=12, day <= month_days - IsoDateInner(ArithmeticDate::new_unchecked(year, month, day)) - } - - pub(crate) fn day_of_year(date: IsoDateInner) -> u16 { - // Cumulatively how much are dates in each month - // offset from "30 days in each month" (in non leap years) - let month_offset = [0, 1, -1, 0, 0, 1, 1, 2, 3, 3, 4, 4]; - #[allow(clippy::indexing_slicing)] // date.0.month in 1..=12 - let mut offset = month_offset[date.0.month as usize - 1]; - if Self::provided_year_is_leap(date.0.year) && date.0.month > 2 { - // Months after February in a leap year are offset by one less - offset += 1; - } - let prev_month_days = (30 * (date.0.month as i32 - 1) + offset) as u16; - - prev_month_days + date.0.day as u16 - } } #[cfg(test)] mod test { use super::*; - use crate::types::Weekday; + use crate::types::{DateDuration, RataDie, Weekday}; + use crate::Calendar; #[test] fn iso_overflow() { @@ -435,31 +272,20 @@ mod test { assert_eq!(Date::try_new_iso(1983, 2, 2).unwrap().day_of_year().0, 33,); } - fn simple_subtract(a: &Date, b: &Date) -> DateDuration { - let a = a.inner(); - let b = b.inner(); - DateDuration::new( - a.0.year - b.0.year, - a.0.month as i32 - b.0.month as i32, - 0, - a.0.day as i32 - b.0.day as i32, - ) - } - #[test] fn test_offset() { let today = Date::try_new_iso(2021, 6, 23).unwrap(); let today_plus_5000 = Date::try_new_iso(2035, 3, 2).unwrap(); - let offset = today.added(DateDuration::new(0, 0, 0, 5000)); - assert_eq!(offset, today_plus_5000); - let offset = today.added(simple_subtract(&today_plus_5000, &today)); + let offset = today + .try_added_with_options(DateDuration::for_days(5000), Default::default()) + .unwrap(); assert_eq!(offset, today_plus_5000); let today = Date::try_new_iso(2021, 6, 23).unwrap(); let today_minus_5000 = Date::try_new_iso(2007, 10, 15).unwrap(); - let offset = today.added(DateDuration::new(0, 0, 0, -5000)); - assert_eq!(offset, today_minus_5000); - let offset = today.added(simple_subtract(&today_minus_5000, &today)); + let offset = today + .try_added_with_options(DateDuration::for_days(-5000), Default::default()) + .unwrap(); assert_eq!(offset, today_minus_5000); } @@ -467,32 +293,44 @@ mod test { fn test_offset_at_month_boundary() { let today = Date::try_new_iso(2020, 2, 28).unwrap(); let today_plus_2 = Date::try_new_iso(2020, 3, 1).unwrap(); - let offset = today.added(DateDuration::new(0, 0, 0, 2)); + let offset = today + .try_added_with_options(DateDuration::for_days(2), Default::default()) + .unwrap(); assert_eq!(offset, today_plus_2); let today = Date::try_new_iso(2020, 2, 28).unwrap(); let today_plus_3 = Date::try_new_iso(2020, 3, 2).unwrap(); - let offset = today.added(DateDuration::new(0, 0, 0, 3)); + let offset = today + .try_added_with_options(DateDuration::for_days(3), Default::default()) + .unwrap(); assert_eq!(offset, today_plus_3); let today = Date::try_new_iso(2020, 2, 28).unwrap(); let today_plus_1 = Date::try_new_iso(2020, 2, 29).unwrap(); - let offset = today.added(DateDuration::new(0, 0, 0, 1)); + let offset = today + .try_added_with_options(DateDuration::for_days(1), Default::default()) + .unwrap(); assert_eq!(offset, today_plus_1); let today = Date::try_new_iso(2019, 2, 28).unwrap(); let today_plus_2 = Date::try_new_iso(2019, 3, 2).unwrap(); - let offset = today.added(DateDuration::new(0, 0, 0, 2)); + let offset = today + .try_added_with_options(DateDuration::for_days(2), Default::default()) + .unwrap(); assert_eq!(offset, today_plus_2); let today = Date::try_new_iso(2019, 2, 28).unwrap(); let today_plus_1 = Date::try_new_iso(2019, 3, 1).unwrap(); - let offset = today.added(DateDuration::new(0, 0, 0, 1)); + let offset = today + .try_added_with_options(DateDuration::for_days(1), Default::default()) + .unwrap(); assert_eq!(offset, today_plus_1); let today = Date::try_new_iso(2020, 3, 1).unwrap(); let today_minus_1 = Date::try_new_iso(2020, 2, 29).unwrap(); - let offset = today.added(DateDuration::new(0, 0, 0, -1)); + let offset = today + .try_added_with_options(DateDuration::for_days(-1), Default::default()) + .unwrap(); assert_eq!(offset, today_minus_1); } @@ -500,37 +338,57 @@ mod test { fn test_offset_handles_negative_month_offset() { let today = Date::try_new_iso(2020, 3, 1).unwrap(); let today_minus_2_months = Date::try_new_iso(2020, 1, 1).unwrap(); - let offset = today.added(DateDuration::new(0, -2, 0, 0)); + let offset = today + .try_added_with_options(DateDuration::for_months(-2), Default::default()) + .unwrap(); assert_eq!(offset, today_minus_2_months); let today = Date::try_new_iso(2020, 3, 1).unwrap(); let today_minus_4_months = Date::try_new_iso(2019, 11, 1).unwrap(); - let offset = today.added(DateDuration::new(0, -4, 0, 0)); + let offset = today + .try_added_with_options(DateDuration::for_months(-4), Default::default()) + .unwrap(); assert_eq!(offset, today_minus_4_months); let today = Date::try_new_iso(2020, 3, 1).unwrap(); let today_minus_24_months = Date::try_new_iso(2018, 3, 1).unwrap(); - let offset = today.added(DateDuration::new(0, -24, 0, 0)); + let offset = today + .try_added_with_options(DateDuration::for_months(-24), Default::default()) + .unwrap(); assert_eq!(offset, today_minus_24_months); let today = Date::try_new_iso(2020, 3, 1).unwrap(); let today_minus_27_months = Date::try_new_iso(2017, 12, 1).unwrap(); - let offset = today.added(DateDuration::new(0, -27, 0, 0)); + let offset = today + .try_added_with_options(DateDuration::for_months(-27), Default::default()) + .unwrap(); assert_eq!(offset, today_minus_27_months); } #[test] fn test_offset_handles_out_of_bound_month_offset() { let today = Date::try_new_iso(2021, 1, 31).unwrap(); - // since 2021/02/31 isn't a valid date, `offset_date` auto-adjusts by adding 3 days to 2021/02/28 - let today_plus_1_month = Date::try_new_iso(2021, 3, 3).unwrap(); - let offset = today.added(DateDuration::new(0, 1, 0, 0)); + // since 2021/02/31 isn't a valid date, `offset_date` auto-adjusts by constraining to the last day in February + let today_plus_1_month = Date::try_new_iso(2021, 2, 28).unwrap(); + let offset = today + .try_added_with_options(DateDuration::for_months(1), Default::default()) + .unwrap(); assert_eq!(offset, today_plus_1_month); let today = Date::try_new_iso(2021, 1, 31).unwrap(); - // since 2021/02/31 isn't a valid date, `offset_date` auto-adjusts by adding 3 days to 2021/02/28 - let today_plus_1_month_1_day = Date::try_new_iso(2021, 3, 4).unwrap(); - let offset = today.added(DateDuration::new(0, 1, 0, 1)); + // since 2021/02/31 isn't a valid date, `offset_date` auto-adjusts by constraining to the last day in February + // and then adding the days + let today_plus_1_month_1_day = Date::try_new_iso(2021, 3, 1).unwrap(); + let offset = today + .try_added_with_options( + DateDuration { + months: 1, + days: 1, + ..Default::default() + }, + Default::default(), + ) + .unwrap(); assert_eq!(offset, today_plus_1_month_1_day); } diff --git a/deps/crates/vendor/icu_calendar/src/cal/japanese.rs b/deps/crates/vendor/icu_calendar/src/cal/japanese.rs index d52874b265413d..37ad427b9dd334 100644 --- a/deps/crates/vendor/icu_calendar/src/cal/japanese.rs +++ b/deps/crates/vendor/icu_calendar/src/cal/japanese.rs @@ -2,59 +2,41 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -//! This module contains types and implementations for the Japanese calendar. -//! -//! ```rust -//! use icu::calendar::cal::Japanese; -//! use icu::calendar::Date; -//! use tinystr::tinystr; -//! -//! let japanese_calendar = Japanese::new(); -//! -//! let date_iso = Date::try_new_iso(1970, 1, 2) -//! .expect("Failed to initialize ISO Date instance."); -//! let date_japanese = Date::new_from_iso(date_iso, japanese_calendar); -//! -//! assert_eq!(date_japanese.era_year().year, 45); -//! assert_eq!(date_japanese.month().ordinal, 1); -//! assert_eq!(date_japanese.day_of_month().0, 2); -//! assert_eq!(date_japanese.era_year().era, "showa"); -//! ``` - -use crate::cal::iso::{Iso, IsoDateInner}; -use crate::error::{year_check, DateError}; +use crate::cal::abstract_gregorian::{impl_with_abstract_gregorian, GregorianYears}; +use crate::cal::gregorian::CeBce; +use crate::calendar_arithmetic::ArithmeticDate; +use crate::error::{DateError, UnknownEraError}; use crate::provider::{CalendarJapaneseExtendedV1, CalendarJapaneseModernV1, EraStartDate}; -use crate::{types, AsCalendar, Calendar, Date, DateDuration, DateDurationUnit, Ref}; -use calendrical_calculations::rata_die::RataDie; +use crate::{types, AsCalendar, Date}; use icu_provider::prelude::*; -use tinystr::{tinystr, TinyStr16}; +use tinystr::tinystr; /// The [Japanese Calendar] (with modern eras only) /// -/// The [Japanese calendar] is a solar calendar used in Japan, with twelve months. -/// The months and days are identical to that of the Gregorian calendar, however the years are counted -/// differently using the Japanese era system. +/// The [Japanese Calendar] is a variant of the [`Gregorian`](crate::cal::Gregorian) calendar +/// created by the Japanese government. It is identical to the Gregorian calendar except that +/// is uses Japanese eras instead of the Common Era. /// -/// This calendar only contains eras after Meiji, for all historical eras, check out [`JapaneseExtended`]. +/// This implementation extends proleptically for dates before the calendar's creation +/// in 6 Meiji (1873 CE). +/// The Meiji era is used proleptically back to and including 1868-10-23, Gregorian eras are used before that. /// -/// This type can be used with [`Date`] to represent dates in this calendar. +/// For a variant that uses approximations of historical Japanese eras proleptically, check out [`JapaneseExtended`]. +/// +/// This corresponds to the `"japanese"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). /// /// [Japanese calendar]: https://en.wikipedia.org/wiki/Japanese_calendar /// /// # Era codes /// -/// This calendar currently supports seven era codes. It supports the five post-Meiji eras -/// (`meiji`, `taisho`, `showa`, `heisei`, `reiwa`), as well as using the Gregorian -/// `bce` (alias `bc`), and `ce` (alias `ad`) for dates before the Meiji era. +/// This calendar currently supports seven era codes. It supports the five eras since its +/// introduction (`meiji`, `taisho`, `showa`, `heisei`, `reiwa`), as well as the Gregorian +/// `bce` (alias `bc`), and `ce` (alias `ad`) for earlier dates. /// /// Future eras will also be added to this type when they are decided. /// /// These eras are loaded from data, requiring a data provider capable of providing [`CalendarJapaneseModernV1`] /// data. -/// -/// # Month codes -/// -/// This calendar supports 12 solar month codes (`M01` - `M12`) #[derive(Clone, Debug, Default)] pub struct Japanese { eras: DataPayload, @@ -62,40 +44,35 @@ pub struct Japanese { /// The [Japanese Calendar] (with historical eras) /// -/// The [Japanese calendar] is a solar calendar used in Japan, with twelve months. -/// The months and days are identical to that of the Gregorian calendar, however the years are counted -/// differently using the Japanese era system. +/// The [Japanese Calendar] is a variant of the [`Gregorian`](crate::cal::Gregorian) calendar +/// created by the Japanese government. It is identical to the Gregorian calendar except that +/// is uses Japanese eras instead of the Common Era. +/// +/// This implementation extends proleptically for dates before the calendar's creation +/// in 6 Meiji (1873 CE). +/// This implementation uses approximations of earlier Japanese eras proleptically and uses the Gregorian eras for +/// even earlier dates that don't have an approximate Japanese era. +/// +/// For a variant whose Japanese eras start with Meiji, check out [`Japanese`]. /// -/// This type can be used with [`Date`] to represent dates in this calendar. +/// This corresponds to the `"japanext"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). /// /// [Japanese calendar]: https://en.wikipedia.org/wiki/Japanese_calendar /// /// # Era codes /// -/// This calendar supports a large number of era codes. It supports the five post-Meiji eras -/// (`meiji`, `taisho`, `showa`, `heisei`, `reiwa`). Pre-Meiji eras are represented -/// with their names converted to lowercase ascii and followed by their start year. E.g. the *Ten'ō* +/// This calendar supports a large number of era codes. It supports the five eras since its introduction +/// (`meiji`, `taisho`, `showa`, `heisei`, `reiwa`). Proleptic eras are represented +/// with their names converted to lowercase ASCII and followed by their start year. E.g. the *Ten'ō* /// era (781 - 782 CE) has the code `teno-781`. The Gregorian `bce` (alias `bc`), and `ce` (alias `ad`) /// are used for dates before the first known era era. /// /// /// These eras are loaded from data, requiring a data provider capable of providing [`CalendarJapaneseExtendedV1`] /// data. -/// -/// # Month codes -/// -/// This calendar supports 12 solar month codes (`M01` - `M12`) #[derive(Clone, Debug, Default)] pub struct JapaneseExtended(Japanese); -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] -/// The inner date type used for representing [`Date`]s of [`Japanese`]. See [`Date`] and [`Japanese`] for more details. -pub struct JapaneseDateInner { - inner: IsoDateInner, - adjusted_year: i32, - era: TinyStr16, -} - impl Japanese { /// Creates a new [`Japanese`] using only modern eras (post-meiji) from compiled data. /// @@ -127,8 +104,6 @@ impl Japanese { eras: provider.load(Default::default())?.payload, }) } - - pub(crate) const DEBUG_NAME: &'static str = "Japanese"; } impl JapaneseExtended { @@ -162,232 +137,165 @@ impl JapaneseExtended { eras: provider.load(Default::default())?.payload.cast(), })) } - - pub(crate) const DEBUG_NAME: &'static str = "Japanese (historical era data)"; } -impl crate::cal::scaffold::UnstableSealed for Japanese {} -impl Calendar for Japanese { - type DateInner = JapaneseDateInner; - type Year = types::EraYear; +const MEIJI_START: EraStartDate = EraStartDate { + year: 1868, + month: 10, + day: 23, +}; +const TAISHO_START: EraStartDate = EraStartDate { + year: 1912, + month: 7, + day: 30, +}; +const SHOWA_START: EraStartDate = EraStartDate { + year: 1926, + month: 12, + day: 25, +}; +const HEISEI_START: EraStartDate = EraStartDate { + year: 1989, + month: 1, + day: 8, +}; +const REIWA_START: EraStartDate = EraStartDate { + year: 2019, + month: 5, + day: 1, +}; - fn from_codes( +impl GregorianYears for &'_ Japanese { + fn extended_from_era_year( &self, - era: Option<&str>, + era: Option<&[u8]>, year: i32, - month_code: types::MonthCode, - day: u8, - ) -> Result { - let Some((month, false)) = month_code.parsed() else { - return Err(DateError::UnknownMonthCode(month_code)); + ) -> Result { + if let Ok(g) = CeBce.extended_from_era_year(era, year) { + return Ok(g); + } + let Some(era) = era else { + // unreachable, handled by CeBce + return Err(UnknownEraError); }; - if month > 12 { - return Err(DateError::UnknownMonthCode(month_code)); + // Avoid linear search by trying well known eras + if era == b"reiwa" { + return Ok(year - 1 + REIWA_START.year); + } else if era == b"heisei" { + return Ok(year - 1 + HEISEI_START.year); + } else if era == b"showa" { + return Ok(year - 1 + SHOWA_START.year); + } else if era == b"taisho" { + return Ok(year - 1 + TAISHO_START.year); + } else if era == b"meiji" { + return Ok(year - 1 + MEIJI_START.year); } - self.new_japanese_date_inner(era.unwrap_or("ce"), year, month, day) - } + let data = &self.eras.get().dates_to_eras; - fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { - self.from_iso(Iso.from_rata_die(rd)) - } - - fn to_rata_die(&self, date: &Self::DateInner) -> RataDie { - Iso.to_rata_die(&self.to_iso(date)) - } - - fn from_iso(&self, iso: IsoDateInner) -> JapaneseDateInner { - let (adjusted_year, era) = self.adjusted_year_for(iso); - JapaneseDateInner { - inner: iso, - adjusted_year, - era, + // Try to avoid linear search by binary searching for the year suffix + if let Some(start_year) = era + .split(|x| *x == b'-') + .nth(1) + .and_then(|y| core::str::from_utf8(y).ok()?.parse::().ok()) + { + if let Ok(index) = data.binary_search_by(|(d, _)| d.year.cmp(&start_year)) { + // There is a slight chance we hit the case where there are two eras in the same year + // There are a couple of rare cases of this, but it's not worth writing a range-based binary search + // to catch them since this is an optimization + #[expect(clippy::unwrap_used)] // binary search + if data.get(index).unwrap().1.as_bytes() == era { + return Ok(start_year + year - 1); + } + } } - } - - fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { - date.inner - } - - fn months_in_year(&self, date: &Self::DateInner) -> u8 { - Iso.months_in_year(&date.inner) - } - fn days_in_year(&self, date: &Self::DateInner) -> u16 { - Iso.days_in_year(&date.inner) - } - - fn days_in_month(&self, date: &Self::DateInner) -> u8 { - Iso.days_in_month(&date.inner) - } - - fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) { - Iso.offset_date(&mut date.inner, offset.cast_unit()); - let (adjusted_year, era) = self.adjusted_year_for(date.inner); - date.adjusted_year = adjusted_year; - date.era = era - } - - fn until( - &self, - date1: &Self::DateInner, - date2: &Self::DateInner, - _calendar2: &Self, - largest_unit: DateDurationUnit, - smallest_unit: DateDurationUnit, - ) -> DateDuration { - Iso.until( - &date1.inner, - &date2.inner, - &Iso, - largest_unit, - smallest_unit, - ) - .cast_unit() - } + // Avoidance didn't work. Let's find the era manually, searching back from the present + let era_start = data + .iter() + .rev() + .find_map(|(s, e)| (e.as_bytes() == era).then_some(s)) + .ok_or(UnknownEraError)?; + Ok(era_start.year + year - 1) + } + + fn era_year_from_extended(&self, year: i32, month: u8, day: u8) -> types::EraYear { + let date: EraStartDate = EraStartDate { year, month, day }; + + let (start, era) = if date >= MEIJI_START + && self + .eras + .get() + .dates_to_eras + .last() + .is_some_and(|(_, e)| e == tinystr!(16, "reiwa")) + { + // We optimize for the five "modern" post-Meiji eras, which are stored in a smaller + // array and also hardcoded. The hardcoded version is not used if data indicates the + // presence of newer eras. + if date >= REIWA_START { + (REIWA_START, tinystr!(16, "reiwa")) + } else if date >= HEISEI_START { + (HEISEI_START, tinystr!(16, "heisei")) + } else if date >= SHOWA_START { + (SHOWA_START, tinystr!(16, "showa")) + } else if date >= TAISHO_START { + (TAISHO_START, tinystr!(16, "taisho")) + } else { + (MEIJI_START, tinystr!(16, "meiji")) + } + } else { + let data = &self.eras.get().dates_to_eras; + #[allow(clippy::unwrap_used)] // binary search + match data.binary_search_by(|(d, _)| d.cmp(&date)) { + Err(0) => { + return types::EraYear { + // TODO: return era indices? + era_index: None, + ..CeBce.era_year_from_extended(year, month, day) + }; + } + Ok(index) => data.get(index).unwrap(), + Err(index) => data.get(index - 1).unwrap(), + } + }; - fn year_info(&self, date: &Self::DateInner) -> Self::Year { types::EraYear { - era: date.era, + era, era_index: None, - year: date.adjusted_year, + year: year - start.year + 1, + extended_year: year, ambiguity: types::YearAmbiguity::CenturyRequired, } } - fn extended_year(&self, date: &Self::DateInner) -> i32 { - Iso.extended_year(&date.inner) - } - - fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { - Iso.is_in_leap_year(&date.inner) - } - - /// The calendar-specific month represented by `date` - fn month(&self, date: &Self::DateInner) -> types::MonthInfo { - Iso.month(&date.inner) - } - - /// The calendar-specific day-of-month represented by `date` - fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { - Iso.day_of_month(&date.inner) - } - - fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear { - Iso.day_of_year(&date.inner) - } - fn debug_name(&self) -> &'static str { - Self::DEBUG_NAME + if self.eras.get().dates_to_eras.len() > 10 { + "Japanese (historical era data)" + } else { + "Japanese" + } } fn calendar_algorithm(&self) -> Option { - Some(crate::preferences::CalendarAlgorithm::Japanese) + if self.eras.get().dates_to_eras.len() > 10 { + None + } else { + Some(crate::preferences::CalendarAlgorithm::Japanese) + } } } -impl crate::cal::scaffold::UnstableSealed for JapaneseExtended {} -impl Calendar for JapaneseExtended { - type DateInner = JapaneseDateInner; - type Year = types::EraYear; - - fn from_codes( - &self, - era: Option<&str>, - year: i32, - month_code: types::MonthCode, - day: u8, - ) -> Result { - self.0.from_codes(era, year, month_code, day) - } - - fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { - Japanese::from_rata_die(&self.0, rd) - } +impl_with_abstract_gregorian!(Japanese, JapaneseDateInner, Japanese, this, this); - fn to_rata_die(&self, date: &Self::DateInner) -> RataDie { - Japanese::to_rata_die(&self.0, date) - } - - fn from_iso(&self, iso: IsoDateInner) -> JapaneseDateInner { - Japanese::from_iso(&self.0, iso) - } - - fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { - Japanese::to_iso(&self.0, date) - } - - fn months_in_year(&self, date: &Self::DateInner) -> u8 { - Japanese::months_in_year(&self.0, date) - } - - fn days_in_year(&self, date: &Self::DateInner) -> u16 { - Japanese::days_in_year(&self.0, date) - } - - fn days_in_month(&self, date: &Self::DateInner) -> u8 { - Japanese::days_in_month(&self.0, date) - } - - fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) { - Japanese::offset_date(&self.0, date, offset.cast_unit()) - } - - fn until( - &self, - date1: &Self::DateInner, - date2: &Self::DateInner, - calendar2: &Self, - largest_unit: DateDurationUnit, - smallest_unit: DateDurationUnit, - ) -> DateDuration { - Japanese::until( - &self.0, - date1, - date2, - &calendar2.0, - largest_unit, - smallest_unit, - ) - .cast_unit() - } - - fn year_info(&self, date: &Self::DateInner) -> Self::Year { - Japanese::year_info(&self.0, date) - } - - fn extended_year(&self, date: &Self::DateInner) -> i32 { - Japanese::extended_year(&self.0, date) - } - - fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { - Japanese::is_in_leap_year(&self.0, date) - } - - /// The calendar-specific month represented by `date` - fn month(&self, date: &Self::DateInner) -> types::MonthInfo { - Japanese::month(&self.0, date) - } - - /// The calendar-specific day-of-month represented by `date` - fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { - Japanese::day_of_month(&self.0, date) - } - - /// Information of the day of the year - fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear { - Japanese::day_of_year(&self.0, date) - } - - fn debug_name(&self) -> &'static str { - Self::DEBUG_NAME - } - - fn calendar_algorithm(&self) -> Option { - Some(crate::preferences::CalendarAlgorithm::Japanese) - } -} +impl_with_abstract_gregorian!( + JapaneseExtended, + JapaneseExtendedDateInner, + Japanese, + this, + &this.0 +); impl Date { /// Construct a new Japanese Date. @@ -418,13 +326,7 @@ impl Date { /// assert_eq!(date.month().ordinal, 1); /// assert_eq!(date.day_of_month().0, 2); /// - /// // This function will error for eras that are out of bounds: - /// // (Heisei was 32 years long, Heisei 33 is in Reiwa) - /// let oob_date = - /// Date::try_new_japanese_with_calendar(era, 33, 1, 2, japanese_calendar); - /// assert!(oob_date.is_err()); - /// - /// // and for unknown eras + /// // This function will error for unknown eras /// let fake_era = "neko"; // 🐱 /// let fake_date = Date::try_new_japanese_with_calendar( /// fake_era, @@ -442,10 +344,15 @@ impl Date { day: u8, japanese_calendar: A, ) -> Result, DateError> { - let inner = japanese_calendar + let extended = japanese_calendar .as_calendar() - .new_japanese_date_inner(era, year, month, day)?; - Ok(Date::from_raw(inner, japanese_calendar)) + .extended_from_era_year(Some(era.as_bytes()), year)?; + Ok(Date::from_raw( + JapaneseDateInner(ArithmeticDate::new_gregorian::<&Japanese>( + extended, month, day, + )?), + japanese_calendar, + )) } } @@ -490,248 +397,14 @@ impl Date { day: u8, japanext_calendar: A, ) -> Result, DateError> { - let inner = japanext_calendar - .as_calendar() - .0 - .new_japanese_date_inner(era, year, month, day)?; - Ok(Date::from_raw(inner, japanext_calendar)) - } -} - -const MEIJI_START: EraStartDate = EraStartDate { - year: 1868, - month: 10, - day: 23, -}; -const TAISHO_START: EraStartDate = EraStartDate { - year: 1912, - month: 7, - day: 30, -}; -const SHOWA_START: EraStartDate = EraStartDate { - year: 1926, - month: 12, - day: 25, -}; -const HEISEI_START: EraStartDate = EraStartDate { - year: 1989, - month: 1, - day: 8, -}; -const REIWA_START: EraStartDate = EraStartDate { - year: 2019, - month: 5, - day: 1, -}; - -impl Japanese { - /// Given an ISO date, give year and era for that date in the Japanese calendar - /// - /// This will also use Gregorian eras for eras that are before the earliest era - fn adjusted_year_for(&self, date: IsoDateInner) -> (i32, TinyStr16) { - let date: EraStartDate = EraStartDate { - year: date.0.year, - month: date.0.month, - day: date.0.day, - }; - let (start, era) = self.japanese_era_for(date); - // The year in which an era starts is Year 1, and it may be short - // The only time this function will experience dates that are *before* - // the era start date are for the first era (Currently, taika-645 - // for japanext, meiji for japanese), - // In such a case, we instead fall back to Gregorian era codes - if date < start { - if date.year <= 0 { - (1 - date.year, tinystr!(16, "bce")) - } else { - (date.year, tinystr!(16, "ce")) - } - } else { - (date.year - start.year + 1, era) - } - } - - /// Given an date, obtain the era data (not counting spliced gregorian eras) - fn japanese_era_for(&self, date: EraStartDate) -> (EraStartDate, TinyStr16) { - let era_data = self.eras.get(); - // We optimize for the five "modern" post-Meiji eras, which are stored in a smaller - // array and also hardcoded. The hardcoded version is not used if data indicates the - // presence of newer eras. - if date >= MEIJI_START - && era_data.dates_to_eras.last().map(|x| x.1) == Some(tinystr!(16, "reiwa")) - { - // Fast path in case eras have not changed since this code was written - return if date >= REIWA_START { - (REIWA_START, tinystr!(16, "reiwa")) - } else if date >= HEISEI_START { - (HEISEI_START, tinystr!(16, "heisei")) - } else if date >= SHOWA_START { - (SHOWA_START, tinystr!(16, "showa")) - } else if date >= TAISHO_START { - (TAISHO_START, tinystr!(16, "taisho")) - } else { - (MEIJI_START, tinystr!(16, "meiji")) - }; - } - let data = &era_data.dates_to_eras; - match data.binary_search_by(|(d, _)| d.cmp(&date)) { - Ok(index) => data.get(index), - Err(index) if index == 0 => data.get(index), - Err(index) => data.get(index - 1).or_else(|| data.iter().next_back()), - } - .unwrap_or((REIWA_START, tinystr!(16, "reiwa"))) - } - - /// Returns the range of dates for a given Japanese era code, - /// not handling "bce" or "ce" - /// - /// Returns (era_start, era_end) - fn japanese_era_range_for( - &self, - era: TinyStr16, - ) -> Result<(EraStartDate, Option), DateError> { - // Avoid linear search by trying well known eras - if era == tinystr!(16, "reiwa") { - // Check if we're the last - if let Some(last) = self.eras.get().dates_to_eras.last() { - if last.1 == era { - return Ok((REIWA_START, None)); - } - } - } else if era == tinystr!(16, "heisei") { - return Ok((HEISEI_START, Some(REIWA_START))); - } else if era == tinystr!(16, "showa") { - return Ok((SHOWA_START, Some(HEISEI_START))); - } else if era == tinystr!(16, "taisho") { - return Ok((TAISHO_START, Some(SHOWA_START))); - } else if era == tinystr!(16, "meiji") { - return Ok((MEIJI_START, Some(TAISHO_START))); - } - - let era_data = self.eras.get(); - let data = &era_data.dates_to_eras; - // Try to avoid linear search by binary searching for the year suffix - if let Some(year) = era.split('-').nth(1) { - if let Ok(ref int) = year.parse::() { - if let Ok(index) = data.binary_search_by(|(d, _)| d.year.cmp(int)) { - #[allow(clippy::expect_used)] // see expect message - let (era_start, code) = data - .get(index) - .expect("Indexing from successful binary search must succeed"); - // There is a slight chance we hit the case where there are two eras in the same year - // There are a couple of rare cases of this, but it's not worth writing a range-based binary search - // to catch them since this is an optimization - if code == era { - return Ok((era_start, data.get(index + 1).map(|e| e.0))); - } - } - } - } - - // Avoidance didn't work. Let's find the era manually, searching back from the present - if let Some((index, (start, _))) = data.iter().enumerate().rev().find(|d| d.1 .1 == era) { - return Ok((start, data.get(index + 1).map(|e| e.0))); - } - - Err(DateError::UnknownEra) - } - - fn new_japanese_date_inner( - &self, - era: &str, - year: i32, - month: u8, - day: u8, - ) -> Result { - let cal = Ref(self); - let era = match era { - "ce" | "ad" => { - return Ok(Date::try_new_gregorian(year_check(year, 1..)?, month, day)? - .to_calendar(cal) - .inner); - } - "bce" | "bc" => { - return Ok( - Date::try_new_gregorian(1 - year_check(year, 1..)?, month, day)? - .to_calendar(cal) - .inner, - ); - } - e => e.parse().map_err(|_| DateError::UnknownEra)?, - }; - - let (era_start, next_era_start) = self.japanese_era_range_for(era)?; - - let next_era_start = next_era_start.unwrap_or(EraStartDate { - year: i32::MAX, - month: 12, - day: 31, - }); - - let date_in_iso = EraStartDate { - year: era_start.year + year - 1, - month, - day, - }; - - if date_in_iso < era_start { - return Err(if date_in_iso.year < era_start.year { - DateError::Range { - field: "year", - value: year, - min: 1, - max: 1 + next_era_start.year - era_start.year, - } - } else if date_in_iso.month < era_start.month { - DateError::Range { - field: "month", - value: month as i32, - min: era_start.month as i32, - max: 12, - } - } else - /* if date_in_iso.day < era_start.day */ - { - DateError::Range { - field: "day", - value: day as i32, - min: era_start.day as i32, - max: 31, - } - }); - } else if date_in_iso >= next_era_start { - return Err(if date_in_iso.year > era_start.year { - DateError::Range { - field: "year", - value: year, - min: 1, - max: 1 + next_era_start.year - era_start.year, - } - } else if date_in_iso.month > era_start.month { - DateError::Range { - field: "month", - value: month as i32, - min: 1, - max: next_era_start.month as i32 - 1, - } - } else - /* if date_in_iso.day >= era_start.day */ - { - DateError::Range { - field: "day", - value: day as i32, - min: 1, - max: next_era_start.day as i32 - 1, - } - }); - } - - let iso = Date::try_new_iso(date_in_iso.year, date_in_iso.month, date_in_iso.day)?; - Ok(JapaneseDateInner { - inner: iso.inner, - adjusted_year: year, - era, - }) + let extended = (&japanext_calendar.as_calendar().0) + .extended_from_era_year(Some(era.as_bytes()), year)?; + Ok(Date::from_raw( + JapaneseExtendedDateInner(ArithmeticDate::new_gregorian::<&Japanese>( + extended, month, day, + )?), + japanext_calendar, + )) } } @@ -776,9 +449,9 @@ mod tests { ) } - // test that the Gregorian eras roundtrip to Japanese ones - fn single_test_gregorian_roundtrip_ext( - calendar: Ref, + // test that out-of-range era values roundtrip to other eras + fn single_test_era_range_roundtrip( + calendar: Ref, era: &str, year: i32, month: u8, @@ -786,14 +459,14 @@ mod tests { era2: &str, year2: i32, ) { - let expected = Date::try_new_japanese_extended_with_calendar(era2, year2, month, day, calendar) + let expected = Date::try_new_japanese_with_calendar(era2, year2, month, day, calendar) .unwrap_or_else(|e| { panic!( "Failed to construct expectation date with {era2:?}, {year2}, {month}, {day}: {e:?}" ) }); - let date = Date::try_new_japanese_extended_with_calendar(era, year, month, day, calendar) + let date = Date::try_new_japanese_with_calendar(era, year, month, day, calendar) .unwrap_or_else(|e| { panic!("Failed to construct date with {era:?}, {year}, {month}, {day}: {e:?}") }); @@ -804,32 +477,43 @@ mod tests { "Failed to roundtrip with {era:?}, {year}, {month}, {day} == {era2:?}, {year}" ) } - - fn single_test_error( - calendar: Ref, + fn single_test_era_range_roundtrip_ext( + calendar: Ref, era: &str, year: i32, month: u8, day: u8, - error: DateError, + era2: &str, + year2: i32, ) { - let date = Date::try_new_japanese_with_calendar(era, year, month, day, calendar); + let expected = Date::try_new_japanese_extended_with_calendar(era2, year2, month, day, calendar) + .unwrap_or_else(|e| { + panic!( + "Failed to construct expectation date with {era2:?}, {year2}, {month}, {day}: {e:?}" + ) + }); + + let date = Date::try_new_japanese_extended_with_calendar(era, year, month, day, calendar) + .unwrap_or_else(|e| { + panic!("Failed to construct date with {era:?}, {year}, {month}, {day}: {e:?}") + }); + let iso = date.to_iso(); + let reconstructed = Date::new_from_iso(iso, calendar); assert_eq!( - date, - Err(error), - "Construction with {era:?}, {year}, {month}, {day} did not return {error:?}" + expected, reconstructed, + "Failed to roundtrip with {era:?}, {year}, {month}, {day} == {era2:?}, {year}" ) } - fn single_test_error_ext( - calendar: Ref, + fn single_test_error( + calendar: Ref, era: &str, year: i32, month: u8, day: u8, error: DateError, ) { - let date = Date::try_new_japanese_extended_with_calendar(era, year, month, day, calendar); + let date = Date::try_new_japanese_with_calendar(era, year, month, day, calendar); assert_eq!( date, Err(error), @@ -847,35 +531,11 @@ mod tests { single_test_roundtrip(calendar, "heisei", 12, 3, 1); single_test_roundtrip(calendar, "taisho", 3, 3, 1); // Heisei did not start until later in the year - single_test_error( - calendar, - "heisei", - 1, - 1, - 1, - DateError::Range { - field: "day", - value: 1, - min: 8, - max: 31, - }, - ); + single_test_era_range_roundtrip(calendar, "heisei", 1, 1, 1, "showa", 64); single_test_roundtrip_ext(calendar_ext, "heisei", 12, 3, 1); single_test_roundtrip_ext(calendar_ext, "taisho", 3, 3, 1); - single_test_error_ext( - calendar_ext, - "heisei", - 1, - 1, - 1, - DateError::Range { - field: "day", - value: 1, - min: 8, - max: 31, - }, - ); + single_test_era_range_roundtrip_ext(calendar_ext, "heisei", 1, 1, 1, "showa", 64); single_test_roundtrip_ext(calendar_ext, "hakuho-672", 4, 3, 1); single_test_error(calendar, "hakuho-672", 4, 3, 1, DateError::UnknownEra); @@ -887,69 +547,38 @@ mod tests { single_test_roundtrip(calendar, "ce", 100, 3, 1); single_test_roundtrip_ext(calendar_ext, "ce", 100, 3, 1); single_test_roundtrip(calendar, "ce", 1000, 3, 1); - single_test_error( - calendar, - "ce", - 0, - 3, - 1, - DateError::Range { - field: "year", - value: 0, - min: 1, - max: i32::MAX, - }, - ); - single_test_error( - calendar, - "bce", - -1, - 3, - 1, - DateError::Range { - field: "year", - value: -1, - min: 1, - max: i32::MAX, - }, - ); + single_test_era_range_roundtrip(calendar, "ce", 0, 3, 1, "bce", 1); + single_test_era_range_roundtrip(calendar, "bce", -1, 3, 1, "ce", 2); // handle the cases where bce/ce get adjusted to different eras // single_test_gregorian_roundtrip(calendar, "ce", 2021, 3, 1, "reiwa", 3); - single_test_gregorian_roundtrip_ext(calendar_ext, "ce", 1000, 3, 1, "choho-999", 2); - single_test_gregorian_roundtrip_ext(calendar_ext, "ce", 749, 5, 10, "tenpyokampo-749", 1); - single_test_gregorian_roundtrip_ext(calendar_ext, "bce", 10, 3, 1, "bce", 10); + single_test_era_range_roundtrip_ext(calendar_ext, "ce", 1000, 3, 1, "choho-999", 2); + single_test_era_range_roundtrip_ext(calendar_ext, "ce", 749, 5, 10, "tenpyokampo-749", 1); + single_test_era_range_roundtrip_ext(calendar_ext, "bce", 10, 3, 1, "bce", 10); + single_test_era_range_roundtrip_ext(calendar_ext, "ce", -1, 3, 1, "bce", 2); // There were multiple eras in this year // This one is from Apr 14 to July 2 single_test_roundtrip_ext(calendar_ext, "tenpyokampo-749", 1, 4, 20); single_test_roundtrip_ext(calendar_ext, "tenpyokampo-749", 1, 4, 14); single_test_roundtrip_ext(calendar_ext, "tenpyokampo-749", 1, 7, 1); - single_test_error_ext( + single_test_era_range_roundtrip_ext( calendar_ext, "tenpyokampo-749", 1, 7, 5, - DateError::Range { - field: "month", - value: 7, - min: 1, - max: 6, - }, + "tenpyoshoho-749", + 1, ); - single_test_error_ext( + single_test_era_range_roundtrip_ext( calendar_ext, "tenpyokampo-749", 1, 4, 13, - DateError::Range { - field: "day", - value: 13, - min: 14, - max: 31, - }, + "tenpyoshoho-749", + 1, ); } } diff --git a/deps/crates/vendor/icu_calendar/src/cal/julian.rs b/deps/crates/vendor/icu_calendar/src/cal/julian.rs index 92379e0bde1f22..f0a48379d6fe22 100644 --- a/deps/crates/vendor/icu_calendar/src/cal/julian.rs +++ b/deps/crates/vendor/icu_calendar/src/cal/julian.rs @@ -2,59 +2,90 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -//! This module contains types and implementations for the Julian calendar. -//! -//! ```rust -//! use icu::calendar::{cal::Julian, Date}; -//! -//! let date_iso = Date::try_new_iso(1970, 1, 2) -//! .expect("Failed to initialize ISO Date instance."); -//! let date_julian = Date::new_from_iso(date_iso, Julian); -//! -//! assert_eq!(date_julian.era_year().year, 1969); -//! assert_eq!(date_julian.month().ordinal, 12); -//! assert_eq!(date_julian.day_of_month().0, 20); -//! ``` - -use crate::cal::iso::{Iso, IsoDateInner}; -use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic}; -use crate::error::{year_check, DateError}; -use crate::{types, Calendar, Date, DateDuration, DateDurationUnit, RangeError}; +use crate::calendar_arithmetic::ArithmeticDate; +use crate::calendar_arithmetic::DateFieldsResolver; +use crate::error::{DateError, DateFromFieldsError, EcmaReferenceYearError, UnknownEraError}; +use crate::options::DateFromFieldsOptions; +use crate::options::{DateAddOptions, DateDifferenceOptions}; +use crate::types::DateFields; +use crate::{types, Calendar, Date, RangeError}; use calendrical_calculations::helpers::I32CastError; use calendrical_calculations::rata_die::RataDie; use tinystr::tinystr; -/// The [Julian Calendar] +/// The [Julian Calendar](https://en.wikipedia.org/wiki/Julian_calendar). /// -/// The [Julian calendar] is a solar calendar that was used commonly historically, with twelve months. +/// The Julian calendar is a solar calendar that was introduced in the Roman Republic under +/// Julius Caesar in 45 BCE, and used in Europe and much of the western world until it was +/// eventually replaced by the more accurate [`Gregorian`](super::Gregorian) calendar. /// -/// This type can be used with [`Date`] to represent dates in this calendar. +/// This implementation extends proleptically for dates before the calendar's creation. /// -/// [Julian calendar]: https://en.wikipedia.org/wiki/Julian_calendar +/// While no country uses the Julian calendar as its civil calendar today, it is still +/// used by eastern Christian churches to determine lithurgical dates like Christmas and +/// Easter. /// /// # Era codes /// /// This calendar uses two era codes: `bce` (alias `bc`), and `ce` (alias `ad`), corresponding to the BCE and CE eras. /// -/// # Month codes +/// # Months and days /// -/// This calendar supports 12 solar month codes (`"M01" - "M12"`) +/// The 12 months are called January (`M01`, 31 days), February (`M02`, 28 days), +/// March (`M03`, 31 days), April (`M04`, 30 days), May (`M05`, 31 days), June (`M06`, 30 days), +/// July (`M07`, 31 days), August (`M08`, 31 days), September (`M09`, 30 days), +/// October (`M10`, 31 days), November (`M11`, 30 days), December (`M12`, 31 days). +/// +/// In leap years (years divisible by 4), February gains a 29th day. +/// +/// Standard years thus have 365 days, and leap years 366. +/// +/// # Calendar drift +/// +/// The Julian calendar has an average year length of 365.25, slightly longer than +/// the mean solar year, so this calendar drifts 1 day in ~128 years with +/// respect to the seasons. This significant drift was the reason for its replacement +/// by the Gregorian calendar. The Julian calendar is currently 14 days ahead of the +/// Gregorian calendar and the solar year. +/// +/// # Historical accuracy +/// +/// Historically, a variety of year reckoning schemes have been used with the Julian +/// calendar, such as Roman consular years, regnal years, [indictions]( +/// https://en.wikipedia.org/wiki/Indiction), [Anno Mundi]( +/// https://en.wikipedia.org/wiki/Anno_Mundi#Byzantine_era), the [Diocletian era]( +/// https://en.wikipedia.org/wiki/Era_of_the_Martyrs), [Anno Domini]( +/// https://en.wikipedia.org/wiki/Anno_Domini), and the (equivalent) [Common era]( +/// https://en.wikipedia.org/wiki/Common_Era). +/// The latter, which is used today and by this implementation, has been used by +/// western European authorities since the early middle ages, however some eastern +/// European countries/churches have not adopted it until fairly recently, or, in +/// some cases, are still using a different year reckoning scheme. +/// +/// Also during the middle ages, [some countries](https://en.wikipedia.org/wiki/New_Year#Historical_European_new_year_dates) +/// used different dates for the first day of the year, ranging from late December to +/// late March. Care has to be taken when interpreting year numbers with dates in this +/// range. +/// +/// The calendar was used [incorrectly](https://en.wikipedia.org/wiki/Julian_calendar#Leap_year_error) +/// for a while after adoption, so the first year where the months align with this proleptic +/// implementation is probably 4 CE. #[derive(Copy, Clone, Debug, Hash, Default, Eq, PartialEq, PartialOrd, Ord)] #[allow(clippy::exhaustive_structs)] // this type is stable pub struct Julian; /// The inner date type used for representing [`Date`]s of [`Julian`]. See [`Date`] and [`Julian`] for more details. -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] // The inner date type used for representing Date pub struct JulianDateInner(pub(crate) ArithmeticDate); -impl CalendarArithmetic for Julian { +impl DateFieldsResolver for Julian { type YearInfo = i32; fn days_in_provided_month(year: i32, month: u8) -> u8 { match month { 4 | 6 | 9 | 11 => 30, - 2 if Self::provided_year_is_leap(year) => 29, + 2 if calendrical_calculations::julian::is_leap_year(year) => 29, 2 => 28, 1 | 3 | 5 | 7 | 8 | 10 | 12 => 31, _ => 0, @@ -65,20 +96,41 @@ impl CalendarArithmetic for Julian { 12 } - fn provided_year_is_leap(year: i32) -> bool { - calendrical_calculations::julian::is_leap_year(year) + #[inline] + fn year_info_from_era( + &self, + era: &[u8], + era_year: i32, + ) -> Result { + match era { + b"ad" | b"ce" => Ok(era_year), + b"bc" | b"bce" => Ok(1 - era_year), + _ => Err(UnknownEraError), + } } - fn last_month_day_in_provided_year(_year: i32) -> (u8, u8) { - (12, 31) + #[inline] + fn year_info_from_extended(&self, extended_year: i32) -> Self::YearInfo { + extended_year } - fn days_in_provided_year(year: i32) -> u16 { - if Self::provided_year_is_leap(year) { - 366 + #[inline] + fn reference_year_from_month_day( + &self, + month_code: types::ValidMonthCode, + day: u8, + ) -> Result { + let (ordinal_month, false) = month_code.to_tuple() else { + return Err(EcmaReferenceYearError::MonthCodeNotInCalendar); + }; + // December 31, 1972 occurs on 12th month, 18th day, 1972 Old Style + // Note: 1972 is a leap year + let julian_year = if ordinal_month < 12 || (ordinal_month == 12 && day <= 18) { + 1972 } else { - 365 - } + 1971 + }; + Ok(julian_year) } } @@ -86,6 +138,7 @@ impl crate::cal::scaffold::UnstableSealed for Julian {} impl Calendar for Julian { type DateInner = JulianDateInner; type Year = types::EraYear; + type DifferenceError = core::convert::Infallible; fn from_codes( &self, @@ -94,20 +147,23 @@ impl Calendar for Julian { month_code: types::MonthCode, day: u8, ) -> Result { - let year = match era { - Some("ce" | "ad") | None => year_check(year, 1..)?, - Some("bce" | "bc") => 1 - year_check(year, 1..)?, - Some(_) => return Err(DateError::UnknownEra), - }; + ArithmeticDate::from_codes(era, year, month_code, day, self).map(JulianDateInner) + } - ArithmeticDate::new_from_codes(self, year, month_code, day).map(JulianDateInner) + #[cfg(feature = "unstable")] + fn from_fields( + &self, + fields: DateFields, + options: DateFromFieldsOptions, + ) -> Result { + ArithmeticDate::from_fields(fields, options, self).map(JulianDateInner) } fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { JulianDateInner( match calendrical_calculations::julian::julian_from_fixed(rd) { - Err(I32CastError::BelowMin) => ArithmeticDate::min_date(), - Err(I32CastError::AboveMax) => ArithmeticDate::max_date(), + Err(I32CastError::BelowMin) => ArithmeticDate::new_unchecked(i32::MIN, 1, 1), + Err(I32CastError::AboveMax) => ArithmeticDate::new_unchecked(i32::MAX, 12, 31), Ok((year, month, day)) => ArithmeticDate::new_unchecked(year, month, day), }, ) @@ -117,83 +173,90 @@ impl Calendar for Julian { calendrical_calculations::julian::fixed_from_julian(date.0.year, date.0.month, date.0.day) } - fn from_iso(&self, iso: IsoDateInner) -> JulianDateInner { - self.from_rata_die(Iso.to_rata_die(&iso)) - } - - fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { - Iso.from_rata_die(self.to_rata_die(date)) + fn has_cheap_iso_conversion(&self) -> bool { + false } fn months_in_year(&self, date: &Self::DateInner) -> u8 { - date.0.months_in_year() + Self::months_in_provided_year(date.0.year) } fn days_in_year(&self, date: &Self::DateInner) -> u16 { - date.0.days_in_year() + if self.is_in_leap_year(date) { + 366 + } else { + 365 + } } fn days_in_month(&self, date: &Self::DateInner) -> u8 { - date.0.days_in_month() + Self::days_in_provided_month(date.0.year, date.0.month) } - fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) { - date.0.offset_date(offset, &()); + #[cfg(feature = "unstable")] + fn add( + &self, + date: &Self::DateInner, + duration: types::DateDuration, + options: DateAddOptions, + ) -> Result { + date.0.added(duration, self, options).map(JulianDateInner) } - #[allow(clippy::field_reassign_with_default)] + #[cfg(feature = "unstable")] fn until( &self, date1: &Self::DateInner, date2: &Self::DateInner, - _calendar2: &Self, - _largest_unit: DateDurationUnit, - _smallest_unit: DateDurationUnit, - ) -> DateDuration { - date1.0.until(date2.0, _largest_unit, _smallest_unit) + options: DateDifferenceOptions, + ) -> Result { + Ok(date1.0.until(&date2.0, self, options)) } /// The calendar-specific year represented by `date` /// Julian has the same era scheme as Gregorian fn year_info(&self, date: &Self::DateInner) -> Self::Year { - let extended_year = self.extended_year(date); + let extended_year = date.0.year; if extended_year > 0 { types::EraYear { era: tinystr!(16, "ce"), era_index: Some(1), year: extended_year, + extended_year, ambiguity: types::YearAmbiguity::CenturyRequired, } } else { types::EraYear { era: tinystr!(16, "bce"), era_index: Some(0), - year: 1_i32.saturating_sub(extended_year), + year: 1 - extended_year, + extended_year, ambiguity: types::YearAmbiguity::EraAndCenturyRequired, } } } - fn extended_year(&self, date: &Self::DateInner) -> i32 { - date.0.extended_year() - } - fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { - Self::provided_year_is_leap(date.0.year) + calendrical_calculations::julian::is_leap_year(date.0.year) } /// The calendar-specific month represented by `date` fn month(&self, date: &Self::DateInner) -> types::MonthInfo { - date.0.month() + types::MonthInfo::non_lunisolar(date.0.month) } /// The calendar-specific day-of-month represented by `date` fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { - date.0.day_of_month() + types::DayOfMonth(date.0.day) } fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear { - date.0.day_of_year() + types::DayOfYear( + (1..date.0.month) + .map(|m| Self::days_in_provided_month(date.0.year, m) as u16) + .sum::() + + date.0.day as u16, + ) } fn debug_name(&self) -> &'static str { @@ -210,6 +273,11 @@ impl Julian { pub fn new() -> Self { Self } + + /// Returns the date of (Orthodox) Easter in the given year. + pub fn easter(year: i32) -> Date { + Date::from_rata_die(calendrical_calculations::julian::easter(year), Self) + } } impl Date { @@ -228,7 +296,7 @@ impl Date { /// assert_eq!(date_julian.day_of_month().0, 20); /// ``` pub fn try_new_julian(year: i32, month: u8, day: u8) -> Result, RangeError> { - ArithmeticDate::new_from_ordinals(year, month, day) + ArithmeticDate::try_from_ymd(year, month, day) .map(JulianDateInner) .map(|inner| Date::from_raw(inner, Julian)) } @@ -474,20 +542,11 @@ mod test { } } - #[test] - fn test_hebrew_epoch() { - assert_eq!( - calendrical_calculations::julian::fixed_from_julian_book_version(-3761, 10, 7), - RataDie::new(-1373427) - ); - } - #[test] fn test_julian_leap_years() { - assert!(Julian::provided_year_is_leap(4)); - assert!(Julian::provided_year_is_leap(0)); - assert!(Julian::provided_year_is_leap(-4)); - + Date::try_new_julian(4, 2, 29).unwrap(); + Date::try_new_julian(0, 2, 29).unwrap(); + Date::try_new_julian(-4, 2, 29).unwrap(); Date::try_new_julian(2020, 2, 29).unwrap(); } } diff --git a/deps/crates/vendor/icu_calendar/src/cal/mod.rs b/deps/crates/vendor/icu_calendar/src/cal/mod.rs index 0014aac559b5e3..cd442f6f979116 100644 --- a/deps/crates/vendor/icu_calendar/src/cal/mod.rs +++ b/deps/crates/vendor/icu_calendar/src/cal/mod.rs @@ -4,14 +4,14 @@ //! Types for individual calendars pub(crate) mod buddhist; -pub(crate) mod chinese; -pub(crate) mod chinese_based; pub(crate) mod coptic; -pub(crate) mod dangi; +#[path = "east_asian_traditional.rs"] +pub(crate) mod east_asian_traditional_internal; pub(crate) mod ethiopian; pub(crate) mod gregorian; pub(crate) mod hebrew; -pub(crate) mod hijri; +#[path = "hijri.rs"] +pub(crate) mod hijri_internal; pub(crate) mod indian; pub(crate) mod iso; pub(crate) mod japanese; @@ -19,16 +19,42 @@ pub(crate) mod julian; pub(crate) mod persian; pub(crate) mod roc; +pub(crate) mod abstract_gregorian; + pub use buddhist::Buddhist; -pub use chinese::Chinese; +/// Customizations for the [`EastAsianTraditional`](east_asian_traditional::EastAsianTraditional) calendar. +pub mod east_asian_traditional { + pub use super::east_asian_traditional_internal::{China, EastAsianTraditional, Korea}; + + // TODO(#6962) Stabilize + #[cfg(feature = "unstable")] + pub use super::east_asian_traditional_internal::{EastAsianTraditionalYearData, Rules}; +} pub use coptic::Coptic; -pub use dangi::Dangi; +pub use east_asian_traditional_internal::{ChineseTraditional, KoreanTraditional}; pub use ethiopian::{Ethiopian, EthiopianEraStyle}; pub use gregorian::Gregorian; pub use hebrew::Hebrew; -pub use hijri::{ - HijriSimulated, HijriTabular, HijriTabularEpoch, HijriTabularLeapYears, HijriUmmAlQura, -}; +pub use hijri_internal::Hijri; +/// Customizations for the [`Hijri`] calendar. +pub mod hijri { + pub use super::hijri_internal::{ + AstronomicalSimulation, TabularAlgorithm, TabularAlgorithmEpoch, TabularAlgorithmLeapYears, + UmmAlQura, + }; + + // TODO(#6962) Stabilize + #[cfg(feature = "unstable")] + pub use super::hijri_internal::{HijriYearData, Rules}; + + #[doc(hidden)] + /// These are unstable traits but we expose them on stable to + /// icu_datetime. + pub mod unstable_internal { + pub use super::super::hijri_internal::Rules; + } +} + pub use indian::Indian; pub use iso::Iso; pub use japanese::{Japanese, JapaneseExtended}; @@ -36,9 +62,31 @@ pub use julian::Julian; pub use persian::Persian; pub use roc::Roc; -pub use crate::any_calendar::{AnyCalendar, AnyCalendarKind}; +/// Deprecated +#[deprecated] +pub use hijri::{ + TabularAlgorithmEpoch as HijriTabularEpoch, TabularAlgorithmLeapYears as HijriTabularLeapYears, +}; +/// Deprecated +#[deprecated] +pub type HijriSimulated = Hijri; +/// Deprecated +#[deprecated] +pub type HijriUmmAlQura = Hijri; +/// Deprecated +#[deprecated] +pub type HijriTabular = Hijri; +/// Use [`KoreanTraditional`] +#[deprecated(since = "2.1.0", note = "use `KoreanTraditional`")] +pub type Dangi = KoreanTraditional; +/// Use [`ChineseTraditional`] +#[deprecated(since = "2.1.0", note = "use `ChineseTraditional`")] +pub type Chinese = ChineseTraditional; + +pub use crate::any_calendar::{AnyCalendar, AnyCalendarDifferenceError, AnyCalendarKind}; /// Internal scaffolding types +#[cfg_attr(not(feature = "unstable"), doc(hidden))] pub mod scaffold { /// Trait marking other traits that are considered unstable and should not generally be /// implemented outside of the calendar crate. diff --git a/deps/crates/vendor/icu_calendar/src/cal/persian.rs b/deps/crates/vendor/icu_calendar/src/cal/persian.rs index fc58e879925737..0e1a95b111953f 100644 --- a/deps/crates/vendor/icu_calendar/src/cal/persian.rs +++ b/deps/crates/vendor/icu_calendar/src/cal/persian.rs @@ -2,41 +2,46 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -//! This module contains types and implementations for the Persian calendar. -//! -//! ```rust -//! use icu::calendar::Date; -//! -//! let persian_date = Date::try_new_persian(1348, 10, 11) -//! .expect("Failed to initialize Persian Date instance."); -//! -//! assert_eq!(persian_date.era_year().year, 1348); -//! assert_eq!(persian_date.month().ordinal, 10); -//! assert_eq!(persian_date.day_of_month().0, 11); -//! ``` - -use crate::cal::iso::{Iso, IsoDateInner}; -use crate::calendar_arithmetic::{ArithmeticDate, CalendarArithmetic}; -use crate::error::DateError; -use crate::{types, Calendar, Date, DateDuration, DateDurationUnit, RangeError}; +use crate::calendar_arithmetic::ArithmeticDate; +use crate::calendar_arithmetic::DateFieldsResolver; +use crate::error::{DateError, DateFromFieldsError, EcmaReferenceYearError, UnknownEraError}; +use crate::options::DateFromFieldsOptions; +use crate::options::{DateAddOptions, DateDifferenceOptions}; +use crate::types::DateFields; +use crate::{types, Calendar, Date, RangeError}; use ::tinystr::tinystr; use calendrical_calculations::helpers::I32CastError; use calendrical_calculations::rata_die::RataDie; /// The [Persian Calendar](https://en.wikipedia.org/wiki/Solar_Hijri_calendar) /// -/// The Persian Calendar is a solar calendar used officially by the countries of Iran and Afghanistan and many Persian-speaking regions. -/// It has 12 months and other similarities to the [`Gregorian`](super::Gregorian) Calendar. +/// The Persian Calendar is a solar calendar used officially by the countries of Iran and +/// Afghanistan and many Persian-speaking regions. /// -/// This type can be used with [`Date`] to represent dates in this calendar. +/// This implementation extends proleptically for dates before the calendar's creation +/// in 458 AP (1079 CE). +/// +/// This corresponds to the `"persian"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). /// /// # Era codes /// -/// This calendar uses a single era code `ap` (aliases `sh`, `hs`), with Anno Persico/Anno Persarum starting the year of the Hijra. Dates before this era use negative years. +/// This calendar uses a single era code `ap`, with Anno Persico/Anno Persarum starting the year of the Hijra. Dates before this era use negative years. +/// +/// # Months and days +/// +/// The 12 months are called Farvardin (`M01`, 31 days), Ordibehesht (`M02`, 31 days), +/// Khordad (`M03`, 31 days), Tir (`M04`, 31 days), Mordad (`M05`, 31 days), Shahrivar (`M06`, 31 days), +/// Mehr (`M07`, 30 days), Aban (`M08`, 30 days), Azar (`M09`, 30 days), +/// Dey (`M10`, 30 days), Bahman (`M11`, 30 days), Esfand (`M12`, 29 days). +/// +/// In leap years (determined astronomically with respect to the vernal equinox), Esfand gains a 30th day. +/// +/// Standard years thus have 365 days, and leap years 366. /// -/// # Month codes +/// # Calendar drift /// -/// This calendar supports 12 solar month codes (`"M01" - "M12"`) +/// As leap years are determined with respect to the solar year, this calendar stays anchored +/// to the seasons. #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq, PartialOrd, Ord)] #[allow(clippy::exhaustive_structs)] pub struct Persian; @@ -46,14 +51,14 @@ pub struct Persian; /// The inner date type used for representing [`Date`]s of [`Persian`]. See [`Date`] and [`Persian`] for more details. pub struct PersianDateInner(ArithmeticDate); -impl CalendarArithmetic for Persian { +impl DateFieldsResolver for Persian { type YearInfo = i32; fn days_in_provided_month(year: i32, month: u8) -> u8 { match month { 1..=6 => 31, 7..=11 => 30, - 12 if Self::provided_year_is_leap(year) => 30, + 12 if calendrical_calculations::persian::is_leap_year(year) => 30, 12 => 29, _ => 0, } @@ -63,24 +68,40 @@ impl CalendarArithmetic for Persian { 12 } - fn provided_year_is_leap(p_year: i32) -> bool { - calendrical_calculations::persian::is_leap_year(p_year) + #[inline] + fn year_info_from_era( + &self, + era: &[u8], + era_year: i32, + ) -> Result { + match era { + b"ap" => Ok(era_year), + _ => Err(UnknownEraError), + } } - fn days_in_provided_year(year: i32) -> u16 { - if Self::provided_year_is_leap(year) { - 366 - } else { - 365 - } + #[inline] + fn year_info_from_extended(&self, extended_year: i32) -> Self::YearInfo { + extended_year } - fn last_month_day_in_provided_year(year: i32) -> (u8, u8) { - if Self::provided_year_is_leap(year) { - (12, 30) + #[inline] + fn reference_year_from_month_day( + &self, + month_code: types::ValidMonthCode, + day: u8, + ) -> Result { + let (ordinal_month, false) = month_code.to_tuple() else { + return Err(EcmaReferenceYearError::MonthCodeNotInCalendar); + }; + // December 31, 1972 occurs on 10th month, 10th day, 1351 AP + let persian_year = if ordinal_month < 10 || (ordinal_month == 10 && day <= 10) { + 1351 } else { - (12, 29) - } + // Note: 1350 is a leap year + 1350 + }; + Ok(persian_year) } } @@ -88,6 +109,7 @@ impl crate::cal::scaffold::UnstableSealed for Persian {} impl Calendar for Persian { type DateInner = PersianDateInner; type Year = types::EraYear; + type DifferenceError = core::convert::Infallible; fn from_codes( &self, @@ -96,19 +118,23 @@ impl Calendar for Persian { month_code: types::MonthCode, day: u8, ) -> Result { - let year = match era { - Some("ap" | "sh" | "hs") | None => year, - Some(_) => return Err(DateError::UnknownEra), - }; + ArithmeticDate::from_codes(era, year, month_code, day, self).map(PersianDateInner) + } - ArithmeticDate::new_from_codes(self, year, month_code, day).map(PersianDateInner) + #[cfg(feature = "unstable")] + fn from_fields( + &self, + fields: DateFields, + options: DateFromFieldsOptions, + ) -> Result { + ArithmeticDate::from_fields(fields, options, self).map(PersianDateInner) } fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { PersianDateInner( match calendrical_calculations::persian::fast_persian_from_fixed(rd) { - Err(I32CastError::BelowMin) => ArithmeticDate::min_date(), - Err(I32CastError::AboveMax) => ArithmeticDate::max_date(), + Err(I32CastError::BelowMin) => ArithmeticDate::new_unchecked(i32::MIN, 1, 1), + Err(I32CastError::AboveMax) => ArithmeticDate::new_unchecked(i32::MAX, 12, 29), Ok((year, month, day)) => ArithmeticDate::new_unchecked(year, month, day), }, ) @@ -122,69 +148,74 @@ impl Calendar for Persian { ) } - fn from_iso(&self, iso: IsoDateInner) -> PersianDateInner { - self.from_rata_die(Iso.to_rata_die(&iso)) - } - - fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { - Iso.from_rata_die(self.to_rata_die(date)) + fn has_cheap_iso_conversion(&self) -> bool { + false } fn months_in_year(&self, date: &Self::DateInner) -> u8 { - date.0.months_in_year() + Self::months_in_provided_year(date.0.year) } fn days_in_year(&self, date: &Self::DateInner) -> u16 { - date.0.days_in_year() + if self.is_in_leap_year(date) { + 366 + } else { + 365 + } } fn days_in_month(&self, date: &Self::DateInner) -> u8 { - date.0.days_in_month() + Self::days_in_provided_month(date.0.year, date.0.month) } - fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration) { - date.0.offset_date(offset, &()) + #[cfg(feature = "unstable")] + fn add( + &self, + date: &Self::DateInner, + duration: types::DateDuration, + options: DateAddOptions, + ) -> Result { + date.0.added(duration, self, options).map(PersianDateInner) } - #[allow(clippy::field_reassign_with_default)] + #[cfg(feature = "unstable")] fn until( &self, date1: &Self::DateInner, date2: &Self::DateInner, - _calendar2: &Self, - _largest_unit: DateDurationUnit, - _smallest_unit: DateDurationUnit, - ) -> DateDuration { - date1.0.until(date2.0, _largest_unit, _smallest_unit) + options: DateDifferenceOptions, + ) -> Result { + Ok(date1.0.until(&date2.0, self, options)) } fn year_info(&self, date: &Self::DateInner) -> Self::Year { + let extended_year = date.0.year; types::EraYear { era: tinystr!(16, "ap"), era_index: Some(0), - year: self.extended_year(date), + year: extended_year, + extended_year, ambiguity: types::YearAmbiguity::CenturyRequired, } } - fn extended_year(&self, date: &Self::DateInner) -> i32 { - date.0.extended_year() - } - fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { - Self::provided_year_is_leap(date.0.year) + calendrical_calculations::persian::is_leap_year(date.0.year) } fn month(&self, date: &Self::DateInner) -> types::MonthInfo { - date.0.month() + types::MonthInfo::non_lunisolar(date.0.month) } fn day_of_month(&self, date: &Self::DateInner) -> types::DayOfMonth { - date.0.day_of_month() + types::DayOfMonth(date.0.day) } fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear { - date.0.day_of_year() + types::DayOfYear( + (date.0.month as u16 - 1) * 31 - (date.0.month as u16 - 1).saturating_sub(6) + + date.0.day as u16, + ) } fn debug_name(&self) -> &'static str { @@ -219,7 +250,7 @@ impl Date { /// assert_eq!(date_persian.day_of_month().0, 25); /// ``` pub fn try_new_persian(year: i32, month: u8, day: u8) -> Result, RangeError> { - ArithmeticDate::new_from_ordinals(year, month, day) + ArithmeticDate::try_from_ymd(year, month, day) .map(PersianDateInner) .map(|inner| Date::from_raw(inner, Persian)) } @@ -358,15 +389,6 @@ mod tests { }, ]; - fn days_in_provided_year_core(year: i32) -> u16 { - let ny = - calendrical_calculations::persian::fixed_from_fast_persian(year, 1, 1).to_i64_date(); - let next_ny = calendrical_calculations::persian::fixed_from_fast_persian(year + 1, 1, 1) - .to_i64_date(); - - (next_ny - ny) as u16 - } - #[test] fn test_persian_leap_year() { let mut leap_years: [i32; 21] = [0; 21]; @@ -379,8 +401,11 @@ mod tests { for (index, case) in CASES.iter().enumerate() { leap_years[index] = case.year; } - for (year, bool) in leap_years.iter().zip(expected_values.iter()) { - assert_eq!(Persian::provided_year_is_leap(*year), *bool); + for (&year, &is_leap) in leap_years.iter().zip(expected_values.iter()) { + assert_eq!( + Date::try_new_persian(year, 1, 1).unwrap().is_in_leap_year(), + is_leap + ); } } @@ -388,8 +413,12 @@ mod tests { fn days_in_provided_year_test() { for case in CASES.iter() { assert_eq!( - days_in_provided_year_core(case.year), - Persian::days_in_provided_year(case.year) + Date::try_new_persian(case.year, 1, 1) + .unwrap() + .days_in_year(), + (calendrical_calculations::persian::fixed_from_fast_persian(case.year + 1, 1, 1) + - calendrical_calculations::persian::fixed_from_fast_persian(case.year, 1, 1)) + as u16 ); } } @@ -714,13 +743,13 @@ mod tests { #[test] fn test_calendar_ut_ac_ir_data() { - for (p_year, leap, iso_year, iso_month, iso_day) in CALENDAR_UT_AC_IR_TEST_DATA.iter() { - assert_eq!(Persian::provided_year_is_leap(*p_year), *leap); - let persian_date = Date::try_new_persian(*p_year, 1, 1).unwrap(); - let iso_date = persian_date.to_calendar(Iso); - assert_eq!(iso_date.era_year().year, *iso_year); - assert_eq!(iso_date.month().ordinal, *iso_month); - assert_eq!(iso_date.day_of_month().0, *iso_day); + for &(p_year, leap, iso_year, iso_month, iso_day) in CALENDAR_UT_AC_IR_TEST_DATA.iter() { + let persian_date = Date::try_new_persian(p_year, 1, 1).unwrap(); + assert_eq!(persian_date.is_in_leap_year(), leap); + let iso_date = persian_date.to_iso(); + assert_eq!(iso_date.era_year().year, iso_year); + assert_eq!(iso_date.month().ordinal, iso_month); + assert_eq!(iso_date.day_of_month().0, iso_day); } } } diff --git a/deps/crates/vendor/icu_calendar/src/cal/roc.rs b/deps/crates/vendor/icu_calendar/src/cal/roc.rs index 1c81c0a2646620..1ae6cdbf4e461c 100644 --- a/deps/crates/vendor/icu_calendar/src/cal/roc.rs +++ b/deps/crates/vendor/icu_calendar/src/cal/roc.rs @@ -2,136 +2,63 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -//! This module contains types and implementations for the Republic of China calendar. -//! -//! ```rust -//! use icu::calendar::{cal::Roc, Date}; -//! -//! let date_iso = Date::try_new_iso(1970, 1, 2) -//! .expect("Failed to initialize ISO Date instance."); -//! let date_roc = Date::new_from_iso(date_iso, Roc); -//! -//! assert_eq!(date_roc.era_year().year, 59); -//! assert_eq!(date_roc.month().ordinal, 1); -//! assert_eq!(date_roc.day_of_month().0, 2); -//! ``` - -use crate::error::year_check; -use crate::{ - cal::iso::IsoDateInner, calendar_arithmetic::ArithmeticDate, error::DateError, types, Calendar, - Date, Iso, RangeError, -}; -use calendrical_calculations::rata_die::RataDie; +use crate::cal::abstract_gregorian::{impl_with_abstract_gregorian, GregorianYears}; +use crate::calendar_arithmetic::ArithmeticDate; +use crate::error::UnknownEraError; +use crate::preferences::CalendarAlgorithm; +use crate::{types, Date, DateError, RangeError}; use tinystr::tinystr; -/// Year of the beginning of the Taiwanese (ROC/Minguo) calendar. -/// 1912 ISO = ROC 1 -const ROC_ERA_OFFSET: i32 = 1911; - /// The [Republic of China Calendar](https://en.wikipedia.org/wiki/Republic_of_China_calendar) /// -/// The ROC calendar is a solar calendar used in Taiwan and Penghu, as well as by overseas diaspora from -/// those locations. Months and days are identical to the [`Gregorian`](super::Gregorian) calendar, while years are counted -/// with 1912, the year of the establishment of the Republic of China, as year 1 of the ROC/Minguo/民国/民國 era. +/// The ROC Calendar is a variant of the [`Gregorian`](crate::cal::Gregorian) calendar +/// created by the government of the Republic of China. It is identical to the Gregorian +/// calendar except that is uses the ROC/Minguo/民国/民國 Era (1912 CE) instead of the Common Era. +/// +/// This implementation extends proleptically for dates before the calendar's creation +/// in 1 Minguo (1912 CE). /// -/// The ROC calendar should not be confused with the Chinese traditional lunar calendar -/// (see [`Chinese`](crate::cal::Chinese)). +/// The ROC calendar should not be confused with the [`ChineseTraditional`](crate::cal::ChineseTraditional) +/// lunisolar calendar. +/// +/// This corresponds to the `"roc"` [CLDR calendar](https://unicode.org/reports/tr35/#UnicodeCalendarIdentifier). /// /// # Era codes /// /// This calendar uses two era codes: `roc`, corresponding to years in the 民國 era (CE year 1912 and /// after), and `broc`, corresponding to years before the 民國 era (CE year 1911 and before). -/// -/// -/// # Month codes -/// -/// This calendar supports 12 solar month codes (`"M01" - "M12"`) #[derive(Copy, Clone, Debug, Default)] #[allow(clippy::exhaustive_structs)] // this type is stable pub struct Roc; -/// The inner date type used for representing [`Date`]s of [`Roc`]. See [`Date`] and [`Roc`] for more info. -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)] -pub struct RocDateInner(IsoDateInner); - -impl crate::cal::scaffold::UnstableSealed for Roc {} -impl Calendar for Roc { - type DateInner = RocDateInner; - type Year = types::EraYear; +impl_with_abstract_gregorian!(crate::cal::Roc, RocDateInner, RocEra, _x, RocEra); - fn from_codes( - &self, - era: Option<&str>, - year: i32, - month_code: crate::types::MonthCode, - day: u8, - ) -> Result { - let year = match era { - Some("roc") | None => ROC_ERA_OFFSET + year_check(year, 1..)?, - Some("broc") => ROC_ERA_OFFSET + 1 - year_check(year, 1..)?, - Some(_) => return Err(DateError::UnknownEra), - }; +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub(crate) struct RocEra; - ArithmeticDate::new_from_codes(self, year, month_code, day) - .map(IsoDateInner) - .map(RocDateInner) - } +impl GregorianYears for RocEra { + const EXTENDED_YEAR_OFFSET: i32 = 1911; - fn from_rata_die(&self, rd: RataDie) -> Self::DateInner { - RocDateInner(Iso.from_rata_die(rd)) - } - - fn to_rata_die(&self, date: &Self::DateInner) -> RataDie { - Iso.to_rata_die(&date.0) - } - - fn from_iso(&self, iso: IsoDateInner) -> Self::DateInner { - RocDateInner(iso) - } - - fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { - date.0 - } - - fn months_in_year(&self, date: &Self::DateInner) -> u8 { - Iso.months_in_year(&date.0) - } - - fn days_in_year(&self, date: &Self::DateInner) -> u16 { - Iso.days_in_year(&date.0) - } - - fn days_in_month(&self, date: &Self::DateInner) -> u8 { - Iso.days_in_month(&date.0) - } - - fn offset_date(&self, date: &mut Self::DateInner, offset: crate::DateDuration) { - Iso.offset_date(&mut date.0, offset.cast_unit()) - } - - fn until( + fn extended_from_era_year( &self, - date1: &Self::DateInner, - date2: &Self::DateInner, - _calendar2: &Self, - largest_unit: crate::DateDurationUnit, - smallest_unit: crate::DateDurationUnit, - ) -> crate::DateDuration { - Iso.until(&date1.0, &date2.0, &Iso, largest_unit, smallest_unit) - .cast_unit() - } - - fn debug_name(&self) -> &'static str { - "ROC" + era: Option<&[u8]>, + year: i32, + ) -> Result { + match era { + None => Ok(year), + Some(b"roc") => Ok(year), + Some(b"broc") => Ok(1 - year), + Some(_) => Err(UnknownEraError), + } } - fn year_info(&self, date: &Self::DateInner) -> Self::Year { - let extended_year = self.extended_year(date); + fn era_year_from_extended(&self, extended_year: i32, _month: u8, _day: u8) -> types::EraYear { if extended_year > 0 { types::EraYear { era: tinystr!(16, "roc"), era_index: Some(1), year: extended_year, + extended_year, ambiguity: types::YearAmbiguity::CenturyRequired, } } else { @@ -139,33 +66,18 @@ impl Calendar for Roc { era: tinystr!(16, "broc"), era_index: Some(0), year: 1 - extended_year, + extended_year, ambiguity: types::YearAmbiguity::EraAndCenturyRequired, } } } - fn extended_year(&self, date: &Self::DateInner) -> i32 { - Iso.extended_year(&date.0) - ROC_ERA_OFFSET - } - - fn is_in_leap_year(&self, date: &Self::DateInner) -> bool { - Iso.is_in_leap_year(&date.0) - } - - fn month(&self, date: &Self::DateInner) -> crate::types::MonthInfo { - Iso.month(&date.0) - } - - fn day_of_month(&self, date: &Self::DateInner) -> crate::types::DayOfMonth { - Iso.day_of_month(&date.0) - } - - fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear { - Iso.day_of_year(&date.0) + fn debug_name(&self) -> &'static str { + "ROC" } - fn calendar_algorithm(&self) -> Option { - Some(crate::preferences::CalendarAlgorithm::Roc) + fn calendar_algorithm(&self) -> Option { + Some(CalendarAlgorithm::Roc) } } @@ -185,7 +97,7 @@ impl Date { /// let date_roc = Date::try_new_roc(1, 2, 3) /// .expect("Failed to initialize ROC Date instance."); /// - /// assert_eq!(date_roc.era_year().era, tinystr!(16, "roc")); + /// assert_eq!(date_roc.era_year().era, "roc"); /// assert_eq!(date_roc.era_year().year, 1, "ROC year check failed!"); /// assert_eq!(date_roc.month().ordinal, 2, "ROC month check failed!"); /// assert_eq!(date_roc.day_of_month().0, 3, "ROC day of month check failed!"); @@ -197,8 +109,9 @@ impl Date { /// assert_eq!(date_gregorian.month().ordinal, 2, "Gregorian from ROC month check failed!"); /// assert_eq!(date_gregorian.day_of_month().0, 3, "Gregorian from ROC day of month check failed!"); pub fn try_new_roc(year: i32, month: u8, day: u8) -> Result, RangeError> { - let iso_year = year.saturating_add(ROC_ERA_OFFSET); - Date::try_new_iso(iso_year, month, day).map(|d| Date::new_from_iso(d, Roc)) + ArithmeticDate::new_gregorian::(year, month, day) + .map(RocDateInner) + .map(|i| Date::from_raw(i, Roc)) } } @@ -206,6 +119,7 @@ impl Date { mod test { use super::*; + use crate::cal::Iso; use calendrical_calculations::rata_die::RataDie; #[derive(Debug)] diff --git a/deps/crates/vendor/icu_calendar/src/calendar.rs b/deps/crates/vendor/icu_calendar/src/calendar.rs index 5b0ea851d1388e..716121b5fac28c 100644 --- a/deps/crates/vendor/icu_calendar/src/calendar.rs +++ b/deps/crates/vendor/icu_calendar/src/calendar.rs @@ -5,8 +5,10 @@ use calendrical_calculations::rata_die::RataDie; use crate::cal::iso::IsoDateInner; -use crate::error::DateError; -use crate::{types, DateDuration, DateDurationUnit}; +use crate::error::{DateError, DateFromFieldsError}; +use crate::options::DateFromFieldsOptions; +use crate::options::{DateAddOptions, DateDifferenceOptions}; +use crate::{types, Iso}; use core::fmt; /// A calendar implementation @@ -26,14 +28,18 @@ use core::fmt; /// pub trait Calendar: crate::cal::scaffold::UnstableSealed { /// The internal type used to represent dates - type DateInner: Eq + Copy + fmt::Debug; + /// + /// Equality and ordering should observe normal calendar semantics. + type DateInner: Eq + Copy + PartialOrd + fmt::Debug; /// The type of YearInfo returned by the date type Year: fmt::Debug + Into; + /// The type of error returned by `until` + type DifferenceError; /// Construct a date from era/month codes and fields /// - /// The year is extended_year if no era is provided - #[allow(clippy::wrong_self_convention)] + /// The year is the [extended year](crate::Date::extended_year) if no era is provided + #[expect(clippy::wrong_self_convention)] fn from_codes( &self, era: Option<&str>, @@ -42,14 +48,44 @@ pub trait Calendar: crate::cal::scaffold::UnstableSealed { day: u8, ) -> Result; - /// Construct the date from an ISO date - #[allow(clippy::wrong_self_convention)] - fn from_iso(&self, iso: IsoDateInner) -> Self::DateInner; - /// Obtain an ISO date from this date - fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner; + /// Construct a date from a bag of date fields. + /// + ///
+ /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, + /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break. + /// + /// Graduation tracking issue: [issue #7161](https://github.com/unicode-org/icu4x/issues/7161). + ///
+ /// + /// ✨ *Enabled with the `unstable` Cargo feature.* + #[expect(clippy::wrong_self_convention)] + #[cfg(feature = "unstable")] + fn from_fields( + &self, + fields: types::DateFields, + options: DateFromFieldsOptions, + ) -> Result; + + /// Whether `from_iso`/`to_iso` is more efficient + /// than `from_rata_die`/`to_rata_die`. + fn has_cheap_iso_conversion(&self) -> bool; + + /// Construct the date from an ISO date. + /// + /// Only called if `HAS_CHEAP_ISO_CONVERSION` is set. + #[expect(clippy::wrong_self_convention)] + fn from_iso(&self, iso: IsoDateInner) -> Self::DateInner { + self.from_rata_die(Iso.to_rata_die(&iso)) + } + /// Obtain an ISO date from this date. + /// + /// Only called if `HAS_CHEAP_ISO_CONVERSION` is set. + fn to_iso(&self, date: &Self::DateInner) -> IsoDateInner { + Iso.from_rata_die(self.to_rata_die(date)) + } /// Construct the date from a [`RataDie`] - #[allow(clippy::wrong_self_convention)] + #[expect(clippy::wrong_self_convention)] fn from_rata_die(&self, rd: RataDie) -> Self::DateInner; /// Obtain a [`RataDie`] from this date fn to_rata_die(&self, date: &Self::DateInner) -> RataDie; @@ -68,8 +104,11 @@ pub trait Calendar: crate::cal::scaffold::UnstableSealed { /// Information about the year fn year_info(&self, date: &Self::DateInner) -> Self::Year; - /// The extended year value - fn extended_year(&self, date: &Self::DateInner) -> i32; + + /// The [extended year](crate::Date::extended_year). + fn extended_year(&self, date: &Self::DateInner) -> i32 { + self.year_info(date).into().extended_year() + } /// The calendar-specific month represented by `date` fn month(&self, date: &Self::DateInner) -> types::MonthInfo; /// The calendar-specific day-of-month represented by `date` @@ -77,22 +116,44 @@ pub trait Calendar: crate::cal::scaffold::UnstableSealed { /// Information of the day of the year fn day_of_year(&self, date: &Self::DateInner) -> types::DayOfYear; - #[doc(hidden)] // unstable - /// Add `offset` to `date` - fn offset_date(&self, date: &mut Self::DateInner, offset: DateDuration); - #[doc(hidden)] // unstable + /// Add `duration` to `date` + /// + ///
+ /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, + /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break. + /// + /// Graduation tracking issue: [issue #3964](https://github.com/unicode-org/icu4x/issues/3964). + ///
+ /// + /// ✨ *Enabled with the `unstable` Cargo feature.* + #[cfg(feature = "unstable")] + fn add( + &self, + date: &Self::DateInner, + duration: types::DateDuration, + options: DateAddOptions, + ) -> Result; + /// Calculate `date2 - date` as a duration /// /// `calendar2` is the calendar object associated with `date2`. In case the specific calendar objects /// differ on data, the data for the first calendar is used, and `date2` may be converted if necessary. + /// + ///
+ /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, + /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break. + /// + /// Graduation tracking issue: [issue #3964](https://github.com/unicode-org/icu4x/issues/3964). + ///
+ /// + /// ✨ *Enabled with the `unstable` Cargo feature.* + #[cfg(feature = "unstable")] fn until( &self, date1: &Self::DateInner, date2: &Self::DateInner, - calendar2: &Self, - largest_unit: DateDurationUnit, - smallest_unit: DateDurationUnit, - ) -> DateDuration; + options: DateDifferenceOptions, + ) -> Result; /// Returns the [`CalendarAlgorithm`](crate::preferences::CalendarAlgorithm) that is required to match /// when parsing into this calendar. diff --git a/deps/crates/vendor/icu_calendar/src/calendar_arithmetic.rs b/deps/crates/vendor/icu_calendar/src/calendar_arithmetic.rs index fc1da7d8c6823a..3e3078d11f663c 100644 --- a/deps/crates/vendor/icu_calendar/src/calendar_arithmetic.rs +++ b/deps/crates/vendor/icu_calendar/src/calendar_arithmetic.rs @@ -2,66 +2,78 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -use crate::error::DateError; -use crate::types::DayOfYear; -use crate::{types, Calendar, DateDuration, DateDurationUnit, RangeError}; +use crate::duration::{DateDuration, DateDurationUnit}; +use crate::error::{ + range_check, range_check_with_overflow, DateFromFieldsError, EcmaReferenceYearError, + MonthCodeError, MonthCodeParseError, UnknownEraError, +}; +use crate::options::{DateAddOptions, DateDifferenceOptions}; +use crate::options::{DateFromFieldsOptions, MissingFieldsStrategy, Overflow}; +use crate::types::{DateFields, ValidMonthCode}; +use crate::{types, Calendar, DateError, RangeError}; use core::cmp::Ordering; -use core::convert::TryInto; use core::fmt::Debug; use core::hash::{Hash, Hasher}; -use core::marker::PhantomData; -use tinystr::tinystr; +use core::ops::RangeInclusive; + +/// The range ±2²⁷. We use i32::MIN since it is -2³¹ +/// +/// This range is currently global, and applied to both era years and +/// extended years, but may be replaced with a per-calendar check in the future. +/// +/// +const VALID_YEAR_RANGE: RangeInclusive = (i32::MIN / 16)..=-(i32::MIN / 16); #[derive(Debug)] -#[allow(clippy::exhaustive_structs)] // this type is stable -pub(crate) struct ArithmeticDate { +pub(crate) struct ArithmeticDate { pub year: C::YearInfo, /// 1-based month of year pub month: u8, /// 1-based day of month pub day: u8, - marker: PhantomData, } // Manual impls since the derive will introduce a C: Trait bound // and only the year value should be compared -impl Copy for ArithmeticDate {} -impl Clone for ArithmeticDate { +impl Copy for ArithmeticDate {} +impl Clone for ArithmeticDate { fn clone(&self) -> Self { *self } } -impl PartialEq for ArithmeticDate { +impl PartialEq for ArithmeticDate { fn eq(&self, other: &Self) -> bool { - self.year.into() == other.year.into() && self.month == other.month && self.day == other.day + self.year.to_extended_year() == other.year.to_extended_year() + && self.month == other.month + && self.day == other.day } } -impl Eq for ArithmeticDate {} +impl Eq for ArithmeticDate {} -impl Ord for ArithmeticDate { +impl Ord for ArithmeticDate { fn cmp(&self, other: &Self) -> Ordering { self.year - .into() - .cmp(&other.year.into()) + .to_extended_year() + .cmp(&other.year.to_extended_year()) .then(self.month.cmp(&other.month)) .then(self.day.cmp(&other.day)) } } -impl PartialOrd for ArithmeticDate { +impl PartialOrd for ArithmeticDate { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Hash for ArithmeticDate { +impl Hash for ArithmeticDate { fn hash(&self, state: &mut H) where H: Hasher, { - self.year.into().hash(state); + self.year.to_extended_year().hash(state); self.month.hash(state); self.day.hash(state); } @@ -71,341 +83,613 @@ impl Hash for ArithmeticDate { #[allow(dead_code)] // TODO: Remove dead code tag after use pub(crate) const MAX_ITERS_FOR_DAYS_OF_MONTH: u8 = 33; -pub(crate) trait CalendarArithmetic: Calendar { +pub(crate) trait ToExtendedYear { + fn to_extended_year(&self) -> i32; +} + +impl ToExtendedYear for i32 { + fn to_extended_year(&self) -> i32 { + *self + } +} + +/// Trait for converting from era codes, month codes, and other fields to year/month/day ordinals. +pub(crate) trait DateFieldsResolver: Calendar { /// This stores the year as either an i32, or a type containing more /// useful computational information. - type YearInfo: Copy + Debug + Into; + type YearInfo: Copy + Debug + PartialEq + ToExtendedYear; - // TODO(#3933): potentially make these methods take &self instead, and absorb certain y/m parameters - // based on usage patterns (e.g month_days is only ever called with self.year) fn days_in_provided_month(year: Self::YearInfo, month: u8) -> u8; - fn months_in_provided_year(year: Self::YearInfo) -> u8; - fn provided_year_is_leap(year: Self::YearInfo) -> bool; - fn last_month_day_in_provided_year(year: Self::YearInfo) -> (u8, u8); - /// Calculate the days in a given year - /// Can be overridden with simpler implementations for solar calendars - /// (typically, 366 in leap, 365 otherwise) Leave this as the default - /// for lunar calendars - /// - /// The name has `provided` in it to avoid clashes with Calendar - fn days_in_provided_year(year: Self::YearInfo) -> u16 { - let months_in_year = Self::months_in_provided_year(year); - let mut days: u16 = 0; - for month in 1..=months_in_year { - days += Self::days_in_provided_month(year, month) as u16; - } - days - } -} - -pub(crate) trait PrecomputedDataSource { - /// Given a calendar year, load (or compute) the YearInfo for it - /// - /// In the future we may pass in an optional previous YearInfo alongside the year - /// it matches to allow code to take shortcuts. - fn load_or_compute_info(&self, year: i32) -> YearInfo; -} + fn months_in_provided_year(year: Self::YearInfo) -> u8; -impl PrecomputedDataSource for () { - fn load_or_compute_info(&self, year: i32) -> i32 { - year - } -} + /// Converts the era and era year to a YearInfo. If the calendar does not have eras, + /// this should always return an Err result. + fn year_info_from_era( + &self, + era: &[u8], + era_year: i32, + ) -> Result; -impl ArithmeticDate { - /// Create a new `ArithmeticDate` without checking that `month` and `day` are in bounds. - #[inline] - pub const fn new_unchecked(year: C::YearInfo, month: u8, day: u8) -> Self { - ArithmeticDate { - year, - month, - day, - marker: PhantomData, - } - } + /// Converts an extended year to a YearInfo. + fn year_info_from_extended(&self, extended_year: i32) -> Self::YearInfo; - #[inline] - pub fn min_date() -> Self - where - C: CalendarArithmetic, - { - ArithmeticDate { - year: i32::MIN, - month: 1, - day: 1, - marker: PhantomData, - } - } + /// Calculates the ECMA reference year for the month code and day, or an error + /// if the month code and day are invalid. + /// + /// Note that this is called before any potential Overflow::Constrain application, + /// so this should accept out-of-range day values as if they are the highest possible + /// day for the given month. + fn reference_year_from_month_day( + &self, + month_code: ValidMonthCode, + day: u8, + ) -> Result; + /// Calculates the ordinal month for the given year and month code. + /// + /// The default impl is for non-lunisolar calendars with 12 months! #[inline] - pub fn max_date() -> Self - where - C: CalendarArithmetic, - { - let year = i32::MAX; - let (month, day) = C::last_month_day_in_provided_year(year); - ArithmeticDate { - year: i32::MAX, - month, - day, - marker: PhantomData, + fn ordinal_month_from_code( + &self, + _year: &Self::YearInfo, + month_code: ValidMonthCode, + _options: DateFromFieldsOptions, + ) -> Result { + match month_code.to_tuple() { + (month_number @ 1..=12, false) => Ok(month_number), + _ => Err(MonthCodeError::NotInCalendar), } } + /// Calculates the month code from the given ordinal month and year. + /// + /// The caller must ensure that the ordinal is in range. + /// + /// The default impl is for non-lunisolar calendars! #[inline] - fn offset_days(&mut self, mut day_offset: i32, data: &impl PrecomputedDataSource) { - while day_offset != 0 { - let month_days = C::days_in_provided_month(self.year, self.month); - if self.day as i32 + day_offset > month_days as i32 { - self.offset_months(1, data); - day_offset -= month_days as i32; - } else if self.day as i32 + day_offset < 1 { - self.offset_months(-1, data); - day_offset += C::days_in_provided_month(self.year, self.month) as i32; - } else { - self.day = (self.day as i32 + day_offset) as u8; - day_offset = 0; - } - } + fn month_code_from_ordinal(&self, _year: &Self::YearInfo, ordinal_month: u8) -> ValidMonthCode { + ValidMonthCode::new_unchecked(ordinal_month, false) } +} +impl ArithmeticDate { #[inline] - fn offset_months( - &mut self, - mut month_offset: i32, - data: &impl PrecomputedDataSource, - ) { - while month_offset != 0 { - let year_months = C::months_in_provided_year(self.year); - if self.month as i32 + month_offset > year_months as i32 { - self.year = data.load_or_compute_info(self.year.into() + 1); - month_offset -= year_months as i32; - } else if self.month as i32 + month_offset < 1 { - self.year = data.load_or_compute_info(self.year.into() - 1); - month_offset += C::months_in_provided_year(self.year) as i32; - } else { - self.month = (self.month as i32 + month_offset) as u8; - month_offset = 0 - } - } + pub(crate) const fn new_unchecked(year: C::YearInfo, month: u8, day: u8) -> Self { + ArithmeticDate { year, month, day } } - #[inline] - pub fn offset_date( - &mut self, - offset: DateDuration, - data: &impl PrecomputedDataSource, - ) { - if offset.years != 0 { - // For offset_date to work with lunar calendars, need to handle an edge case where the original month is not valid in the future year. - self.year = data.load_or_compute_info(self.year.into() + offset.years); + pub(crate) const fn cast>( + self, + ) -> ArithmeticDate { + ArithmeticDate { + year: self.year, + month: self.month, + day: self.day, } - - self.offset_months(offset.months, data); - - let day_offset = offset.days + offset.weeks * 7 + self.day as i32 - 1; - self.day = 1; - self.offset_days(day_offset, data); } - #[inline] - pub fn until( - &self, - date2: ArithmeticDate, - _largest_unit: DateDurationUnit, - _smaller_unit: DateDurationUnit, - ) -> DateDuration { - // This simple implementation does not need C::PrecomputedDataSource right now, but it - // likely will once we've written a proper implementation - DateDuration::new( - self.year.into() - date2.year.into(), - self.month as i32 - date2.month as i32, - 0, - self.day as i32 - date2.day as i32, - ) + pub(crate) fn from_codes( + era: Option<&str>, + year: i32, + month_code: types::MonthCode, + day: u8, + calendar: &C, + ) -> Result { + let year = range_check(year, "year", VALID_YEAR_RANGE)?; + let year = if let Some(era) = era { + calendar.year_info_from_era(era.as_bytes(), year)? + } else { + calendar.year_info_from_extended(year) + }; + let validated = + ValidMonthCode::try_from_utf8(month_code.0.as_bytes()).map_err(|e| match e { + MonthCodeParseError::InvalidSyntax => DateError::UnknownMonthCode(month_code), + })?; + let month = calendar + .ordinal_month_from_code(&year, validated, Default::default()) + .map_err(|e| match e { + MonthCodeError::NotInCalendar | MonthCodeError::NotInYear => { + DateError::UnknownMonthCode(month_code) + } + })?; + + let day = range_check(day, "day", 1..=C::days_in_provided_month(year, month))?; + + Ok(ArithmeticDate::new_unchecked(year, month, day)) } - #[inline] - pub fn days_in_year(&self) -> u16 { - C::days_in_provided_year(self.year) - } + pub(crate) fn from_fields( + fields: DateFields, + options: DateFromFieldsOptions, + calendar: &C, + ) -> Result { + let missing_fields_strategy = options.missing_fields_strategy.unwrap_or_default(); + + let day = match fields.day { + Some(day) => day, + None => match missing_fields_strategy { + MissingFieldsStrategy::Reject => return Err(DateFromFieldsError::NotEnoughFields), + MissingFieldsStrategy::Ecma => { + if fields.extended_year.is_some() || fields.era_year.is_some() { + // The ECMAScript strategy is to pick day 1, always, regardless of whether + // that day exists for the month/year combo + 1 + } else { + return Err(DateFromFieldsError::NotEnoughFields); + } + } + }, + }; - #[inline] - pub fn months_in_year(&self) -> u8 { - C::months_in_provided_year(self.year) - } + if fields.month_code.is_none() && fields.ordinal_month.is_none() { + // We're returning this error early so that we return structural type + // errors before range errors, see comment in the year code below. + return Err(DateFromFieldsError::NotEnoughFields); + } - #[inline] - pub fn days_in_month(&self) -> u8 { - C::days_in_provided_month(self.year, self.month) - } + let mut valid_month_code = None; + + // NOTE: The year/extendedyear range check is important to avoid arithmetic + // overflow in `year_info_from_era` and `year_info_from_extended`. It + // must happen before they are called. + // + // To better match the Temporal specification's order of operations, we try + // to return structural type errors (`NotEnoughFields`) before checking for range errors. + // This isn't behavior we *must* have, but it is not much additional work to maintain + // so we make an attempt. + let year = match (fields.era, fields.era_year) { + (None, None) => match fields.extended_year { + Some(extended_year) => calendar.year_info_from_extended(range_check( + extended_year, + "year", + VALID_YEAR_RANGE, + )?), + None => match missing_fields_strategy { + MissingFieldsStrategy::Reject => { + return Err(DateFromFieldsError::NotEnoughFields) + } + MissingFieldsStrategy::Ecma => { + match (fields.month_code, fields.ordinal_month) { + (Some(month_code), None) => { + let validated = ValidMonthCode::try_from_utf8(month_code)?; + valid_month_code = Some(validated); + calendar.reference_year_from_month_day(validated, day)? + } + _ => return Err(DateFromFieldsError::NotEnoughFields), + } + } + }, + }, + (Some(era), Some(era_year)) => { + let era_year_as_year_info = calendar + .year_info_from_era(era, range_check(era_year, "year", VALID_YEAR_RANGE)?)?; + if let Some(extended_year) = fields.extended_year { + if era_year_as_year_info + != calendar.year_info_from_extended(range_check( + extended_year, + "year", + VALID_YEAR_RANGE, + )?) + { + return Err(DateFromFieldsError::InconsistentYear); + } + } + era_year_as_year_info + } + // Era and Era Year must be both or neither + (Some(_), None) | (None, Some(_)) => return Err(DateFromFieldsError::NotEnoughFields), + }; - #[inline] - pub fn date_from_year_day(year: i32, year_day: u32) -> ArithmeticDate - where - C: CalendarArithmetic, - { - let mut month = 1; - let mut day = year_day as i32; - while month <= C::months_in_provided_year(year) { - let month_days = C::days_in_provided_month(year, month) as i32; - if day <= month_days { - break; - } else { - day -= month_days; - month += 1; + let month = match fields.month_code { + Some(month_code) => { + let validated = match valid_month_code { + Some(validated) => validated, + None => ValidMonthCode::try_from_utf8(month_code)?, + }; + let computed_month = calendar.ordinal_month_from_code(&year, validated, options)?; + if let Some(ordinal_month) = fields.ordinal_month { + if computed_month != ordinal_month { + return Err(DateFromFieldsError::InconsistentMonth); + } + } + computed_month } - } + None => match fields.ordinal_month { + Some(month) => month, + None => { + debug_assert!(false, "Already checked above"); + return Err(DateFromFieldsError::NotEnoughFields); + } + }, + }; - debug_assert!(day <= C::days_in_provided_month(year, month) as i32); - #[allow(clippy::unwrap_used)] - // The day is expected to be within the range of month_days of C - ArithmeticDate { - year, + let constrained_month = range_check_with_overflow( month, - day: day.try_into().unwrap_or(1), - marker: PhantomData, - } + "month", + 1..=C::months_in_provided_year(year), + options.overflow.unwrap_or_default(), + )?; + Ok(Self::new_unchecked( + year, + constrained_month, + range_check_with_overflow( + day, + "day", + 1..=C::days_in_provided_month(year, constrained_month), + options.overflow.unwrap_or_default(), + )?, + )) } - #[inline] - pub fn day_of_month(&self) -> types::DayOfMonth { - types::DayOfMonth(self.day) + pub(crate) fn try_from_ymd(year: C::YearInfo, month: u8, day: u8) -> Result { + range_check(month, "month", 1..=C::months_in_provided_year(year))?; + range_check(day, "day", 1..=C::days_in_provided_month(year, month))?; + Ok(ArithmeticDate::new_unchecked(year, month, day)) } - #[inline] - pub fn day_of_year(&self) -> DayOfYear { - let mut day_of_year = 0; - for month in 1..self.month { - day_of_year += C::days_in_provided_month(self.year, month) as u16; + /// Implements the Temporal abstract operation BalanceNonISODate. + /// + /// This takes a year, month, and day, where the month and day might be out of range, then + /// balances excess months into the year field and excess days into the month field. + pub(crate) fn new_balanced(year: C::YearInfo, ordinal_month: i64, day: i64, cal: &C) -> Self { + // 1. Let _resolvedYear_ be _arithmeticYear_. + // 1. Let _resolvedMonth_ be _ordinalMonth_. + let mut resolved_year = year; + let mut resolved_month = ordinal_month; + // 1. Let _monthsInYear_ be CalendarMonthsInYear(_calendar_, _resolvedYear_). + let mut months_in_year = C::months_in_provided_year(resolved_year); + // 1. Repeat, while _resolvedMonth_ ≤ 0, + // 1. Set _resolvedYear_ to _resolvedYear_ - 1. + // 1. Set _monthsInYear_ to CalendarMonthsInYear(_calendar_, _resolvedYear_). + // 1. Set _resolvedMonth_ to _resolvedMonth_ + _monthsInYear_. + while resolved_month <= 0 { + resolved_year = cal.year_info_from_extended(resolved_year.to_extended_year() - 1); + months_in_year = C::months_in_provided_year(resolved_year); + resolved_month += i64::from(months_in_year); } - DayOfYear(day_of_year + (self.day as u16)) - } - - pub fn extended_year(&self) -> i32 { - self.year.into() + // 1. Repeat, while _resolvedMonth_ > _monthsInYear_, + // 1. Set _resolvedMonth_ to _resolvedMonth_ - _monthsInYear_. + // 1. Set _resolvedYear_ to _resolvedYear_ + 1. + // 1. Set _monthsInYear_ to CalendarMonthsInYear(_calendar_, _resolvedYear_). + while resolved_month > i64::from(months_in_year) { + resolved_month -= i64::from(months_in_year); + resolved_year = cal.year_info_from_extended(resolved_year.to_extended_year() + 1); + months_in_year = C::months_in_provided_year(resolved_year); + } + debug_assert!(u8::try_from(resolved_month).is_ok()); + let mut resolved_month = resolved_month as u8; + // 1. Let _resolvedDay_ be _day_. + let mut resolved_day = day; + // 1. Let _daysInMonth_ be CalendarDaysInMonth(_calendar_, _resolvedYear_, _resolvedMonth_). + let mut days_in_month = C::days_in_provided_month(resolved_year, resolved_month); + // 1. Repeat, while _resolvedDay_ ≤ 0, + while resolved_day <= 0 { + // 1. Set _resolvedMonth_ to _resolvedMonth_ - 1. + // 1. If _resolvedMonth_ is 0, then + resolved_month -= 1; + if resolved_month == 0 { + // 1. Set _resolvedYear_ to _resolvedYear_ - 1. + // 1. Set _monthsInYear_ to CalendarMonthsInYear(_calendar_, _resolvedYear_). + // 1. Set _resolvedMonth_ to _monthsInYear_. + resolved_year = cal.year_info_from_extended(resolved_year.to_extended_year() - 1); + months_in_year = C::months_in_provided_year(resolved_year); + resolved_month = months_in_year; + } + // 1. Set _daysInMonth_ to CalendarDaysInMonth(_calendar_, _resolvedYear_, _resolvedMonth_). + // 1. Set _resolvedDay_ to _resolvedDay_ + _daysInMonth_. + days_in_month = C::days_in_provided_month(resolved_year, resolved_month); + resolved_day += i64::from(days_in_month); + } + // 1. Repeat, while _resolvedDay_ > _daysInMonth_, + while resolved_day > i64::from(days_in_month) { + // 1. Set _resolvedDay_ to _resolvedDay_ - _daysInMonth_. + // 1. Set _resolvedMonth_ to _resolvedMonth_ + 1. + // 1. If _resolvedMonth_ > _monthsInYear_, then + resolved_day -= i64::from(days_in_month); + resolved_month += 1; + if resolved_month > months_in_year { + // 1. Set _resolvedYear_ to _resolvedYear_ + 1. + // 1. Set _monthsInYear_ to CalendarMonthsInYear(_calendar_, _resolvedYear_). + // 1. Set _resolvedMonth_ to 1. + resolved_year = cal.year_info_from_extended(resolved_year.to_extended_year() + 1); + months_in_year = C::months_in_provided_year(resolved_year); + resolved_month = 1; + } + // 1. Set _daysInMonth_ to CalendarDaysInMonth(_calendar_, _resolvedYear_, _resolvedMonth_). + days_in_month = C::days_in_provided_month(resolved_year, resolved_month); + } + debug_assert!(u8::try_from(resolved_day).is_ok()); + let resolved_day = resolved_day as u8; + // 1. Return the Record { [[Year]]: _resolvedYear_, [[Month]]: _resolvedMonth_, [[Day]]: _resolvedDay_ }. + Self::new_unchecked(resolved_year, resolved_month, resolved_day) } - /// The [`types::MonthInfo`] for the current month (with month code) for a solar calendar - /// Lunar calendars should not use this method and instead manually implement a month code - /// resolver. - /// Originally "solar_month" but renamed because it can be used for some lunar calendars + /// Implements the Temporal abstract operation NonISODateSurpasses. /// - /// Returns "und" if run with months that are out of bounds for the current - /// calendar. - #[inline] - pub fn month(&self) -> types::MonthInfo { - let code = match self.month { - a if a > C::months_in_provided_year(self.year) => tinystr!(4, "und"), - 1 => tinystr!(4, "M01"), - 2 => tinystr!(4, "M02"), - 3 => tinystr!(4, "M03"), - 4 => tinystr!(4, "M04"), - 5 => tinystr!(4, "M05"), - 6 => tinystr!(4, "M06"), - 7 => tinystr!(4, "M07"), - 8 => tinystr!(4, "M08"), - 9 => tinystr!(4, "M09"), - 10 => tinystr!(4, "M10"), - 11 => tinystr!(4, "M11"), - 12 => tinystr!(4, "M12"), - 13 => tinystr!(4, "M13"), - _ => tinystr!(4, "und"), + /// This takes two dates (`self` and `other`), `duration`, and `sign` (either -1 or 1), then + /// returns whether adding the duration to `self` results in a year/month/day that exceeds + /// `other` in the direction indicated by `sign`, constraining the month but not the day. + pub(crate) fn surpasses( + &self, + other: &Self, + duration: DateDuration, + sign: i64, + cal: &C, + ) -> bool { + // 1. Let _parts_ be CalendarISOToDate(_calendar_, _fromIsoDate_). + // 1. Let _y0_ be _parts_.[[Year]] + _years_. + let y0 = cal.year_info_from_extended(duration.add_years_to(self.year.to_extended_year())); + // 1. Let _m0_ be MonthCodeToOrdinal(_calendar_, _y0_, ! ConstrainMonthCode(_calendar_, _y0_, _parts_.[[MonthCode]], ~constrain~)). + let base_month_code = cal.month_code_from_ordinal(&self.year, self.month); + let constrain = DateFromFieldsOptions { + overflow: Some(Overflow::Constrain), + ..Default::default() + }; + let m0_result = cal.ordinal_month_from_code(&y0, base_month_code, constrain); + let m0 = match m0_result { + Ok(m0) => m0, + Err(_) => { + debug_assert!( + false, + "valid month code for calendar, and constrained to the year" + ); + 1 + } }; - types::MonthInfo { - ordinal: self.month, - standard_code: types::MonthCode(code), - formatting_code: types::MonthCode(code), + // 1. Let _endOfMonth_ be BalanceNonISODate(_calendar_, _y0_, _m0_ + _months_ + 1, 0). + let end_of_month = Self::new_balanced(y0, duration.add_months_to(m0) + 1, 0, cal); + // 1. Let _baseDay_ be _parts_.[[Day]]. + let base_day = self.day; + let y1; + let m1; + let d1; + // 1. If _weeks_ is not 0 or _days_ is not 0, then + if duration.weeks != 0 || duration.days != 0 { + // 1. If _baseDay_ < _endOfMonth_.[[Day]], then + // 1. Let _regulatedDay_ be _baseDay_. + // 1. Else, + // 1. Let _regulatedDay_ be _endOfMonth_.[[Day]]. + let regulated_day = if base_day < end_of_month.day { + base_day + } else { + end_of_month.day + }; + // 1. Let _balancedDate_ be BalanceNonISODate(_calendar_, _endOfMonth_.[[Year]], _endOfMonth_.[[Month]], _regulatedDay_ + 7 * _weeks_ + _days_). + // 1. Let _y1_ be _balancedDate_.[[Year]]. + // 1. Let _m1_ be _balancedDate_.[[Month]]. + // 1. Let _d1_ be _balancedDate_.[[Day]]. + let balanced_date = Self::new_balanced( + end_of_month.year, + i64::from(end_of_month.month), + duration.add_weeks_and_days_to(regulated_day), + cal, + ); + y1 = balanced_date.year; + m1 = balanced_date.month; + d1 = balanced_date.day; + } else { + // 1. Else, + // 1. Let _y1_ be _endOfMonth_.[[Year]]. + // 1. Let _m1_ be _endOfMonth_.[[Month]]. + // 1. Let _d1_ be _baseDay_. + y1 = end_of_month.year; + m1 = end_of_month.month; + d1 = base_day; } + // 1. Let _calDate2_ be CalendarISOToDate(_calendar_, _toIsoDate_). + // 1. If _y1_ ≠ _calDate2_.[[Year]], then + // 1. If _sign_ × (_y1_ - _calDate2_.[[Year]]) > 0, return *true*. + // 1. Else if _m1_ ≠ _calDate2_.[[Month]], then + // 1. If _sign_ × (_m1_ - _calDate2_.[[Month]]) > 0, return *true*. + // 1. Else if _d1_ ≠ _calDate2_.[[Day]], then + // 1. If _sign_ × (_d1_ - _calDate2_.[[Day]]) > 0, return *true*. + #[allow(clippy::collapsible_if)] // to align with the spec + if y1 != other.year { + if sign * (i64::from(y1.to_extended_year()) - i64::from(other.year.to_extended_year())) + > 0 + { + return true; + } + } else if m1 != other.month { + if sign * (i64::from(m1) - i64::from(other.month)) > 0 { + return true; + } + } else if d1 != other.day { + if sign * (i64::from(d1) - i64::from(other.day)) > 0 { + return true; + } + } + // 1. Return *false*. + false } - /// Construct a new arithmetic date from a year, month code, and day, bounds checking - /// the month and day - /// Originally (new_from_solar_codes) but renamed because it works for some lunar calendars - pub fn new_from_codes( - // Separate type since the debug_name() impl may differ when DateInner types - // are nested (e.g. in GregorianDateInner) - _cal: &C2, - year: i32, - month_code: types::MonthCode, - day: u8, - ) -> Result - where - C: CalendarArithmetic, - { - let month = if let Some((ordinal, false)) = month_code.parsed() { - ordinal + /// Implements the Temporal abstract operation NonISODateAdd. + /// + /// This takes a date (`self`) and `duration`, then returns a new date resulting from + /// adding `duration` to `self`, constrained according to `options`. + pub(crate) fn added( + &self, + duration: DateDuration, + cal: &C, + options: DateAddOptions, + ) -> Result { + // 1. Let _parts_ be CalendarISOToDate(_calendar_, _isoDate_). + // 1. Let _y0_ be _parts_.[[Year]] + _duration_.[[Years]]. + let y0 = cal.year_info_from_extended(duration.add_years_to(self.year.to_extended_year())); + // 1. Let _m0_ be MonthCodeToOrdinal(_calendar_, _y0_, ! ConstrainMonthCode(_calendar_, _y0_, _parts_.[[MonthCode]], _overflow_)). + let base_month = cal.month_code_from_ordinal(&self.year, self.month); + let m0 = cal + .ordinal_month_from_code( + &y0, + base_month, + DateFromFieldsOptions::from_add_options(options), + ) + .map_err(|e| { + // TODO: Use a narrower error type here. For now, convert into DateError. + match e { + MonthCodeError::NotInCalendar => { + DateError::UnknownMonthCode(base_month.to_month_code()) + } + MonthCodeError::NotInYear => { + DateError::UnknownMonthCode(base_month.to_month_code()) + } + } + })?; + // 1. Let _endOfMonth_ be BalanceNonISODate(_calendar_, _y0_, _m0_ + _duration_.[[Months]] + 1, 0). + let end_of_month = Self::new_balanced(y0, duration.add_months_to(m0) + 1, 0, cal); + // 1. Let _baseDay_ be _parts_.[[Day]]. + let base_day = self.day; + // 1. If _baseDay_ < _endOfMonth_.[[Day]], then + // 1. Let _regulatedDay_ be _baseDay_. + let regulated_day = if base_day < end_of_month.day { + base_day } else { - return Err(DateError::UnknownMonthCode(month_code)); + // 1. Else, + // 1. If _overflow_ is ~reject~, throw a *RangeError* exception. + // Note: ICU4X default is constrain here + if matches!(options.overflow, Some(Overflow::Reject)) { + return Err(DateError::Range { + field: "day", + value: i32::from(base_day), + min: 1, + max: i32::from(end_of_month.day), + }); + } + end_of_month.day }; + // 1. Let _balancedDate_ be BalanceNonISODate(_calendar_, _endOfMonth_.[[Year]], _endOfMonth_.[[Month]], _regulatedDay_ + 7 * _duration_.[[Weeks]] + _duration_.[[Days]]). + // 1. Let _result_ be ? CalendarIntegersToISO(_calendar_, _balancedDate_.[[Year]], _balancedDate_.[[Month]], _balancedDate_.[[Day]]). + // 1. Return _result_. + Ok(Self::new_balanced( + end_of_month.year, + i64::from(end_of_month.month), + duration.add_weeks_and_days_to(regulated_day), + cal, + )) + } - if month > C::months_in_provided_year(year) { - return Err(DateError::UnknownMonthCode(month_code)); + /// Implements the Temporal abstract operation NonISODateUntil. + /// + /// This takes a duration (`self`) and a date (`other`), then returns a duration that, when + /// added to `self`, results in `other`, with largest unit according to `options`. + pub(crate) fn until( + &self, + other: &Self, + cal: &C, + options: DateDifferenceOptions, + ) -> DateDuration { + // 1. Let _sign_ be -1 × CompareISODate(_one_, _two_). + // 1. If _sign_ = 0, return ZeroDateDuration(). + let sign = match other.cmp(self) { + Ordering::Greater => 1i64, + Ordering::Equal => return DateDuration::default(), + Ordering::Less => -1i64, + }; + // 1. Let _years_ be 0. + // 1. If _largestUnit_ is ~year~, then + // 1. Let _candidateYears_ be _sign_. + // 1. Repeat, while NonISODateSurpasses(_calendar_, _sign_, _one_, _two_, _candidateYears_, 0, 0, 0) is *false*, + // 1. Set _years_ to _candidateYears_. + // 1. Set _candidateYears_ to _candidateYears_ + _sign_. + let mut years = 0; + if matches!(options.largest_unit, Some(DateDurationUnit::Years)) { + let mut candidate_years = sign; + while !self.surpasses( + other, + DateDuration::from_signed_ymwd(candidate_years, 0, 0, 0), + sign, + cal, + ) { + years = candidate_years; + candidate_years += sign; + } } - - let max_day = C::days_in_provided_month(year, month); - if day == 0 || day > max_day { - return Err(DateError::Range { - field: "day", - value: day as i32, - min: 1, - max: max_day as i32, - }); + // 1. Let _months_ be 0. + // 1. If _largestUnit_ is ~year~ or _largestUnit_ is ~month~, then + // 1. Let _candidateMonths_ be _sign_. + // 1. Repeat, while NonISODateSurpasses(_calendar_, _sign_, _one_, _two_, _years_, _candidateMonths_, 0, 0) is *false*, + // 1. Set _months_ to _candidateMonths_. + // 1. Set _candidateMonths_ to _candidateMonths_ + _sign_. + let mut months = 0; + if matches!( + options.largest_unit, + Some(DateDurationUnit::Years) | Some(DateDurationUnit::Months) + ) { + let mut candidate_months = sign; + while !self.surpasses( + other, + DateDuration::from_signed_ymwd(years, candidate_months, 0, 0), + sign, + cal, + ) { + months = candidate_months; + candidate_months += sign; + } } - - Ok(Self::new_unchecked(year, month, day)) - } - - /// Construct a new arithmetic date from a year, month ordinal, and day, bounds checking - /// the month and day - pub fn new_from_ordinals(year: C::YearInfo, month: u8, day: u8) -> Result { - let max_month = C::months_in_provided_year(year); - if month == 0 || month > max_month { - return Err(RangeError { - field: "month", - value: month as i32, - min: 1, - max: max_month as i32, - }); + // 1. Let _weeks_ be 0. + // 1. If _largestUnit_ is ~week~, then + // 1. Let _candidateWeeks_ be _sign_. + // 1. Repeat, while NonISODateSurpasses(_calendar_, _sign_, _one_, _two_, _years_, _months_, _candidateWeeks_, 0) is *false*, + // 1. Set _weeks_ to _candidateWeeks_. + // 1. Set _candidateWeeks_ to _candidateWeeks_ + sign. + let mut weeks = 0; + if matches!(options.largest_unit, Some(DateDurationUnit::Weeks)) { + let mut candidate_weeks = sign; + while !self.surpasses( + other, + DateDuration::from_signed_ymwd(years, months, candidate_weeks, 0), + sign, + cal, + ) { + weeks = candidate_weeks; + candidate_weeks += sign; + } } - let max_day = C::days_in_provided_month(year, month); - if day == 0 || day > max_day { - return Err(RangeError { - field: "day", - value: day as i32, - min: 1, - max: max_day as i32, - }); + // 1. Let _days_ be 0. + // 1. Let _candidateDays_ be _sign_. + // 1. Repeat, while NonISODateSurpasses(_calendar_, _sign_, _one_, _two_, _years_, _months_, _weeks_, _candidateDays_) is *false*, + // 1. Set _days_ to _candidateDays_. + // 1. Set _candidateDays_ to _candidateDays_ + _sign_. + let mut days = 0; + let mut candidate_days = sign; + while !self.surpasses( + other, + DateDuration::from_signed_ymwd(years, months, weeks, candidate_days), + sign, + cal, + ) { + days = candidate_days; + candidate_days += sign; } - - Ok(Self::new_unchecked(year, month, day)) + // 1. Return ! CreateDateDurationRecord(_years_, _months_, _weeks_, _days_). + DateDuration::from_signed_ymwd(years, months, weeks, days) } } #[cfg(test)] mod tests { use super::*; - use crate::cal::Iso; + use crate::cal::{abstract_gregorian::AbstractGregorian, iso::IsoEra}; #[test] fn test_ord() { let dates_in_order = [ - ArithmeticDate::::new_unchecked(-10, 1, 1), - ArithmeticDate::::new_unchecked(-10, 1, 2), - ArithmeticDate::::new_unchecked(-10, 2, 1), - ArithmeticDate::::new_unchecked(-1, 1, 1), - ArithmeticDate::::new_unchecked(-1, 1, 2), - ArithmeticDate::::new_unchecked(-1, 2, 1), - ArithmeticDate::::new_unchecked(0, 1, 1), - ArithmeticDate::::new_unchecked(0, 1, 2), - ArithmeticDate::::new_unchecked(0, 2, 1), - ArithmeticDate::::new_unchecked(1, 1, 1), - ArithmeticDate::::new_unchecked(1, 1, 2), - ArithmeticDate::::new_unchecked(1, 2, 1), - ArithmeticDate::::new_unchecked(10, 1, 1), - ArithmeticDate::::new_unchecked(10, 1, 2), - ArithmeticDate::::new_unchecked(10, 2, 1), + ArithmeticDate::>::new_unchecked(-10, 1, 1), + ArithmeticDate::>::new_unchecked(-10, 1, 2), + ArithmeticDate::>::new_unchecked(-10, 2, 1), + ArithmeticDate::>::new_unchecked(-1, 1, 1), + ArithmeticDate::>::new_unchecked(-1, 1, 2), + ArithmeticDate::>::new_unchecked(-1, 2, 1), + ArithmeticDate::>::new_unchecked(0, 1, 1), + ArithmeticDate::>::new_unchecked(0, 1, 2), + ArithmeticDate::>::new_unchecked(0, 2, 1), + ArithmeticDate::>::new_unchecked(1, 1, 1), + ArithmeticDate::>::new_unchecked(1, 1, 2), + ArithmeticDate::>::new_unchecked(1, 2, 1), + ArithmeticDate::>::new_unchecked(10, 1, 1), + ArithmeticDate::>::new_unchecked(10, 1, 2), + ArithmeticDate::>::new_unchecked(10, 2, 1), ]; for (i, i_date) in dates_in_order.iter().enumerate() { for (j, j_date) in dates_in_order.iter().enumerate() { diff --git a/deps/crates/vendor/icu_calendar/src/date.rs b/deps/crates/vendor/icu_calendar/src/date.rs index 5c4c0cf5d9fcab..5b65612c260b75 100644 --- a/deps/crates/vendor/icu_calendar/src/date.rs +++ b/deps/crates/vendor/icu_calendar/src/date.rs @@ -3,11 +3,12 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use crate::any_calendar::{AnyCalendar, IntoAnyCalendar}; -use crate::calendar_arithmetic::CalendarArithmetic; -use crate::error::DateError; +use crate::error::{DateError, DateFromFieldsError}; +use crate::options::DateFromFieldsOptions; +use crate::options::{DateAddOptions, DateDifferenceOptions}; use crate::types::{CyclicYear, EraYear, IsoWeekOfYear}; use crate::week::{RelativeUnit, WeekCalculator, WeekOf}; -use crate::{types, Calendar, DateDuration, DateDurationUnit, Iso}; +use crate::{types, Calendar, Iso}; #[cfg(feature = "alloc")] use alloc::rc::Rc; #[cfg(feature = "alloc")] @@ -36,6 +37,7 @@ impl AsCalendar for C { } #[cfg(feature = "alloc")] +/// ✨ *Enabled with the `alloc` Cargo feature.* impl AsCalendar for Rc { type Calendar = C::Calendar; #[inline] @@ -45,6 +47,7 @@ impl AsCalendar for Rc { } #[cfg(feature = "alloc")] +/// ✨ *Enabled with the `alloc` Cargo feature.* impl AsCalendar for Arc { type Calendar = C::Calendar; #[inline] @@ -119,7 +122,11 @@ pub struct Date { impl Date
{ /// Construct a date from from era/month codes and fields, and some calendar representation /// - /// The year is `extended_year` if no era is provided + /// The year is `extended_year` if no era is provided. + /// + /// This function will not accept year/extended_year values that are outside of the range `[-2²⁷, 2²⁷]`, + /// regardless of the calendar, instead returning a [`DateError::Range`]. See [`Date::try_from_fields()`] for more + /// information. #[inline] pub fn try_new_from_codes( era: Option<&str>, @@ -134,6 +141,59 @@ impl Date { Ok(Date { inner, calendar }) } + /// Construct a date from from a bag of fields. + /// + /// This function allows specifying the year as either extended year or era + era year, + /// and the month as either ordinal or month code. It can constrain out-of-bounds values + /// and fill in missing fields. See [`DateFromFieldsOptions`] for more information. + /// + /// This function will not accept year/extended_year values that are outside of the range `[-2²⁷, 2²⁷]`, + /// regardless of the calendar, instead returning a [`DateFromFieldsError::Range`]. This allows us to to keep + /// all operations on [`Date`]s infallible by staying clear of integer limits. + /// Currently, calendar-specific `Date::try_new_calendarname()` constructors + /// do not do this, and it is possible to obtain such extreme dates via calendar conversion or arithmetic, + /// though [we may change that behavior in the future](https://github.com/unicode-org/icu4x/issues/7076). + /// + /// # Examples + /// + /// ``` + /// use icu::calendar::cal::Gregorian; + /// use icu::calendar::types::DateFields; + /// use icu::calendar::Date; + /// + /// let mut fields = DateFields::default(); + /// fields.extended_year = Some(2000); + /// fields.ordinal_month = Some(1); + /// fields.day = Some(1); + /// + /// let d1 = Date::try_from_fields(fields, Default::default(), Gregorian) + /// .expect("Jan 1 in year 2000"); + /// + /// let d2 = Date::try_new_gregorian(2000, 1, 1).unwrap(); + /// assert_eq!(d1, d2); + /// ``` + /// + /// See [`DateFromFieldsError`] for examples of error conditions. + /// + ///
+ /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, + /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break. + /// + /// Graduation tracking issue: [issue #7161](https://github.com/unicode-org/icu4x/issues/7161). + ///
+ /// + /// ✨ *Enabled with the `unstable` Cargo feature.* + #[cfg(feature = "unstable")] + #[inline] + pub fn try_from_fields( + fields: types::DateFields, + options: DateFromFieldsOptions, + calendar: A, + ) -> Result { + let inner = calendar.as_calendar().from_fields(fields, options)?; + Ok(Date { inner, calendar }) + } + /// Construct a date from a [`RataDie`] and some calendar representation #[inline] pub fn from_rata_die(rd: RataDie, calendar: A) -> Self { @@ -152,20 +212,26 @@ impl Date
{ /// Construct a date from an ISO date and some calendar representation #[inline] pub fn new_from_iso(iso: Date, calendar: A) -> Self { - let inner = calendar.as_calendar().from_iso(iso.inner); - Date { inner, calendar } + iso.to_calendar(calendar) } /// Convert the Date to an ISO Date #[inline] pub fn to_iso(&self) -> Date { - Date::from_raw(self.calendar.as_calendar().to_iso(self.inner()), Iso) + self.to_calendar(Iso) } /// Convert the Date to a date in a different calendar #[inline] pub fn to_calendar(&self, calendar: A2) -> Date { - Date::new_from_iso(self.to_iso(), calendar) + let c1 = self.calendar.as_calendar(); + let c2 = calendar.as_calendar(); + let inner = if c1.has_cheap_iso_conversion() && c2.has_cheap_iso_conversion() { + c2.from_iso(c1.to_iso(self.inner())) + } else { + c2.from_rata_die(c1.to_rata_die(self.inner())) + }; + Date { inner, calendar } } /// The number of months in the year of this date @@ -193,38 +259,95 @@ impl Date { } /// Add a `duration` to this date, mutating it - #[doc(hidden)] // unstable + /// + ///
+ /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, + /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break. + /// + /// Graduation tracking issue: [issue #3964](https://github.com/unicode-org/icu4x/issues/3964). + ///
+ /// + /// ✨ *Enabled with the `unstable` Cargo feature.* + #[cfg(feature = "unstable")] #[inline] - pub fn add(&mut self, duration: DateDuration) { - self.calendar + pub fn try_add_with_options( + &mut self, + duration: types::DateDuration, + options: DateAddOptions, + ) -> Result<(), DateError> { + let inner = self + .calendar .as_calendar() - .offset_date(&mut self.inner, duration) + .add(&self.inner, duration, options)?; + self.inner = inner; + Ok(()) } /// Add a `duration` to this date, returning the new one - #[doc(hidden)] // unstable + /// + ///
+ /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, + /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break. + /// + /// Graduation tracking issue: [issue #3964](https://github.com/unicode-org/icu4x/issues/3964). + ///
+ /// + /// ✨ *Enabled with the `unstable` Cargo feature.* + #[cfg(feature = "unstable")] #[inline] - pub fn added(mut self, duration: DateDuration) -> Self { - self.add(duration); - self + pub fn try_added_with_options( + mut self, + duration: types::DateDuration, + options: DateAddOptions, + ) -> Result { + self.try_add_with_options(duration, options)?; + Ok(self) } /// Calculating the duration between `other - self` - #[doc(hidden)] // unstable + /// + /// Although this returns a [`Result`], with most fixed calendars, this operation can't fail. + /// In such cases, the error type is [`Infallible`], and the inner value can be safely + /// unwrapped using [`Result::into_ok()`], which is available in nightly Rust as of this + /// writing. In stable Rust, the value can be unwrapped using [pattern matching]. + /// + /// # Examples + /// + /// ``` + /// use icu::calendar::types::DateDuration; + /// use icu::calendar::Date; + /// + /// let d1 = Date::try_new_iso(2020, 1, 1).unwrap(); + /// let d2 = Date::try_new_iso(2025, 10, 2).unwrap(); + /// let options = Default::default(); + /// + /// // The value can be unwrapped with destructuring syntax: + /// let Ok(duration) = d1.try_until_with_options(&d2, options); + /// + /// assert_eq!(duration, DateDuration::for_days(2101)); + /// ``` + /// + /// [`Infallible`]: core::convert::Infallible + /// [pattern matching]: https://doc.rust-lang.org/book/ch19-03-pattern-syntax.html + /// + ///
+ /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, + /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break. + /// + /// Graduation tracking issue: [issue #3964](https://github.com/unicode-org/icu4x/issues/3964). + ///
+ /// + /// ✨ *Enabled with the `unstable` Cargo feature.* + #[cfg(feature = "unstable")] #[inline] - pub fn until>( + pub fn try_until_with_options>( &self, other: &Date, - largest_unit: DateDurationUnit, - smallest_unit: DateDurationUnit, - ) -> DateDuration { - self.calendar.as_calendar().until( - self.inner(), - other.inner(), - other.calendar.as_calendar(), - largest_unit, - smallest_unit, - ) + options: DateDifferenceOptions, + ) -> Result::DifferenceError> { + self.calendar + .as_calendar() + .until(self.inner(), other.inner(), options) } /// The calendar-specific year-info. @@ -236,13 +359,21 @@ impl Date
{ self.calendar.as_calendar().year_info(&self.inner).into() } - /// The "extended year", typically anchored with year 1 as the year 1 of either the most modern or - /// otherwise some "major" era for the calendar + /// The "extended year". + /// + /// This year number can be used when you need a simple numeric representation + /// of the year, and can be meaningfully compared with extended years from other + /// eras or used in arithmetic. + /// + /// For calendars defined in Temporal, this will match the "arithmetic year" + /// as defined in . + /// This is typically anchored with year 1 as the year 1 of either the most modern or + /// otherwise some "major" era for the calendar. /// /// See [`Self::year()`] for more information about the year. #[inline] pub fn extended_year(&self) -> i32 { - self.calendar.as_calendar().extended_year(&self.inner) + self.year().extended_year() } /// Returns whether `self` is in a calendar-specific leap year @@ -339,7 +470,8 @@ impl Date { pub fn week_of_year(&self) -> IsoWeekOfYear { let week_of = WeekCalculator::ISO .week_of( - Iso::days_in_provided_year(self.inner.0.year.saturating_sub(1)), + 365 + calendrical_calculations::gregorian::is_leap_year(self.inner.0.year - 1) + as u16, self.days_in_year(), self.day_of_year().0, self.day_of_week(), @@ -357,8 +489,8 @@ impl Date { week_number: week_of.week, iso_year: match week_of.unit { RelativeUnit::Current => self.inner.0.year, - RelativeUnit::Next => self.inner.0.year.saturating_add(1), - RelativeUnit::Previous => self.inner.0.year.saturating_sub(1), + RelativeUnit::Next => self.inner.0.year + 1, + RelativeUnit::Previous => self.inner.0.year - 1, }, } } @@ -378,6 +510,8 @@ impl Date { /// Wrap the contained calendar type in `Rc`, making it cheaper to clone. /// /// Useful when paired with [`Self::to_any()`] to obtain a `Date>` + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] pub fn into_ref_counted(self) -> Date> { Date::from_raw(self.inner, Rc::new(self.calendar)) @@ -386,6 +520,8 @@ impl Date { /// Wrap the contained calendar type in `Arc`, making it cheaper to clone in a thread-safe manner. /// /// Useful when paired with [`Self::to_any()`] to obtain a `Date>` + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] pub fn into_atomic_ref_counted(self) -> Date> { Date::from_raw(self.inner, Arc::new(self.calendar)) @@ -395,7 +531,7 @@ impl Date { /// /// Useful for converting a `&Date` into an equivalent `Date` without cloning /// the calendar. - pub fn as_borrowed(&self) -> Date> { + pub fn as_borrowed(&self) -> Date> { Date::from_raw(self.inner, Ref(&self.calendar)) } } @@ -416,7 +552,6 @@ impl Eq for Date {} impl PartialOrd> for Date where C: Calendar, - C::DateInner: PartialOrd, A: AsCalendar, B: AsCalendar, { diff --git a/deps/crates/vendor/icu_calendar/src/duration.rs b/deps/crates/vendor/icu_calendar/src/duration.rs index b8f21743d1460a..d089dd0644ac99 100644 --- a/deps/crates/vendor/icu_calendar/src/duration.rs +++ b/deps/crates/vendor/icu_calendar/src/duration.rs @@ -2,18 +2,25 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -use crate::Calendar; -use core::fmt; -use core::marker::PhantomData; - -/// A duration between two dates +/// A signed length of time in terms of days, weeks, months, and years. +/// +/// This type represents the abstract concept of a date duration. For example, a duration of +/// "1 month" is represented as "1 month" in the data model, without any context of how many +/// days the month might be. +/// +/// Use [`DateDuration`] for calculating the difference between two [`Date`]s and adding +/// date units to a [`Date`]. /// -/// Can be used to perform date arithmetic +/// [`Date`]: crate::Date /// /// # Example /// /// ```rust -/// use icu::calendar::{types::Weekday, Date, DateDuration, DateDurationUnit}; +/// use icu::calendar::options::DateDifferenceOptions; +/// use icu::calendar::types::DateDuration; +/// use icu::calendar::types::DateDurationUnit; +/// use icu::calendar::types::Weekday; +/// use icu::calendar::Date; /// /// // Creating ISO date: 1992-09-02. /// let mut date_iso = Date::try_new_iso(1992, 9, 2) @@ -29,70 +36,116 @@ use core::marker::PhantomData; /// assert_eq!(date_iso.days_in_month(), 30); /// /// // Advancing date in-place by 1 year, 2 months, 3 weeks, 4 days. -/// date_iso.add(DateDuration::new(1, 2, 3, 4)); +/// date_iso +/// .try_add_with_options( +/// DateDuration { +/// is_negative: false, +/// years: 1, +/// months: 2, +/// weeks: 3, +/// days: 4, +/// }, +/// Default::default(), +/// ) +/// .unwrap(); /// assert_eq!(date_iso.era_year().year, 1993); /// assert_eq!(date_iso.month().ordinal, 11); /// assert_eq!(date_iso.day_of_month().0, 27); /// /// // Reverse date advancement. -/// date_iso.add(DateDuration::new(-1, -2, -3, -4)); +/// date_iso +/// .try_add_with_options( +/// DateDuration { +/// is_negative: true, +/// years: 1, +/// months: 2, +/// weeks: 3, +/// days: 4, +/// }, +/// Default::default(), +/// ) +/// .unwrap(); /// assert_eq!(date_iso.era_year().year, 1992); /// assert_eq!(date_iso.month().ordinal, 9); /// assert_eq!(date_iso.day_of_month().0, 2); /// /// // Creating ISO date: 2022-01-30. -/// let newer_date_iso = Date::try_new_iso(2022, 1, 30) +/// let newer_date_iso = Date::try_new_iso(2022, 10, 30) /// .expect("Failed to initialize ISO Date instance."); /// /// // Comparing dates: 2022-01-30 and 1992-09-02. -/// let duration = newer_date_iso.until( -/// &date_iso, -/// DateDurationUnit::Years, -/// DateDurationUnit::Days, -/// ); +/// let mut options = DateDifferenceOptions::default(); +/// options.largest_unit = Some(DateDurationUnit::Years); +/// let Ok(duration) = +/// newer_date_iso.try_until_with_options(&date_iso, options); /// assert_eq!(duration.years, 30); -/// assert_eq!(duration.months, -8); +/// assert_eq!(duration.months, 1); /// assert_eq!(duration.days, 28); /// /// // Create new date with date advancement. Reassign to new variable. -/// let mutated_date_iso = date_iso.added(DateDuration::new(1, 2, 3, 4)); +/// let mutated_date_iso = date_iso +/// .try_added_with_options( +/// DateDuration { +/// is_negative: false, +/// years: 1, +/// months: 2, +/// weeks: 3, +/// days: 4, +/// }, +/// Default::default(), +/// ) +/// .unwrap(); /// assert_eq!(mutated_date_iso.era_year().year, 1993); /// assert_eq!(mutated_date_iso.month().ordinal, 11); /// assert_eq!(mutated_date_iso.day_of_month().0, 27); /// ``` /// /// Currently unstable for ICU4X 1.0 -#[derive(Eq, PartialEq)] -#[allow(clippy::exhaustive_structs)] // this type should be stable (and is intended to be constructed manually) -#[doc(hidden)] // unstable -pub struct DateDuration { +/// +///
+/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, +/// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break. +/// +/// Graduation tracking issue: [issue #3964](https://github.com/unicode-org/icu4x/issues/3964). +///
+/// +/// ✨ *Enabled with the `unstable` Cargo feature.* +#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)] +#[allow(clippy::exhaustive_structs)] // spec-defined in Temporal +pub struct DateDuration { + /// Whether the duration is negative. + /// + /// A negative duration is an abstract concept that could result, for example, from + /// taking the difference between two [`Date`](crate::Date)s. + /// + /// The fields of the duration are either all positive or all negative. Mixed signs + /// are not allowed. + /// + /// By convention, this field should be `false` if the duration is zero. + pub is_negative: bool, /// The number of years - pub years: i32, + pub years: u32, /// The number of months - pub months: i32, + pub months: u32, /// The number of weeks - pub weeks: i32, + pub weeks: u32, /// The number of days - pub days: i32, - /// A marker for the calendar - pub marker: PhantomData, + pub days: u64, } -// Custom impl so that C need not be bound on Copy/Clone -impl Clone for DateDuration { - fn clone(&self) -> Self { - *self - } -} - -// Custom impl so that C need not be bound on Copy/Clone -impl Copy for DateDuration {} - /// A "duration unit" used to specify the minimum or maximum duration of time to /// care about +/// +///
+/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, +/// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break. +/// +/// Graduation tracking issue: [issue #3964](https://github.com/unicode-org/icu4x/issues/3964). +///
+/// +/// ✨ *Enabled with the `unstable` Cargo feature.* #[derive(Copy, Clone, Eq, PartialEq, Debug)] #[allow(clippy::exhaustive_enums)] // this type should be stable -#[doc(hidden)] // unstable pub enum DateDurationUnit { /// Duration in years Years, @@ -104,55 +157,134 @@ pub enum DateDurationUnit { Days, } -impl Default for DateDuration { - fn default() -> Self { +impl DateDuration { + /// Returns a new [`DateDuration`] representing a number of years. + pub fn for_years(years: i32) -> Self { Self { - years: 0, - months: 0, - weeks: 0, - days: 0, - marker: PhantomData, + is_negative: years.is_negative(), + years: years.unsigned_abs(), + ..Default::default() } } -} -impl DateDuration { - /// Construct a DateDuration - /// - /// ```rust - /// # use icu::calendar::*; - /// // two years, three months, and five days - /// let duration: DateDuration = DateDuration::new(2, 3, 0, 5); - /// ``` - pub fn new(years: i32, months: i32, weeks: i32, days: i32) -> Self { - DateDuration { - years, - months, - weeks, - days, - marker: PhantomData, + /// Returns a new [`DateDuration`] representing a number of months. + pub fn for_months(months: i32) -> Self { + Self { + is_negative: months.is_negative(), + months: months.unsigned_abs(), + ..Default::default() } } - /// Explicitly cast duration to one for a different calendar - pub fn cast_unit(self) -> DateDuration { - DateDuration { - years: self.years, - months: self.months, - days: self.days, - weeks: self.weeks, - marker: PhantomData, + /// Returns a new [`DateDuration`] representing a number of weeks. + pub fn for_weeks(weeks: i32) -> Self { + Self { + is_negative: weeks.is_negative(), + weeks: weeks.unsigned_abs(), + ..Default::default() + } + } + + /// Returns a new [`DateDuration`] representing a number of days. + pub fn for_days(days: i64) -> Self { + Self { + is_negative: days.is_negative(), + days: days.unsigned_abs(), + ..Default::default() + } + } + + /// Do NOT pass this function values of mixed signs! + pub(crate) fn from_signed_ymwd(years: i64, months: i64, weeks: i64, days: i64) -> Self { + let is_negative = years.is_negative() + || months.is_negative() + || weeks.is_negative() + || days.is_negative(); + if is_negative + && (years.is_positive() + || months.is_positive() + || weeks.is_positive() + || days.is_positive()) + { + debug_assert!(false, "mixed signs in from_signed_ymd"); + } + Self { + is_negative, + years: match u32::try_from(years.unsigned_abs()) { + Ok(x) => x, + Err(_) => { + debug_assert!(false, "years out of range"); + u32::MAX + } + }, + months: match u32::try_from(months.unsigned_abs()) { + Ok(x) => x, + Err(_) => { + debug_assert!(false, "months out of range"); + u32::MAX + } + }, + weeks: match u32::try_from(weeks.unsigned_abs()) { + Ok(x) => x, + Err(_) => { + debug_assert!(false, "weeks out of range"); + u32::MAX + } + }, + days: days.unsigned_abs(), + } + } + + #[inline] + pub(crate) fn add_years_to(&self, year: i32) -> i32 { + if !self.is_negative { + match year.checked_add_unsigned(self.years) { + Some(x) => x, + None => { + debug_assert!(false, "{year} + {self:?} out of year range"); + i32::MAX + } + } + } else { + match year.checked_sub_unsigned(self.years) { + Some(x) => x, + None => { + debug_assert!(false, "{year} - {self:?} out of year range"); + i32::MIN + } + } } } -} -impl fmt::Debug for DateDuration { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - f.debug_struct("DateDuration") - .field("years", &self.years) - .field("months", &self.months) - .field("weeks", &self.weeks) - .field("days", &self.days) - .finish() + #[inline] + pub(crate) fn add_months_to(&self, month: u8) -> i64 { + if !self.is_negative { + i64::from(month) + i64::from(self.months) + } else { + i64::from(month) - i64::from(self.months) + } + } + + #[inline] + pub(crate) fn add_weeks_and_days_to(&self, day: u8) -> i64 { + if !self.is_negative { + let day = i64::from(day) + i64::from(self.weeks) * 7; + match day.checked_add_unsigned(self.days) { + Some(x) => x, + None => { + debug_assert!(false, "{day} + {self:?} out of day range"); + i64::MAX + } + } + } else { + let day = i64::from(day) - i64::from(self.weeks) * 7; + match day.checked_sub_unsigned(self.days) { + Some(x) => x, + None => { + debug_assert!(false, "{day} - {self:?} out of day range"); + i64::MIN + } + } + } } } diff --git a/deps/crates/vendor/icu_calendar/src/error.rs b/deps/crates/vendor/icu_calendar/src/error.rs index 2e050a93a3f04a..437700befb830f 100644 --- a/deps/crates/vendor/icu_calendar/src/error.rs +++ b/deps/crates/vendor/icu_calendar/src/error.rs @@ -2,11 +2,15 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -use crate::types::MonthCode; +//! Error types for functions in the calendar crate + +use crate::{options::Overflow, types::MonthCode}; use displaydoc::Display; #[derive(Debug, Copy, Clone, PartialEq, Display)] -/// Error type for date creation. +/// Error type for date creation via [`Date::try_new_from_codes`]. +/// +/// [`Date::try_new_from_codes`]: crate::Date::try_new_from_codes #[non_exhaustive] pub enum DateError { /// A field is out of range for its domain. @@ -21,15 +25,351 @@ pub enum DateError { /// The maximum value (inclusive). This might not be tight. max: i32, }, - /// Unknown era + /// The era code is invalid for the calendar. #[displaydoc("Unknown era")] UnknownEra, - /// Unknown month code + /// The month code is invalid for the calendar or year. + /// + /// # Examples + /// + /// ``` + /// use icu::calendar::cal::Hebrew; + /// use icu::calendar::types::MonthCode; + /// use icu::calendar::Date; + /// use icu::calendar::DateError; + /// use tinystr::tinystr; + /// + /// Date::try_new_from_codes( + /// None, + /// 5784, + /// MonthCode::new_leap(5).unwrap(), + /// 1, + /// Hebrew, + /// ) + /// .expect("5784 is a leap year"); + /// + /// let err = Date::try_new_from_codes( + /// None, + /// 5785, + /// MonthCode::new_leap(5).unwrap(), + /// 1, + /// Hebrew, + /// ) + /// .expect_err("5785 is a common year"); + /// + /// assert!(matches!(err, DateError::UnknownMonthCode(_))); + /// ``` #[displaydoc("Unknown month code {0:?}")] UnknownMonthCode(MonthCode), } impl core::error::Error for DateError {} +#[cfg(feature = "unstable")] +pub use unstable::DateFromFieldsError; +#[cfg(not(feature = "unstable"))] +pub(crate) use unstable::DateFromFieldsError; + +mod unstable { + pub use super::*; + /// Error type for date creation via [`Date::try_from_fields`]. + /// + /// [`Date::try_from_fields`]: crate::Date::try_from_fields + /// + ///
+ /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, + /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break. + /// + /// Graduation tracking issue: [issue #7161](https://github.com/unicode-org/icu4x/issues/7161). + ///
+ /// + /// ✨ *Enabled with the `unstable` Cargo feature.* + #[derive(Debug, Copy, Clone, PartialEq, Display)] + #[non_exhaustive] + pub enum DateFromFieldsError { + /// A field is out of range for its domain. + /// + /// # Examples + /// + /// ``` + /// use icu::calendar::error::DateFromFieldsError; + /// use icu::calendar::error::RangeError; + /// use icu::calendar::types::DateFields; + /// use icu::calendar::Date; + /// use icu::calendar::Iso; + /// + /// let mut fields = DateFields::default(); + /// fields.extended_year = Some(2000); + /// fields.ordinal_month = Some(13); + /// fields.day = Some(1); + /// + /// let err = Date::try_from_fields(fields, Default::default(), Iso) + /// .expect_err("no month 13 in the ISO calendar"); + /// + /// assert!(matches!( + /// err, + /// DateFromFieldsError::Range(RangeError { field: "month", .. }) + /// )); + /// ``` + #[displaydoc("{0}")] + Range(RangeError), + /// The era code is invalid for the calendar. + #[displaydoc("Unknown era or invalid syntax")] + UnknownEra, + /// The month code syntax is invalid. + /// + /// # Examples + /// + /// ``` + /// use icu::calendar::error::DateFromFieldsError; + /// use icu::calendar::types::DateFields; + /// use icu::calendar::Date; + /// use icu::calendar::Iso; + /// + /// let mut fields = DateFields::default(); + /// fields.extended_year = Some(2000); + /// fields.month_code = Some(b"????"); + /// fields.day = Some(1); + /// + /// let err = Date::try_from_fields(fields, Default::default(), Iso) + /// .expect_err("month code is invalid"); + /// + /// assert_eq!(err, DateFromFieldsError::MonthCodeInvalidSyntax); + /// ``` + #[displaydoc("Invalid month code syntax")] + MonthCodeInvalidSyntax, + /// The specified month code does not exist in this calendar. + /// + /// # Examples + /// + /// ``` + /// use icu::calendar::cal::Hebrew; + /// use icu::calendar::error::DateFromFieldsError; + /// use icu::calendar::types::DateFields; + /// use icu::calendar::Date; + /// + /// let mut fields = DateFields::default(); + /// fields.extended_year = Some(5783); + /// fields.month_code = Some(b"M13"); + /// fields.day = Some(1); + /// + /// let err = Date::try_from_fields(fields, Default::default(), Hebrew) + /// .expect_err("no month M13 in Hebrew"); + /// assert_eq!(err, DateFromFieldsError::MonthCodeNotInCalendar); + /// ``` + #[displaydoc("The specified month code does not exist in this calendar")] + MonthCodeNotInCalendar, + /// The specified month code exists in this calendar, but not in the specified year. + /// + /// # Examples + /// + /// ``` + /// use icu::calendar::cal::Hebrew; + /// use icu::calendar::error::DateFromFieldsError; + /// use icu::calendar::types::DateFields; + /// use icu::calendar::Date; + /// + /// let mut fields = DateFields::default(); + /// fields.extended_year = Some(5783); + /// fields.month_code = Some(b"M05L"); + /// fields.day = Some(1); + /// + /// let err = Date::try_from_fields(fields, Default::default(), Hebrew) + /// .expect_err("no month M05L in Hebrew year 5783"); + /// assert_eq!(err, DateFromFieldsError::MonthCodeNotInYear); + /// ``` + #[displaydoc("The specified month code exists in calendar, but not for this year")] + MonthCodeNotInYear, + /// The year was specified in multiple inconsistent ways. + /// + /// # Examples + /// + /// ``` + /// use icu::calendar::cal::Japanese; + /// use icu::calendar::error::DateFromFieldsError; + /// use icu::calendar::types::DateFields; + /// use icu::calendar::Date; + /// + /// let mut fields = DateFields::default(); + /// fields.era = Some(b"reiwa"); + /// fields.era_year = Some(6); + /// fields.ordinal_month = Some(1); + /// fields.day = Some(1); + /// + /// Date::try_from_fields(fields, Default::default(), Japanese::new()) + /// .expect("a well-defined Japanese date"); + /// + /// fields.extended_year = Some(1900); + /// + /// let err = + /// Date::try_from_fields(fields, Default::default(), Japanese::new()) + /// .expect_err("year 1900 is not the same as 6 Reiwa"); + /// + /// assert_eq!(err, DateFromFieldsError::InconsistentYear); + /// ``` + #[displaydoc("Inconsistent year")] + InconsistentYear, + /// The month was specified in multiple inconsistent ways. + /// + /// # Examples + /// + /// ``` + /// use icu::calendar::cal::Hebrew; + /// use icu::calendar::error::DateFromFieldsError; + /// use icu::calendar::types::DateFields; + /// use icu::calendar::Date; + /// use tinystr::tinystr; + /// + /// let mut fields = DateFields::default(); + /// fields.extended_year = Some(5783); + /// fields.month_code = Some(b"M06"); + /// fields.ordinal_month = Some(6); + /// fields.day = Some(1); + /// + /// Date::try_from_fields(fields, Default::default(), Hebrew) + /// .expect("a well-defined Hebrew date in a common year"); + /// + /// fields.extended_year = Some(5784); + /// + /// let err = Date::try_from_fields(fields, Default::default(), Hebrew) + /// .expect_err("month M06 is not the 6th month in leap year 5784"); + /// + /// assert_eq!(err, DateFromFieldsError::InconsistentMonth); + /// ``` + #[displaydoc("Inconsistent month")] + InconsistentMonth, + /// Not enough fields were specified to form a well-defined date. + /// + /// # Examples + /// + /// ``` + /// use icu::calendar::cal::Hebrew; + /// use icu::calendar::error::DateFromFieldsError; + /// use icu::calendar::types::DateFields; + /// use icu::calendar::Date; + /// use tinystr::tinystr; + /// + /// let mut fields = DateFields::default(); + /// + /// fields.ordinal_month = Some(3); + /// + /// let err = Date::try_from_fields(fields, Default::default(), Hebrew) + /// .expect_err("need more than just an ordinal month"); + /// assert_eq!(err, DateFromFieldsError::NotEnoughFields); + /// + /// fields.era_year = Some(5783); + /// + /// let err = Date::try_from_fields(fields, Default::default(), Hebrew) + /// .expect_err("need more than an ordinal month and an era year"); + /// assert_eq!(err, DateFromFieldsError::NotEnoughFields); + /// + /// fields.extended_year = Some(5783); + /// + /// let err = Date::try_from_fields(fields, Default::default(), Hebrew) + /// .expect_err("era year still needs an era"); + /// assert_eq!(err, DateFromFieldsError::NotEnoughFields); + /// + /// fields.era = Some(b"am"); + /// + /// let date = Date::try_from_fields(fields, Default::default(), Hebrew) + /// .expect_err("still missing the day"); + /// assert_eq!(err, DateFromFieldsError::NotEnoughFields); + /// + /// fields.day = Some(1); + /// let date = Date::try_from_fields(fields, Default::default(), Hebrew) + /// .expect("we have enough fields!"); + /// ``` + #[displaydoc("Not enough fields")] + NotEnoughFields, + } + + impl core::error::Error for DateFromFieldsError {} + + impl From for DateFromFieldsError { + #[inline] + fn from(value: RangeError) -> Self { + DateFromFieldsError::Range(value) + } + } +} + +/// Internal narrow error type for functions that only fail on unknown eras +pub(crate) struct UnknownEraError; + +impl From for DateError { + #[inline] + fn from(_value: UnknownEraError) -> Self { + DateError::UnknownEra + } +} + +impl From for DateFromFieldsError { + #[inline] + fn from(_value: UnknownEraError) -> Self { + DateFromFieldsError::UnknownEra + } +} + +/// Internal narrow error type for functions that only fail on parsing month codes +#[derive(Debug)] +pub(crate) enum MonthCodeParseError { + InvalidSyntax, +} + +impl From for DateFromFieldsError { + #[inline] + fn from(value: MonthCodeParseError) -> Self { + match value { + MonthCodeParseError::InvalidSyntax => DateFromFieldsError::MonthCodeInvalidSyntax, + } + } +} + +/// Internal narrow error type for functions that only fail on month code operations +#[derive(Debug, PartialEq)] +pub(crate) enum MonthCodeError { + NotInCalendar, + NotInYear, +} + +impl From for DateFromFieldsError { + #[inline] + fn from(value: MonthCodeError) -> Self { + match value { + MonthCodeError::NotInCalendar => DateFromFieldsError::MonthCodeNotInCalendar, + MonthCodeError::NotInYear => DateFromFieldsError::MonthCodeNotInYear, + } + } +} + +mod inner { + /// Internal narrow error type for calculating the ECMA reference year + /// + /// Public but unstable because it is used on hijri::Rules + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + #[allow(missing_docs)] // TODO: fix when graduating + #[non_exhaustive] + pub enum EcmaReferenceYearError { + Unimplemented, + MonthCodeNotInCalendar, + } +} + +#[cfg(feature = "unstable")] +pub use inner::EcmaReferenceYearError; +#[cfg(not(feature = "unstable"))] +pub(crate) use inner::EcmaReferenceYearError; + +impl From for DateFromFieldsError { + #[inline] + fn from(value: EcmaReferenceYearError) -> Self { + match value { + EcmaReferenceYearError::Unimplemented => DateFromFieldsError::NotEnoughFields, + EcmaReferenceYearError::MonthCodeNotInCalendar => { + DateFromFieldsError::MonthCodeNotInCalendar + } + } + } +} #[derive(Debug, Copy, Clone, PartialEq, Display)] /// An argument is out of range for its domain. @@ -49,6 +389,7 @@ pub struct RangeError { impl core::error::Error for RangeError {} impl From for DateError { + #[inline] fn from(value: RangeError) -> Self { let RangeError { field, @@ -65,28 +406,31 @@ impl From for DateError { } } -pub(crate) fn year_check( - year: i32, - bounds: impl core::ops::RangeBounds, -) -> Result { - use core::ops::Bound::*; +pub(crate) fn range_check_with_overflow + Copy>( + value: T, + field: &'static str, + bounds: core::ops::RangeInclusive, + overflow: Overflow, +) -> Result { + if matches!(overflow, Overflow::Constrain) { + Ok(value.clamp(*bounds.start(), *bounds.end())) + } else { + range_check(value, field, bounds) + } +} - if !bounds.contains(&year) { +pub(crate) fn range_check + Copy>( + value: T, + field: &'static str, + bounds: core::ops::RangeInclusive, +) -> Result { + if !bounds.contains(&value) { return Err(RangeError { - field: "year", - value: year, - min: match bounds.start_bound() { - Included(&m) => m, - Excluded(&m) => m + 1, - Unbounded => i32::MIN, - }, - max: match bounds.end_bound() { - Included(&m) => m, - Excluded(&m) => m - 1, - Unbounded => i32::MAX, - }, + field, + value: value.into(), + min: (*bounds.start()).into(), + max: (*bounds.end()).into(), }); } - - Ok(year) + Ok(value) } diff --git a/deps/crates/vendor/icu_calendar/src/ixdtf.rs b/deps/crates/vendor/icu_calendar/src/ixdtf.rs index 0256dcd6c40eb6..1fe60d9720b68e 100644 --- a/deps/crates/vendor/icu_calendar/src/ixdtf.rs +++ b/deps/crates/vendor/icu_calendar/src/ixdtf.rs @@ -6,11 +6,12 @@ use core::str::FromStr; use crate::{AsCalendar, Calendar, Date, Iso, RangeError}; use icu_locale_core::preferences::extensions::unicode::keywords::CalendarAlgorithm; -use ixdtf::parsers::records::IxdtfParseRecord; +use ixdtf::encoding::Utf8; use ixdtf::parsers::IxdtfParser; +use ixdtf::records::IxdtfParseRecord; use ixdtf::ParseError as Rfc9557Error; -/// An error returned from parsing an RFC 9557 string to an `icu_calendar` type. +/// An error returned from parsing an RFC 9557 string to an `icu::calendar` type. #[derive(Debug, displaydoc::Display)] #[non_exhaustive] pub enum ParseError { @@ -68,10 +69,7 @@ impl Date
{ /// Date::try_from_str("2024-07-17[u-ca=hebrew]", Gregorian).unwrap_err(); /// /// assert_eq!(date.era_year().year, 2024); - /// assert_eq!( - /// date.month().standard_code, - /// icu::calendar::types::MonthCode(tinystr::tinystr!(4, "M07")) - /// ); + /// assert_eq!(date.month().standard_code.0, "M07"); /// assert_eq!(date.day_of_month().0, 17); /// ``` pub fn try_from_str(rfc_9557_str: &str, calendar: A) -> Result { @@ -93,7 +91,7 @@ impl Date { #[doc(hidden)] pub fn try_from_ixdtf_record( - ixdtf_record: &IxdtfParseRecord, + ixdtf_record: &IxdtfParseRecord<'_, Utf8>, calendar: A, ) -> Result { let date_record = ixdtf_record.date.ok_or(ParseError::MissingFields)?; diff --git a/deps/crates/vendor/icu_calendar/src/lib.rs b/deps/crates/vendor/icu_calendar/src/lib.rs index 77d5a4b46aeadf..ca8c9923881996 100644 --- a/deps/crates/vendor/icu_calendar/src/lib.rs +++ b/deps/crates/vendor/icu_calendar/src/lib.rs @@ -88,6 +88,9 @@ ) )] #![warn(missing_docs)] +// It's not worth it to try and maintain clean import lists for both +// stable and unstable mode when the code is so entangled. +#![cfg_attr(not(feature = "unstable"), allow(unused))] #[cfg(feature = "alloc")] extern crate alloc; @@ -98,6 +101,7 @@ mod date; // Public modules mod any_calendar; pub mod cal; +pub mod options; pub mod provider; pub mod types; pub mod week; @@ -105,7 +109,7 @@ pub mod week; mod calendar; mod calendar_arithmetic; mod duration; -mod error; +pub mod error; #[cfg(feature = "ixdtf")] mod ixdtf; @@ -113,8 +117,6 @@ mod ixdtf; pub use any_calendar::IntoAnyCalendar; pub use calendar::Calendar; pub use date::{AsCalendar, Date, Ref}; -#[doc(hidden)] // unstable -pub use duration::{DateDuration, DateDurationUnit}; pub use error::{DateError, RangeError}; #[cfg(feature = "ixdtf")] pub use ixdtf::ParseError; diff --git a/deps/crates/vendor/icu_calendar/src/options.rs b/deps/crates/vendor/icu_calendar/src/options.rs new file mode 100644 index 00000000000000..37eba042536a54 --- /dev/null +++ b/deps/crates/vendor/icu_calendar/src/options.rs @@ -0,0 +1,559 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +//! Options used by types in this crate + +#[cfg(feature = "unstable")] +pub use unstable::{ + DateAddOptions, DateDifferenceOptions, DateFromFieldsOptions, MissingFieldsStrategy, Overflow, +}; +#[cfg(not(feature = "unstable"))] +pub(crate) use unstable::{ + DateAddOptions, DateDifferenceOptions, DateFromFieldsOptions, MissingFieldsStrategy, Overflow, +}; + +mod unstable { + /// Options bag for [`Date::try_from_fields`](crate::Date::try_from_fields). + /// + ///
+ /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, + /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break. + /// + /// Graduation tracking issue: [issue #7161](https://github.com/unicode-org/icu4x/issues/7161). + ///
+ /// + /// ✨ *Enabled with the `unstable` Cargo feature.* + #[derive(Copy, Clone, Debug, PartialEq, Default)] + #[non_exhaustive] + pub struct DateFromFieldsOptions { + /// How to behave with out-of-bounds fields. + /// + /// Defaults to [`Overflow::Reject`]. + /// + /// # Examples + /// + /// ``` + /// use icu::calendar::options::DateFromFieldsOptions; + /// use icu::calendar::options::Overflow; + /// use icu::calendar::types::DateFields; + /// use icu::calendar::Date; + /// use icu::calendar::Iso; + /// + /// // There is no day 31 in September. + /// let mut fields = DateFields::default(); + /// fields.extended_year = Some(2025); + /// fields.ordinal_month = Some(9); + /// fields.day = Some(31); + /// + /// let options_default = DateFromFieldsOptions::default(); + /// assert!(Date::try_from_fields(fields, options_default, Iso).is_err()); + /// + /// let mut options_reject = options_default; + /// options_reject.overflow = Some(Overflow::Reject); + /// assert!(Date::try_from_fields(fields, options_reject, Iso).is_err()); + /// + /// let mut options_constrain = options_default; + /// options_constrain.overflow = Some(Overflow::Constrain); + /// assert_eq!( + /// Date::try_from_fields(fields, options_constrain, Iso).unwrap(), + /// Date::try_new_iso(2025, 9, 30).unwrap() + /// ); + /// ``` + pub overflow: Option, + /// How to behave when the fields that are present do not fully constitute a Date. + /// + /// This option can be used to fill in a missing year given a month and a day according to + /// the ECMAScript Temporal specification. + /// + /// # Examples + /// + /// ``` + /// use icu::calendar::options::DateFromFieldsOptions; + /// use icu::calendar::options::MissingFieldsStrategy; + /// use icu::calendar::types::DateFields; + /// use icu::calendar::Date; + /// use icu::calendar::Iso; + /// + /// // These options are missing a year. + /// let mut fields = DateFields::default(); + /// fields.month_code = Some(b"M02"); + /// fields.day = Some(1); + /// + /// let options_default = DateFromFieldsOptions::default(); + /// assert!(Date::try_from_fields(fields, options_default, Iso).is_err()); + /// + /// let mut options_reject = options_default; + /// options_reject.missing_fields_strategy = + /// Some(MissingFieldsStrategy::Reject); + /// assert!(Date::try_from_fields(fields, options_reject, Iso).is_err()); + /// + /// let mut options_ecma = options_default; + /// options_ecma.missing_fields_strategy = Some(MissingFieldsStrategy::Ecma); + /// assert_eq!( + /// Date::try_from_fields(fields, options_ecma, Iso).unwrap(), + /// Date::try_new_iso(1972, 2, 1).unwrap() + /// ); + /// ``` + pub missing_fields_strategy: Option, + } + + impl DateFromFieldsOptions { + pub(crate) fn from_add_options(options: DateAddOptions) -> Self { + Self { + overflow: options.overflow, + missing_fields_strategy: Default::default(), + } + } + } + + /// Options for adding a duration to a date. + /// + ///
+ /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, + /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break. + /// + /// Graduation tracking issue: [issue #3964](https://github.com/unicode-org/icu4x/issues/3964). + ///
+ /// + /// ✨ *Enabled with the `unstable` Cargo feature.* + #[derive(Copy, Clone, PartialEq, Debug, Default)] + #[non_exhaustive] + pub struct DateAddOptions { + /// How to behave with out-of-bounds fields during arithmetic. + /// + /// Defaults to [`Overflow::Constrain`]. + /// + /// # Examples + /// + /// ``` + /// use icu::calendar::options::DateAddOptions; + /// use icu::calendar::options::Overflow; + /// use icu::calendar::types::DateDuration; + /// use icu::calendar::Date; + /// + /// // There is a day 31 in October but not in November. + /// let d1 = Date::try_new_iso(2025, 10, 31).unwrap(); + /// let duration = DateDuration::for_months(1); + /// + /// let options_default = DateAddOptions::default(); + /// assert_eq!( + /// d1.try_added_with_options(duration, options_default) + /// .unwrap(), + /// Date::try_new_iso(2025, 11, 30).unwrap() + /// ); + /// + /// let mut options_reject = options_default; + /// options_reject.overflow = Some(Overflow::Reject); + /// assert!(d1.try_added_with_options(duration, options_reject).is_err()); + /// + /// let mut options_constrain = options_default; + /// options_constrain.overflow = Some(Overflow::Constrain); + /// assert_eq!( + /// d1.try_added_with_options(duration, options_constrain) + /// .unwrap(), + /// Date::try_new_iso(2025, 11, 30).unwrap() + /// ); + /// ``` + pub overflow: Option, + } + + /// Options for taking the difference between two dates. + /// + ///
+ /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, + /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break. + /// + /// Graduation tracking issue: [issue #3964](https://github.com/unicode-org/icu4x/issues/3964). + ///
+ /// + /// ✨ *Enabled with the `unstable` Cargo feature.* + #[derive(Copy, Clone, PartialEq, Debug, Default)] + #[non_exhaustive] + pub struct DateDifferenceOptions { + /// Which date field to allow as the largest in a duration when taking the difference. + /// + /// When choosing [`Months`] or [`Years`], the resulting [`DateDuration`] might not be + /// associative or commutative in subsequent arithmetic operations, and it might require + /// [`Overflow::Constrain`] in addition. + /// + /// # Examples + /// + /// ``` + /// use icu::calendar::options::DateDifferenceOptions; + /// use icu::calendar::types::DateDuration; + /// use icu::calendar::types::DateDurationUnit; + /// use icu::calendar::Date; + /// + /// let d1 = Date::try_new_iso(2025, 3, 31).unwrap(); + /// let d2 = Date::try_new_iso(2026, 5, 15).unwrap(); + /// + /// let options_default = DateDifferenceOptions::default(); + /// assert_eq!( + /// d1.try_until_with_options(&d2, options_default).unwrap(), + /// DateDuration::for_days(410) + /// ); + /// + /// let mut options_days = options_default; + /// options_days.largest_unit = Some(DateDurationUnit::Days); + /// assert_eq!( + /// d1.try_until_with_options(&d2, options_default).unwrap(), + /// DateDuration::for_days(410) + /// ); + /// + /// let mut options_weeks = options_default; + /// options_weeks.largest_unit = Some(DateDurationUnit::Weeks); + /// assert_eq!( + /// d1.try_until_with_options(&d2, options_weeks).unwrap(), + /// DateDuration { + /// weeks: 58, + /// days: 4, + /// ..Default::default() + /// } + /// ); + /// + /// let mut options_months = options_default; + /// options_months.largest_unit = Some(DateDurationUnit::Months); + /// assert_eq!( + /// d1.try_until_with_options(&d2, options_months).unwrap(), + /// DateDuration { + /// months: 13, + /// days: 15, + /// ..Default::default() + /// } + /// ); + /// + /// let mut options_years = options_default; + /// options_years.largest_unit = Some(DateDurationUnit::Years); + /// assert_eq!( + /// d1.try_until_with_options(&d2, options_years).unwrap(), + /// DateDuration { + /// years: 1, + /// months: 1, + /// days: 15, + /// ..Default::default() + /// } + /// ); + /// ``` + /// + /// [`Months`]: crate::types::DateDurationUnit::Months + /// [`Years`]: crate::types::DateDurationUnit::Years + /// [`DateDuration`]: crate::types::DateDuration + pub largest_unit: Option, + } + + /// Whether to constrain or reject out-of-bounds values when constructing a Date. + /// + /// The behavior conforms to the ECMAScript Temporal specification. + /// + ///
+ /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, + /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break. + /// + /// Graduation tracking issue: [issue #7161](https://github.com/unicode-org/icu4x/issues/7161). + ///
+ /// + /// ✨ *Enabled with the `unstable` Cargo feature.* + #[derive(Copy, Clone, Debug, PartialEq, Default)] + #[non_exhaustive] + pub enum Overflow { + /// Constrain out-of-bounds fields to the nearest in-bounds value. + /// + /// Only the out-of-bounds field is constrained. If the other fields are not themselves + /// out of bounds, they are not changed. + /// + /// This is the [default option]( + /// https://tc39.es/proposal-temporal/#sec-temporal-gettemporaloverflowoption), + /// following the ECMAScript Temporal specification. See also the [docs on MDN]( + /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDate#invalid_date_clamping). + /// + /// # Examples + /// + /// ``` + /// use icu::calendar::cal::Hebrew; + /// use icu::calendar::options::DateFromFieldsOptions; + /// use icu::calendar::options::Overflow; + /// use icu::calendar::types::DateFields; + /// use icu::calendar::Date; + /// use icu::calendar::DateError; + /// + /// let mut options = DateFromFieldsOptions::default(); + /// options.overflow = Some(Overflow::Constrain); + /// + /// // 5784, a leap year, contains M05L, but the day is too big. + /// let mut fields = DateFields::default(); + /// fields.extended_year = Some(5784); + /// fields.month_code = Some(b"M05L"); + /// fields.day = Some(50); + /// + /// let date = Date::try_from_fields(fields, options, Hebrew).unwrap(); + /// + /// // Constrained to the 30th day of M05L of year 5784 + /// assert_eq!(date.year().extended_year(), 5784); + /// assert_eq!(date.month().standard_code.0, "M05L"); + /// assert_eq!(date.day_of_month().0, 30); + /// + /// // 5785, a common year, does not contain M05L. + /// fields.extended_year = Some(5785); + /// + /// let date = Date::try_from_fields(fields, options, Hebrew).unwrap(); + /// + /// // Constrained to the 29th day of M06 of year 5785 + /// assert_eq!(date.year().extended_year(), 5785); + /// assert_eq!(date.month().standard_code.0, "M06"); + /// assert_eq!(date.day_of_month().0, 29); + /// ``` + Constrain, + /// Return an error if any fields are out of bounds. + /// + /// # Examples + /// + /// ``` + /// use icu::calendar::cal::Hebrew; + /// use icu::calendar::error::DateFromFieldsError; + /// use icu::calendar::options::DateFromFieldsOptions; + /// use icu::calendar::options::Overflow; + /// use icu::calendar::types::DateFields; + /// use icu::calendar::Date; + /// use tinystr::tinystr; + /// + /// let mut options = DateFromFieldsOptions::default(); + /// options.overflow = Some(Overflow::Reject); + /// + /// // 5784, a leap year, contains M05L, but the day is too big. + /// let mut fields = DateFields::default(); + /// fields.extended_year = Some(5784); + /// fields.month_code = Some(b"M05L"); + /// fields.day = Some(50); + /// + /// let err = Date::try_from_fields(fields, options, Hebrew) + /// .expect_err("Day is out of bounds"); + /// assert!(matches!(err, DateFromFieldsError::Range { .. })); + /// + /// // Set the day to one that exists + /// fields.day = Some(1); + /// Date::try_from_fields(fields, options, Hebrew) + /// .expect("A valid Hebrew date"); + /// + /// // 5785, a common year, does not contain M05L. + /// fields.extended_year = Some(5785); + /// + /// let err = Date::try_from_fields(fields, options, Hebrew) + /// .expect_err("Month is out of bounds"); + /// assert!(matches!(err, DateFromFieldsError::MonthCodeNotInYear)); + /// ``` + #[default] + Reject, + } + + /// How to infer missing fields when the fields that are present do not fully constitute a Date. + /// + /// In order for the fields to fully constitute a Date, they must identify a year, a month, + /// and a day. The fields `era`, `era_year`, and `extended_year` identify the year: + /// + /// | Era? | Era Year? | Extended Year? | Outcome | + /// |------|-----------|----------------|---------| + /// | - | - | - | Error | + /// | Some | - | - | Error | + /// | - | Some | - | Error | + /// | - | - | Some | OK | + /// | Some | Some | - | OK | + /// | Some | - | Some | Error (era requires era year) | + /// | - | Some | Some | Error (era year requires era) | + /// | Some | Some | Some | OK (but error if inconsistent) | + /// + /// The fields `month_code` and `ordinal_month` identify the month: + /// + /// | Month Code? | Ordinal Month? | Outcome | + /// |-------------|----------------|---------| + /// | - | - | Error | + /// | Some | - | OK | + /// | - | Some | OK | + /// | Some | Some | OK (but error if inconsistent) | + /// + /// The field `day` identifies the day. + /// + /// If the fields identify a year, a month, and a day, then there are no missing fields, so + /// the strategy chosen here has no effect (fields that are out-of-bounds or inconsistent + /// are handled by other errors). + /// + ///
+ /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, + /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break. + /// + /// Graduation tracking issue: [issue #7161](https://github.com/unicode-org/icu4x/issues/7161). + ///
+ /// + /// ✨ *Enabled with the `unstable` Cargo feature.* + #[derive(Copy, Clone, Debug, PartialEq, Default)] + #[non_exhaustive] + pub enum MissingFieldsStrategy { + /// If the fields that are present do not fully constitute a Date, + /// return [`DateFromFieldsError::NotEnoughFields`]. + /// + /// [`DateFromFieldsError::NotEnoughFields`]: crate::error::DateFromFieldsError::NotEnoughFields + #[default] + Reject, + /// If the fields that are present do not fully constitute a Date, + /// follow the ECMAScript specification when possible. + /// + /// ⚠️ This option causes a year or day to be implicitly added to the Date! + /// + /// This strategy makes the following changes: + /// + /// 1. If the fields identify a year and a month, but not a day, then set `day` to 1. + /// 2. If `month_code` and `day` are set but nothing else, then set the year to a + /// _reference year_: some year in the calendar that contains the specified month + /// and day, according to the ECMAScript specification. + /// + /// Note that the reference year is _not_ added if an ordinal month is present, since + /// the identity of an ordinal month changes from year to year. + Ecma, + } +} +#[cfg(test)] +mod tests { + use crate::{error::DateFromFieldsError, types::DateFields, Date, Gregorian}; + use itertools::Itertools; + use std::collections::{BTreeMap, BTreeSet}; + + use super::*; + + #[test] + #[allow(clippy::field_reassign_with_default)] // want out-of-crate code style + fn test_missing_fields_strategy() { + // The sets of fields that identify a year, according to the table in the docs + let valid_year_field_sets = [ + &["era", "era_year"][..], + &["extended_year"][..], + &["era", "era_year", "extended_year"][..], + ] + .into_iter() + .map(|field_names| field_names.iter().copied().collect()) + .collect::>>(); + + // The sets of fields that identify a month, according to the table in the docs + let valid_month_field_sets = [ + &["month_code"][..], + &["ordinal_month"][..], + &["month_code", "ordinal_month"][..], + ] + .into_iter() + .map(|field_names| field_names.iter().copied().collect()) + .collect::>>(); + + // The sets of fields that identify a day, according to the table in the docs + let valid_day_field_sets = [&["day"][..]] + .into_iter() + .map(|field_names| field_names.iter().copied().collect()) + .collect::>>(); + + // All possible valid sets of fields + let all_valid_field_sets = valid_year_field_sets + .iter() + .cartesian_product(valid_month_field_sets.iter()) + .cartesian_product(valid_day_field_sets.iter()) + .map(|((year_fields, month_fields), day_fields)| { + year_fields + .iter() + .chain(month_fields.iter()) + .chain(day_fields.iter()) + .copied() + .collect::>() + }) + .collect::>>(); + + // Field sets with year and month but without day that ECMA accepts + let field_sets_without_day = valid_year_field_sets + .iter() + .cartesian_product(valid_month_field_sets.iter()) + .map(|(year_fields, month_fields)| { + year_fields + .iter() + .chain(month_fields.iter()) + .copied() + .collect::>() + }) + .collect::>>(); + + // Field sets with month and day but without year that ECMA accepts + let field_sets_without_year = [&["month_code", "day"][..]] + .into_iter() + .map(|field_names| field_names.iter().copied().collect()) + .collect::>>(); + + // A map from field names to a function that sets that field + let mut field_fns = BTreeMap::<&str, &dyn Fn(&mut DateFields)>::new(); + field_fns.insert("era", &|fields| fields.era = Some(b"ad")); + field_fns.insert("era_year", &|fields| fields.era_year = Some(2000)); + field_fns.insert("extended_year", &|fields| fields.extended_year = Some(2000)); + field_fns.insert("month_code", &|fields| fields.month_code = Some(b"M04")); + field_fns.insert("ordinal_month", &|fields| fields.ordinal_month = Some(4)); + field_fns.insert("day", &|fields| fields.day = Some(20)); + + for field_set in field_fns.keys().copied().powerset() { + let field_set = field_set.into_iter().collect::>(); + + // Check whether this case should succeed: whether it identifies a year, + // a month, and a day. + let should_succeed_rejecting = all_valid_field_sets.contains(&field_set); + + // Check whether it should succeed in ECMA mode. + let should_succeed_ecma = should_succeed_rejecting + || field_sets_without_day.contains(&field_set) + || field_sets_without_year.contains(&field_set); + + // Populate the fields in the field set + let mut fields = Default::default(); + for field_name in field_set { + field_fns.get(field_name).unwrap()(&mut fields); + } + + // Check whether we were able to successfully construct the date + let mut options = DateFromFieldsOptions::default(); + options.missing_fields_strategy = Some(MissingFieldsStrategy::Reject); + match Date::try_from_fields(fields, options, Gregorian) { + Ok(_) => assert!( + should_succeed_rejecting, + "Succeeded, but should have rejected: {fields:?}" + ), + Err(DateFromFieldsError::NotEnoughFields) => assert!( + !should_succeed_rejecting, + "Rejected, but should have succeeded: {fields:?}" + ), + Err(e) => panic!("Unexpected error: {e} for {fields:?}"), + } + + // Check ECMA mode + let mut options = DateFromFieldsOptions::default(); + options.missing_fields_strategy = Some(MissingFieldsStrategy::Ecma); + match Date::try_from_fields(fields, options, Gregorian) { + Ok(_) => assert!( + should_succeed_ecma, + "Succeeded, but should have rejected (ECMA): {fields:?}" + ), + Err(DateFromFieldsError::NotEnoughFields) => assert!( + !should_succeed_ecma, + "Rejected, but should have succeeded (ECMA): {fields:?}" + ), + Err(e) => panic!("Unexpected error: {e} for {fields:?}"), + } + } + } + + #[test] + fn test_constrain_large_months() { + let fields = DateFields { + extended_year: Some(2004), + ordinal_month: Some(15), + day: Some(1), + ..Default::default() + }; + let options = DateFromFieldsOptions { + overflow: Some(Overflow::Constrain), + ..Default::default() + }; + + let _ = Date::try_from_fields(fields, options, crate::cal::Persian).unwrap(); + } +} diff --git a/deps/crates/vendor/icu_calendar/src/provider.rs b/deps/crates/vendor/icu_calendar/src/provider.rs index 71e7369abfd360..b8f7feaf9181be 100644 --- a/deps/crates/vendor/icu_calendar/src/provider.rs +++ b/deps/crates/vendor/icu_calendar/src/provider.rs @@ -15,11 +15,6 @@ // Provider structs must be stable #![allow(clippy::exhaustive_structs, clippy::exhaustive_enums)] -pub mod chinese_based; -pub mod hijri; -pub use chinese_based::{CalendarChineseV1, CalendarDangiV1}; -pub use hijri::CalendarHijriSimulatedMeccaV1; - use crate::types::Weekday; use icu_provider::fallback::{LocaleFallbackConfig, LocaleFallbackPriority}; use icu_provider::prelude::*; @@ -46,9 +41,6 @@ const _: () = { pub use icu_locale as locale; } make_provider!(Baked); - impl_calendar_chinese_v1!(Baked); - impl_calendar_dangi_v1!(Baked); - impl_calendar_hijri_simulated_mecca_v1!(Baked); impl_calendar_japanese_modern_v1!(Baked); impl_calendar_japanese_extended_v1!(Baked); impl_calendar_week_v1!(Baked); @@ -83,9 +75,6 @@ icu_provider::data_marker!( #[cfg(feature = "datagen")] /// The latest minimum set of markers required by this component. pub const MARKERS: &[DataMarkerInfo] = &[ - CalendarChineseV1::INFO, - CalendarDangiV1::INFO, - CalendarHijriSimulatedMeccaV1::INFO, CalendarJapaneseModernV1::INFO, CalendarJapaneseExtendedV1::INFO, CalendarWeekV1::INFO, @@ -107,6 +96,7 @@ pub const MARKERS: &[DataMarkerInfo] = &[ #[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))] #[cfg_attr(feature = "datagen", databake(path = icu_calendar::provider))] #[cfg_attr(feature = "serde", derive(serde::Deserialize))] +#[cfg_attr(not(feature = "alloc"), zerovec::skip_derive(ZeroMapKV))] pub struct EraStartDate { /// The year the era started in pub year: i32, @@ -198,7 +188,7 @@ impl WeekdaySet { pub const fn new(days: &[Weekday]) -> Self { let mut i = 0; let mut w = 0; - #[allow(clippy::indexing_slicing)] + #[expect(clippy::indexing_slicing)] while i < days.len() { w |= days[i].bit_value(); i += 1; @@ -295,6 +285,7 @@ impl<'de> serde::Deserialize<'de> for WeekdaySet { } #[test] +#[cfg(feature = "datagen")] fn test_weekdayset_bake() { databake::test_bake!( WeekdaySet, diff --git a/deps/crates/vendor/icu_calendar/src/provider/chinese_based.rs b/deps/crates/vendor/icu_calendar/src/provider/chinese_based.rs deleted file mode 100644 index da6fbd372b069e..00000000000000 --- a/deps/crates/vendor/icu_calendar/src/provider/chinese_based.rs +++ /dev/null @@ -1,298 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -//! 🚧 \[Unstable\] Data provider struct definitions for chinese-based calendars. -//! -//!
-//! 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, -//! including in SemVer minor releases. While the serde representation of data structs is guaranteed -//! to be stable, their Rust representation might not be. Use with caution. -//!
-//! -//! Read more about data providers: [`icu_provider`] - -use icu_provider::prelude::*; -use zerovec::ule::{AsULE, ULE}; -use zerovec::ZeroVec; - -icu_provider::data_marker!( - /// Precomputed data for the Chinese calendar - CalendarChineseV1, - "calendar/chinese/v1", - ChineseBasedCache<'static>, - is_singleton = true -); -icu_provider::data_marker!( - /// Precomputed data for the Dangi calendar - CalendarDangiV1, - "calendar/dangi/v1", - ChineseBasedCache<'static>, - is_singleton = true -); - -/// Cached/precompiled data for a certain range of years for a chinese-based -/// calendar. Avoids the need to perform lunar calendar arithmetic for most calendrical -/// operations. -#[derive(Debug, PartialEq, Clone, Default, yoke::Yokeable, zerofrom::ZeroFrom)] -#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))] -#[cfg_attr(feature = "datagen", databake(path = icu_calendar::provider::chinese_based))] -#[cfg_attr(feature = "serde", derive(serde::Deserialize))] -pub struct ChineseBasedCache<'data> { - /// The ISO year corresponding to the first data entry for this year - pub first_related_iso_year: i32, - /// A list of precomputed data for each year beginning with first_related_iso_year - #[cfg_attr(feature = "serde", serde(borrow))] - pub data: ZeroVec<'data, PackedChineseBasedYearInfo>, -} - -icu_provider::data_struct!( - ChineseBasedCache<'_>, - #[cfg(feature = "datagen")] -); - -/// The struct containing compiled ChineseData -/// -/// Bit structure (little endian: note that shifts go in the opposite direction!) -/// -/// ```text -/// Bit: 0 1 2 3 4 5 6 7 -/// Byte 0: [ month lengths ............. -/// Byte 1: .. month lengths ] | [ leap month index .. -/// Byte 2: ] | [ NY offset ] | unused -/// ``` -/// -/// Where the New Year Offset is the offset from ISO Jan 21 of that year for Chinese New Year, -/// the month lengths are stored as 1 = 30, 0 = 29 for each month including the leap month. -/// The largest possible offset is 33, which requires 6 bits of storage. -/// -///
-/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, -/// including in SemVer minor releases. While the serde representation of data structs is guaranteed -/// to be stable, their Rust representation might not be. Use with caution. -///
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ULE)] -#[cfg_attr(feature = "datagen", derive(databake::Bake))] -#[cfg_attr(feature = "datagen", databake(path = icu_calendar::provider))] -#[repr(C, packed)] -pub struct PackedChineseBasedYearInfo(pub u8, pub u8, pub u8); - -impl PackedChineseBasedYearInfo { - /// The first day of the ISO year on which Chinese New Year may occur - /// - /// According to Reingold & Dershowitz, ch 19.6, Chinese New Year occurs on Jan 21 - Feb 21 inclusive. - /// - /// Chinese New Year in the year 30 AD is January 20 (30-01-20). - /// - /// We allow it to occur as early as January 19 which is the earliest the second new moon - /// could occur after the Winter Solstice if the solstice is pinned to December 20. - const FIRST_NY: i64 = 18; - - pub(crate) fn new( - month_lengths: [bool; 13], - leap_month_idx: Option, - ny_offset: i64, - ) -> Self { - debug_assert!( - !month_lengths[12] || leap_month_idx.is_some(), - "Last month length should not be set for non-leap years" - ); - let ny_offset = ny_offset - Self::FIRST_NY; - debug_assert!(ny_offset >= 0, "Year offset too small to store"); - debug_assert!(ny_offset < 34, "Year offset too big to store"); - debug_assert!( - leap_month_idx.map(|l| l <= 13).unwrap_or(true), - "Leap month indices must be 1 <= i <= 13" - ); - let mut all = 0u32; // last byte unused - - for (month, length_30) in month_lengths.iter().enumerate() { - #[allow(clippy::indexing_slicing)] - if *length_30 { - all |= 1 << month as u32; - } - } - let leap_month_idx = leap_month_idx.unwrap_or(0); - all |= (leap_month_idx as u32) << (8 + 5); - all |= (ny_offset as u32) << (16 + 1); - let le = all.to_le_bytes(); - Self(le[0], le[1], le[2]) - } - - // Get the new year difference from the ISO new year - pub(crate) fn ny_offset(self) -> u8 { - Self::FIRST_NY as u8 + (self.2 >> 1) - } - - pub(crate) fn leap_month(self) -> Option { - let bits = (self.1 >> 5) + ((self.2 & 0b1) << 3); - - (bits != 0).then_some(bits) - } - - // Whether a particular month has 30 days (month is 1-indexed) - pub(crate) fn month_has_30_days(self, month: u8) -> bool { - let months = u16::from_le_bytes([self.0, self.1]); - months & (1 << (month - 1) as u16) != 0 - } - - #[cfg(any(test, feature = "datagen"))] - pub(crate) fn month_lengths(self) -> [bool; 13] { - core::array::from_fn(|i| self.month_has_30_days(i as u8 + 1)) - } - - // Which day of year is the last day of a month (month is 1-indexed) - pub(crate) fn last_day_of_month(self, month: u8) -> u16 { - let months = u16::from_le_bytes([self.0, self.1]); - // month is 1-indexed, so `29 * month` includes the current month - let mut prev_month_lengths = 29 * month as u16; - // month is 1-indexed, so `1 << month` is a mask with all zeroes except - // for a 1 at the bit index at the next month. Subtracting 1 from it gets us - // a bitmask for all months up to now - let long_month_bits = months & ((1 << month as u16) - 1); - prev_month_lengths += long_month_bits.count_ones().try_into().unwrap_or(0); - prev_month_lengths - } -} - -impl AsULE for PackedChineseBasedYearInfo { - type ULE = Self; - fn to_unaligned(self) -> Self { - self - } - fn from_unaligned(other: Self) -> Self { - other - } -} - -#[cfg(feature = "serde")] -mod serialization { - use super::*; - - #[cfg(feature = "datagen")] - use serde::{ser, Serialize}; - use serde::{Deserialize, Deserializer}; - - #[derive(Deserialize)] - #[cfg_attr(feature = "datagen", derive(Serialize))] - struct SerdePackedChineseBasedYearInfo { - ny_offset: u8, - month_has_30_days: [bool; 13], - leap_month_idx: Option, - } - - impl<'de> Deserialize<'de> for PackedChineseBasedYearInfo { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - if deserializer.is_human_readable() { - SerdePackedChineseBasedYearInfo::deserialize(deserializer).map(Into::into) - } else { - let data = <(u8, u8, u8)>::deserialize(deserializer)?; - Ok(PackedChineseBasedYearInfo(data.0, data.1, data.2)) - } - } - } - - #[cfg(feature = "datagen")] - impl Serialize for PackedChineseBasedYearInfo { - fn serialize(&self, serializer: S) -> Result - where - S: ser::Serializer, - { - if serializer.is_human_readable() { - SerdePackedChineseBasedYearInfo::from(*self).serialize(serializer) - } else { - (self.0, self.1, self.2).serialize(serializer) - } - } - } - - #[cfg(feature = "datagen")] - impl From for SerdePackedChineseBasedYearInfo { - fn from(other: PackedChineseBasedYearInfo) -> Self { - Self { - ny_offset: other.ny_offset(), - month_has_30_days: other.month_lengths(), - leap_month_idx: other.leap_month(), - } - } - } - - impl From for PackedChineseBasedYearInfo { - fn from(other: SerdePackedChineseBasedYearInfo) -> Self { - Self::new( - other.month_has_30_days, - other.leap_month_idx, - other.ny_offset as i64, - ) - } - } -} - -#[cfg(test)] -mod test { - use super::*; - - fn packed_roundtrip_single( - mut month_lengths: [bool; 13], - leap_month_idx: Option, - ny_offset: i64, - ) { - if leap_month_idx.is_none() { - // Avoid bad invariants - month_lengths[12] = false; - } - let packed = PackedChineseBasedYearInfo::new(month_lengths, leap_month_idx, ny_offset); - - assert_eq!( - ny_offset, - packed.ny_offset() as i64, - "Roundtrip with {month_lengths:?}, {leap_month_idx:?}, {ny_offset}" - ); - assert_eq!( - leap_month_idx, - packed.leap_month(), - "Roundtrip with {month_lengths:?}, {leap_month_idx:?}, {ny_offset}" - ); - let month_lengths_roundtrip = packed.month_lengths(); - assert_eq!( - month_lengths, month_lengths_roundtrip, - "Roundtrip with {month_lengths:?}, {leap_month_idx:?}, {ny_offset}" - ); - } - - #[test] - fn test_roundtrip_packed() { - const SHORT: [bool; 13] = [false; 13]; - const LONG: [bool; 13] = [true; 13]; - const ALTERNATING1: [bool; 13] = [ - false, true, false, true, false, true, false, true, false, true, false, true, false, - ]; - const ALTERNATING2: [bool; 13] = [ - true, false, true, false, true, false, true, false, true, false, true, false, true, - ]; - const RANDOM1: [bool; 13] = [ - true, true, false, false, true, true, false, true, true, true, true, false, true, - ]; - const RANDOM2: [bool; 13] = [ - false, true, true, true, true, false, true, true, true, false, false, true, false, - ]; - packed_roundtrip_single(SHORT, None, 18 + 5); - packed_roundtrip_single(SHORT, None, 18 + 10); - packed_roundtrip_single(SHORT, Some(11), 18 + 15); - packed_roundtrip_single(LONG, Some(12), 18 + 15); - packed_roundtrip_single(ALTERNATING1, None, 18 + 2); - packed_roundtrip_single(ALTERNATING1, Some(3), 18 + 5); - packed_roundtrip_single(ALTERNATING2, None, 18 + 9); - packed_roundtrip_single(ALTERNATING2, Some(7), 18 + 26); - packed_roundtrip_single(RANDOM1, None, 18 + 29); - packed_roundtrip_single(RANDOM1, Some(12), 18 + 29); - packed_roundtrip_single(RANDOM1, Some(2), 18 + 21); - packed_roundtrip_single(RANDOM2, None, 18 + 25); - packed_roundtrip_single(RANDOM2, Some(2), 18 + 19); - packed_roundtrip_single(RANDOM2, Some(5), 18 + 2); - packed_roundtrip_single(RANDOM2, Some(12), 18 + 5); - } -} diff --git a/deps/crates/vendor/icu_calendar/src/provider/hijri.rs b/deps/crates/vendor/icu_calendar/src/provider/hijri.rs deleted file mode 100644 index d0ff61f8b13b57..00000000000000 --- a/deps/crates/vendor/icu_calendar/src/provider/hijri.rs +++ /dev/null @@ -1,165 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -//! 🚧 \[Unstable\] Data provider struct definitions for chinese-based calendars. -//! -//!
-//! 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, -//! including in SemVer minor releases. While the serde representation of data structs is guaranteed -//! to be stable, their Rust representation might not be. Use with caution. -//!
-//! -//! Read more about data providers: [`icu_provider`] - -use calendrical_calculations::rata_die::RataDie; -use icu_provider::prelude::*; -use zerovec::ule::AsULE; -use zerovec::ZeroVec; - -icu_provider::data_marker!( - /// Precomputed data for the Hijri obsevational calendar - CalendarHijriSimulatedMeccaV1, - "calendar/hijri/simulated/mecca/v1", - HijriData<'static>, - is_singleton = true, -); - -/// Cached/precompiled data for a certain range of years for a chinese-based -/// calendar. Avoids the need to perform lunar calendar arithmetic for most calendrical -/// operations. -#[derive(Debug, PartialEq, Clone, Default, yoke::Yokeable, zerofrom::ZeroFrom)] -#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))] -#[cfg_attr(feature = "datagen", databake(path = icu_calendar::provider::hijri))] -#[cfg_attr(feature = "serde", derive(serde::Deserialize))] -pub struct HijriData<'data> { - /// The extended year corresponding to the first data entry for this year - pub first_extended_year: i32, - /// A list of precomputed data for each year beginning with first_extended_year - #[cfg_attr(feature = "serde", serde(borrow))] - pub data: ZeroVec<'data, PackedHijriYearInfo>, -} - -icu_provider::data_struct!( - HijriData<'_>, - #[cfg(feature = "datagen")] -); - -/// The struct containing compiled Hijri YearInfo -/// -/// Bit structure -/// -/// ```text -/// Bit: F.........C B.............0 -/// Value: [ start day ][ month lengths ] -/// ``` -/// -/// The start day is encoded as a signed offset from `Self::mean_synodic_start_day`. This number does not -/// appear to be less than 2, however we use all remaining bits for it in case of drift in the math. -/// The month lengths are stored as 1 = 30, 0 = 29 for each month including the leap month. -/// -///
-/// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, -/// including in SemVer minor releases. While the serde representation of data structs is guaranteed -/// to be stable, their Rust representation might not be. Use with caution. -///
-#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] -#[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))] -#[cfg_attr(feature = "datagen", databake(path = icu_calendar::provider))] -#[cfg_attr(feature = "serde", derive(serde::Deserialize))] -pub struct PackedHijriYearInfo(pub u16); - -impl PackedHijriYearInfo { - pub(crate) const fn new( - extended_year: i32, - month_lengths: [bool; 12], - start_day: RataDie, - ) -> Self { - let start_offset = start_day.since(Self::mean_synodic_start_day(extended_year)); - - debug_assert!( - -8 < start_offset && start_offset < 8, - "Year offset too big to store" - ); - let start_offset = start_offset as i8; - - let mut all = 0u16; // last byte unused - - let mut i = 0; - while i < 12 { - #[allow(clippy::indexing_slicing)] - if month_lengths[i] { - all |= 1 << i; - } - i += 1; - } - - if start_offset < 0 { - all |= 1 << 12; - } - all |= (start_offset.unsigned_abs() as u16) << 13; - Self(all) - } - - pub(crate) fn unpack(self, extended_year: i32) -> ([bool; 12], RataDie) { - let month_lengths = core::array::from_fn(|i| self.0 & (1 << (i as u8) as u16) != 0); - let start_offset = if (self.0 & 0b1_0000_0000_0000) != 0 { - -((self.0 >> 13) as i64) - } else { - (self.0 >> 13) as i64 - }; - ( - month_lengths, - Self::mean_synodic_start_day(extended_year) + start_offset, - ) - } - - const fn mean_synodic_start_day(extended_year: i32) -> RataDie { - // -1 because the epoch is new year of year 1 - // truncating instead of flooring does not matter, as this is used for positive years only - calendrical_calculations::islamic::ISLAMIC_EPOCH_FRIDAY.add( - ((extended_year - 1) as f64 * calendrical_calculations::islamic::MEAN_YEAR_LENGTH) - as i64, - ) - } -} - -impl AsULE for PackedHijriYearInfo { - type ULE = ::ULE; - fn from_unaligned(unaligned: Self::ULE) -> Self { - Self(::from_unaligned(unaligned)) - } - fn to_unaligned(self) -> Self::ULE { - ::to_unaligned(self.0) - } -} - -#[test] -fn test_hijri_packed_roundtrip() { - fn single_roundtrip(month_lengths: [bool; 12], year_start: RataDie) { - let packed = PackedHijriYearInfo::new(1600, month_lengths, year_start); - let (month_lengths2, year_start2) = packed.unpack(1600); - assert_eq!(month_lengths, month_lengths2, "Month lengths must match for testcase {month_lengths:?} / {year_start:?}, with packed repr: {packed:?}"); - assert_eq!(year_start, year_start2, "Month lengths must match for testcase {month_lengths:?} / {year_start:?}, with packed repr: {packed:?}"); - } - - let l = true; - let s = false; - let all_short = [s; 12]; - let all_long = [l; 12]; - let mixed1 = [l, s, l, s, l, s, l, s, l, s, l, s]; - let mixed2 = [s, s, l, l, l, s, l, s, s, s, l, l]; - - let start_1600 = PackedHijriYearInfo::mean_synodic_start_day(1600); - single_roundtrip(all_short, start_1600); - single_roundtrip(all_long, start_1600); - single_roundtrip(mixed1, start_1600); - single_roundtrip(mixed2, start_1600); - - single_roundtrip(mixed1, start_1600 - 7); - single_roundtrip(mixed2, start_1600 + 7); - single_roundtrip(mixed2, start_1600 + 4); - single_roundtrip(mixed2, start_1600 + 1); - single_roundtrip(mixed2, start_1600 - 1); - single_roundtrip(mixed2, start_1600 - 4); -} diff --git a/deps/crates/vendor/icu_calendar/src/tests/continuity_test.rs b/deps/crates/vendor/icu_calendar/src/tests/continuity_test.rs index f157bdd28826ff..ba22c7c1e51de1 100644 --- a/deps/crates/vendor/icu_calendar/src/tests/continuity_test.rs +++ b/deps/crates/vendor/icu_calendar/src/tests/continuity_test.rs @@ -2,25 +2,20 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -use crate::*; -use core::marker::PhantomData; - -fn check_continuity(mut date: Date
) { - let one_day_duration = DateDuration:: { - years: 0, - months: 0, - weeks: 0, - days: 1, - marker: PhantomData, - }; +use crate::{types::*, *}; + +fn check_continuity(mut date: Date, years_to_check: usize) { + let duration = DateDuration::for_days(1); let mut rata_die = date.to_rata_die(); let mut weekday = date.day_of_week(); let mut year = date.year(); let mut is_in_leap_year = date.is_in_leap_year(); - for _ in 0..(366 * 20) { - let next_date = date.added(one_day_duration); + for _ in 0..(366 * years_to_check) { + let next_date = date + .try_added_with_options(duration, Default::default()) + .unwrap(); let next_rata_die = next_date.to_iso().to_rata_die(); assert_eq!(next_rata_die, rata_die + 1, "{next_date:?}"); let next_weekday = next_date.day_of_week(); @@ -42,19 +37,15 @@ fn check_continuity(mut date: Date) { } } -fn check_every_250_days(mut date: Date) { - let one_thousand_days_duration = DateDuration:: { - years: 0, - months: 0, - weeks: 0, - days: 250, - marker: PhantomData, - }; +fn check_every_250_days(mut date: Date, iters: usize) { + let duration = DateDuration::for_days(250); let mut rata_die = date.to_rata_die(); - for _ in 0..2000 { - let next_date = date.added(one_thousand_days_duration); + for _ in 0..iters { + let next_date = date + .try_added_with_options(duration, Default::default()) + .unwrap(); let next_iso = next_date.to_iso(); let next_rata_die = next_iso.to_rata_die(); assert_eq!(next_rata_die, rata_die + 250, "{next_date:?}"); @@ -68,175 +59,192 @@ fn check_every_250_days(mut date: Date) { #[test] fn test_buddhist_continuity() { let date = Date::try_new_buddhist(-10, 1, 1); - check_continuity(date.unwrap()); + check_continuity(date.unwrap(), 20); let date = Date::try_new_buddhist(-300, 1, 1); - check_every_250_days(date.unwrap()); + check_every_250_days(date.unwrap(), 2000); } #[test] fn test_chinese_continuity() { - let cal = crate::cal::Chinese::new(); - let cal = Ref(&cal); - let date = Date::try_new_chinese_with_calendar(-10, 1, 1, cal); - check_continuity(date.unwrap()); - let date = Date::try_new_chinese_with_calendar(-300, 1, 1, cal); - check_every_250_days(date.unwrap()); - let date = Date::try_new_chinese_with_calendar(-10000, 1, 1, cal); - check_every_250_days(date.unwrap()); + let cal = crate::cal::ChineseTraditional::new(); + let date = Date::try_new_from_codes(None, -10, MonthCode::new_normal(1).unwrap(), 1, cal); + check_continuity(date.unwrap(), 20); + let date = Date::try_new_from_codes(None, -300, MonthCode::new_normal(1).unwrap(), 1, cal); + check_every_250_days(date.unwrap(), 2000); + let date = Date::try_new_from_codes(None, -10000, MonthCode::new_normal(1).unwrap(), 1, cal); + check_every_250_days(date.unwrap(), 2000); + + let date = Date::try_new_from_codes(None, 1899, MonthCode::new_normal(1).unwrap(), 1, cal); + check_continuity(date.unwrap(), 20); + + let date = Date::try_new_from_codes(None, 2099, MonthCode::new_normal(1).unwrap(), 1, cal); + check_continuity(date.unwrap(), 20); } #[test] fn test_coptic_continuity() { let date = Date::try_new_coptic(-10, 1, 1); - check_continuity(date.unwrap()); + check_continuity(date.unwrap(), 20); let date = Date::try_new_coptic(-300, 1, 1); - check_every_250_days(date.unwrap()); + check_every_250_days(date.unwrap(), 2000); } #[test] -fn test_dangi_continuity() { - let cal = crate::cal::Dangi::new(); - let cal = Ref(&cal); - let date = Date::try_new_dangi_with_calendar(-10, 1, 1, cal); - check_continuity(date.unwrap()); - let date = Date::try_new_dangi_with_calendar(-300, 1, 1, cal); - check_every_250_days(date.unwrap()); +fn test_korean_continuity() { + let cal = cal::KoreanTraditional::new(); + let date = Date::try_new_from_codes(None, -10, MonthCode::new_normal(1).unwrap(), 1, cal); + check_continuity(date.unwrap(), 20); + let date = Date::try_new_from_codes(None, -300, MonthCode::new_normal(1).unwrap(), 1, cal); + check_every_250_days(date.unwrap(), 2000); + + let date = Date::try_new_from_codes(None, 1900, MonthCode::new_normal(1).unwrap(), 1, cal); + check_continuity(date.unwrap(), 20); + + let date = Date::try_new_from_codes(None, 2100, MonthCode::new_normal(1).unwrap(), 1, cal); + check_continuity(date.unwrap(), 20); } #[test] fn test_ethiopian_continuity() { - use crate::cal::EthiopianEraStyle::*; + use cal::EthiopianEraStyle::*; let date = Date::try_new_ethiopian(AmeteMihret, -10, 1, 1); - check_continuity(date.unwrap()); + check_continuity(date.unwrap(), 20); let date = Date::try_new_ethiopian(AmeteMihret, -300, 1, 1); - check_every_250_days(date.unwrap()); + check_every_250_days(date.unwrap(), 2000); } #[test] fn test_ethiopian_amete_alem_continuity() { - use crate::cal::EthiopianEraStyle::*; + use cal::EthiopianEraStyle::*; let date = Date::try_new_ethiopian(AmeteAlem, -10, 1, 1); - check_continuity(date.unwrap()); + check_continuity(date.unwrap(), 20); let date = Date::try_new_ethiopian(AmeteAlem, -300, 1, 1); - check_every_250_days(date.unwrap()); + check_every_250_days(date.unwrap(), 2000); } #[test] fn test_gregorian_continuity() { let date = Date::try_new_gregorian(-10, 1, 1); - check_continuity(date.unwrap()); + check_continuity(date.unwrap(), 20); let date = Date::try_new_gregorian(-300, 1, 1); - check_every_250_days(date.unwrap()); + check_every_250_days(date.unwrap(), 2000); } #[test] fn test_hebrew_continuity() { - let date = Date::try_new_hebrew(-10, 1, 1); - check_continuity(date.unwrap()); - let date = Date::try_new_hebrew(-300, 1, 1); - check_every_250_days(date.unwrap()); + let date = + Date::try_new_from_codes(None, -10, MonthCode::new_normal(1).unwrap(), 1, cal::Hebrew); + check_continuity(date.unwrap(), 20); + let date = Date::try_new_from_codes( + None, + -300, + MonthCode::new_normal(1).unwrap(), + 1, + cal::Hebrew, + ); + check_every_250_days(date.unwrap(), 2000); } #[test] fn test_indian_continuity() { let date = Date::try_new_indian(-10, 1, 1); - check_continuity(date.unwrap()); + check_continuity(date.unwrap(), 20); let date = Date::try_new_indian(-300, 1, 1); - check_every_250_days(date.unwrap()); + check_every_250_days(date.unwrap(), 2000); } #[test] fn test_hijri_civil_continuity() { - let cal = crate::cal::HijriTabular::new( - crate::cal::HijriTabularLeapYears::TypeII, - crate::cal::HijriTabularEpoch::Friday, + let cal = cal::Hijri::new_tabular( + cal::hijri::TabularAlgorithmLeapYears::TypeII, + cal::hijri::TabularAlgorithmEpoch::Friday, ); - let cal = Ref(&cal); - let date = Date::try_new_hijri_tabular_with_calendar(-10, 1, 1, cal); - check_continuity(date.unwrap()); - let date = Date::try_new_hijri_tabular_with_calendar(-300, 1, 1, cal); - check_every_250_days(date.unwrap()); + let date = Date::try_new_hijri_with_calendar(-10, 1, 1, cal); + check_continuity(date.unwrap(), 20); + let date = Date::try_new_hijri_with_calendar(-300, 1, 1, cal); + check_every_250_days(date.unwrap(), 2000); } #[test] fn test_hijri_simulated_mecca_continuity() { #[cfg(feature = "logging")] let _ = simple_logger::SimpleLogger::new().env().init(); - let cal = crate::cal::HijriSimulated::new_mecca_always_calculating(); - let cal = Ref(&cal); - let date = Date::try_new_simulated_hijri_with_calendar(-10, 1, 1, cal); - check_continuity(date.unwrap()); - let date = Date::try_new_simulated_hijri_with_calendar(-300, 1, 1, cal); - check_every_250_days(date.unwrap()); + let cal = cal::Hijri::new_simulated_mecca(); + let date = Date::try_new_hijri_with_calendar(-10, 1, 1, cal); + // This test is slow since it is doing astronomical calculations, so check only 3 years + check_continuity(date.unwrap(), 3); + let date = Date::try_new_hijri_with_calendar(-300, 1, 1, cal); + // This test is slow since it is doing astronomical calculations, so check only 100 dates + check_every_250_days(date.unwrap(), 100); } #[test] fn test_hijri_tabular_continuity() { - let cal = crate::cal::HijriTabular::new( - crate::cal::HijriTabularLeapYears::TypeII, - crate::cal::HijriTabularEpoch::Thursday, + let cal = cal::Hijri::new_tabular( + cal::hijri::TabularAlgorithmLeapYears::TypeII, + cal::hijri::TabularAlgorithmEpoch::Thursday, ); - let cal = Ref(&cal); - let date = Date::try_new_hijri_tabular_with_calendar(-10, 1, 1, cal); - check_continuity(date.unwrap()); - let date = Date::try_new_hijri_tabular_with_calendar(-300, 1, 1, cal); - check_every_250_days(date.unwrap()); + let date = Date::try_new_hijri_with_calendar(-10, 1, 1, cal); + check_continuity(date.unwrap(), 20); + let date = Date::try_new_hijri_with_calendar(-300, 1, 1, cal); + check_every_250_days(date.unwrap(), 2000); } #[test] fn test_hijri_umm_al_qura_continuity() { #[cfg(feature = "logging")] let _ = simple_logger::SimpleLogger::new().env().init(); - let date = Date::try_new_ummalqura(-10, 1, 1); - check_continuity(date.unwrap()); - let date = Date::try_new_ummalqura(1290, 1, 1); - check_continuity(date.unwrap()); - let date = Date::try_new_ummalqura(1590, 1, 1); - check_continuity(date.unwrap()); - let date = Date::try_new_ummalqura(-300, 1, 1); - check_every_250_days(date.unwrap()); + let cal = cal::Hijri::new_umm_al_qura(); + let date = Date::try_new_hijri_with_calendar(-10, 1, 1, cal); + check_continuity(date.unwrap(), 20); + let date = Date::try_new_hijri_with_calendar(1290, 1, 1, cal); + check_continuity(date.unwrap(), 20); + let date = Date::try_new_hijri_with_calendar(1590, 1, 1, cal); + check_continuity(date.unwrap(), 20); + let date = Date::try_new_hijri_with_calendar(-300, 1, 1, cal); + check_every_250_days(date.unwrap(), 2000); } #[test] fn test_iso_continuity() { let date = Date::try_new_iso(-10, 1, 1); - check_continuity(date.unwrap()); + check_continuity(date.unwrap(), 20); let date = Date::try_new_iso(-300, 1, 1); - check_every_250_days(date.unwrap()); + check_every_250_days(date.unwrap(), 2000); } #[test] fn test_japanese_continuity() { - let cal = crate::cal::Japanese::new(); + let cal = cal::Japanese::new(); let cal = Ref(&cal); let date = Date::try_new_japanese_with_calendar("heisei", 20, 1, 1, cal); - check_continuity(date.unwrap()); + check_continuity(date.unwrap(), 20); let date = Date::try_new_japanese_with_calendar("bce", 500, 1, 1, cal); - check_every_250_days(date.unwrap()); + check_every_250_days(date.unwrap(), 2000); } #[test] fn test_japanese_extended_continuity() { - let cal = crate::cal::JapaneseExtended::new(); + let cal = cal::JapaneseExtended::new(); let cal = Ref(&cal); let date = Date::try_new_japanese_extended_with_calendar("heisei", 20, 1, 1, cal); - check_continuity(date.unwrap()); + check_continuity(date.unwrap(), 20); let date = Date::try_new_japanese_extended_with_calendar("bce", 500, 1, 1, cal); - check_every_250_days(date.unwrap()); + check_every_250_days(date.unwrap(), 2000); } #[test] fn test_persian_continuity() { let date = Date::try_new_persian(-10, 1, 1); - check_continuity(date.unwrap()); + check_continuity(date.unwrap(), 20); let date = Date::try_new_persian(-300, 1, 1); - check_every_250_days(date.unwrap()); + check_every_250_days(date.unwrap(), 2000); } #[test] fn test_roc_continuity() { let date = Date::try_new_roc(-10, 1, 1); - check_continuity(date.unwrap()); + check_continuity(date.unwrap(), 20); let date = Date::try_new_roc(-300, 1, 1); - check_every_250_days(date.unwrap()); + check_every_250_days(date.unwrap(), 2000); } diff --git a/deps/crates/vendor/icu_calendar/src/tests/extrema.rs b/deps/crates/vendor/icu_calendar/src/tests/extrema.rs new file mode 100644 index 00000000000000..d4bb47d395fc79 --- /dev/null +++ b/deps/crates/vendor/icu_calendar/src/tests/extrema.rs @@ -0,0 +1,69 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use crate::cal::*; +use crate::Calendar; +use crate::Date; +use crate::Ref; + +#[track_caller] +fn check_extrema(cal: C) { + // Minimum and maximum dates allowed in ECMA-262 Temporal. + let min_date_iso = Date::try_new_iso(-271821, 4, 19).unwrap(); + let max_date_iso = Date::try_new_iso(275760, 9, 13).unwrap(); + let min_date = min_date_iso.to_calendar(Ref(&cal)); + let max_date = max_date_iso.to_calendar(Ref(&cal)); + + println!( + "min.year = {:?}, max.year = {:?} (cal = {})", + min_date.year(), + max_date.year(), + cal.debug_name() + ); +} + +// Test all calendars that have any amount of tricky mathematics +// to ensure that they do not trigger debug assertions for large dates. + +#[test] +fn check_extrema_chinese() { + check_extrema(ChineseTraditional::new()) +} + +#[test] +fn check_extrema_korean() { + check_extrema(KoreanTraditional::new()) +} + +#[test] +fn check_extrema_hijri_simulated_mecca() { + check_extrema(Hijri::new_simulated_mecca()) +} + +#[test] +fn check_extrema_hijri_uaq() { + check_extrema(Hijri::new_umm_al_qura()) +} + +#[test] +fn check_extrema_hijri_tabular() { + check_extrema(Hijri::new_tabular( + hijri::TabularAlgorithmLeapYears::TypeII, + hijri::TabularAlgorithmEpoch::Thursday, + )); + check_extrema(Hijri::new_tabular( + hijri::TabularAlgorithmLeapYears::TypeII, + hijri::TabularAlgorithmEpoch::Friday, + )); +} + +#[test] +fn check_extrema_hebrew() { + check_extrema(Hebrew::new()) +} + +#[test] +fn check_extrema_persian() { + check_extrema(Persian::new()) +} diff --git a/deps/crates/vendor/icu_calendar/src/tests/mod.rs b/deps/crates/vendor/icu_calendar/src/tests/mod.rs index a4330b4af10b0c..b753567880b6ea 100644 --- a/deps/crates/vendor/icu_calendar/src/tests/mod.rs +++ b/deps/crates/vendor/icu_calendar/src/tests/mod.rs @@ -3,3 +3,5 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). mod continuity_test; +mod extrema; +mod not_enough_fields; diff --git a/deps/crates/vendor/icu_calendar/src/tests/not_enough_fields.rs b/deps/crates/vendor/icu_calendar/src/tests/not_enough_fields.rs new file mode 100644 index 00000000000000..34aebf6f8996cc --- /dev/null +++ b/deps/crates/vendor/icu_calendar/src/tests/not_enough_fields.rs @@ -0,0 +1,237 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use crate::error::DateFromFieldsError; +use crate::options::{DateFromFieldsOptions, MissingFieldsStrategy, Overflow}; +use crate::types::DateFields; +use crate::Date; + +#[test] +fn test_from_fields_not_enough_fields() { + // Pick a sufficiently complex calendar. + let calendar = crate::cal::Hebrew::new(); + + let big_i32 = Some(i32::MAX); + let big_u8 = Some(u8::MAX); + let small_u8 = Some(1); + let small_i32 = Some(5000); + let valid_month_code: Option<&[_]> = Some(b"M01"); + let invalid_month_code: Option<&[_]> = Some(b"M99"); + + // We want to ensure that most NotEnoughFields cases return NotEnoughFields + // even when we're providing out-of-range values, so that + // this produces TypeError in Temporal as opposed to RangeError. + + for overflow in [Overflow::Reject, Overflow::Constrain] { + for missing_fields in [MissingFieldsStrategy::Reject, MissingFieldsStrategy::Ecma] { + let options = DateFromFieldsOptions { + overflow: Some(overflow), + missing_fields_strategy: Some(missing_fields), + }; + + // No month data always errors + assert_eq!( + Date::try_from_fields( + DateFields { + era: Some(b"hebrew"), + era_year: big_i32, + extended_year: None, + ordinal_month: None, + month_code: None, + day: small_u8, + }, + options, + calendar + ), + Err(DateFromFieldsError::NotEnoughFields), + "Test with {options:?}" + ); + assert_eq!( + Date::try_from_fields( + DateFields { + era: Some(b"hebrew"), + era_year: small_i32, + extended_year: None, + ordinal_month: None, + month_code: None, + day: big_u8, + }, + options, + calendar + ), + Err(DateFromFieldsError::NotEnoughFields), + "Test with {options:?}" + ); + assert_eq!( + Date::try_from_fields( + DateFields { + era: None, + era_year: None, + extended_year: big_i32, + ordinal_month: None, + month_code: None, + day: small_u8, + }, + options, + calendar + ), + Err(DateFromFieldsError::NotEnoughFields), + "Test with {options:?}" + ); + + // Insufficient era-year data always errors + assert_eq!( + Date::try_from_fields( + DateFields { + era: Some(b"hebrew"), + era_year: None, + extended_year: None, + ordinal_month: big_u8, + month_code: None, + day: small_u8, + }, + options, + calendar + ), + Err(DateFromFieldsError::NotEnoughFields), + "Test with {options:?}" + ); + assert_eq!( + Date::try_from_fields( + DateFields { + era: Some(b"hebrew"), + era_year: None, + extended_year: None, + ordinal_month: small_u8, + month_code: None, + day: big_u8, + }, + options, + calendar + ), + Err(DateFromFieldsError::NotEnoughFields), + "Test with {options:?}" + ); + + // No year info errors for ordinal months regardless of missing fields strategy + assert_eq!( + Date::try_from_fields( + DateFields { + era: None, + era_year: None, + extended_year: None, + ordinal_month: small_u8, + month_code: None, + day: big_u8, + }, + options, + calendar + ), + Err(DateFromFieldsError::NotEnoughFields), + "Test with {options:?}" + ); + assert_eq!( + Date::try_from_fields( + DateFields { + era: None, + era_year: None, + extended_year: None, + ordinal_month: big_u8, + month_code: None, + day: small_u8, + }, + options, + calendar + ), + Err(DateFromFieldsError::NotEnoughFields), + "Test with {options:?}" + ); + if missing_fields != MissingFieldsStrategy::Ecma { + // No year info errors only when there is no missing fields strategy + assert_eq!( + Date::try_from_fields( + DateFields { + era: None, + era_year: None, + extended_year: None, + ordinal_month: None, + month_code: valid_month_code, + day: big_u8, + }, + options, + calendar + ), + Err(DateFromFieldsError::NotEnoughFields), + "Test with {options:?}" + ); + assert_eq!( + Date::try_from_fields( + DateFields { + era: None, + era_year: None, + extended_year: None, + ordinal_month: None, + month_code: invalid_month_code, + day: small_u8, + }, + options, + calendar + ), + Err(DateFromFieldsError::NotEnoughFields), + "Test with {options:?}" + ); + + // No day info errors only when there is no missing field strategy + assert_eq!( + Date::try_from_fields( + DateFields { + era: None, + era_year: None, + extended_year: big_i32, + ordinal_month: small_u8, + month_code: None, + day: None, + }, + options, + calendar + ), + Err(DateFromFieldsError::NotEnoughFields), + "Test with {options:?}" + ); + assert_eq!( + Date::try_from_fields( + DateFields { + era: Some(b"hebrew"), + era_year: big_i32, + extended_year: None, + ordinal_month: small_u8, + month_code: None, + day: None, + }, + options, + calendar + ), + Err(DateFromFieldsError::NotEnoughFields), + "Test with {options:?}" + ); + assert_eq!( + Date::try_from_fields( + DateFields { + era: Some(b"hebrew"), + era_year: small_i32, + extended_year: None, + ordinal_month: big_u8, + month_code: None, + day: None, + }, + options, + calendar + ), + Err(DateFromFieldsError::NotEnoughFields), + "Test with {options:?}" + ); + } + } + } +} diff --git a/deps/crates/vendor/icu_calendar/src/types.rs b/deps/crates/vendor/icu_calendar/src/types.rs index c01f363694e57e..82c5164c6e9a0c 100644 --- a/deps/crates/vendor/icu_calendar/src/types.rs +++ b/deps/crates/vendor/icu_calendar/src/types.rs @@ -2,16 +2,220 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). -//! This module contains various types used by `icu_calendar` and `icu::datetime` +//! This module contains various types used by `icu::calendar` and `icu::datetime` #[doc(no_inline)] pub use calendrical_calculations::rata_die::RataDie; use core::fmt; use tinystr::TinyAsciiStr; -use tinystr::{TinyStr16, TinyStr4}; -use zerovec::maps::ZeroMapKV; use zerovec::ule::AsULE; +// Export the duration types from here +#[cfg(feature = "unstable")] +pub use crate::duration::{DateDuration, DateDurationUnit}; +use crate::error::MonthCodeParseError; + +#[cfg(feature = "unstable")] +pub use unstable::DateFields; +#[cfg(not(feature = "unstable"))] +pub(crate) use unstable::DateFields; + +mod unstable { + /// A bag of various ways of expressing the year, month, and/or day. + /// + /// Pass this into [`Date::try_from_fields`](crate::Date::try_from_fields). + /// + ///
+ /// 🚧 This code is considered unstable; it may change at any time, in breaking or non-breaking ways, + /// including in SemVer minor releases. Do not use this type unless you are prepared for things to occasionally break. + /// + /// Graduation tracking issue: [issue #7161](https://github.com/unicode-org/icu4x/issues/7161). + ///
+ /// + /// ✨ *Enabled with the `unstable` Cargo feature.* + #[derive(Copy, Clone, PartialEq, Default)] + #[non_exhaustive] + pub struct DateFields<'a> { + /// The era code as a UTF-8 string. + /// + /// The acceptable codes are defined by CLDR and documented on each calendar. + /// + /// If set, [`Self::era_year`] must also be set. + /// + /// # Examples + /// + /// To set the era field, use a byte string: + /// + /// ``` + /// use icu::calendar::types::DateFields; + /// + /// let mut fields = DateFields::default(); + /// + /// // As a byte string literal: + /// fields.era = Some(b"reiwa"); + /// + /// // Using str::as_bytes: + /// fields.era = Some("reiwa".as_bytes()); + /// ``` + /// + /// For a full example, see [`Self::extended_year`]. + pub era: Option<&'a [u8]>, + /// The numeric year in [`Self::era`]. + /// + /// If set, [`Self::era`] must also be set. + /// + /// For an example, see [`Self::extended_year`]. + pub era_year: Option, + /// See [`Date::extended_year()`](crate::Date::extended_year). + /// + /// If both this and [`Self::era`]/[`Self::era_year`] are set, they must + /// refer to the same year. + /// + /// # Examples + /// + /// Either `extended_year` or `era` + `era_year` can be used in DateFields: + /// + /// ``` + /// use icu::calendar::cal::Japanese; + /// use icu::calendar::types::DateFields; + /// use icu::calendar::Date; + /// + /// let mut fields1 = DateFields::default(); + /// fields1.era = Some(b"reiwa"); + /// fields1.era_year = Some(7); + /// fields1.ordinal_month = Some(1); + /// fields1.day = Some(1); + /// + /// let date1 = + /// Date::try_from_fields(fields1, Default::default(), Japanese::new()) + /// .expect("a well-defined Japanese date from era year"); + /// + /// let mut fields2 = DateFields::default(); + /// fields2.extended_year = Some(2025); + /// fields2.ordinal_month = Some(1); + /// fields2.day = Some(1); + /// + /// let date2 = + /// Date::try_from_fields(fields2, Default::default(), Japanese::new()) + /// .expect("a well-defined Japanese date from extended year"); + /// + /// assert_eq!(date1, date2); + /// + /// let year_info = date1.year().era().unwrap(); + /// assert_eq!(year_info.year, 7); + /// assert_eq!(year_info.era.as_str(), "reiwa"); + /// assert_eq!(year_info.extended_year, 2025); + /// ``` + pub extended_year: Option, + /// The month code representing a valid month in this calendar year, + /// as a UTF-8 string. + /// + /// See [`MonthCode`](crate::types::MonthCode) for information on the syntax. + /// + /// # Examples + /// + /// To set the month code field, use a byte string: + /// + /// ``` + /// use icu::calendar::types::DateFields; + /// + /// let mut fields = DateFields::default(); + /// + /// // As a byte string literal: + /// fields.era = Some(b"M02L"); + /// + /// // Using str::as_bytes: + /// fields.era = Some("M02L".as_bytes()); + /// ``` + /// + /// For a full example, see [`Self::ordinal_month`]. + pub month_code: Option<&'a [u8]>, + /// See [`MonthInfo::ordinal`](crate::types::MonthInfo::ordinal). + /// + /// If both this and [`Self::month_code`] are set, they must refer to + /// the same month. + /// + /// Note: using [`Self::month_code`] is recommended, because the ordinal month numbers + /// can vary from year to year, as illustrated in the following example. + /// + /// # Examples + /// + /// Either `month_code` or `ordinal_month` can be used in DateFields, but they + /// might not resolve to the same month number: + /// + /// ``` + /// use icu::calendar::cal::ChineseTraditional; + /// use icu::calendar::types::DateFields; + /// use icu::calendar::Date; + /// + /// // The 2023 Year of the Rabbit had a leap month after the 2nd month. + /// let mut fields1 = DateFields::default(); + /// fields1.extended_year = Some(2023); + /// fields1.month_code = Some(b"M02L"); + /// fields1.day = Some(1); + /// + /// let date1 = Date::try_from_fields( + /// fields1, + /// Default::default(), + /// ChineseTraditional::new(), + /// ) + /// .expect("a well-defined Chinese date from month code"); + /// + /// let mut fields2 = DateFields::default(); + /// fields2.extended_year = Some(2023); + /// fields2.ordinal_month = Some(3); + /// fields2.day = Some(1); + /// + /// let date2 = Date::try_from_fields( + /// fields2, + /// Default::default(), + /// ChineseTraditional::new(), + /// ) + /// .expect("a well-defined Chinese date from ordinal month"); + /// + /// assert_eq!(date1, date2); + /// + /// let month_info = date1.month(); + /// assert_eq!(month_info.ordinal, 3); + /// assert_eq!(month_info.standard_code.0, "M02L"); + /// ``` + pub ordinal_month: Option, + /// See [`DayOfMonth`](crate::types::DayOfMonth). + pub day: Option, + } +} + +// Custom impl to stringify era and month_code where possible. +impl fmt::Debug for DateFields<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // Ensures we catch future fields + let Self { + era, + era_year, + extended_year, + month_code, + ordinal_month, + day, + } = *self; + let mut builder = f.debug_struct("DateFields"); + if let Some(s) = era.and_then(|s| core::str::from_utf8(s).ok()) { + builder.field("era", &Some(s)); + } else { + builder.field("era", &era); + } + builder.field("era_year", &era_year); + builder.field("extended_year", &extended_year); + if let Some(s) = month_code.and_then(|s| core::str::from_utf8(s).ok()) { + builder.field("month_code", &Some(s)); + } else { + builder.field("month_code", &month_code); + } + builder.field("ordinal_month", &ordinal_month); + builder.field("day", &day); + builder.finish() + } +} + /// The type of year: Calendars like Chinese don't have an era and instead format with cyclic years. #[derive(Copy, Clone, Debug, PartialEq)] #[non_exhaustive] @@ -48,6 +252,15 @@ impl YearInfo { } } + /// Get the extended year (See [`Date::extended_year`](crate::Date::extended_year)) + /// for more information + pub fn extended_year(self) -> i32 { + match self { + YearInfo::Era(e) => e.extended_year, + YearInfo::Cyclic(c) => c.related_iso, + } + } + /// Get the era year information, if available pub fn era(self) -> Option { match self { @@ -88,8 +301,10 @@ pub enum YearAmbiguity { pub struct EraYear { /// The numeric year in that era pub year: i32, + /// See [`YearInfo::extended_year()`] + pub extended_year: i32, /// The era code as defined by CLDR, expect for cases where CLDR does not define a code. - pub era: TinyStr16, + pub era: TinyAsciiStr<16>, /// An era index, for calendars with a small set of eras. /// /// The only guarantee we make is that these values are stable. These do *not* @@ -126,12 +341,13 @@ pub struct CyclicYear { #[cfg_attr(feature = "datagen", derive(serde::Serialize, databake::Bake))] #[cfg_attr(feature = "datagen", databake(path = icu_calendar::types))] #[cfg_attr(feature = "serde", derive(serde::Deserialize))] -pub struct MonthCode(pub TinyStr4); +pub struct MonthCode(pub TinyAsciiStr<4>); impl MonthCode { /// Returns an option which is `Some` containing the non-month version of a leap month /// if the [`MonthCode`] this method is called upon is a leap month, and `None` otherwise. /// This method assumes the [`MonthCode`] is valid. + #[deprecated(since = "2.1.0")] pub fn get_normal_if_leap(self) -> Option { let bytes = self.0.all_bytes(); if bytes[3] == b'L' { @@ -140,67 +356,65 @@ impl MonthCode { None } } + + #[deprecated(since = "2.1.0")] /// Get the month number and whether or not it is leap from the month code pub fn parsed(self) -> Option<(u8, bool)> { - // Match statements on tinystrs are annoying so instead - // we calculate it from the bytes directly - - let bytes = self.0.all_bytes(); - let is_leap = bytes[3] == b'L'; - if bytes[0] != b'M' { - return None; - } - if bytes[1] == b'0' { - if bytes[2] >= b'1' && bytes[2] <= b'9' { - return Some((bytes[2] - b'0', is_leap)); - } - } else if bytes[1] == b'1' && bytes[2] >= b'0' && bytes[2] <= b'3' { - return Some((10 + bytes[2] - b'0', is_leap)); - } - None + ValidMonthCode::try_from_utf8(self.0.as_bytes()) + .ok() + .map(ValidMonthCode::to_tuple) } /// Construct a "normal" month code given a number ("Mxx"). /// /// Returns an error for months greater than 99 pub fn new_normal(number: u8) -> Option { - let tens = number / 10; - let ones = number % 10; - if tens > 9 { - return None; - } + (1..=99) + .contains(&number) + .then(|| ValidMonthCode::new_unchecked(number, false).to_month_code()) + } - let bytes = [b'M', b'0' + tens, b'0' + ones, 0]; - Some(MonthCode(TinyAsciiStr::try_from_raw(bytes).ok()?)) + /// Construct a "leap" month code given a number ("MxxL"). + /// + /// Returns an error for months greater than 99 + pub fn new_leap(number: u8) -> Option { + (1..=99) + .contains(&number) + .then(|| ValidMonthCode::new_unchecked(number, true).to_month_code()) } } #[test] fn test_get_normal_month_code_if_leap() { - let mc1 = MonthCode(tinystr::tinystr!(4, "M01L")); - let result1 = mc1.get_normal_if_leap(); - assert_eq!(result1, Some(MonthCode(tinystr::tinystr!(4, "M01")))); - - let mc2 = MonthCode(tinystr::tinystr!(4, "M11L")); - let result2 = mc2.get_normal_if_leap(); - assert_eq!(result2, Some(MonthCode(tinystr::tinystr!(4, "M11")))); - - let mc_invalid = MonthCode(tinystr::tinystr!(4, "M10")); - let result_invalid = mc_invalid.get_normal_if_leap(); - assert_eq!(result_invalid, None); + #![allow(deprecated)] + assert_eq!( + MonthCode::new_leap(1).unwrap().get_normal_if_leap(), + MonthCode::new_normal(1) + ); + + assert_eq!( + MonthCode::new_leap(11).unwrap().get_normal_if_leap(), + MonthCode::new_normal(11) + ); + + assert_eq!( + MonthCode::new_normal(10).unwrap().get_normal_if_leap(), + None + ); } impl AsULE for MonthCode { - type ULE = TinyStr4; - fn to_unaligned(self) -> TinyStr4 { + type ULE = TinyAsciiStr<4>; + fn to_unaligned(self) -> TinyAsciiStr<4> { self.0 } - fn from_unaligned(u: TinyStr4) -> Self { + fn from_unaligned(u: TinyAsciiStr<4>) -> Self { Self(u) } } -impl<'a> ZeroMapKV<'a> for MonthCode { +#[cfg(feature = "alloc")] +impl<'a> zerovec::maps::ZeroMapKV<'a> for MonthCode { type Container = zerovec::ZeroVec<'a, MonthCode>; type Slice = zerovec::ZeroSlice; type GetType = ::ULE; @@ -213,6 +427,89 @@ impl fmt::Display for MonthCode { } } +/// A [`MonthCode`] that has been parsed into its internal representation. +#[derive(Copy, Clone, Debug, PartialEq)] +pub(crate) struct ValidMonthCode { + /// Month number between 0 and 99 + number: u8, + is_leap: bool, +} + +impl ValidMonthCode { + #[inline] + pub(crate) fn try_from_utf8(bytes: &[u8]) -> Result { + match *bytes { + [b'M', tens, ones] => Ok(Self { + number: (tens - b'0') * 10 + ones - b'0', + is_leap: false, + }), + [b'M', tens, ones, b'L'] => Ok(Self { + number: (tens - b'0') * 10 + ones - b'0', + is_leap: true, + }), + _ => Err(MonthCodeParseError::InvalidSyntax), + } + } + + /// Create a new ValidMonthCode without checking that the number is between 1 and 99 + #[inline] + pub(crate) const fn new_unchecked(number: u8, is_leap: bool) -> Self { + debug_assert!(1 <= number && number <= 99); + Self { number, is_leap } + } + + /// Returns the month number according to the month code. + /// + /// This is NOT the same as the ordinal month! + /// + /// # Examples + /// + /// ```ignore + /// use icu::calendar::Date; + /// use icu::calendar::cal::Hebrew; + /// + /// let hebrew_date = Date::try_new_iso(2024, 7, 1).unwrap().to_calendar(Hebrew); + /// let month_info = hebrew_date.month(); + /// + /// // Hebrew year 5784 was a leap year, so the ordinal month and month number diverge. + /// assert_eq!(month_info.ordinal, 10); + /// assert_eq!(month_info.valid_month_code.number(), 9); + /// ``` + #[inline] + pub fn number(self) -> u8 { + self.number + } + + /// Returns whether the month is a leap month. + /// + /// This is true for intercalary months in [`Hebrew`] and [`LunarChinese`]. + /// + /// [`Hebrew`]: crate::cal::Hebrew + /// [`LunarChinese`]: crate::cal::LunarChinese + #[inline] + pub fn is_leap(self) -> bool { + self.is_leap + } + + #[inline] + pub(crate) fn to_tuple(self) -> (u8, bool) { + (self.number, self.is_leap) + } + + pub(crate) fn to_month_code(self) -> MonthCode { + #[allow(clippy::unwrap_used)] // by construction + MonthCode( + TinyAsciiStr::try_from_raw([ + b'M', + b'0' + self.number / 10, + b'0' + self.number % 10, + if self.is_leap { b'L' } else { 0 }, + ]) + .unwrap(), + ) + } +} + /// Representation of a formattable month. #[derive(Copy, Clone, Debug, PartialEq)] #[non_exhaustive] @@ -225,33 +522,71 @@ pub struct MonthInfo { /// The month code, used to distinguish months during leap years. /// + /// Round-trips through `Date` constructors like [`Date::try_new_from_codes`] and [`Date::try_from_fields`]. + /// /// This follows [Temporal's specification](https://tc39.es/proposal-intl-era-monthcode/#table-additional-month-codes). /// Months considered the "same" have the same code: This means that the Hebrew months "Adar" and "Adar II" ("Adar, but during a leap year") - /// are considered the same month and have the code M05 + /// are considered the same month and have the code M05. + /// + /// [`Date::try_new_from_codes`]: crate::Date::try_new_from_codes + /// [`Date::try_from_fields`]: crate::Date::try_from_fields pub standard_code: MonthCode, - /// A month code, useable for formatting + + /// Same as [`Self::standard_code`] but with invariants validated. + pub(crate) valid_standard_code: ValidMonthCode, + + /// A month code, useable for formatting. + /// + /// Does NOT necessarily round-trip through `Date` constructors like [`Date::try_new_from_codes`] and [`Date::try_from_fields`]. /// /// This may not necessarily be the canonical month code for a month in cases where a month has different /// formatting in a leap year, for example Adar/Adar II in the Hebrew calendar in a leap year has /// the standard code M06, but for formatting specifically the Hebrew calendar will return M06L since it is formatted /// differently. + /// + /// [`Date::try_new_from_codes`]: crate::Date::try_new_from_codes + /// [`Date::try_from_fields`]: crate::Date::try_from_fields pub formatting_code: MonthCode, + + /// Same as [`Self::formatting_code`] but with invariants validated. + pub(crate) valid_formatting_code: ValidMonthCode, } impl MonthInfo { + pub(crate) fn non_lunisolar(number: u8) -> Self { + Self::for_code_and_ordinal(ValidMonthCode::new_unchecked(number, false), number) + } + + pub(crate) fn for_code_and_ordinal(code: ValidMonthCode, ordinal: u8) -> Self { + Self { + ordinal, + standard_code: code.to_month_code(), + valid_standard_code: code, + formatting_code: code.to_month_code(), + valid_formatting_code: code, + } + } + /// Gets the month number. A month number N is not necessarily the Nth month in the year /// if there are leap months in the year, rather it is associated with the Nth month of a "regular" /// year. There may be multiple month Ns in a year pub fn month_number(self) -> u8 { - self.standard_code - .parsed() - .map(|(i, _)| i) - .unwrap_or(self.ordinal) + self.valid_standard_code.number() } /// Get whether the month is a leap month pub fn is_leap(self) -> bool { - self.standard_code.parsed().map(|(_, l)| l).unwrap_or(false) + self.valid_standard_code.is_leap() + } + + #[doc(hidden)] + pub fn formatting_month_number(self) -> u8 { + self.valid_formatting_code.number() + } + + #[doc(hidden)] + pub fn formatting_is_leap(self) -> bool { + self.valid_formatting_code.is_leap() } } diff --git a/deps/crates/vendor/icu_calendar/src/week.rs b/deps/crates/vendor/icu_calendar/src/week.rs index 384b4f55d99290..e835fa1c811362 100644 --- a/deps/crates/vendor/icu_calendar/src/week.rs +++ b/deps/crates/vendor/icu_calendar/src/week.rs @@ -144,7 +144,7 @@ fn add_to_weekday(weekday: Weekday, num_days: i32) -> Weekday { /// Which year or month that a calendar assigns a week to relative to the year/month /// the week is in. #[derive(Clone, Copy, Debug, PartialEq)] -#[allow(clippy::enum_variant_names)] +#[expect(clippy::enum_variant_names)] enum RelativeWeek { /// A week that is assigned to the last week of the previous year/month. e.g. 2021-01-01 is week 54 of 2020 per the ISO calendar. LastWeekOfPreviousUnit, @@ -294,7 +294,7 @@ impl Iterator for WeekdaySetIterator { #[cfg(test)] mod tests { use super::*; - use crate::{types::Weekday, Date, DateDuration, RangeError}; + use crate::{types::DateDuration, types::Weekday, Date, RangeError}; static ISO_CALENDAR: WeekCalculator = WeekCalculator { first_weekday: Weekday::Monday, @@ -457,7 +457,9 @@ mod tests { let day = (yyyymmdd % 100) as u8; let date = Date::try_new_iso(year, month, day)?; - let previous_month = date.added(DateDuration::new(0, -1, 0, 0)); + let previous_month = date + .try_added_with_options(DateDuration::for_months(-1), Default::default()) + .unwrap(); calendar.week_of( u16::from(previous_month.days_in_month()), @@ -646,7 +648,7 @@ fn test_iso_weeks() { use crate::types::IsoWeekOfYear; use crate::Date; - #[allow(clippy::zero_prefixed_literal)] + #[expect(clippy::zero_prefixed_literal)] for ((y, m, d), (iso_year, week_number)) in [ // 2010 starts on a Thursday, so 2009 has 53 ISO weeks ((2009, 12, 30), (2009, 53)), diff --git a/deps/crates/vendor/icu_calendar/tests/arithmetic.rs b/deps/crates/vendor/icu_calendar/tests/arithmetic.rs new file mode 100644 index 00000000000000..37c4b97ffb7926 --- /dev/null +++ b/deps/crates/vendor/icu_calendar/tests/arithmetic.rs @@ -0,0 +1,251 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use std::convert::Infallible; + +use icu_calendar::{ + cal::Hebrew, + options::{DateAddOptions, DateDifferenceOptions, Overflow}, + types::{DateDuration, DateDurationUnit, MonthCode}, + AsCalendar, Calendar, Date, Iso, +}; + +#[rustfmt::skip] +#[allow(clippy::type_complexity)] +const ISO_DATE_PAIRS: &[(&str, &str, u64, (u32, u64), (u32, u64), (u32, u32, u64))] = &[ + // d0, d1, D, (W, D), (M, D), (Y, M, D) + ("2020-01-03", "2020-02-15", 43, (6, 1), (1, 12), (0, 1, 12)), + ("2020-01-31", "2020-06-30", 151, (21, 4), (4, 30), (0, 4, 30)), + ("2020-03-31", "2020-07-30", 121, (17, 2), (3, 30), (0, 3, 30)), + ("2020-03-31", "2020-07-31", 122, (17, 3), (4, 0), (0, 4, 0)), + ("2016-03-20", "2020-03-05", 1446, (206, 4), (47, 14), (3, 11, 14)), + ("2020-02-29", "2022-03-01", 731, (104, 3), (24, 1), (2, 0, 1)), + + // Negative direction: + ("2020-02-15", "2020-01-03", 43, (6, 1), (1, 12), (0, 1, 12)), + ("2020-06-30", "2020-01-31", 151, (21, 4), (4, 29), (0, 4, 29)), // DIFF +/- + ("2020-07-30", "2020-03-31", 121, (17, 2), (3, 30), (0, 3, 30)), + ("2020-07-31", "2020-03-31", 122, (17, 3), (4, 0), (0, 4, 0)), + ("2020-03-05", "2016-03-20", 1446, (206, 4), (47, 16), (3, 11, 16)), // DIFF +/- + ("2022-03-01", "2020-02-29", 731, (104, 3), (24, 1), (2, 0, 1)), +]; + +fn check
( + d0: &Date, + d1: &Date, + exp0: &u64, + exp1: &(u32, u64), + exp2: &(u32, u64), + exp3: &(u32, u32, u64), +) where + A: AsCalendar + Copy, + ::Calendar: Calendar, + <::Calendar as Calendar>::DateInner: PartialOrd, +{ + let is_negative = d0 > d1; + let mut add_options = DateAddOptions::default(); + add_options.overflow = Some(Overflow::Constrain); + let mut until_options0 = DateDifferenceOptions::default(); + until_options0.largest_unit = Some(DateDurationUnit::Days); + let mut until_options1 = DateDifferenceOptions::default(); + until_options1.largest_unit = Some(DateDurationUnit::Weeks); + let mut until_options2 = DateDifferenceOptions::default(); + until_options2.largest_unit = Some(DateDurationUnit::Months); + let mut until_options3 = DateDifferenceOptions::default(); + until_options3.largest_unit = Some(DateDurationUnit::Years); + + let Ok(p0) = d0.try_until_with_options(d1, until_options0); + assert_eq!( + p0, + DateDuration { + is_negative, + days: *exp0, + ..Default::default() + }, + "{d0:?}/{d1:?}" + ); + assert_eq!( + d0.try_added_with_options(p0, add_options).unwrap(), + *d1, + "{d0:?}/{d1:?}" + ); + + let Ok(p1) = d0.try_until_with_options(d1, until_options1); + assert_eq!( + p1, + DateDuration { + is_negative, + weeks: exp1.0, + days: exp1.1, + ..Default::default() + }, + "{d0:?}/{d1:?}" + ); + assert_eq!( + d0.try_added_with_options(p1, add_options).unwrap(), + *d1, + "{d0:?}/{d1:?}" + ); + + let Ok(p2) = d0.try_until_with_options(d1, until_options2); + assert_eq!( + p2, + DateDuration { + is_negative, + months: exp2.0, + days: exp2.1, + ..Default::default() + }, + "{d0:?}/{d1:?}" + ); + assert_eq!( + d0.try_added_with_options(p2, add_options).unwrap(), + *d1, + "{d0:?}/{d1:?}" + ); + + let Ok(p3) = d0.try_until_with_options(d1, until_options3); + assert_eq!( + p3, + DateDuration { + is_negative, + years: exp3.0, + months: exp3.1, + days: exp3.2, + ..Default::default() + }, + "{d0:?}/{d1:?}" + ); + assert_eq!( + d0.try_added_with_options(p3, add_options).unwrap(), + *d1, + "{d0:?}/{d1:?}" + ); + + // RataDie addition should be equivalent for largest unit Days and Weeks + let rd_diff = d1.to_rata_die() - d0.to_rata_die(); + if is_negative { + assert!(rd_diff.is_negative()); + } + assert_eq!(p0.days, rd_diff.unsigned_abs()); + assert_eq!(p1.days + u64::from(p1.weeks) * 7, rd_diff.unsigned_abs()); +} + +#[test] +fn test_arithmetic_cases() { + for (d0, d1, exp0, exp1, exp2, exp3) in ISO_DATE_PAIRS { + let d0 = Date::try_from_str(d0, Iso).unwrap(); + let d1 = Date::try_from_str(d1, Iso).unwrap(); + check(&d0, &d1, exp0, exp1, exp2, exp3); + } +} + +#[test] +fn test_hebrew() { + let m06z_20 = + Date::try_new_from_codes(None, 5783, MonthCode::new_normal(6).unwrap(), 20, Hebrew) + .unwrap(); + let m05l_15 = + Date::try_new_from_codes(None, 5784, MonthCode::new_leap(5).unwrap(), 15, Hebrew).unwrap(); + let m05l_30 = + Date::try_new_from_codes(None, 5784, MonthCode::new_leap(5).unwrap(), 30, Hebrew).unwrap(); + let m06a_29 = + Date::try_new_from_codes(None, 5784, MonthCode::new_normal(6).unwrap(), 29, Hebrew) + .unwrap(); + let m07a_10 = + Date::try_new_from_codes(None, 5784, MonthCode::new_normal(7).unwrap(), 10, Hebrew) + .unwrap(); + let m06b_15 = + Date::try_new_from_codes(None, 5785, MonthCode::new_normal(6).unwrap(), 15, Hebrew) + .unwrap(); + let m07b_20 = + Date::try_new_from_codes(None, 5785, MonthCode::new_normal(7).unwrap(), 20, Hebrew) + .unwrap(); + + #[rustfmt::skip] + #[allow(clippy::type_complexity)] + let cases: &[(&Date, &Date, u64, (u32, u64), (u32, u64), (u32, u32, u64))] = &[ + (&m06z_20, &m05l_15, 348, (49, 5), (11, 25), (0, 11, 25)), + (&m06z_20, &m05l_30, 363, (51, 6), (12, 10), (0, 12, 10)), + (&m06z_20, &m06a_29, 392, (56, 0), (13, 9), (1, 0, 9)), + (&m06z_20, &m07a_10, 402, (57, 3), (13, 19), (1, 0, 19)), + (&m06z_20, &m06b_15, 733, (104,5), (24, 25), (1, 11, 25)), + (&m06z_20, &m07b_20, 767, (109,4), (26, 0), (2, 1, 0)), + + (&m05l_15, &m05l_30, 15, (2, 1), (0, 15), (0, 0, 15)), + (&m05l_15, &m06a_29, 44, (6, 2), (1, 14), (0, 1, 14)), + (&m05l_15, &m07a_10, 54, (7, 5), (1, 24), (0, 1, 24)), + (&m05l_15, &m06b_15, 385, (55, 0), (13, 0), (1, 0, 0)), // M05L to M06 common year + (&m05l_15, &m07b_20, 419, (59, 6), (14, 5), (1, 1, 5)), // M05L to M07 common year + + (&m05l_30, &m06a_29, 29, (4, 1), (0, 29), (0, 0, 29)), + (&m05l_30, &m07a_10, 39, (5, 4), (1, 10), (0, 1, 10)), + (&m05l_30, &m06b_15, 370, (52, 6), (12, 15), (0, 12, 15)), // M05L to M06 common year + (&m05l_30, &m07b_20, 404, (57, 5), (13, 20), (1, 0, 20)), // M05L to M07 common year + + (&m06a_29, &m07a_10, 10, (1, 3), (0, 10), (0, 0, 10)), + (&m06a_29, &m06b_15, 341, (48, 5), (11, 16), (0, 11, 16)), // M06 leap year to M06 common year + (&m06a_29, &m07b_20, 375, (53, 4), (12, 20), (1, 0, 20)), // M06 leap year to M07 common year + (&m07a_10, &m06b_15, 331, (47, 2), (11, 5), (0, 11, 5)), // M07 leap year to M06 common year + (&m07a_10, &m07b_20, 365, (52, 1), (12, 10), (1, 0, 10)), // M07 leap year to M06 common year + (&m06b_15, &m07b_20, 34, (4, 6), (1, 5), (0, 1, 5)), + ]; + + for (d0, d1, exp0, exp1, exp2, exp3) in cases { + check(d0, d1, exp0, exp1, exp2, exp3); + } +} + +#[test] +fn test_tricky_leap_months() { + let mut add_options = DateAddOptions::default(); + add_options.overflow = Some(Overflow::Constrain); + let mut until_options = DateDifferenceOptions::default(); + until_options.largest_unit = Some(DateDurationUnit::Years); + + fn hebrew_date(year: i32, month: &str, day: u8) -> Date { + Date::try_new_from_codes(None, year, MonthCode(month.parse().unwrap()), day, Hebrew) + .unwrap() + } + + // M06 + 1yr = M06 (common to leap) + let date0 = hebrew_date(5783, "M06", 20); + let duration0 = DateDuration::for_years(1); + let date1 = date0 + .try_added_with_options(duration0, add_options) + .unwrap(); + assert_eq!(date1, hebrew_date(5784, "M06", 20)); + let duration0_actual = date0.try_until_with_options(&date1, until_options).unwrap(); + assert_eq!(duration0_actual, duration0); + + // M06 - 1mo = M05L (leap to leap) + let duration1 = DateDuration::for_months(-1); + let date2 = date1 + .try_added_with_options(duration1, add_options) + .unwrap(); + assert_eq!(date2, hebrew_date(5784, "M05L", 20)); + let duration1_actual = date1.try_until_with_options(&date2, until_options).unwrap(); + assert_eq!(duration1_actual, duration1); + + // M05L + 1yr1mo = M07 (leap to common) + let duration2 = DateDuration { + years: 1, + months: 1, + ..Default::default() + }; + let date3 = date2 + .try_added_with_options(duration2, add_options) + .unwrap(); + assert_eq!(date3, hebrew_date(5785, "M07", 20)); + let duration2_actual = date2.try_until_with_options(&date3, until_options).unwrap(); + assert_eq!(duration2_actual, duration2); + + // M06 + 1yr1mo = M07 (leap to common) + let date4 = date1 + .try_added_with_options(duration2, add_options) + .unwrap(); + assert_eq!(date4, hebrew_date(5785, "M07", 20)); + let duration2_actual = date1.try_until_with_options(&date4, until_options).unwrap(); + assert_eq!(duration2_actual, duration2); +} diff --git a/deps/crates/vendor/icu_calendar/tests/exhaustive.rs b/deps/crates/vendor/icu_calendar/tests/exhaustive.rs new file mode 100644 index 00000000000000..7552900a92fb2b --- /dev/null +++ b/deps/crates/vendor/icu_calendar/tests/exhaustive.rs @@ -0,0 +1,201 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use icu_calendar::*; + +const MAGNITUDE: i32 = 1_000_000; + +// Check rd -> date -> iso -> date -> rd for whole range +#[test] +#[ignore] // takes about 200 seconds in release-with-assertions +fn check_round_trip() { + fn test(cal: C) { + let cal = Ref(&cal); + let low = Date::try_new_iso(-MAGNITUDE, 1, 1).unwrap().to_rata_die(); + let high = Date::try_new_iso(MAGNITUDE, 12, 31).unwrap().to_rata_die(); + let mut prev = Date::from_rata_die(low, cal); + let mut curr = low + 1; + while curr <= high { + let date = Date::from_rata_die(curr, cal); + assert!(prev < date); + + let rd = date.to_rata_die(); + assert_eq!(rd, curr, "{}", cal.as_calendar().debug_name()); + + let date2 = Date::new_from_iso(date.to_iso(), cal); + assert_eq!(date, date2, "{:?}", cal.as_calendar().debug_name()); + + prev = date; + curr += 1; + } + } + + for_each_calendar!(test); +} + +#[test] +#[ignore] // takes about 90 seconds in release-with-assertions +fn check_from_fields() { + fn test(cal: C) { + let cal = Ref(&cal); + + let codes = (1..19) + .flat_map(|i| { + [ + types::MonthCode::new_normal(i).unwrap(), + types::MonthCode::new_leap(i).unwrap(), + ] + .into_iter() + }) + .collect::>(); + for year in -MAGNITUDE..=MAGNITUDE { + if year % 50000 == 0 { + println!("{} {year:?}", cal.as_calendar().debug_name()); + } + for overflow in [options::Overflow::Constrain, options::Overflow::Reject] { + let mut options = options::DateFromFieldsOptions::default(); + options.overflow = Some(overflow); + for mut fields in codes + .iter() + .map(|m| { + let mut fields = types::DateFields::default(); + fields.month_code = Some(m.0.as_bytes()); + fields + }) + .chain((1..20).map(|m| { + let mut fields = types::DateFields::default(); + fields.ordinal_month = Some(m); + fields + })) + { + for day in 1..50 { + fields.extended_year = Some(year); + fields.day = Some(day); + let _ = Date::try_from_fields(fields, options, Ref(&cal)); + } + } + } + } + } + for_each_calendar!(test); +} + +macro_rules! for_each_calendar { + ($f:ident) => { + [ + || { + $f(cal::Buddhist); + println!("Buddhist done"); + }, + || { + $f(cal::east_asian_traditional::EastAsianTraditional( + EastAsianTraditionalYears::new(cal::east_asian_traditional::China::default()), + )); + println!("Chinese done"); + }, + || { + $f(cal::Coptic); + println!("Coptic done"); + }, + || { + $f(cal::east_asian_traditional::EastAsianTraditional( + EastAsianTraditionalYears::new(cal::east_asian_traditional::Korea::default()), + )); + println!("Korean done"); + }, + || { + $f(cal::Ethiopian::new()); + println!("Ethiopian done"); + }, + || { + $f(cal::Ethiopian::new_with_era_style( + cal::EthiopianEraStyle::AmeteAlem, + )); + println!("Ethiopian (Amete Alem) done"); + }, + || { + $f(cal::Gregorian); + println!("Gregorian done"); + }, + || { + $f(cal::Hebrew::new()); + println!("Hebrew done"); + }, + || { + $f(cal::Hijri::new_tabular( + cal::hijri::TabularAlgorithmLeapYears::TypeII, + cal::hijri::TabularAlgorithmEpoch::Friday, + )); + println!("Hijri (tabular) done"); + }, + || { + $f(cal::Hijri::new_tabular( + cal::hijri::TabularAlgorithmLeapYears::TypeII, + cal::hijri::TabularAlgorithmEpoch::Thursday, + )); + println!("Hijri (astronomical) done"); + }, + || { + $f(cal::Hijri::new_umm_al_qura()); + println!("Hijri (UAQ) done"); + }, + || { + $f(cal::Indian::new()); + println!("Indian done"); + }, + || { + $f(cal::Iso::new()); + println!("Iso done"); + }, + || { + $f(cal::Julian::new()); + println!("Julian done"); + }, + || { + $f(cal::Japanese::new()); + println!("Japanese done"); + }, + || { + $f(cal::JapaneseExtended::new()); + println!("JapaneseExtended done"); + }, + || { + $f(cal::Persian::new()); + println!("Persian done"); + }, + || { + $f(cal::Roc); + println!("Roc done"); + }, + ] + .map(std::thread::spawn) + .into_iter() + .for_each(|h| h.join().unwrap()); + }; +} +use for_each_calendar; + +// Precalculates Chinese years, significant performance improvement +#[derive(Debug, Clone)] +struct EastAsianTraditionalYears(Vec); + +impl EastAsianTraditionalYears { + fn new(r: R) -> Self { + Self( + ((-MAGNITUDE - 1)..=MAGNITUDE) + .map(|i| r.year_data(i)) + .collect(), + ) + } +} + +impl cal::scaffold::UnstableSealed for EastAsianTraditionalYears {} +impl cal::east_asian_traditional::Rules for EastAsianTraditionalYears { + fn year_data( + &self, + related_iso: i32, + ) -> cal::east_asian_traditional::EastAsianTraditionalYearData { + self.0[(related_iso + MAGNITUDE + 1) as usize] + } +} diff --git a/deps/crates/vendor/icu_calendar/tests/extended_year.rs b/deps/crates/vendor/icu_calendar/tests/extended_year.rs new file mode 100644 index 00000000000000..262dec5c24c913 --- /dev/null +++ b/deps/crates/vendor/icu_calendar/tests/extended_year.rs @@ -0,0 +1,85 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use icu_calendar::types::MonthCode; +use icu_calendar::AnyCalendar; +use icu_calendar::AnyCalendarKind; +use icu_calendar::Date; + +#[cfg(test)] +use std::rc::Rc; + +/// Reference: +static EXTENDED_EPOCHS: &[(AnyCalendarKind, i32)] = &[ + (AnyCalendarKind::Buddhist, -543), + (AnyCalendarKind::Chinese, 0), + (AnyCalendarKind::Coptic, 283), + (AnyCalendarKind::Dangi, 0), + (AnyCalendarKind::Ethiopian, 7), + (AnyCalendarKind::EthiopianAmeteAlem, -5493), + (AnyCalendarKind::Gregorian, 0), + (AnyCalendarKind::Hebrew, -3761), + (AnyCalendarKind::Indian, 78), + (AnyCalendarKind::HijriTabularTypeIIFriday, 621), + (AnyCalendarKind::HijriSimulatedMecca, 621), + (AnyCalendarKind::HijriTabularTypeIIThursday, 621), + (AnyCalendarKind::HijriUmmAlQura, 621), + (AnyCalendarKind::Iso, 0), + (AnyCalendarKind::Japanese, 0), + (AnyCalendarKind::JapaneseExtended, 0), + (AnyCalendarKind::Persian, 621), + (AnyCalendarKind::Roc, 1911), +]; + +#[test] +fn test_extended_year() { + let iso = icu_calendar::cal::Iso; + let m_01 = MonthCode::new_normal(1).unwrap(); + for (kind, extended_epoch) in EXTENDED_EPOCHS.iter() { + let calendar = Rc::new(AnyCalendar::new(*kind)); + + // Create the first date in the epoch year (extended_year = 0) + let date_in_epoch_year = + Date::try_new_from_codes(None, 0, m_01, 1, calendar.clone()).unwrap(); + let iso_date_in_epoch_year = date_in_epoch_year.to_calendar(iso); + assert_eq!( + iso_date_in_epoch_year.extended_year(), + *extended_epoch, + "Extended year for {date_in_epoch_year:?} should be {extended_epoch}" + ); + + // Test that for all calendars except Japanese, the *current* era is + // the same as that used for the extended year + // This date can be anything as long as it is vaguely modern. + // + // Note that this property is not *required* by the specification, new + // calendars may have epochs that do not follow this property. This + // property is strongly suggested by the specification as a rule of thumb + // to follow where possible. + let iso_date_in_2025 = Date::try_new_iso(2025, 1, 1).unwrap(); + let date_in_2025 = iso_date_in_2025.to_calendar(calendar.clone()); + + // The extended year should align with the year in the modern era or related ISO. + // There is a special case for Japanese since it has a modern era but uses ISO for the extended year. + if matches!( + kind, + AnyCalendarKind::Japanese | AnyCalendarKind::JapaneseExtended + ) { + assert_eq!( + date_in_2025.extended_year(), + 2025, + "Extended year for {date_in_2025:?} should be 2025" + ); + } else { + // Note: This code only works because 2025 is in the modern era for all calendars. + // These two function calls are not equivalent in general. + let expected = date_in_2025.year().era_year_or_related_iso(); + assert_eq!( + date_in_2025.extended_year(), + expected, + "Extended year for {date_in_2025:?} should be {expected}" + ); + } + } +} diff --git a/deps/crates/vendor/icu_calendar/tests/reference_year.rs b/deps/crates/vendor/icu_calendar/tests/reference_year.rs new file mode 100644 index 00000000000000..35293569a68a9c --- /dev/null +++ b/deps/crates/vendor/icu_calendar/tests/reference_year.rs @@ -0,0 +1,323 @@ +// This file is part of ICU4X. For terms of use, please see the file +// called LICENSE at the top level of the ICU4X source tree +// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +use std::{collections::HashSet, fmt::Debug}; + +use icu_calendar::{ + cal::*, + error::DateFromFieldsError, + options::{DateFromFieldsOptions, MissingFieldsStrategy, Overflow}, + types::{DateFields, MonthCode}, + Calendar, Date, Ref, +}; + +/// Test that a given calendar produces valid monthdays +/// +/// `valid_md_condition`, given (month_number, is_leap, day_number), should return whether or not +/// that combination is ever possible in that calendar +fn test_reference_year_impl(cal: C, valid_md_condition: impl Fn(u8, bool, u8) -> bool) +where + C: Calendar + Debug, +{ + // Test that all dates in a certain range behave according to Temporal + let mut month_days_seen = HashSet::new(); + let mut rd = Date::try_new_iso(1972, 12, 31).unwrap().to_rata_die(); + for _ in 1..2000 { + let date = Date::from_rata_die(rd, Ref(&cal)); + let month_day = (date.month().standard_code, date.day_of_month().0); + let mut fields = DateFields::default(); + fields.month_code = Some(month_day.0 .0.as_bytes()); + fields.day = Some(month_day.1); + let mut options = DateFromFieldsOptions::default(); + options.missing_fields_strategy = Some(MissingFieldsStrategy::Ecma); + let reference_date = Date::try_from_fields(fields, options, Ref(&cal)).unwrap(); + if month_days_seen.contains(&month_day) { + assert_ne!(date, reference_date, "{cal:?}"); + } else { + assert_eq!(date, reference_date, "{cal:?}"); + month_days_seen.insert(month_day); + } + rd -= 1; + } + // Test that all MonthDay values round-trip + for month_number in 1..=14 { + for is_leap in [false, true] { + let mut valid_day_number = 1; + let is_valid_month = valid_md_condition(month_number, is_leap, valid_day_number); + for day_number in 1..=32 { + if valid_md_condition(month_number, is_leap, day_number) { + valid_day_number = day_number; + } + let mut fields = DateFields::default(); + let mc = match is_leap { + false => MonthCode::new_normal(month_number), + true => MonthCode::new_leap(month_number), + }; + fields.month_code = mc.as_ref().map(|m| m.0.as_bytes()); + fields.day = Some(day_number); + let mut options = DateFromFieldsOptions::default(); + options.overflow = Some(Overflow::Constrain); + options.missing_fields_strategy = Some(MissingFieldsStrategy::Ecma); + let reference_date = match Date::try_from_fields(fields, options, Ref(&cal)) { + Ok(d) => { + assert!( + is_valid_month, + "try_from_fields passed but should have failed: {fields:?} => {d:?}" + ); + d + } + Err(DateFromFieldsError::MonthCodeNotInCalendar) => { + assert!( + !is_valid_month, + "try_from_fields failed but should have passed: {fields:?}" + ); + continue; + } + Err(e) => { + panic!("Unexpected error in month day from fields: {e}"); + } + }; + + // Test round-trip (to valid day number) + assert_eq!( + fields.month_code.unwrap(), + reference_date.month().standard_code.0.as_bytes(), + "{fields:?} {cal:?}" + ); + assert_eq!( + valid_day_number, + reference_date.day_of_month().0, + "{fields:?} {cal:?}" + ); + + // Test Overflow::Reject + options.overflow = Some(Overflow::Reject); + let reject_result = Date::try_from_fields(fields, options, Ref(&cal)); + if valid_day_number == day_number { + assert_eq!(reject_result, Ok(reference_date)); + } else { + assert!(matches!( + reject_result, + Err(DateFromFieldsError::Range { .. }) + )) + } + + // Test that ordinal months cause it to fail (even if the month code is still set) + fields.ordinal_month = Some(month_number); + let ordinal_result = Date::try_from_fields(fields, options, Ref(&cal)); + assert!(matches!( + ordinal_result, + Err(DateFromFieldsError::NotEnoughFields) + )); + } + } + } +} + +fn gregorian_md_condition(month_number: u8, is_leap: bool, day_number: u8) -> bool { + // No leap months + if is_leap { + return false; + } + + match month_number { + 1 | 3 | 5 | 7 | 8 | 10 | 12 => day_number <= 31, + 2 => day_number <= 29, + 4 | 6 | 9 | 11 => day_number <= 30, + _ => { + assert!(month_number > 12); + // No other months + false + } + } +} + +fn chinese_md_condition(month_number: u8, _is_leap: bool, day_number: u8) -> bool { + month_number <= 12 && day_number <= 30 +} + +fn coptic_md_condition(month_number: u8, is_leap: bool, day_number: u8) -> bool { + // No leap months + if is_leap { + return false; + } + match month_number { + 1..=12 => day_number <= 30, + 13 => day_number <= 6, + _ => false, + } +} + +fn hijri_md_condition(month_number: u8, is_leap: bool, day_number: u8) -> bool { + // No leap months + if is_leap { + return false; + } + month_number <= 12 && day_number <= 30 +} + +fn hijri_tabular_md_condition(month_number: u8, is_leap: bool, day_number: u8) -> bool { + // No leap months + if is_leap { + return false; + } + + if month_number > 12 { + return false; + } + + // Odd months have 30 days, even months have 29, except for M12 in a leap year + if month_number % 2 == 0 { + if month_number == 12 { + day_number <= 30 + } else { + day_number <= 29 + } + } else { + day_number <= 30 + } +} + +fn hebrew_md_condition(month_number: u8, is_leap: bool, day_number: u8) -> bool { + if is_leap { + return month_number == 5 && day_number <= 30; + } + match month_number { + 1 | 2 | 3 | 5 | 7 | 9 | 11 => day_number <= 30, + // Tevet, Adar, Iyar, Tammuz, Elul + 4 | 6 | 8 | 10 | 12 => day_number <= 29, + _ => { + assert!(month_number > 12); + // No other months + false + } + } +} + +#[test] +fn test_reference_year_buddhist() { + test_reference_year_impl(Buddhist, gregorian_md_condition) +} + +#[test] +fn test_reference_year_chinese() { + test_reference_year_impl(ChineseTraditional::new(), chinese_md_condition) +} + +#[test] +fn test_reference_year_coptic() { + test_reference_year_impl(Coptic, coptic_md_condition) +} + +#[test] +fn test_reference_year_korean() { + test_reference_year_impl(KoreanTraditional::new(), chinese_md_condition) +} + +#[test] +fn test_reference_year_ethiopian() { + test_reference_year_impl(Ethiopian::new(), coptic_md_condition) +} + +#[test] +fn test_reference_year_ethiopian_amete_alem() { + test_reference_year_impl( + Ethiopian::new_with_era_style(EthiopianEraStyle::AmeteAlem), + coptic_md_condition, + ) +} + +#[test] +fn test_reference_year_gregorian() { + test_reference_year_impl(Gregorian, gregorian_md_condition) +} + +#[test] +fn test_reference_year_julian() { + test_reference_year_impl(Julian, gregorian_md_condition) +} + +#[test] +fn test_reference_year_hebrew() { + test_reference_year_impl(Hebrew, hebrew_md_condition) +} + +#[test] +fn test_reference_year_indian() { + test_reference_year_impl(Indian, |month_number, is_leap, day_number| { + if is_leap { + // No leap months + return false; + } + // First half of the year has long months, second half short + if month_number <= 6 { + day_number <= 31 + } else if month_number <= 12 { + day_number <= 30 + } else { + // No larger months + false + } + }) +} + +#[test] +fn test_reference_year_hijri_tabular_type_ii_friday() { + test_reference_year_impl( + Hijri::new_tabular(HijriTabularLeapYears::TypeII, HijriTabularEpoch::Friday), + hijri_tabular_md_condition, + ) +} + +#[test] +fn test_reference_year_hijri_tabular_type_ii_thursday() { + test_reference_year_impl( + Hijri::new_tabular(HijriTabularLeapYears::TypeII, HijriTabularEpoch::Thursday), + hijri_tabular_md_condition, + ) +} + +#[test] +fn test_reference_year_hijri_umm_al_qura() { + test_reference_year_impl(Hijri::new_umm_al_qura(), hijri_md_condition) +} + +#[test] +fn test_reference_year_iso() { + test_reference_year_impl(Iso, gregorian_md_condition) +} + +#[test] +fn test_reference_year_japanese() { + test_reference_year_impl(Japanese::new(), gregorian_md_condition) +} + +#[test] +fn test_reference_year_japanese_extended() { + test_reference_year_impl(JapaneseExtended::new(), gregorian_md_condition) +} + +#[test] +fn test_reference_year_persian() { + test_reference_year_impl(Persian, |month_number, is_leap, day_number| { + if is_leap { + // No leap months + return false; + } + // First half of the year has long months, second half short + if month_number <= 6 { + day_number <= 31 + } else if month_number <= 12 { + day_number <= 30 + } else { + // No larger months + false + } + }) +} + +#[test] +fn test_reference_year_roc() { + test_reference_year_impl(Roc, gregorian_md_condition) +} diff --git a/deps/crates/vendor/icu_calendar_data/.cargo-checksum.json b/deps/crates/vendor/icu_calendar_data/.cargo-checksum.json index 1f89ad9e1d30ab..5581eabccf52bd 100644 --- a/deps/crates/vendor/icu_calendar_data/.cargo-checksum.json +++ b/deps/crates/vendor/icu_calendar_data/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"53ee9b1dd6ad1a0b1dcb72e7c08db14631db21ecbf7f9f1ed3b10f29b6a8899a","LICENSE":"f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2","README.md":"c34a8f4d0526ef4b3acc8383a1ab33422dc040dd3b9cf5bf0684125beb8fdd71","build.rs":"c2d446772e3d766a804963dbf36e51729f910920f91f4b68c0c199fe6ca0853e","data/calendar_chinese_v1.rs.data":"245c945efcd1ab04d9aad235617d9580bac52061403d371c47d23cce14eaab65","data/calendar_dangi_v1.rs.data":"916f004b0aba23972d96faffb83a06459034a8603037c35ea0e5d4e084bfbd2a","data/calendar_hijri_simulated_mecca_v1.rs.data":"111da8179793ee6d03091a525419e3d34dc6018474189e2f246f0775f3324814","data/calendar_japanese_extended_v1.rs.data":"24c71e99ec40cfecdcd10e2e006b8b708498f2427b7fdf7f63ae2ecbdb7e8b61","data/calendar_japanese_modern_v1.rs.data":"f34dd70c859071b74235200d3389a22c8fb08a895fb326e11fbc1be16c92e686","data/calendar_week_v1.rs.data":"908fba042125ff2c1ff911619ef5926423dd0e2d15f8c70ea9838e3a357002ec","data/mod.rs":"9a9f9b8da50eba75f93763b90bf068cf9de34795a9baca05146912dab9fc1bc8","src/lib.rs":"62940139b0cb9cbe9629ab45e716b095403f13042b08c378f17de8357ccab253"},"package":"7219c8639ab936713a87b571eed2bc2615aa9137e8af6eb221446ee5644acc18"} \ No newline at end of file +{"files":{".cargo_vcs_info.json":"5ddfa3bbe4563249b2050508901cbefb05bd351ea39f5f4add8bc520346ce932","Cargo.lock":"af8b0f1887466167d9776494d3fd9cd8d63b742147ef69538987e7ec190da413","Cargo.toml":"ecdae7056aa05f5e981175be5c1ba744f819438cef7db31d3f9873fbbfe22575","Cargo.toml.orig":"31d1f8d246401f127cd0738522290375cd6124a8ef9232a650aded78f8071ded","LICENSE":"f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2","README.md":"089095cfdb8ce866d7ca71b51433144fb4878dc4ca9b5590b2327b11fdb64b1b","build.rs":"c2d446772e3d766a804963dbf36e51729f910920f91f4b68c0c199fe6ca0853e","data/calendar_japanese_extended_v1.rs.data":"079e4f46ffd69977a95364c12df5455342cd8dc03593b44d2fb73fe06c7145ef","data/calendar_japanese_modern_v1.rs.data":"3b836a21d5e537e06e3b767d44aee023222113415bcc3dbf87248fa89de70928","data/calendar_week_v1.rs.data":"c59edb26ec8b391b52ffa6ad9088d8a51b8353cffc04268701a824e0e9b76c21","data/mod.rs":"ad146e2fac0e7858fea7a10082a8bd63ae0a014b6ff885b041c66c7cc2579bbd","src/lib.rs":"bfc8989a13fe15781d30b59aa152d1806d99a77dbf326d118c5e196a534ccef0"},"package":"527f04223b17edfe0bd43baf14a0cb1b017830db65f3950dc00224860a9a446d"} \ No newline at end of file diff --git a/deps/crates/vendor/icu_calendar_data/.cargo_vcs_info.json b/deps/crates/vendor/icu_calendar_data/.cargo_vcs_info.json new file mode 100644 index 00000000000000..266c749a288779 --- /dev/null +++ b/deps/crates/vendor/icu_calendar_data/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "38a49da495248dd1ded84cf306e4ca42e64d5bb3" + }, + "path_in_vcs": "provider/data/calendar" +} \ No newline at end of file diff --git a/deps/crates/vendor/icu_calendar_data/Cargo.lock b/deps/crates/vendor/icu_calendar_data/Cargo.lock new file mode 100644 index 00000000000000..5b794b991b85ba --- /dev/null +++ b/deps/crates/vendor/icu_calendar_data/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "icu_calendar_data" +version = "2.1.1" diff --git a/deps/crates/vendor/icu_calendar_data/Cargo.toml b/deps/crates/vendor/icu_calendar_data/Cargo.toml index 48da7be47196bc..0f20ba005c23ec 100644 --- a/deps/crates/vendor/icu_calendar_data/Cargo.toml +++ b/deps/crates/vendor/icu_calendar_data/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.82" +rust-version = "1.83" name = "icu_calendar_data" -version = "2.0.0" +version = "2.1.1" authors = ["The ICU4X Project Developers"] build = "build.rs" include = [ @@ -40,10 +40,10 @@ license = "Unicode-3.0" repository = "https://github.com/unicode-org/icu4x" [package.metadata.sources.cldr] -tagged = "47.0.0" +tagged = "48.0.0" [package.metadata.sources.icuexport] -tagged = "icu4x/2025-05-01/77.x" +tagged = "release-78.1rc" [package.metadata.sources.segmenter_lstm] tagged = "v0.1.0" diff --git a/deps/crates/vendor/icu_calendar_data/Cargo.toml.orig b/deps/crates/vendor/icu_calendar_data/Cargo.toml.orig new file mode 100644 index 00000000000000..238a48230dabce --- /dev/null +++ b/deps/crates/vendor/icu_calendar_data/Cargo.toml.orig @@ -0,0 +1,27 @@ +# This file is part of ICU4X. For terms of use, please see the file +# called LICENSE at the top level of the ICU4X source tree +# (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +[package] +name = "icu_calendar_data" +description = "Data for the icu_calendar crate" +license = "Unicode-3.0" +version.workspace = true + +authors.workspace = true +categories.workspace = true +edition.workspace = true +homepage.workspace = true +include.workspace = true +repository.workspace = true +rust-version.workspace = true + +[package.metadata.sources] +cldr = { tagged = "48.0.0" } +icuexport = { tagged = "release-78.1rc" } +segmenter_lstm = { tagged = "v0.1.0" } + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(icu4x_custom_data)'] } + +[dependencies] diff --git a/deps/crates/vendor/icu_calendar_data/README.md b/deps/crates/vendor/icu_calendar_data/README.md index 19c1f48292c481..b90473a6571cc5 100644 --- a/deps/crates/vendor/icu_calendar_data/README.md +++ b/deps/crates/vendor/icu_calendar_data/README.md @@ -4,7 +4,7 @@ Data for the `icu_calendar` crate -This data was generated with CLDR version 47.0.0, ICU version icu4x/2025-05-01/77.x, and +This data was generated with CLDR version 48.0.0, ICU version release-78.1rc, and LSTM segmenter version v0.1.0. diff --git a/deps/crates/vendor/icu_calendar_data/data/calendar_chinese_v1.rs.data b/deps/crates/vendor/icu_calendar_data/data/calendar_chinese_v1.rs.data deleted file mode 100644 index 944a49c45490c8..00000000000000 --- a/deps/crates/vendor/icu_calendar_data/data/calendar_chinese_v1.rs.data +++ /dev/null @@ -1,75 +0,0 @@ -// @generated -/// Implement `DataProvider` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -/// -/// Using this implementation will embed the following data in the binary's data segment: -/// * 782B[^1] for the singleton data struct -/// -/// [^1]: these numbers can be smaller in practice due to linker deduplication -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_calendar_chinese_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.82"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.82"] - impl $provider { - #[doc(hidden)] - pub const SINGLETON_CALENDAR_CHINESE_V1: &'static ::DataStruct = &icu::calendar::provider::chinese_based::ChineseBasedCache { first_related_iso_year: 1900i32, data: unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xD26\x19R\x07>\xA5\x0E(J\xD6\x14K\x068\x9B\n Z\xB5\x0Cj\x052Y\x0B\x1CRw\x06R\x07,%\xFB\x16%\x0B+\x05([\xEA\x10\xAD\n6j\x05\"U\xBB\x0C\xA4\x0B2I\x0B\x1C\x93z\x06\x95\n,-\x15\x156\x05:\xAD\n$\xAA\xD5\x10\xB2\x054\xA5\r\x1EJ\x9D\nJ\r0\x95*\x19\x97\n\xD5\x06&\xC9\xD6\x12I\x078\x93\x06\"+\xB5\n+\x050[\n\x1AZu\x06j\x05*U\x1B\x15\xA4\x0B\xA5\r(J\xFD\x12J\r8\x95\x0C\".\xB5\x0CV\x050\xB5\n\x1A\xB2u\x06\xD2\x06,\xA5\xEE\x14%\x07:K\x06$\x97\xCC\x0E\xAB\x0C2Z\x05\x1E\xD6\x8A\x08i\x0B.R\x97\x19R\x0B>%\x0B(K\xFA\x12K\n6\xAB\x04 [\xC5\n\xAD\x050j\x0B\x1AR{\x06\x92\r,%\x1D\x17%\r:U\n$\xAD\xD4\x0E\xB6\x044\xB5\x05\x1C\xAA\x8D\x08\xC9\x0E.\x92>\x1B\x92\x0E>&\r(V\xEA\x12W\n6V\x05 \xD5\xA6\nU\x070I\x07\x1C\x93\x8E\x04\x93\x06*+\x15\x15+\x05:[\n\"Z\xD5\x0Ej\x054e\x0B\x1EJ\xB7\x08J\x0B.\x95:\x19\x95\n>-\x05&\xAD\xEA\x10\xB5\n6\xAA\x05\"\xA5\xAB\n\xA5\r0J\r\x1C\x95\x9C\x06\x96\x0C*N\x19\x15V\x05:\xB5\n$\xB2\xD5\x0E\xD2\x064\xA5\x0E\x1EJ\xAE\n\x8B\x06,\x97,\x17\xAB\x04<[\x05&\xD6\xEA\x10j\x0B6R\x07\"%\xB7\x0CE\x0B0\x8B\n\x1A\x9Bt\x04\xAB\x04*[\t\x15\xAD\x05:\xAA\x0B&R\xDB\x12\x92\r6%\r K\xBA\nU\n0\xADT\x19\xB6\x04>\xB5\x06(\xAA\xED\x14\xC9\x0E8\x92\x0E$&\xBD\x0E*\r4V\n\x1C\xB6\x94\x06V\x05,\xD5\n\x17U\x0B:J\x07&\x93\xCE\x10\x95\x066+\x05\x1EW\xAA\x08\x9B\n.Z\x95\x1Bj\x05>e\x0B(J\xF7\x14J\x0B:\x15\x0B\"+\xD5\x0CM\x052\xAD\n\x1Cju\x06\xAA\x05,\xA5\x0B\x17\xA5\r for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponse { payload: icu_provider::DataPayload::from_static_ref(Self::SINGLETON_CALENDAR_CHINESE_V1), metadata: icu_provider::DataResponseMetadata::default() }) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) - } - } - } - }; - ($ provider : ty , ITER) => { - __impl_calendar_chinese_v1!($provider); - #[clippy::msrv = "1.82"] - impl icu_provider::IterableDataProvider for $provider { - fn iter_ids(&self) -> Result>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; - ($ provider : ty , DRY) => { - __impl_calendar_chinese_v1!($provider); - #[clippy::msrv = "1.82"] - impl icu_provider::DryDataProvider for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) - } - } - } - }; - ($ provider : ty , DRY , ITER) => { - __impl_calendar_chinese_v1!($provider); - #[clippy::msrv = "1.82"] - impl icu_provider::DryDataProvider for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) - } - } - } - #[clippy::msrv = "1.82"] - impl icu_provider::IterableDataProvider for $provider { - fn iter_ids(&self) -> Result>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; -} -#[doc(inline)] -pub use __impl_calendar_chinese_v1 as impl_calendar_chinese_v1; diff --git a/deps/crates/vendor/icu_calendar_data/data/calendar_dangi_v1.rs.data b/deps/crates/vendor/icu_calendar_data/data/calendar_dangi_v1.rs.data deleted file mode 100644 index 30045896317596..00000000000000 --- a/deps/crates/vendor/icu_calendar_data/data/calendar_dangi_v1.rs.data +++ /dev/null @@ -1,75 +0,0 @@ -// @generated -/// Implement `DataProvider` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -/// -/// Using this implementation will embed the following data in the binary's data segment: -/// * 782B[^1] for the singleton data struct -/// -/// [^1]: these numbers can be smaller in practice due to linker deduplication -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_calendar_dangi_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.82"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.82"] - impl $provider { - #[doc(hidden)] - pub const SINGLETON_CALENDAR_DANGI_V1: &'static ::DataStruct = &icu::calendar::provider::chinese_based::ChineseBasedCache { first_related_iso_year: 1900i32, data: unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\xD26\x19R\x07>\xA5\x0E(J\xCE\x14K\x058\x97\n V\xB5\x0Cj\x052U\x0B\x1CRw\x06R\x07,%\xF7\x16%\x0B+\x05([\xEA\x10m\t6j\x0B\"T\xBB\x0E\xA4\x0B2I\x0B\x1C\x93z\x06\x95\n,+\x15\x15-\x05:\xAD\n$j\xD5\x10\xB2\r4\xA4\r I\x9D\nJ\r0\x95:\x19\x96\n>V\x05(\xB5\xEA\x12\xD5\n6\xD2\x06\"\xA5\xAE\x0C\xA5\x0E2J\x0E\x1C\x96\x8C\x06\x9B\n*V\x15\x17j\x05:Y\x0B$R\xD7\x10R\x076%\x07\x1EK\xB6\x08K\n.\xAB2\x19\xAD\x02\xD4\x06(\xC9\xCE\x12I\x078\x93\x06\"'\xB5\n+\x050[\n\x1AZu\x06j\x03*U\x1B\x15\xA4\x0B\xA5\r(J\xDD\x12J\r8\x95\n\"-\xB5\x0CV\x050\xB5\n\x1A\xAAu\x06\xD2\x06,\xA5\xEE\x14\xA5\x0E:J\x0E&\x96\xCC\x10\x9B\x0C2Z\x05\x1E\xD5\x8A\x08i\x0B.R\x97\x19R\x07>%\x0B(K\xF6\x12K\n6\xAB\x04 [\xC5\nm\x050i\x0B\x1AR{\x06\x92\r,%\x1D\x17%\r:M\n$\xAD\xD4\x0E\xB6\x024\xB5\x05\x1C\xA9\x8D\x08\xA9\x0E.\x92=\x1B\x92\x0E>&\r(V\xEA\x12W\n6\xD6\x04 \xB5\xA6\n\xD5\x060\xC9\x0E\x1C\x92\x8E\x06\x93\x06*+\x15\x15+\x05:[\n\"Z\xD5\x0Ej\x054U\x0B\x1EI\xB7\x08I\x0B.\x93:\x19\x95\n>-\x05&\xAD\xEA\x10\xB5\n6\xAA\x05\"\xA5\xAB\n\xA5\r0J\r\x1C\x95\x9A\x06\x95\x0C*.\x15\x15V\x05:\xB5\n$\xB2\xD5\x0E\xD2\x064\xA5\x0E\x1EJ\xBE\nJ\x06.\x97,\x17\xAB\x0C\xB5\x05(\xAA\xED\x14\xC9\x0E8\x92\x0E$%\xBD\x0E&\r4V\n\x1C\xAE\x94\x06\xD6\x04,\xD5\n\x17\xD5\x06:\xC9\x06&\x93\xCE\x10\x93\x066+\x05\x1EW\xAA\x08[\n.ZU\x1Bj\x05>e\x0B(J\xF7\x14I\x0B:\x95\n\"+\xD5\x0C-\x052\xAD\n\x1Cju\x06\xAA\x05,\xA5\x0B\x17\xA5\r for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponse { payload: icu_provider::DataPayload::from_static_ref(Self::SINGLETON_CALENDAR_DANGI_V1), metadata: icu_provider::DataResponseMetadata::default() }) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) - } - } - } - }; - ($ provider : ty , ITER) => { - __impl_calendar_dangi_v1!($provider); - #[clippy::msrv = "1.82"] - impl icu_provider::IterableDataProvider for $provider { - fn iter_ids(&self) -> Result>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; - ($ provider : ty , DRY) => { - __impl_calendar_dangi_v1!($provider); - #[clippy::msrv = "1.82"] - impl icu_provider::DryDataProvider for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) - } - } - } - }; - ($ provider : ty , DRY , ITER) => { - __impl_calendar_dangi_v1!($provider); - #[clippy::msrv = "1.82"] - impl icu_provider::DryDataProvider for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) - } - } - } - #[clippy::msrv = "1.82"] - impl icu_provider::IterableDataProvider for $provider { - fn iter_ids(&self) -> Result>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; -} -#[doc(inline)] -pub use __impl_calendar_dangi_v1 as impl_calendar_dangi_v1; diff --git a/deps/crates/vendor/icu_calendar_data/data/calendar_hijri_simulated_mecca_v1.rs.data b/deps/crates/vendor/icu_calendar_data/data/calendar_hijri_simulated_mecca_v1.rs.data deleted file mode 100644 index 4803503a2a71f8..00000000000000 --- a/deps/crates/vendor/icu_calendar_data/data/calendar_hijri_simulated_mecca_v1.rs.data +++ /dev/null @@ -1,75 +0,0 @@ -// @generated -/// Implement `DataProvider` on the given struct using the data -/// hardcoded in this file. This allows the struct to be used with -/// `icu`'s `_unstable` constructors. -/// -/// Using this implementation will embed the following data in the binary's data segment: -/// * 532B[^1] for the singleton data struct -/// -/// [^1]: these numbers can be smaller in practice due to linker deduplication -#[doc(hidden)] -#[macro_export] -macro_rules! __impl_calendar_hijri_simulated_mecca_v1 { - ($ provider : ty) => { - #[clippy::msrv = "1.82"] - const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.82"] - impl $provider { - #[doc(hidden)] - pub const SINGLETON_CALENDAR_HIJRI_SIMULATED_MECCA_V1: &'static ::DataStruct = &icu::calendar::provider::hijri::HijriData { first_extended_year: 1317i32, data: unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"O9\xAE\x02\xAD\x05\xA9\r\x92-E-\x8D\n-\x05m\x05j\x0BT'I\x07\x8B\x0E&-V\x05\xAE\nl#j\x07T'\xA5\x06M\x05]\n\\\x05\xBA\n\xB4%\xAA\rT-\xAA*6\t\xB6\x02u5\xEA\nT'\xA9\x06+\x05[\n6\x05v\nl\x05Y\x0BJ+\x95\n+\t[\nZ\x05\xD5\n\xD2&\xA5\x0EJ.\x96\x0C.\tm\nj\x05Y\x0BI/\x94.*-Z*\xBA\x04\xB5\x05\xB2\x0B\xA4+I+\x95\n\xB5\x04m\t\xEA\x02\xE9\x06\xD2\x0E\xA4.*-V\n\xB6\x04u\x05\xEA\n\xE4*\xA9*S\n\xAB\x04W9\xB6\x02\xB5\t\xAA\x05S\r&-N\n\xAE\x04m\t\xEA\x02\xD5\n\xA9\x06S\x05\xA7\x0479\xB5\x02k\x05i\x0BR'\xA5\x06K\x05\xAB\x02[5\xEA\n\xD4%\xC9\r\x92-%+U\t\xAD\x02k5\xE9\n\xD2%\xA5\x05K\x05\x97\x02\xB74\xB6\t\xB4\x03\xA9\x0BJ+\x96\n.\t^\x02\xDD4\xDA\n\xD4%\xA5\x05K\x05W:\xAE\x04n\tl\x03U\x0BJ'\x8D\x06'\x05W\n\xB6\x04\xB5\x06\xAA\r\xA4-I-\x95\n-\x05\xAD\nZ\x03U\x07J\x0F\x92.&+V\x06\xAE\x02u\x05j\x0BT'\xA9&U\x06\xAD\x04]9\xBA\x02\xB9\x05\xB2\rT-*+V\t\xB6\x02u\x05Z\x0B\xD4&\xA9\x06K\x05\x9B\x0C6\tv\x02u\x05i\rR-%\rK\n\x9B\x04[9\xDA\n\xD4&\xA9\x0EJ.\x96,-\tm\nl\x05i\x0BQ/\xA4.J-Z*\xDA\x04\xB9\t\xB4\x05\xA9\x0BR+\xA5\nU\x05m\nl\x05\xE9\x06\xD2.\xA4.J-V\n\xB6\x04u\t\xEA\x04\xE5\n\xAA*U\n\xAB\x04W\x02\xB74\xB5\n\xAA\x05\x95\r*-V\n\xAE\x08m\t\xEA\x02\xD5\n\xA9\x06S\x06'\x05W9\xB5\x02\xB5\x05\xAA\x0B\xA2'E'\x93\x06\xAB\x04k9\xEA\n\xD4%\xC9\r\xA2-%-U\t\xAD\x02m\x05\xEA\t\xD4%\xA5\x05K\x05") } }; - } - #[clippy::msrv = "1.82"] - impl icu_provider::DataProvider for $provider { - fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponse { payload: icu_provider::DataPayload::from_static_ref(Self::SINGLETON_CALENDAR_HIJRI_SIMULATED_MECCA_V1), metadata: icu_provider::DataResponseMetadata::default() }) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) - } - } - } - }; - ($ provider : ty , ITER) => { - __impl_calendar_hijri_simulated_mecca_v1!($provider); - #[clippy::msrv = "1.82"] - impl icu_provider::IterableDataProvider for $provider { - fn iter_ids(&self) -> Result>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; - ($ provider : ty , DRY) => { - __impl_calendar_hijri_simulated_mecca_v1!($provider); - #[clippy::msrv = "1.82"] - impl icu_provider::DryDataProvider for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) - } - } - } - }; - ($ provider : ty , DRY , ITER) => { - __impl_calendar_hijri_simulated_mecca_v1!($provider); - #[clippy::msrv = "1.82"] - impl icu_provider::DryDataProvider for $provider { - fn dry_load(&self, req: icu_provider::DataRequest) -> Result { - if req.id.locale.is_unknown() { - Ok(icu_provider::DataResponseMetadata::default()) - } else { - Err(icu_provider::DataErrorKind::InvalidRequest.with_req(::INFO, req)) - } - } - } - #[clippy::msrv = "1.82"] - impl icu_provider::IterableDataProvider for $provider { - fn iter_ids(&self) -> Result>, icu_provider::DataError> { - Ok([Default::default()].into_iter().collect()) - } - } - }; -} -#[doc(inline)] -pub use __impl_calendar_hijri_simulated_mecca_v1 as impl_calendar_hijri_simulated_mecca_v1; diff --git a/deps/crates/vendor/icu_calendar_data/data/calendar_japanese_extended_v1.rs.data b/deps/crates/vendor/icu_calendar_data/data/calendar_japanese_extended_v1.rs.data index 338b69e5c61508..96a1dd8fd31809 100644 --- a/deps/crates/vendor/icu_calendar_data/data/calendar_japanese_extended_v1.rs.data +++ b/deps/crates/vendor/icu_calendar_data/data/calendar_japanese_extended_v1.rs.data @@ -7,18 +7,23 @@ /// * 5238B[^1] for the singleton data struct /// /// [^1]: these numbers can be smaller in practice due to linker deduplication +/// +/// This macro requires the following crates: +/// * `icu` +/// * `icu_provider` +/// * `zerovec` #[doc(hidden)] #[macro_export] macro_rules! __impl_calendar_japanese_extended_v1 { ($ provider : ty) => { - #[clippy::msrv = "1.82"] + #[clippy::msrv = "1.83"] const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.82"] + #[clippy::msrv = "1.83"] impl $provider { #[doc(hidden)] pub const SINGLETON_CALENDAR_JAPANESE_EXTENDED_V1: &'static ::DataStruct = &icu::calendar::provider::JapaneseEras { dates_to_eras: unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"\x85\x02\0\0\x06\x13taika-645\0\0\0\0\0\0\0\x8A\x02\0\0\x02\x0Fhakuchi-650\0\0\0\0\0\xA0\x02\0\0\x01\x01hakuho-672\0\0\0\0\0\0\xAE\x02\0\0\x07\x14shucho-686\0\0\0\0\0\0\xBD\x02\0\0\x03\x15taiho-701\0\0\0\0\0\0\0\xC0\x02\0\0\x05\nkeiun-704\0\0\0\0\0\0\0\xC4\x02\0\0\x01\x0Bwado-708\0\0\0\0\0\0\0\0\xCB\x02\0\0\t\x02reiki-715\0\0\0\0\0\0\0\xCD\x02\0\0\x0B\x11yoro-717\0\0\0\0\0\0\0\0\xD4\x02\0\0\x02\x04jinki-724\0\0\0\0\0\0\0\xD9\x02\0\0\x08\x05tenpyo-729\0\0\0\0\0\0\xED\x02\0\0\x04\x0Etenpyokampo-749\0\xED\x02\0\0\x07\x02tenpyoshoho-749\0\xF5\x02\0\0\x08\x12tenpyohoji-757\0\0\xFD\x02\0\0\x01\x07tenpyojingo-765\0\xFF\x02\0\0\x08\x10jingokeiun-767\0\0\x02\x03\0\0\n\x01hoki-770\0\0\0\0\0\0\0\0\r\x03\0\0\x01\x01teno-781\0\0\0\0\0\0\0\0\x0E\x03\0\0\x08\x13enryaku-782\0\0\0\0\0&\x03\0\0\x05\x12daido-806\0\0\0\0\0\0\0*\x03\0\0\t\x13konin-810\0\0\0\0\0\0\08\x03\0\0\x01\x05tencho-824\0\0\0\0\0\0B\x03\0\0\x01\x03jowa-834\0\0\0\0\0\0\0\0P\x03\0\0\x06\rkajo-848\0\0\0\0\0\0\0\0S\x03\0\0\x04\x1Cninju-851\0\0\0\0\0\0\0V\x03\0\0\x0B\x1Esaiko-854\0\0\0\0\0\0\0Y\x03\0\0\x02\x15tenan-857\0\0\0\0\0\0\0[\x03\0\0\x04\x0Fjogan-859\0\0\0\0\0\0\0m\x03\0\0\x04\x10gangyo-877\0\0\0\0\0\0u\x03\0\0\x02\x15ninna-885\0\0\0\0\0\0\0y\x03\0\0\x04\x1Bkanpyo-889\0\0\0\0\0\0\x82\x03\0\0\x04\x1Ashotai-898\0\0\0\0\0\0\x85\x03\0\0\x07\x0Fengi-901\0\0\0\0\0\0\0\0\x9B\x03\0\0\x04\x0Bencho-923\0\0\0\0\0\0\0\xA3\x03\0\0\x04\x1Ajohei-931\0\0\0\0\0\0\0\xAA\x03\0\0\x05\x16tengyo-938\0\0\0\0\0\0\xB3\x03\0\0\x04\x16tenryaku-947\0\0\0\0\xBD\x03\0\0\n\x1Btentoku-957\0\0\0\0\0\xC1\x03\0\0\x02\x10owa-961\0\0\0\0\0\0\0\0\0\xC4\x03\0\0\x07\nkoho-964\0\0\0\0\0\0\0\0\xC8\x03\0\0\x08\ranna-968\0\0\0\0\0\0\0\0\xCA\x03\0\0\x03\x19tenroku-970\0\0\0\0\0\xCD\x03\0\0\x0C\x14tenen-973\0\0\0\0\0\0\0\xD0\x03\0\0\x07\rjogen-976\0\0\0\0\0\0\0\xD2\x03\0\0\x0B\x1Dtengen-978\0\0\0\0\0\0\xD7\x03\0\0\x04\x0Feikan-983\0\0\0\0\0\0\0\xD9\x03\0\0\x04\x1Bkanna-985\0\0\0\0\0\0\0\xDB\x03\0\0\x04\x05eien-987\0\0\0\0\0\0\0\0\xDD\x03\0\0\x08\x08eiso-989\0\0\0\0\0\0\0\0\xDE\x03\0\0\x0B\x07shoryaku-990\0\0\0\0\xE3\x03\0\0\x02\x16chotoku-995\0\0\0\0\0\xE7\x03\0\0\x01\rchoho-999\0\0\0\0\0\0\0\xEC\x03\0\0\x07\x14kanko-1004\0\0\0\0\0\0\xF4\x03\0\0\x0C\x19chowa-1012\0\0\0\0\0\0\xF9\x03\0\0\x04\x17kannin-1017\0\0\0\0\0\xFD\x03\0\0\x02\x02jian-1021\0\0\0\0\0\0\0\0\x04\0\0\x07\rmanju-1024\0\0\0\0\0\0\x04\x04\0\0\x07\x19chogen-1028\0\0\0\0\0\r\x04\0\0\x04\x15choryaku-1037\0\0\0\x10\x04\0\0\x0B\nchokyu-1040\0\0\0\0\0\x14\x04\0\0\x0B\x18kantoku-1044\0\0\0\0\x16\x04\0\0\x04\x0Eeisho-1046\0\0\0\0\0\0\x1D\x04\0\0\x01\x0Btengi-1053\0\0\0\0\0\0\"\x04\0\0\x08\x1Dkohei-1058\0\0\0\0\0\0)\x04\0\0\x08\x02jiryaku-1065\0\0\0\0-\x04\0\0\x04\renkyu-1069\0\0\0\0\0\x002\x04\0\0\x08\x17shoho-1074\0\0\0\0\0\x005\x04\0\0\x0B\x11shoryaku-1077\0\0\09\x04\0\0\x02\neiho-1081\0\0\0\0\0\0\0<\x04\0\0\x02\x07otoku-1084\0\0\0\0\0\0?\x04\0\0\x04\x07kanji-1087\0\0\0\0\0\0F\x04\0\0\x0C\x0Fkaho-1094\0\0\0\0\0\0\0H\x04\0\0\x0C\x11eicho-1096\0\0\0\0\0\0I\x04\0\0\x0B\x15jotoku-1097\0\0\0\0\0K\x04\0\0\x08\x1Ckowa-1099\0\0\0\0\0\0\0P\x04\0\0\x02\nchoji-1104\0\0\0\0\0\0R\x04\0\0\x04\tkasho-1106\0\0\0\0\0\0T\x04\0\0\x08\x03tennin-1108\0\0\0\0\0V\x04\0\0\x07\rtenei-1110\0\0\0\0\0\0Y\x04\0\0\x07\reikyu-1113\0\0\0\0\0\0^\x04\0\0\x04\x03genei-1118\0\0\0\0\0\0`\x04\0\0\x04\nhoan-1120\0\0\0\0\0\0\0d\x04\0\0\x04\x03tenji-1124\0\0\0\0\0\0f\x04\0\0\x01\x16daiji-1126\0\0\0\0\0\0k\x04\0\0\x01\x1Dtensho-1131\0\0\0\0\0l\x04\0\0\x08\x0Bchosho-1132\0\0\0\0\0o\x04\0\0\x04\x1Bhoen-1135\0\0\0\0\0\0\0u\x04\0\0\x07\neiji-1141\0\0\0\0\0\0\0v\x04\0\0\x04\x1Ckoji-1142\0\0\0\0\0\0\0x\x04\0\0\x02\x17tenyo-1144\0\0\0\0\0\0y\x04\0\0\x07\x16kyuan-1145\0\0\0\0\0\0\x7F\x04\0\0\x01\x1Aninpei-1151\0\0\0\0\0\x82\x04\0\0\n\x1Ckyuju-1154\0\0\0\0\0\0\x84\x04\0\0\x04\x1Bhogen-1156\0\0\0\0\0\0\x87\x04\0\0\x04\x14heiji-1159\0\0\0\0\0\0\x88\x04\0\0\x01\neiryaku-1160\0\0\0\0\x89\x04\0\0\t\x04oho-1161\0\0\0\0\0\0\0\0\x8B\x04\0\0\x03\x1Dchokan-1163\0\0\0\0\0\x8D\x04\0\0\x06\x05eiman-1165\0\0\0\0\0\0\x8E\x04\0\0\x08\x1Bninan-1166\0\0\0\0\0\0\x91\x04\0\0\x04\x08kao-1169\0\0\0\0\0\0\0\0\x93\x04\0\0\x04\x15shoan-1171\0\0\0\0\0\0\x97\x04\0\0\x07\x1Cangen-1175\0\0\0\0\0\0\x99\x04\0\0\x08\x04jisho-1177\0\0\0\0\0\0\x9D\x04\0\0\x07\x0Eyowa-1181\0\0\0\0\0\0\0\x9E\x04\0\0\x05\x1Bjuei-1182\0\0\0\0\0\0\0\xA0\x04\0\0\x04\x10genryaku-1184\0\0\0\xA1\x04\0\0\x08\x0Ebunji-1185\0\0\0\0\0\0\xA6\x04\0\0\x04\x0Bkenkyu-1190\0\0\0\0\0\xAF\x04\0\0\x04\x1Bshoji-1199\0\0\0\0\0\0\xB1\x04\0\0\x02\rkennin-1201\0\0\0\0\0\xB4\x04\0\0\x02\x14genkyu-1204\0\0\0\0\0\xB6\x04\0\0\x04\x1Bkenei-1206\0\0\0\0\0\0\xB7\x04\0\0\n\x19jogen-1207\0\0\0\0\0\0\xBB\x04\0\0\x03\tkenryaku-1211\0\0\0\xBD\x04\0\0\x0C\x06kenpo-1213\0\0\0\0\0\0\xC3\x04\0\0\x04\x0Cjokyu-1219\0\0\0\0\0\0\xC6\x04\0\0\x04\rjoo-1222\0\0\0\0\0\0\0\0\xC8\x04\0\0\x0B\x14gennin-1224\0\0\0\0\0\xC9\x04\0\0\x04\x14karoku-1225\0\0\0\0\0\xCB\x04\0\0\x0C\nantei-1227\0\0\0\0\0\0\xCD\x04\0\0\x03\x05kanki-1229\0\0\0\0\0\0\xD0\x04\0\0\x04\x02joei-1232\0\0\0\0\0\0\0\xD1\x04\0\0\x04\x0Ftenpuku-1233\0\0\0\0\xD2\x04\0\0\x0B\x05bunryaku-1234\0\0\0\xD3\x04\0\0\t\x13katei-1235\0\0\0\0\0\0\xD6\x04\0\0\x0B\x17ryakunin-1238\0\0\0\xD7\x04\0\0\x02\x07eno-1239\0\0\0\0\0\0\0\0\xD8\x04\0\0\x07\x10ninji-1240\0\0\0\0\0\0\xDB\x04\0\0\x02\x1Akangen-1243\0\0\0\0\0\xDF\x04\0\0\x02\x1Choji-1247\0\0\0\0\0\0\0\xE1\x04\0\0\x03\x12kencho-1249\0\0\0\0\0\xE8\x04\0\0\n\x05kogen-1256\0\0\0\0\0\0\xE9\x04\0\0\x03\x0Eshoka-1257\0\0\0\0\0\0\xEB\x04\0\0\x03\x1Ashogen-1259\0\0\0\0\0\xEC\x04\0\0\x04\rbuno-1260\0\0\0\0\0\0\0\xED\x04\0\0\x02\x14kocho-1261\0\0\0\0\0\0\xF0\x04\0\0\x02\x1Cbunei-1264\0\0\0\0\0\0\xFB\x04\0\0\x04\x19kenji-1275\0\0\0\0\0\0\xFE\x04\0\0\x02\x1Ckoan-1278\0\0\0\0\0\0\0\x08\x05\0\0\x04\x1Cshoo-1288\0\0\0\0\0\0\0\r\x05\0\0\x08\x05einin-1293\0\0\0\0\0\0\x13\x05\0\0\x04\x19shoan-1299\0\0\0\0\0\0\x16\x05\0\0\x0B\x15kengen-1302\0\0\0\0\0\x17\x05\0\0\x08\x05kagen-1303\0\0\0\0\0\0\x1A\x05\0\0\x0C\x0Etokuji-1306\0\0\0\0\0\x1C\x05\0\0\n\tenkyo-1308\0\0\0\0\0\0\x1F\x05\0\0\x04\x1Cocho-1311\0\0\0\0\0\0\0 \x05\0\0\x03\x14showa-1312\0\0\0\0\0\0%\x05\0\0\x02\x03bunpo-1317\0\0\0\0\0\0'\x05\0\0\x04\x1Cgeno-1319\0\0\0\0\0\0\0)\x05\0\0\x02\x17genko-1321\0\0\0\0\0\0,\x05\0\0\x0C\tshochu-1324\0\0\0\0\0.\x05\0\0\x04\x1Akaryaku-1326\0\0\0\x001\x05\0\0\x08\x1Dgentoku-1329\0\0\0\x003\x05\0\0\x08\tgenko-1331\0\0\0\0\0\x006\x05\0\0\x01\x1Dkenmu-1334\0\0\0\0\0\08\x05\0\0\x02\x1Dengen-1336\0\0\0\0\0\0<\x05\0\0\x04\x1Ckokoku-1340\0\0\0\0\0B\x05\0\0\x0C\x08shohei-1346\0\0\0\0\0Z\x05\0\0\x07\x18kentoku-1370\0\0\0\0\\\x05\0\0\x04\x01bunchu-1372\0\0\0\0\0_\x05\0\0\x05\x1Btenju-1375\0\0\0\0\0\0c\x05\0\0\x03\x16koryaku-1379\0\0\0\0e\x05\0\0\x02\nkowa-1381\0\0\0\0\0\0\0h\x05\0\0\x04\x1Cgenchu-1384\0\0\0\0\0k\x05\0\0\x08\x16meitoku-1387\0\0\0\0k\x05\0\0\x08\x17kakei-1387\0\0\0\0\0\0m\x05\0\0\x02\tkoo-1389\0\0\0\0\0\0\0\0n\x05\0\0\x03\x1Ameitoku-1390\0\0\0\0r\x05\0\0\x07\x05oei-1394\0\0\0\0\0\0\0\0\x94\x05\0\0\x04\x1Bshocho-1428\0\0\0\0\0\x95\x05\0\0\t\x05eikyo-1429\0\0\0\0\0\0\xA1\x05\0\0\x02\x11kakitsu-1441\0\0\0\0\xA4\x05\0\0\x02\x05bunan-1444\0\0\0\0\0\0\xA9\x05\0\0\x07\x1Chotoku-1449\0\0\0\0\0\xAC\x05\0\0\x07\x19kyotoku-1452\0\0\0\0\xAF\x05\0\0\x07\x19kosho-1455\0\0\0\0\0\0\xB1\x05\0\0\t\x1Cchoroku-1457\0\0\0\0\xB4\x05\0\0\x0C\x15kansho-1460\0\0\0\0\0\xBA\x05\0\0\x02\x1Cbunsho-1466\0\0\0\0\0\xBB\x05\0\0\x03\x03onin-1467\0\0\0\0\0\0\0\xBD\x05\0\0\x04\x1Cbunmei-1469\0\0\0\0\0\xCF\x05\0\0\x07\x1Dchokyo-1487\0\0\0\0\0\xD1\x05\0\0\x08\x15entoku-1489\0\0\0\0\0\xD4\x05\0\0\x07\x13meio-1492\0\0\0\0\0\0\0\xDD\x05\0\0\x02\x1Cbunki-1501\0\0\0\0\0\0\xE0\x05\0\0\x02\x1Deisho-1504\0\0\0\0\0\0\xF1\x05\0\0\x08\x17taiei-1521\0\0\0\0\0\0\xF8\x05\0\0\x08\x14kyoroku-1528\0\0\0\0\xFC\x05\0\0\x07\x1Dtenbun-1532\0\0\0\0\0\x13\x06\0\0\n\x17koji-1555\0\0\0\0\0\0\0\x16\x06\0\0\x02\x1Ceiroku-1558\0\0\0\0\0\"\x06\0\0\x04\x17genki-1570\0\0\0\0\0\0%\x06\0\0\x07\x1Ctensho-1573\0\0\0\0\08\x06\0\0\x0C\x08bunroku-1592\0\0\0\0<\x06\0\0\n\x1Bkeicho-1596\0\0\0\0\0O\x06\0\0\x07\rgenna-1615\0\0\0\0\0\0X\x06\0\0\x02\x1Dkanei-1624\0\0\0\0\0\0l\x06\0\0\x0C\x10shoho-1644\0\0\0\0\0\0p\x06\0\0\x02\x0Fkeian-1648\0\0\0\0\0\0t\x06\0\0\t\x12joo-1652\0\0\0\0\0\0\0\0w\x06\0\0\x04\rmeireki-1655\0\0\0\0z\x06\0\0\x07\x17manji-1658\0\0\0\0\0\0}\x06\0\0\x04\x19kanbun-1661\0\0\0\0\0\x89\x06\0\0\t\x15enpo-1673\0\0\0\0\0\0\0\x91\x06\0\0\t\x1Dtenna-1681\0\0\0\0\0\0\x94\x06\0\0\x02\x15jokyo-1684\0\0\0\0\0\0\x98\x06\0\0\t\x1Egenroku-1688\0\0\0\0\xA8\x06\0\0\x03\rhoei-1704\0\0\0\0\0\0\0\xAF\x06\0\0\x04\x19shotoku-1711\0\0\0\0\xB4\x06\0\0\x06\x16kyoho-1716\0\0\0\0\0\0\xC8\x06\0\0\x04\x1Cgenbun-1736\0\0\0\0\0\xCD\x06\0\0\x02\x1Bkanpo-1741\0\0\0\0\0\0\xD0\x06\0\0\x02\x15enkyo-1744\0\0\0\0\0\0\xD4\x06\0\0\x07\x0Ckanen-1748\0\0\0\0\0\0\xD7\x06\0\0\n\x1Bhoreki-1751\0\0\0\0\0\xE4\x06\0\0\x06\x02meiwa-1764\0\0\0\0\0\0\xEC\x06\0\0\x0B\x10anei-1772\0\0\0\0\0\0\0\xF5\x06\0\0\x04\x02tenmei-1781\0\0\0\0\0\xFD\x06\0\0\x01\x19kansei-1789\0\0\0\0\0\t\x07\0\0\x02\x05kyowa-1801\0\0\0\0\0\0\x0C\x07\0\0\x02\x0Bbunka-1804\0\0\0\0\0\0\x1A\x07\0\0\x04\x16bunsei-1818\0\0\0\0\0&\x07\0\0\x0C\ntenpo-1830\0\0\0\0\0\x004\x07\0\0\x0C\x02koka-1844\0\0\0\0\0\0\08\x07\0\0\x02\x1Ckaei-1848\0\0\0\0\0\0\0>\x07\0\0\x0B\x1Bansei-1854\0\0\0\0\0\0D\x07\0\0\x03\x12manen-1860\0\0\0\0\0\0E\x07\0\0\x02\x13bunkyu-1861\0\0\0\0\0H\x07\0\0\x02\x14genji-1864\0\0\0\0\0\0I\x07\0\0\x04\x07keio-1865\0\0\0\0\0\0\0L\x07\0\0\n\x17meiji\0\0\0\0\0\0\0\0\0\0\0x\x07\0\0\x07\x1Etaisho\0\0\0\0\0\0\0\0\0\0\x86\x07\0\0\x0C\x19showa\0\0\0\0\0\0\0\0\0\0\0\xC5\x07\0\0\x01\x08heisei\0\0\0\0\0\0\0\0\0\0\xE3\x07\0\0\x05\x01reiwa\0\0\0\0\0\0\0\0\0\0\0") } }; } - #[clippy::msrv = "1.82"] + #[clippy::msrv = "1.83"] impl icu_provider::DataProvider for $provider { fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { if req.id.locale.is_unknown() { @@ -31,7 +36,7 @@ macro_rules! __impl_calendar_japanese_extended_v1 { }; ($ provider : ty , ITER) => { __impl_calendar_japanese_extended_v1!($provider); - #[clippy::msrv = "1.82"] + #[clippy::msrv = "1.83"] impl icu_provider::IterableDataProvider for $provider { fn iter_ids(&self) -> Result>, icu_provider::DataError> { Ok([Default::default()].into_iter().collect()) @@ -40,7 +45,7 @@ macro_rules! __impl_calendar_japanese_extended_v1 { }; ($ provider : ty , DRY) => { __impl_calendar_japanese_extended_v1!($provider); - #[clippy::msrv = "1.82"] + #[clippy::msrv = "1.83"] impl icu_provider::DryDataProvider for $provider { fn dry_load(&self, req: icu_provider::DataRequest) -> Result { if req.id.locale.is_unknown() { @@ -53,7 +58,7 @@ macro_rules! __impl_calendar_japanese_extended_v1 { }; ($ provider : ty , DRY , ITER) => { __impl_calendar_japanese_extended_v1!($provider); - #[clippy::msrv = "1.82"] + #[clippy::msrv = "1.83"] impl icu_provider::DryDataProvider for $provider { fn dry_load(&self, req: icu_provider::DataRequest) -> Result { if req.id.locale.is_unknown() { @@ -63,7 +68,7 @@ macro_rules! __impl_calendar_japanese_extended_v1 { } } } - #[clippy::msrv = "1.82"] + #[clippy::msrv = "1.83"] impl icu_provider::IterableDataProvider for $provider { fn iter_ids(&self) -> Result>, icu_provider::DataError> { Ok([Default::default()].into_iter().collect()) diff --git a/deps/crates/vendor/icu_calendar_data/data/calendar_japanese_modern_v1.rs.data b/deps/crates/vendor/icu_calendar_data/data/calendar_japanese_modern_v1.rs.data index b86298cbcec181..31c7a3de95d2b8 100644 --- a/deps/crates/vendor/icu_calendar_data/data/calendar_japanese_modern_v1.rs.data +++ b/deps/crates/vendor/icu_calendar_data/data/calendar_japanese_modern_v1.rs.data @@ -7,18 +7,23 @@ /// * 134B[^1] for the singleton data struct /// /// [^1]: these numbers can be smaller in practice due to linker deduplication +/// +/// This macro requires the following crates: +/// * `icu` +/// * `icu_provider` +/// * `zerovec` #[doc(hidden)] #[macro_export] macro_rules! __impl_calendar_japanese_modern_v1 { ($ provider : ty) => { - #[clippy::msrv = "1.82"] + #[clippy::msrv = "1.83"] const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.82"] + #[clippy::msrv = "1.83"] impl $provider { #[doc(hidden)] pub const SINGLETON_CALENDAR_JAPANESE_MODERN_V1: &'static ::DataStruct = &icu::calendar::provider::JapaneseEras { dates_to_eras: unsafe { zerovec::ZeroVec::from_bytes_unchecked(b"L\x07\0\0\n\x17meiji\0\0\0\0\0\0\0\0\0\0\0x\x07\0\0\x07\x1Etaisho\0\0\0\0\0\0\0\0\0\0\x86\x07\0\0\x0C\x19showa\0\0\0\0\0\0\0\0\0\0\0\xC5\x07\0\0\x01\x08heisei\0\0\0\0\0\0\0\0\0\0\xE3\x07\0\0\x05\x01reiwa\0\0\0\0\0\0\0\0\0\0\0") } }; } - #[clippy::msrv = "1.82"] + #[clippy::msrv = "1.83"] impl icu_provider::DataProvider for $provider { fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { if req.id.locale.is_unknown() { @@ -31,7 +36,7 @@ macro_rules! __impl_calendar_japanese_modern_v1 { }; ($ provider : ty , ITER) => { __impl_calendar_japanese_modern_v1!($provider); - #[clippy::msrv = "1.82"] + #[clippy::msrv = "1.83"] impl icu_provider::IterableDataProvider for $provider { fn iter_ids(&self) -> Result>, icu_provider::DataError> { Ok([Default::default()].into_iter().collect()) @@ -40,7 +45,7 @@ macro_rules! __impl_calendar_japanese_modern_v1 { }; ($ provider : ty , DRY) => { __impl_calendar_japanese_modern_v1!($provider); - #[clippy::msrv = "1.82"] + #[clippy::msrv = "1.83"] impl icu_provider::DryDataProvider for $provider { fn dry_load(&self, req: icu_provider::DataRequest) -> Result { if req.id.locale.is_unknown() { @@ -53,7 +58,7 @@ macro_rules! __impl_calendar_japanese_modern_v1 { }; ($ provider : ty , DRY , ITER) => { __impl_calendar_japanese_modern_v1!($provider); - #[clippy::msrv = "1.82"] + #[clippy::msrv = "1.83"] impl icu_provider::DryDataProvider for $provider { fn dry_load(&self, req: icu_provider::DataRequest) -> Result { if req.id.locale.is_unknown() { @@ -63,7 +68,7 @@ macro_rules! __impl_calendar_japanese_modern_v1 { } } } - #[clippy::msrv = "1.82"] + #[clippy::msrv = "1.83"] impl icu_provider::IterableDataProvider for $provider { fn iter_ids(&self) -> Result>, icu_provider::DataError> { Ok([Default::default()].into_iter().collect()) diff --git a/deps/crates/vendor/icu_calendar_data/data/calendar_week_v1.rs.data b/deps/crates/vendor/icu_calendar_data/data/calendar_week_v1.rs.data index 6a1c737066c3f0..d28cb3677c509d 100644 --- a/deps/crates/vendor/icu_calendar_data/data/calendar_week_v1.rs.data +++ b/deps/crates/vendor/icu_calendar_data/data/calendar_week_v1.rs.data @@ -4,25 +4,30 @@ /// `icu`'s `_unstable` constructors. /// /// Using this implementation will embed the following data in the binary's data segment: -/// * 292B for the lookup data structure (72 data identifiers) +/// * 295B for the lookup data structure (73 data identifiers) /// * 20B[^1] for the actual data (10 unique structs) /// /// [^1]: these numbers can be smaller in practice due to linker deduplication +/// +/// This macro requires the following crates: +/// * `icu` +/// * `icu_provider` +/// * `icu_provider/baked` #[doc(hidden)] #[macro_export] macro_rules! __impl_calendar_week_v1 { ($ provider : ty) => { - #[clippy::msrv = "1.82"] + #[clippy::msrv = "1.83"] const _: () = <$provider>::MUST_USE_MAKE_PROVIDER_MACRO; - #[clippy::msrv = "1.82"] + #[clippy::msrv = "1.83"] impl $provider { const DATA_CALENDAR_WEEK_V1: icu_provider::baked::zerotrie::Data = { - const TRIE: icu_provider::baked::zerotrie::ZeroTrieSimpleAscii<&'static [u8]> = icu_provider::baked::zerotrie::ZeroTrieSimpleAscii { store: b"und\x80-\xD7ABCDEGHIJKLMNOPQSTUVWYZ\t\x1E$06 = icu_provider::baked::zerotrie::ZeroTrieSimpleAscii { store: b"und\x80-\xD7ABCDEGHIJKLMNOPQSTUVWYZ\t\x1E$06::DataStruct] = &[icu::calendar::provider::WeekData { first_weekday: icu::calendar::types::Weekday::Monday, weekend: icu::calendar::provider::WeekdaySet::new(&[icu::calendar::types::Weekday::Saturday, icu::calendar::types::Weekday::Sunday]) }, icu::calendar::provider::WeekData { first_weekday: icu::calendar::types::Weekday::Saturday, weekend: icu::calendar::provider::WeekdaySet::new(&[icu::calendar::types::Weekday::Thursday, icu::calendar::types::Weekday::Friday]) }, icu::calendar::provider::WeekData { first_weekday: icu::calendar::types::Weekday::Sunday, weekend: icu::calendar::provider::WeekdaySet::new(&[icu::calendar::types::Weekday::Saturday, icu::calendar::types::Weekday::Sunday]) }, icu::calendar::provider::WeekData { first_weekday: icu::calendar::types::Weekday::Saturday, weekend: icu::calendar::provider::WeekdaySet::new(&[icu::calendar::types::Weekday::Friday, icu::calendar::types::Weekday::Saturday]) }, icu::calendar::provider::WeekData { first_weekday: icu::calendar::types::Weekday::Saturday, weekend: icu::calendar::provider::WeekdaySet::new(&[icu::calendar::types::Weekday::Saturday, icu::calendar::types::Weekday::Sunday]) }, icu::calendar::provider::WeekData { first_weekday: icu::calendar::types::Weekday::Sunday, weekend: icu::calendar::provider::WeekdaySet::new(&[icu::calendar::types::Weekday::Friday, icu::calendar::types::Weekday::Saturday]) }, icu::calendar::provider::WeekData { first_weekday: icu::calendar::types::Weekday::Sunday, weekend: icu::calendar::provider::WeekdaySet::new(&[icu::calendar::types::Weekday::Sunday]) }, icu::calendar::provider::WeekData { first_weekday: icu::calendar::types::Weekday::Saturday, weekend: icu::calendar::provider::WeekdaySet::new(&[icu::calendar::types::Weekday::Friday]) }, icu::calendar::provider::WeekData { first_weekday: icu::calendar::types::Weekday::Friday, weekend: icu::calendar::provider::WeekdaySet::new(&[icu::calendar::types::Weekday::Saturday, icu::calendar::types::Weekday::Sunday]) }, icu::calendar::provider::WeekData { first_weekday: icu::calendar::types::Weekday::Monday, weekend: icu::calendar::provider::WeekdaySet::new(&[icu::calendar::types::Weekday::Sunday]) }]; unsafe { icu_provider::baked::zerotrie::Data::from_trie_and_values_unchecked(TRIE, VALUES) } }; } - #[clippy::msrv = "1.82"] + #[clippy::msrv = "1.83"] impl icu_provider::DataProvider for $provider { fn load(&self, req: icu_provider::DataRequest) -> Result, icu_provider::DataError> { let mut metadata = icu_provider::DataResponseMetadata::default(); @@ -48,7 +53,7 @@ macro_rules! __impl_calendar_week_v1 { }; ($ provider : ty , ITER) => { __impl_calendar_week_v1!($provider); - #[clippy::msrv = "1.82"] + #[clippy::msrv = "1.83"] impl icu_provider::IterableDataProvider for $provider { fn iter_ids(&self) -> Result>, icu_provider::DataError> { Ok(icu_provider::baked::DataStore::iter(&Self::DATA_CALENDAR_WEEK_V1).collect()) diff --git a/deps/crates/vendor/icu_calendar_data/data/mod.rs b/deps/crates/vendor/icu_calendar_data/data/mod.rs index 84e6f6c55ee844..1ad69179b4969a 100644 --- a/deps/crates/vendor/icu_calendar_data/data/mod.rs +++ b/deps/crates/vendor/icu_calendar_data/data/mod.rs @@ -2,9 +2,6 @@ include!("calendar_japanese_extended_v1.rs.data"); include!("calendar_japanese_modern_v1.rs.data"); include!("calendar_week_v1.rs.data"); -include!("calendar_dangi_v1.rs.data"); -include!("calendar_hijri_simulated_mecca_v1.rs.data"); -include!("calendar_chinese_v1.rs.data"); /// Marks a type as a data provider. You can then use macros like /// `impl_core_helloworld_v1` to add implementations. /// @@ -20,7 +17,7 @@ include!("calendar_chinese_v1.rs.data"); #[macro_export] macro_rules! __make_provider { ($ name : ty) => { - #[clippy::msrv = "1.82"] + #[clippy::msrv = "1.83"] impl $name { #[allow(dead_code)] pub(crate) const MUST_USE_MAKE_PROVIDER_MACRO: () = (); @@ -30,6 +27,11 @@ macro_rules! __make_provider { } #[doc(inline)] pub use __make_provider as make_provider; +/// This macro requires the following crates: +/// * `icu` +/// * `icu_provider` +/// * `icu_provider/baked` +/// * `zerovec` #[allow(unused_macros)] macro_rules! impl_data_provider { ($ provider : ty) => { @@ -37,8 +39,5 @@ macro_rules! impl_data_provider { impl_calendar_japanese_extended_v1!($provider); impl_calendar_japanese_modern_v1!($provider); impl_calendar_week_v1!($provider); - impl_calendar_dangi_v1!($provider); - impl_calendar_hijri_simulated_mecca_v1!($provider); - impl_calendar_chinese_v1!($provider); }; } diff --git a/deps/crates/vendor/icu_calendar_data/src/lib.rs b/deps/crates/vendor/icu_calendar_data/src/lib.rs index 2a3674bc16bb94..02ec18a35cc963 100644 --- a/deps/crates/vendor/icu_calendar_data/src/lib.rs +++ b/deps/crates/vendor/icu_calendar_data/src/lib.rs @@ -4,7 +4,7 @@ //! Data for the `icu_calendar` crate //! -//! This data was generated with CLDR version 47.0.0, ICU version icu4x/2025-05-01/77.x, and +//! This data was generated with CLDR version 48.0.0, ICU version release-78.1rc, and //! LSTM segmenter version v0.1.0. #![no_std] diff --git a/deps/crates/vendor/icu_collections/.cargo-checksum.json b/deps/crates/vendor/icu_collections/.cargo-checksum.json index 87873bb53d1812..c83ec60da50d71 100644 --- a/deps/crates/vendor/icu_collections/.cargo-checksum.json +++ b/deps/crates/vendor/icu_collections/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"5c3e432c15fb18f16c8343adcedc9c1d0f7dc58bc9b3e09438a06c6215545a26","Cargo.toml":"a1bcce20ab29725ab0d9a44d2b09eda57368c56b2b9d12b73b2958f7d7df4d83","LICENSE":"f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2","README.md":"b1a0b37b61d42026996dda3b7d524d42888181f3e7eaf940c9b2e5f561c449e3","benches/codepointtrie.rs":"4052e9e3a3a744955a5ab3f7089cafaf2920ad5c7566fc8b3b77ee1d39376c20","benches/iai_cpt.rs":"a8ed4e67866d415e6ed0c8c95a9b1887b4198ea409d4cd9efafb50b8c13b3ecc","benches/inv_list.rs":"93a540e1dc30d0d356eef56f044a64b87949d777fa21f35042d53ba1bbcf1fb5","benches/tries/gc_fast.rs":"4761a339f9b266813f4fa7ffa229b3464ced2ed106ce712ae6a96c0e49e5224e","benches/tries/gc_small.rs":"a1a75d2325dbce031e0127de8d84e900ca7c73ec81da1679965ab0127a99c205","benches/tries/mod.rs":"82cfdd1c5870d343613098fdff5a7961cfe5645a33480c6a252efae9a074e022","examples/unicode_bmp_blocks_selector.rs":"a75bc5327fa9df8ab0332dcdf10f72a968924a0698bdba4eb79312a8624cbd44","src/char16trie/mod.rs":"5950a1b427743e956b459956cadd72ff7531fe46bfb871d8e3a848b1e4ab0657","src/char16trie/trie.rs":"18ccf56efa1a2b2af6034b8a7a05310a4078127f496a957ca26ee1e1ae4d1aea","src/codepointinvlist/builder.rs":"dae06a19e6a4275006afcf313d492eabbc74bececa99198de88d29c8facf6415","src/codepointinvlist/conversions.rs":"9d4617631328f5ad668eb5ea6fb100f9881dbebf6f46235ae5a445be2dbb8664","src/codepointinvlist/cpinvlist.rs":"025cd179418d5be9ddf41e97e2ebaa4f9943527fc521a4bb11b93dc02893c33c","src/codepointinvlist/mod.rs":"39f18e0be77508696b80d456f861a1264b902e90298c71a54e00a4585069108f","src/codepointinvlist/utils.rs":"2fcb38b4ce33947e831449ca63e0872b1d90830521144e1089f26842f1b746c8","src/codepointinvliststringlist/mod.rs":"4f0f2ae1ecd9068a0100a48308e08405afcee182eb5c5743990f739d4d7fdc42","src/codepointtrie/cptrie.rs":"dfaaa7271eed2e486bc43f3a36e71579bec19b854f491f6375b97113691c41f6","src/codepointtrie/error.rs":"43d758777ef7ce3f87efe4c8c7fb8fbe7d184b2d40f3f5fb737bce69da5d75a7","src/codepointtrie/impl_const.rs":"ff25fa0d54e174c289b25a6060f50e03c8aa41bad922c9386de3148f8ad95109","src/codepointtrie/mod.rs":"934246b867396119195cce3b4243f1951b76f503f6f455fa73cc6cd66ff792db","src/codepointtrie/planes.rs":"637c63a165397831c8ce8d4c28eff11179467a7d7a6382960acd699d8a087f26","src/codepointtrie/serde.rs":"ada65ec125890ccf86d141a128a1f79dcda5f3a2269605da7a2fa145d3cbd07c","src/codepointtrie/toml.rs":"00d10cb710f69f84dd0fde871c4bd61e8cabe319362a11fc74a0af1f0fda2363","src/iterator_utils.rs":"a6401aa583a2d8a6476f632b24983e91aa000c9dfd075bcddbd8de512b5a06ae","src/lib.rs":"a15ba283ccb32fc9a1cbe67166fa8eac5cd9225e4de022d09b057be4ff8eb688","tests/char16trie.rs":"f8018b90187f3b99a6a835c1c41bced18d98a28c41822abf3536cd1f0f08c44f","tests/cpt.rs":"126c6c671a6aa525dd6fabaf57387c828bae0041b04dffcd7b3a22c674e1dd41","tests/data/char16trie/empty.toml":"b900365b9c786f1b185307f5d8835a901d4860b9b097bce13aa0e592fcb384c4","tests/data/char16trie/months.toml":"439245fc4385fe693f283b7bc179bf5558dd8039a89987314dfc8c4a9e0092b2","tests/data/char16trie/test_a.toml":"34b179dd4e7eef73ce373b74e426ecfa05fb7aa2b0fc15e437bfcf3ea4242a9f","tests/data/char16trie/test_a_ab.toml":"b84452cb9c310203599d3cb8279a3f000c39ff8026728573152026f0d5e2c798","tests/data/char16trie/test_branches.toml":"d787ffc89c62a564b487f3c8fb94588258be0d891044e5b3a79c2ab876cd3e57","tests/data/char16trie/test_compact.toml":"30cb3e794d0989e3e087c12de3db077449d82ce6af57666290166d43bdcd27d3","tests/data/char16trie/test_long_branch.toml":"877d408f7d58063723befd01af6e3b0f01060a9ca1c5611ee1ea88d73383fa5a","tests/data/char16trie/test_long_sequence.toml":"f58645b3f14e47850e2a03733f7e47b69b193067f4cccf96124846b1ad49d970","tests/data/char16trie/test_shortest_branch.toml":"af356553506dbc28a2413b9f0ca1489050cd11a72e90ba4b5020bcb596862e64","tests/data/cpt/free-blocks.16.toml":"e0a66e777c13c0885b6a0f6839cdc9bbbddded2f5fbef4710f8e69a0808791d9","tests/data/cpt/free-blocks.32.toml":"b0bb6068a84d08d3fbcbd54dce7a59385a42b2dcdf0a6fe9d4160754a80a5f9e","tests/data/cpt/free-blocks.8.toml":"2de9950cd4475c3cb9cca9c30cb6793b90f3881ea2dd1353bea0701110c76953","tests/data/cpt/free-blocks.small16.toml":"17cbdef8edec19e8d85802eda775b1095ae2d423a589a4b56064b3b13604af36","tests/data/cpt/grow-data.16.toml":"802c7c61c2bb70dd7c96ce4633584a2ac4d2e6a61ecfb6f5d19c3c419b76f97c","tests/data/cpt/grow-data.32.toml":"3cbf6ad1276eda17f18cbeba4db671340ebec0fe6c0b631ea1f52dab63669881","tests/data/cpt/grow-data.8.toml":"e2d0b066e8a0f0bbf21cffa72393e0fd8c9a7534887886438211600bf7717129","tests/data/cpt/grow-data.small16.toml":"1d4c5d4b47a3da6b392729be3aa7cfa2cfb58d9ae37565cf10dbc10f0b48beca","tests/data/cpt/planes.toml":"a2577942758490bd53f4022b30731cff947fae22f4cbbb03b5ae72c65357aa12","tests/data/cpt/set-empty.16.toml":"6a01c051c5dbbe816097da806b943ca1856312059b0842a1238fe75ad5df220b","tests/data/cpt/set-empty.32.toml":"ec9dec0296b150ccabde07c255e2971ba407f647824a7c37af0272fa2ba89e2d","tests/data/cpt/set-empty.8.toml":"478dd49db8670f447f5aae78bcd3cdbeb6f91f7861dec256d480623b5d00941b","tests/data/cpt/set-empty.small16.toml":"5ff232c9b020bdaaaf762f7c0afe48ccb6f94b40dce08c1ba7dcb66c46ad2423","tests/data/cpt/set-single-value.16.toml":"6720f4a4d8c113ab7085e6308792ea0005cc8fe3c5d8acacb2cf43e74b12f4b3","tests/data/cpt/set-single-value.32.toml":"cb93935dc9ce5ed3cbe0f0acb50b49308b232e2d3fc8e39b08d1c33127c9911d","tests/data/cpt/set-single-value.8.toml":"e5cb6b02341bb8992ec93e49a7b2b059af1fd046ede3021dc207f1833c6a3c95","tests/data/cpt/set-single-value.small16.toml":"3aef34147b20a5c2c2c6e20f6024d38f7c0518313371b05d3cb83ae78a9ef0db","tests/data/cpt/set1.16.toml":"01cc1078f281102bd0c9e854a373b7241f2295bb19caa9488caad1b5350d0beb","tests/data/cpt/set1.32.toml":"cd264d011692df42e9007df87c6500bdde4e098a3a85a89a185f7deeff025a3b","tests/data/cpt/set1.8.toml":"039aa2fca8f140f5a060bcf01a1da3d45618242dfb0a3c437d4263d5166398a3","tests/data/cpt/set1.small16.toml":"b8bf6e216201e0a0c61c4b2456eccd1c3b4f38647d67ba251cd7b08f340df0dc","tests/data/cpt/set2-overlap.16.toml":"49f1d7212cb3f7b10f4a0dbab267b64aeb59380cc28d86c67fd640737da5af0a","tests/data/cpt/set2-overlap.32.toml":"406104b0532ae249c603c03729f4596ab24460ccbb3a244e04fa2b8401795ef0","tests/data/cpt/set2-overlap.small16.toml":"4e8d9c5b25cda2fd80fa72e7e9863e6858548608d3fe2a2d774026eda95c959f","tests/data/cpt/set3-initial-9.16.toml":"f5fdc3d7c6d6813cc527ddffecf35db2d144e2706be0541277bbe4672ea29851","tests/data/cpt/set3-initial-9.32.toml":"da2887d40005fc071eee1bf4e828f40410266c44585deda208e78d369b5ca9a9","tests/data/cpt/set3-initial-9.8.toml":"5974d1961bd8334e6fb1be7431f794dfc87d0fecdee4b832ad1c82e2302a6617","tests/data/cpt/set3-initial-9.small16.toml":"f62d46d2b6492c02944d089885b2ce6b975468e6bceabf986b495ab42a06d595","tests/data/cpt/short-all-same.16.toml":"5c0252591699a35398f75b3bec977d6ed44cfffbf335a87ed7c3cff86ff74391","tests/data/cpt/short-all-same.8.toml":"23f7aa3a8e6c3cc75669b8df55827b03c6791aac1ec9f7c8d7f0bbbdd54f23a9","tests/data/cpt/short-all-same.small16.toml":"5c0252591699a35398f75b3bec977d6ed44cfffbf335a87ed7c3cff86ff74391","tests/data/cpt/small0-in-fast.16.toml":"8d00f5657ee11c3b00c7a3c1e6333632b37dba0762cd4868b2f8ef90c03aab6c","tests/data/cpt/small0-in-fast.32.toml":"4736b4ae18cb0e77adc523382ec44bc517a01e17abdb91522b8859d77fbdc7c6","tests/data/cpt/small0-in-fast.8.toml":"e9214d75c421989eb79b7060817f51fa1d648d55b854fad651ff729962bc49e4","tests/data/cpt/small0-in-fast.small16.toml":"20eb07e89364a1fd6ddf26f3bc302e92c1aaa724be792d9bf8656e4e5a7a6379"},"package":"200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"} \ No newline at end of file +{"files":{".cargo_vcs_info.json":"f5ad06d6d816d1d211ec86d639b4fd2b6551db6e9bdcd37c3c7ccc47f1873618","Cargo.lock":"281b1642001f508afaf929a328b2d2801baa78b91f7e98e9aee6f39f7bd467a9","Cargo.toml":"8f7a2c13e5f27b3edcadac862f50ff5fd16689ec83bcca9a5a6bb0670918263d","Cargo.toml.orig":"963d26428f923ead6ef52219b65549eabcba96bef3e3dcb67279e6fa9c4cef3d","LICENSE":"f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2","README.md":"b1a0b37b61d42026996dda3b7d524d42888181f3e7eaf940c9b2e5f561c449e3","benches/codepointtrie.rs":"4052e9e3a3a744955a5ab3f7089cafaf2920ad5c7566fc8b3b77ee1d39376c20","benches/iai_cpt.rs":"a8ed4e67866d415e6ed0c8c95a9b1887b4198ea409d4cd9efafb50b8c13b3ecc","benches/inv_list.rs":"39e0386fd0e908d6e18b16e021345ba8c88fa70e06e26a29913dfa218a68b03d","benches/tries/gc_fast.rs":"4761a339f9b266813f4fa7ffa229b3464ced2ed106ce712ae6a96c0e49e5224e","benches/tries/gc_small.rs":"a1a75d2325dbce031e0127de8d84e900ca7c73ec81da1679965ab0127a99c205","benches/tries/mod.rs":"82cfdd1c5870d343613098fdff5a7961cfe5645a33480c6a252efae9a074e022","src/char16trie/mod.rs":"5950a1b427743e956b459956cadd72ff7531fe46bfb871d8e3a848b1e4ab0657","src/char16trie/trie.rs":"20ac75a0e2f3bcb74c619e98f44b3cc1f41bea2787ceef186d54cf997a1d9264","src/codepointinvlist/builder.rs":"bb0796333ca76d7714ee8425201a5957ab6b26b55dc049c34b3fb1839afc1581","src/codepointinvlist/conversions.rs":"8ac096ae63fa508ee2d7b2805aca864971110accaa358c178855540074e2ad21","src/codepointinvlist/cpinvlist.rs":"f9b47dd0432379637e194c2adf5acfcb91372a7f896cfab378928ffe65969532","src/codepointinvlist/mod.rs":"d48bc8ff1d103c4e37c4729181bc90b5e5e0db7701a49bd53c4d8c67e9089eb0","src/codepointinvlist/utils.rs":"6d6b4f5884beb830c16b6e5df07688f8cd70e2293a96d03037be690896d514e1","src/codepointinvliststringlist/mod.rs":"1fdb0b404f0b9a44218157ae1b58712d3ff7fe5b1d23521514a5eb36587d68df","src/codepointtrie/cptrie.rs":"dc7133751f32c74f3a87b1eb60e705aa0766a622ce48845aaa466f055267f6f2","src/codepointtrie/error.rs":"028dd55421b0bebf1634ad99752dbe349b40ab10ca565aa6bb134c5885ffd87b","src/codepointtrie/impl_const.rs":"ff25fa0d54e174c289b25a6060f50e03c8aa41bad922c9386de3148f8ad95109","src/codepointtrie/mod.rs":"d77de5edc258bbe79e0b6a37fedd315478fea6f9fd46c6923c564d045ac053d6","src/codepointtrie/planes.rs":"8a063b1efce889e46e69c7000ce48eeb420bb861f4ceafa839faaa944715c7bb","src/codepointtrie/serde.rs":"103bf57194a4d2111ed064d9bf2796b4ff7b5c2b1a1222a7378bad8143aa453f","src/codepointtrie/toml.rs":"6185421c1384e6a9a69b57153e1dcd793665ceb385dff2b61a2c1b0508609ec3","src/iterator_utils.rs":"2a5dfab19a752ae495617d68c07d11d1c0fbded233221dc43e9dd8f959001cd9","src/lib.rs":"a15ba283ccb32fc9a1cbe67166fa8eac5cd9225e4de022d09b057be4ff8eb688","tests/char16trie.rs":"f8018b90187f3b99a6a835c1c41bced18d98a28c41822abf3536cd1f0f08c44f","tests/cpt.rs":"3a151ba56273a29777f0a7656e533f4a603281569dd5349e15f837d2b9ec65e8","tests/data/char16trie/empty.toml":"b900365b9c786f1b185307f5d8835a901d4860b9b097bce13aa0e592fcb384c4","tests/data/char16trie/months.toml":"439245fc4385fe693f283b7bc179bf5558dd8039a89987314dfc8c4a9e0092b2","tests/data/char16trie/test_a.toml":"34b179dd4e7eef73ce373b74e426ecfa05fb7aa2b0fc15e437bfcf3ea4242a9f","tests/data/char16trie/test_a_ab.toml":"b84452cb9c310203599d3cb8279a3f000c39ff8026728573152026f0d5e2c798","tests/data/char16trie/test_branches.toml":"d787ffc89c62a564b487f3c8fb94588258be0d891044e5b3a79c2ab876cd3e57","tests/data/char16trie/test_compact.toml":"30cb3e794d0989e3e087c12de3db077449d82ce6af57666290166d43bdcd27d3","tests/data/char16trie/test_long_branch.toml":"877d408f7d58063723befd01af6e3b0f01060a9ca1c5611ee1ea88d73383fa5a","tests/data/char16trie/test_long_sequence.toml":"f58645b3f14e47850e2a03733f7e47b69b193067f4cccf96124846b1ad49d970","tests/data/char16trie/test_shortest_branch.toml":"af356553506dbc28a2413b9f0ca1489050cd11a72e90ba4b5020bcb596862e64","tests/data/cpt/free-blocks.16.toml":"e0a66e777c13c0885b6a0f6839cdc9bbbddded2f5fbef4710f8e69a0808791d9","tests/data/cpt/free-blocks.32.toml":"b0bb6068a84d08d3fbcbd54dce7a59385a42b2dcdf0a6fe9d4160754a80a5f9e","tests/data/cpt/free-blocks.8.toml":"2de9950cd4475c3cb9cca9c30cb6793b90f3881ea2dd1353bea0701110c76953","tests/data/cpt/free-blocks.small16.toml":"17cbdef8edec19e8d85802eda775b1095ae2d423a589a4b56064b3b13604af36","tests/data/cpt/grow-data.16.toml":"802c7c61c2bb70dd7c96ce4633584a2ac4d2e6a61ecfb6f5d19c3c419b76f97c","tests/data/cpt/grow-data.32.toml":"3cbf6ad1276eda17f18cbeba4db671340ebec0fe6c0b631ea1f52dab63669881","tests/data/cpt/grow-data.8.toml":"e2d0b066e8a0f0bbf21cffa72393e0fd8c9a7534887886438211600bf7717129","tests/data/cpt/grow-data.small16.toml":"1d4c5d4b47a3da6b392729be3aa7cfa2cfb58d9ae37565cf10dbc10f0b48beca","tests/data/cpt/planes.toml":"a2577942758490bd53f4022b30731cff947fae22f4cbbb03b5ae72c65357aa12","tests/data/cpt/set-empty.16.toml":"6a01c051c5dbbe816097da806b943ca1856312059b0842a1238fe75ad5df220b","tests/data/cpt/set-empty.32.toml":"ec9dec0296b150ccabde07c255e2971ba407f647824a7c37af0272fa2ba89e2d","tests/data/cpt/set-empty.8.toml":"478dd49db8670f447f5aae78bcd3cdbeb6f91f7861dec256d480623b5d00941b","tests/data/cpt/set-empty.small16.toml":"5ff232c9b020bdaaaf762f7c0afe48ccb6f94b40dce08c1ba7dcb66c46ad2423","tests/data/cpt/set-single-value.16.toml":"6720f4a4d8c113ab7085e6308792ea0005cc8fe3c5d8acacb2cf43e74b12f4b3","tests/data/cpt/set-single-value.32.toml":"cb93935dc9ce5ed3cbe0f0acb50b49308b232e2d3fc8e39b08d1c33127c9911d","tests/data/cpt/set-single-value.8.toml":"e5cb6b02341bb8992ec93e49a7b2b059af1fd046ede3021dc207f1833c6a3c95","tests/data/cpt/set-single-value.small16.toml":"3aef34147b20a5c2c2c6e20f6024d38f7c0518313371b05d3cb83ae78a9ef0db","tests/data/cpt/set1.16.toml":"01cc1078f281102bd0c9e854a373b7241f2295bb19caa9488caad1b5350d0beb","tests/data/cpt/set1.32.toml":"cd264d011692df42e9007df87c6500bdde4e098a3a85a89a185f7deeff025a3b","tests/data/cpt/set1.8.toml":"039aa2fca8f140f5a060bcf01a1da3d45618242dfb0a3c437d4263d5166398a3","tests/data/cpt/set1.small16.toml":"b8bf6e216201e0a0c61c4b2456eccd1c3b4f38647d67ba251cd7b08f340df0dc","tests/data/cpt/set2-overlap.16.toml":"49f1d7212cb3f7b10f4a0dbab267b64aeb59380cc28d86c67fd640737da5af0a","tests/data/cpt/set2-overlap.32.toml":"406104b0532ae249c603c03729f4596ab24460ccbb3a244e04fa2b8401795ef0","tests/data/cpt/set2-overlap.small16.toml":"4e8d9c5b25cda2fd80fa72e7e9863e6858548608d3fe2a2d774026eda95c959f","tests/data/cpt/set3-initial-9.16.toml":"f5fdc3d7c6d6813cc527ddffecf35db2d144e2706be0541277bbe4672ea29851","tests/data/cpt/set3-initial-9.32.toml":"da2887d40005fc071eee1bf4e828f40410266c44585deda208e78d369b5ca9a9","tests/data/cpt/set3-initial-9.8.toml":"5974d1961bd8334e6fb1be7431f794dfc87d0fecdee4b832ad1c82e2302a6617","tests/data/cpt/set3-initial-9.small16.toml":"f62d46d2b6492c02944d089885b2ce6b975468e6bceabf986b495ab42a06d595","tests/data/cpt/short-all-same.16.toml":"5c0252591699a35398f75b3bec977d6ed44cfffbf335a87ed7c3cff86ff74391","tests/data/cpt/short-all-same.8.toml":"23f7aa3a8e6c3cc75669b8df55827b03c6791aac1ec9f7c8d7f0bbbdd54f23a9","tests/data/cpt/short-all-same.small16.toml":"5c0252591699a35398f75b3bec977d6ed44cfffbf335a87ed7c3cff86ff74391","tests/data/cpt/small0-in-fast.16.toml":"8d00f5657ee11c3b00c7a3c1e6333632b37dba0762cd4868b2f8ef90c03aab6c","tests/data/cpt/small0-in-fast.32.toml":"4736b4ae18cb0e77adc523382ec44bc517a01e17abdb91522b8859d77fbdc7c6","tests/data/cpt/small0-in-fast.8.toml":"e9214d75c421989eb79b7060817f51fa1d648d55b854fad651ff729962bc49e4","tests/data/cpt/small0-in-fast.small16.toml":"20eb07e89364a1fd6ddf26f3bc302e92c1aaa724be792d9bf8656e4e5a7a6379"},"package":"4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"} \ No newline at end of file diff --git a/deps/crates/vendor/icu_collections/.cargo_vcs_info.json b/deps/crates/vendor/icu_collections/.cargo_vcs_info.json new file mode 100644 index 00000000000000..4364a1d8632a00 --- /dev/null +++ b/deps/crates/vendor/icu_collections/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "38a49da495248dd1ded84cf306e4ca42e64d5bb3" + }, + "path_in_vcs": "components/collections" +} \ No newline at end of file diff --git a/deps/crates/vendor/icu_collections/Cargo.lock b/deps/crates/vendor/icu_collections/Cargo.lock index 2cf19f6502f5e8..ae29068d4b0956 100644 --- a/deps/crates/vendor/icu_collections/Cargo.lock +++ b/deps/crates/vendor/icu_collections/Cargo.lock @@ -19,21 +19,21 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cast" @@ -43,9 +43,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "ciborium" @@ -101,9 +101,12 @@ checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "cobs" -version = "0.2.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror", +] [[package]] name = "criterion" @@ -168,9 +171,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "databake" @@ -242,15 +245,15 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "hermit-abi" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "iai" @@ -260,7 +263,7 @@ checksum = "71a816c97c42258aa5834d07590b718b4c9a598944cd39a52dc25b351185d678" [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" dependencies = [ "criterion", "databake", @@ -278,9 +281,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.9.0" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", "hashbrown", @@ -288,9 +291,9 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.16" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ "hermit-abi", "libc", @@ -314,9 +317,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" dependencies = [ "once_cell", "wasm-bindgen", @@ -324,21 +327,21 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.172" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "num-traits" @@ -391,9 +394,9 @@ dependencies = [ [[package]] name = "postcard" -version = "1.1.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "170a2601f67cc9dba8edd8c4870b15f71a6a2dc196daec8c83f72b59dff628a8" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" dependencies = [ "cobs", "embedded-io 0.4.0", @@ -403,28 +406,28 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ - "serde", + "serde_core", "zerovec", ] [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] @@ -451,9 +454,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -463,9 +466,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -474,15 +477,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" @@ -501,18 +504,28 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -521,36 +534,37 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "syn" -version = "2.0.101" +version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote", @@ -568,6 +582,26 @@ dependencies = [ "syn", ] +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -580,9 +614,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", @@ -592,18 +626,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.9" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.26" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", @@ -614,9 +648,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" [[package]] name = "walkdir" @@ -630,21 +664,22 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" dependencies = [ "bumpalo", "log", @@ -656,9 +691,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -666,9 +701,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", @@ -679,18 +714,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" dependencies = [ "js-sys", "wasm-bindgen", @@ -698,100 +733,42 @@ dependencies = [ [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ "windows-sys", ] [[package]] -name = "windows-sys" -version = "0.59.0" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows-targets" -version = "0.52.6" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows-link", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - [[package]] name = "winnow" -version = "0.7.10" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -800,9 +777,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", @@ -833,9 +810,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "databake", "serde", @@ -846,9 +823,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", diff --git a/deps/crates/vendor/icu_collections/Cargo.toml b/deps/crates/vendor/icu_collections/Cargo.toml index 5fd8b60b4ee492..abb0a93530006f 100644 --- a/deps/crates/vendor/icu_collections/Cargo.toml +++ b/deps/crates/vendor/icu_collections/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.82" +rust-version = "1.83" name = "icu_collections" -version = "2.0.0" +version = "2.1.1" authors = ["The ICU4X Project Developers"] build = false include = [ @@ -43,7 +43,10 @@ repository = "https://github.com/unicode-org/icu4x" all-features = true [features] -alloc = ["zerovec/alloc"] +alloc = [ + "serde?/alloc", + "zerovec/alloc", +] databake = [ "dep:databake", "zerovec/databake", @@ -60,10 +63,6 @@ name = "icu_collections" path = "src/lib.rs" bench = false -[[example]] -name = "unicode_bmp_blocks_selector" -path = "examples/unicode_bmp_blocks_selector.rs" - [[test]] name = "char16trie" path = "tests/char16trie.rs" @@ -98,16 +97,13 @@ version = "0.2.3" default-features = false [dependencies.potential_utf] -version = "0.1.1" +version = "0.1.3" features = ["zerovec"] default-features = false [dependencies.serde] -version = "1.0.110" -features = [ - "derive", - "alloc", -] +version = "1.0.220" +features = ["derive"] optional = true default-features = false @@ -122,7 +118,7 @@ features = ["derive"] default-features = false [dependencies.zerovec] -version = "0.11.1" +version = "0.11.3" features = [ "derive", "yoke", @@ -138,7 +134,7 @@ features = ["alloc"] default-features = false [dev-dependencies.serde] -version = "1.0.110" +version = "1.0.220" features = ["derive"] default-features = false diff --git a/deps/crates/vendor/icu_collections/Cargo.toml.orig b/deps/crates/vendor/icu_collections/Cargo.toml.orig new file mode 100644 index 00000000000000..5e93a0cd333c53 --- /dev/null +++ b/deps/crates/vendor/icu_collections/Cargo.toml.orig @@ -0,0 +1,66 @@ +# This file is part of ICU4X. For terms of use, please see the file +# called LICENSE at the top level of the ICU4X source tree +# (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +[package] +name = "icu_collections" +description = "Collection of API for use in ICU libraries." + +authors.workspace = true +categories.workspace = true +edition.workspace = true +homepage.workspace = true +include.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true +version.workspace = true + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +displaydoc = { workspace = true } +yoke = { workspace = true, features = ["derive"] } +zerofrom = { workspace = true, features = ["derive"] } +zerovec = { workspace = true, features = ["derive", "yoke"] } +potential_utf = { workspace = true, features = ["zerovec"] } + +serde = { workspace = true, features = ["derive"], optional = true } +databake = { workspace = true, features = ["derive"], optional = true } + +[dev-dependencies] +iai = { workspace = true } +icu = { path = "../../components/icu", default-features = false } +icu_properties = { path = "../../components/properties" } +postcard = { workspace = true, features = ["alloc"] } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } + +toml = { workspace = true } + +[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] +criterion = { workspace = true } + +[features] +serde = ["dep:serde", "zerovec/serde", "potential_utf/serde", "alloc"] +databake = ["dep:databake", "zerovec/databake"] +alloc = ["serde?/alloc", "zerovec/alloc"] + +[lib] +bench = false # This option is required for Benchmark CI + +[[bench]] +name = "codepointtrie" +harness = false +path = "benches/codepointtrie.rs" + +[[bench]] +name = "iai_cpt" +harness = false +path = "benches/iai_cpt.rs" + +[[bench]] +name = "inv_list" +harness = false +path = "benches/inv_list.rs" diff --git a/deps/crates/vendor/icu_collections/benches/inv_list.rs b/deps/crates/vendor/icu_collections/benches/inv_list.rs index 41a23568046090..743c855af8c745 100644 --- a/deps/crates/vendor/icu_collections/benches/inv_list.rs +++ b/deps/crates/vendor/icu_collections/benches/inv_list.rs @@ -14,7 +14,7 @@ fn uniset_bench(c: &mut Criterion) { CodePointInversionList::try_from_u32_inversion_list_slice(&worst_ex).unwrap(); c.bench_function("uniset/overview", |b| { - #[allow(clippy::suspicious_map)] + #[expect(clippy::suspicious_map)] b.iter(|| { best_sample .iter_chars() diff --git a/deps/crates/vendor/icu_collections/examples/unicode_bmp_blocks_selector.rs b/deps/crates/vendor/icu_collections/examples/unicode_bmp_blocks_selector.rs deleted file mode 100644 index c29f1d25000564..00000000000000 --- a/deps/crates/vendor/icu_collections/examples/unicode_bmp_blocks_selector.rs +++ /dev/null @@ -1,71 +0,0 @@ -// This file is part of ICU4X. For terms of use, please see the file -// called LICENSE at the top level of the ICU4X source tree -// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). - -// An example application which uses icu_uniset to test what blocks of -// Basic Multilingual Plane a character belongs to. -// -// In this example we use `CodePointInversionListBuilder` to construct just the first -// two blocks of the first plane, and use an instance of a `BMPBlockSelector` -// to retrieve which of those blocks each character of a string belongs to. -// -// This is a simple example of the API use and is severely oversimplified -// compared to real Unicode block selection. - -#![no_main] // https://github.com/unicode-org/icu4x/issues/395 -icu_benchmark_macros::instrument!(); -use icu_benchmark_macros::println; - -use icu_collections::codepointinvlist::{CodePointInversionList, CodePointInversionListBuilder}; -use std::ops::RangeInclusive; - -#[derive(Copy, Clone, Debug)] -enum BmpBlock { - Basic, - Latin1Supplement, - Unknown, -} - -const BLOCKS: [(BmpBlock, RangeInclusive); 2] = [ - (BmpBlock::Basic, '\u{0000}'..='\u{007F}'), - (BmpBlock::Latin1Supplement, '\u{0080}'..='\u{00FF}'), -]; - -struct BmpBlockSelector { - blocks: [(BmpBlock, CodePointInversionList<'static>); 2], -} - -impl BmpBlockSelector { - pub fn new() -> BmpBlockSelector { - BmpBlockSelector { - blocks: BLOCKS.map(|(ch, range)| { - (ch, { - let mut builder = CodePointInversionListBuilder::new(); - builder.add_range(range); - builder.build() - }) - }), - } - } - - pub fn select(&self, input: char) -> BmpBlock { - for (block, set) in &self.blocks { - if set.contains(input) { - return *block; - } - } - BmpBlock::Unknown - } -} - -fn main() { - let selector = BmpBlockSelector::new(); - - let sample = "Welcome to MyName©®, Алексей!"; - - println!("\n====== Unicode BMP Block Selector example ============"); - for ch in sample.chars() { - let block = selector.select(ch); - println!("{ch}: {block:#?}"); - } -} diff --git a/deps/crates/vendor/icu_collections/src/char16trie/trie.rs b/deps/crates/vendor/icu_collections/src/char16trie/trie.rs index 1d48307957c3ce..5aedccabe5e1c4 100644 --- a/deps/crates/vendor/icu_collections/src/char16trie/trie.rs +++ b/deps/crates/vendor/icu_collections/src/char16trie/trie.rs @@ -88,12 +88,14 @@ pub struct Char16Trie<'data> { impl<'data> Char16Trie<'data> { /// Returns a new [`Char16Trie`] with ownership of the provided data. + #[inline] pub fn new(data: ZeroVec<'data, u16>) -> Self { Self { data } } /// Returns a new [`Char16TrieIterator`] backed by borrowed data from the `trie` data - pub fn iter(&self) -> Char16TrieIterator { + #[inline] + pub fn iter(&self) -> Char16TrieIterator<'_> { Char16TrieIterator::new(&self.data) } } @@ -164,6 +166,7 @@ macro_rules! trie_unwrap { impl<'a> Char16TrieIterator<'a> { /// Returns a new [`Char16TrieIterator`] backed by borrowed data for the `trie` array + #[inline] pub fn new(trie: &'a ZeroSlice) -> Self { Self { trie, diff --git a/deps/crates/vendor/icu_collections/src/codepointinvlist/builder.rs b/deps/crates/vendor/icu_collections/src/codepointinvlist/builder.rs index f5b019dd58ff08..d12cba38626269 100644 --- a/deps/crates/vendor/icu_collections/src/codepointinvlist/builder.rs +++ b/deps/crates/vendor/icu_collections/src/codepointinvlist/builder.rs @@ -32,7 +32,7 @@ impl CodePointInversionListBuilder { .into_iter() .map(PotentialCodePoint::from_u24) .collect(); - #[allow(clippy::unwrap_used)] // by invariant + #[expect(clippy::unwrap_used)] // by invariant CodePointInversionList::try_from_inversion_list(inv_list).unwrap() } @@ -51,7 +51,7 @@ impl CodePointInversionListBuilder { let end_pos_check = (end_ind % 2 == 0) == add; let start_eq_end = start_ind == end_ind; - #[allow(clippy::indexing_slicing)] // all indices are binary search results + #[expect(clippy::indexing_slicing)] // all indices are binary search results if start_eq_end && start_pos_check && end_res.is_err() { self.intervals.splice(start_ind..end_ind, [start, end]); } else { @@ -182,7 +182,7 @@ impl CodePointInversionListBuilder { /// ``` #[allow(unused_assignments)] pub fn add_set(&mut self, set: &CodePointInversionList) { - #[allow(clippy::indexing_slicing)] // chunks + #[expect(clippy::indexing_slicing)] // chunks set.as_inversion_list() .as_ule_slice() .chunks(2) @@ -203,7 +203,7 @@ impl CodePointInversionListBuilder { return; } if let Some(&last) = self.intervals.last() { - #[allow(clippy::indexing_slicing)] + #[expect(clippy::indexing_slicing)] // by invariant, if we have a last we have a (different) first if start <= self.intervals[0] && end >= last { self.intervals.clear(); @@ -267,7 +267,7 @@ impl CodePointInversionListBuilder { /// builder.remove_set(&set); // removes 'A'..='E' /// let check = builder.build(); /// assert_eq!(check.iter_chars().next(), Some('F')); - #[allow(clippy::indexing_slicing)] // chunks + #[expect(clippy::indexing_slicing)] // chunks pub fn remove_set(&mut self, set: &CodePointInversionList) { set.as_inversion_list() .as_ule_slice() @@ -350,7 +350,7 @@ impl CodePointInversionListBuilder { /// assert!(check.contains('A')); /// assert!(!check.contains('G')); /// ``` - #[allow(clippy::indexing_slicing)] // chunks + #[expect(clippy::indexing_slicing)] // chunks pub fn retain_set(&mut self, set: &CodePointInversionList) { let mut prev = 0; for pair in set.as_inversion_list().as_ule_slice().chunks(2) { @@ -424,7 +424,7 @@ impl CodePointInversionListBuilder { /// ``` pub fn complement(&mut self) { if !self.intervals.is_empty() { - #[allow(clippy::indexing_slicing)] // by invariant + #[expect(clippy::indexing_slicing)] // by invariant if self.intervals[0] == 0 { self.intervals.drain(0..1); } else { diff --git a/deps/crates/vendor/icu_collections/src/codepointinvlist/conversions.rs b/deps/crates/vendor/icu_collections/src/codepointinvlist/conversions.rs index 9e4cb380c7b41f..7488654a8f32b2 100644 --- a/deps/crates/vendor/icu_collections/src/codepointinvlist/conversions.rs +++ b/deps/crates/vendor/icu_collections/src/codepointinvlist/conversions.rs @@ -25,7 +25,7 @@ fn try_from_range<'data>( PotentialCodePoint::from_u24(till), ]; let inv_list: ZeroVec = ZeroVec::alloc_from_slice(&set); - #[allow(clippy::unwrap_used)] // valid + #[expect(clippy::unwrap_used)] // valid Ok(CodePointInversionList::try_from_inversion_list(inv_list).unwrap()) } else { Err(RangeError(from, till)) diff --git a/deps/crates/vendor/icu_collections/src/codepointinvlist/cpinvlist.rs b/deps/crates/vendor/icu_collections/src/codepointinvlist/cpinvlist.rs index 3b63ff365d3a79..02f624cdd16a73 100644 --- a/deps/crates/vendor/icu_collections/src/codepointinvlist/cpinvlist.rs +++ b/deps/crates/vendor/icu_collections/src/codepointinvlist/cpinvlist.rs @@ -120,7 +120,7 @@ impl UnicodeCodePoint { if cp <= char::MAX as u32 { Ok(Self(cp)) } else { - Err(format!("Not a Unicode code point {}", cp)) + Err(format!("Not a Unicode code point {cp}")) } } @@ -221,7 +221,7 @@ impl<'data> CodePointInversionList<'data> { pub fn try_from_inversion_list( inv_list: ZeroVec<'data, PotentialCodePoint>, ) -> Result { - #[allow(clippy::indexing_slicing)] // chunks + #[expect(clippy::indexing_slicing)] // chunks if is_valid_zv(&inv_list) { let size = inv_list .as_ule_slice() @@ -255,6 +255,8 @@ impl<'data> CodePointInversionList<'data> { /// The inversion list must be of even length, sorted ascending non-overlapping, /// and within the bounds of `0x0 -> 0x10FFFF` inclusive, and end points being exclusive. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* + /// /// # Examples /// /// ``` @@ -290,6 +292,8 @@ impl<'data> CodePointInversionList<'data> { } /// Attempts to convert this list into a fully-owned one. No-op if already fully owned + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] pub fn into_owned(self) -> CodePointInversionList<'static> { CodePointInversionList { @@ -299,6 +303,8 @@ impl<'data> CodePointInversionList<'data> { } /// Returns an owned inversion list representing the current [`CodePointInversionList`] + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] pub fn get_inversion_list_vec(&self) -> Vec { self.as_inversion_list().iter().map(u32::from).collect() @@ -362,7 +368,7 @@ impl<'data> CodePointInversionList<'data> { /// /// Public only to the crate, not exposed to public #[cfg(feature = "alloc")] - pub(crate) fn as_inversion_list(&self) -> &ZeroVec { + pub(crate) fn as_inversion_list(&self) -> &ZeroVec<'_, PotentialCodePoint> { &self.inv_list } @@ -385,7 +391,7 @@ impl<'data> CodePointInversionList<'data> { /// assert_eq!(None, ex_iter_chars.next()); /// ``` pub fn iter_chars(&self) -> impl Iterator + '_ { - #[allow(clippy::indexing_slicing)] // chunks + #[expect(clippy::indexing_slicing)] // chunks self.inv_list .as_ule_slice() .chunks(2) @@ -418,7 +424,7 @@ impl<'data> CodePointInversionList<'data> { /// assert_eq!(None, example_iter_ranges.next()); /// ``` pub fn iter_ranges(&self) -> impl ExactSizeIterator> + '_ { - #[allow(clippy::indexing_slicing)] // chunks + #[expect(clippy::indexing_slicing)] // chunks self.inv_list.as_ule_slice().chunks(2).map(|pair| { let range_start = u32::from(PotentialCodePoint::from_unaligned(pair[0])); let range_limit = u32::from(PotentialCodePoint::from_unaligned(pair[1])); @@ -471,7 +477,7 @@ impl<'data> CodePointInversionList<'data> { } else { None }; - #[allow(clippy::indexing_slicing)] // chunks + #[expect(clippy::indexing_slicing)] // chunks let chunks = middle.chunks(2).map(|pair| { let range_start = u32::from(PotentialCodePoint::from_unaligned(pair[0])); let range_limit = u32::from(PotentialCodePoint::from_unaligned(pair[1])); diff --git a/deps/crates/vendor/icu_collections/src/codepointinvlist/mod.rs b/deps/crates/vendor/icu_collections/src/codepointinvlist/mod.rs index be4986a301d3c2..34b99b3b8cfd5c 100644 --- a/deps/crates/vendor/icu_collections/src/codepointinvlist/mod.rs +++ b/deps/crates/vendor/icu_collections/src/codepointinvlist/mod.rs @@ -53,8 +53,6 @@ #![warn(missing_docs)] -extern crate alloc; - #[cfg(feature = "alloc")] #[macro_use] mod builder; diff --git a/deps/crates/vendor/icu_collections/src/codepointinvlist/utils.rs b/deps/crates/vendor/icu_collections/src/codepointinvlist/utils.rs index 525b02ffd116f1..ef04d3b18b9a27 100644 --- a/deps/crates/vendor/icu_collections/src/codepointinvlist/utils.rs +++ b/deps/crates/vendor/icu_collections/src/codepointinvlist/utils.rs @@ -12,8 +12,8 @@ use zerovec::ZeroVec; /// Returns whether the vector is sorted ascending non inclusive, of even length, /// and within the bounds of `0x0 -> 0x10FFFF + 1` inclusive. -#[allow(clippy::indexing_slicing)] // windows -#[allow(clippy::unwrap_used)] // by is_empty check +#[expect(clippy::indexing_slicing)] // windows +#[expect(clippy::unwrap_used)] // by is_empty check pub fn is_valid_zv(inv_list_zv: &ZeroVec<'_, PotentialCodePoint>) -> bool { inv_list_zv.is_empty() || (inv_list_zv.len() % 2 == 0 @@ -48,7 +48,7 @@ mod tests { use core::char; use zerovec::ZeroVec; - fn make_zv(slice: &[u32]) -> ZeroVec { + fn make_zv(slice: &[u32]) -> ZeroVec<'_, PotentialCodePoint> { slice .iter() .copied() diff --git a/deps/crates/vendor/icu_collections/src/codepointinvliststringlist/mod.rs b/deps/crates/vendor/icu_collections/src/codepointinvliststringlist/mod.rs index 2562cc5bc69512..136f5ef2c21984 100644 --- a/deps/crates/vendor/icu_collections/src/codepointinvliststringlist/mod.rs +++ b/deps/crates/vendor/icu_collections/src/codepointinvliststringlist/mod.rs @@ -231,6 +231,7 @@ impl<'data> CodePointInversionListAndStringList<'data> { } #[cfg(feature = "alloc")] +/// ✨ *Enabled with the `alloc` Cargo feature.* impl<'a> FromIterator<&'a str> for CodePointInversionListAndStringList<'_> { fn from_iter(it: I) -> Self where diff --git a/deps/crates/vendor/icu_collections/src/codepointtrie/cptrie.rs b/deps/crates/vendor/icu_collections/src/codepointtrie/cptrie.rs index 8a79032afbecfd..5b184a46f894f5 100644 --- a/deps/crates/vendor/icu_collections/src/codepointtrie/cptrie.rs +++ b/deps/crates/vendor/icu_collections/src/codepointtrie/cptrie.rs @@ -17,8 +17,10 @@ use core::num::TryFromIntError; use core::ops::RangeInclusive; use yoke::Yokeable; use zerofrom::ZeroFrom; +use zerovec::ule::AsULE; #[cfg(feature = "alloc")] use zerovec::ule::UleError; +use zerovec::ZeroSlice; use zerovec::ZeroVec; /// The type of trie represents whether the trie has an optimization that @@ -129,8 +131,28 @@ fn maybe_filter_value(value: T, trie_null_value: T, null_value: T) // serde impls in crate::serde #[derive(Debug, Eq, PartialEq, Yokeable, ZeroFrom)] pub struct CodePointTrie<'trie, T: TrieValue> { + /// # Safety Invariant + /// + /// The value of `header.trie_type` must not change after construction. pub(crate) header: CodePointTrieHeader, + /// # Safety Invariant + /// + /// If `header.trie_type == TrieType::Fast`, `index.len()` must be greater + /// than `FAST_TYPE_FAST_INDEXING_MAX`. Otherwise, `index.len()` + /// must be greater than `SMALL_TYPE_FAST_INDEXING_MAX`. Furthermore, + /// this field must not change after construction. (Strictly: It must + /// not become shorter than the length requirement stated above and the + /// values within the prefix up to the length requirement must not change.) pub(crate) index: ZeroVec<'trie, u16>, + /// # Safety Invariant + /// + /// If `header.trie_type == TrieType::Fast`, `data.len()` must be greater + /// than `FAST_TYPE_DATA_MASK` plus the largest value in + /// `index[0..FAST_TYPE_FAST_INDEXING_MAX + 1]`. Otherwise, `data.len()` + /// must be greater than `FAST_TYPE_DATA_MASK` plus the largest value in + /// `index[0..SMALL_TYPE_FAST_INDEXING_MAX + 1]`. Furthermore, this field + /// must not change after construction. (Strictly: The stated length + /// requirement must continue to hold.) pub(crate) data: ZeroVec<'trie, T>, // serde impl skips this field #[zerofrom(clone)] // TrieValue is Copy, this allows us to avoid @@ -139,6 +161,13 @@ pub struct CodePointTrie<'trie, T: TrieValue> { } /// This struct contains the fixed-length header fields of a [`CodePointTrie`]. +/// +/// # Safety Invariant +/// +/// The `trie_type` field must not change after construction. +/// +/// (In practice, all the fields here remain unchanged during the lifetime +/// of the trie.) #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "databake", derive(databake::Bake))] #[cfg_attr(feature = "databake", databake(path = icu_collections::codepointtrie))] @@ -173,6 +202,10 @@ pub struct CodePointTrieHeader { pub null_value: u32, /// The enum value representing the type of trie, where trie type is as it /// is defined in ICU (ex: Fast, Small). + /// + /// # Safety Invariant + /// + /// Must not change after construction. pub trie_type: TrieType, } @@ -232,12 +265,21 @@ macro_rules! w( impl<'trie, T: TrieValue> CodePointTrie<'trie, T> { #[doc(hidden)] // databake internal - pub const fn from_parts( + /// # Safety + /// + /// `header.trie_type`, `index`, and `data` must + /// satisfy the invariants for the fields of the + /// same names on `CodePointTrie`. + pub const unsafe fn from_parts_unstable_unchecked_v1( header: CodePointTrieHeader, index: ZeroVec<'trie, u16>, data: ZeroVec<'trie, T>, error_value: T, ) -> Self { + // Field invariants upheld: The caller is responsible. + // In practice, this means that datagen in the databake + // mode upholds these invariants when constructing the + // `CodePointTrie` that is then baked. Self { header, index, @@ -253,19 +295,8 @@ impl<'trie, T: TrieValue> CodePointTrie<'trie, T> { index: ZeroVec<'trie, u16>, data: ZeroVec<'trie, T>, ) -> Result, Error> { - // Validation invariants are not needed here when constructing a new - // `CodePointTrie` because: - // - // - Rust includes the size of a slice (or Vec or similar), which allows it - // to prevent lookups at out-of-bounds indices, whereas in C++, it is the - // programmer's responsibility to keep track of length info. - // - For lookups into collections, Rust guarantees that a fallback value will - // be returned in the case of `.get()` encountering a lookup error, via - // the `Option` type. - // - The `ZeroVec` serializer stores the length of the array along with the - // ZeroVec data, meaning that a deserializer would also see that length info. - - let error_value = data.last().ok_or(Error::EmptyDataVector)?; + let error_value = Self::validate_fields(&header, &index, &data)?; + // Field invariants upheld: Checked by `validate_fields` above. let trie: CodePointTrie<'trie, T> = CodePointTrie { header, index, @@ -275,9 +306,122 @@ impl<'trie, T: TrieValue> CodePointTrie<'trie, T> { Ok(trie) } + /// Checks the invariant on the fields that fast-path access relies on for + /// safety in order to omit slice bound checks and upon success returns the + /// `error_value` for the trie. + /// + /// # Safety Usable Invariant + /// + /// Iff this function returns `Ok(T)`, the arguments satisfy the invariants + /// for corresponding fields of `CodePointTrie`. (Other than proving that + /// nothing else changes the fields subsequently.) + pub(crate) fn validate_fields( + header: &CodePointTrieHeader, + index: &ZeroSlice, + data: &ZeroSlice, + ) -> Result { + let error_value = data.last().ok_or(Error::EmptyDataVector)?; + + // `CodePointTrie` lookup has two stages: fast and small (the trie types + // are also fast and small; they affect where the boundary between fast + // and small lookups is). + // + // The length requirements for `index` and `data` are checked here only + // for the fast lookup case so that the fast lookup can omit bound checks + // at the time of access. In the small lookup case, bounds are checked at + // the time of access. + // + // The fast lookup happens on the prefixes of `index` and `data` with + // more items for the small lookup case afterwards. The check here + // only looks at the prefixes relevant to the fast case. + // + // In the fast lookup case, the bits of the of the code point are + // partitioned into a bit prefix and a bit suffix. First, a value + // is read from `index` by indexing into it using the bit prefix. + // Then `data` is accessed by the value just read from `index` plus + // the bit suffix. + // + // Therefore, the length of `index` needs to accommodate access + // by the maximum possible bit prefix, and the length of `data` + // needs to accommodate access by the largest value stored in the part + // of `data` reachable by the bit prefix plus the maximum possible bit + // suffix. + // + // The maximum possible bit prefix depends on the trie type. + + // The maximum code point that can be used for fast-path access: + let fast_max = match header.trie_type { + TrieType::Fast => FAST_TYPE_FAST_INDEXING_MAX, + TrieType::Small => SMALL_TYPE_FAST_INDEXING_MAX, + }; + // Keep only the prefix bits: + let max_bit_prefix = fast_max >> FAST_TYPE_SHIFT; + // Attempt slice the part of `index` that the fast path can index into. + // Since `max_bit_prefix` is the largest possible value used for + // indexing (inclusive bound), we need to add one to get the exclusive + // bound, which is what `get_subslice` wants. + let fast_index = index + .get_subslice(0..(max_bit_prefix as usize) + 1) + .ok_or(Error::IndexTooShortForFastAccess)?; + // Invariant upheld for `index`: If we got this far, the length of `index` + // satisfies its length invariant on the assumption that `header.trie_type` + // will not change subsequently. + + // Now find the largest offset in the part of `index` reachable by the + // bit prefix. `max` can never actually return `None`, since we already + // know the slice isn't empty. Hence, reusing the error kind instead of + // minting a new one for this check. + let max_offset = fast_index + .iter() + .max() + .ok_or(Error::IndexTooShortForFastAccess)?; + // `FAST_TYPE_DATA_MASK` is the maximum possible bit suffix, since the + // maximum is when all the bits in the suffix are set, and the mask + // has that many bits set. + if (max_offset) as usize + (FAST_TYPE_DATA_MASK as usize) >= data.len() { + return Err(Error::DataTooShortForFastAccess); + } + + // Invariant upheld for `data`: If we got this far, the length of `data` + // satisfies `data`'s length invariant on the assumption that the contents + // of `fast_index` subslice of `index` and `header.trie_type` will not + // change subsequently. + + Ok(error_value) + } + + /// Turns this trie into a version whose trie type is encoded in the Rust type. + #[inline] + pub fn to_typed(self) -> Typed, SmallCodePointTrie<'trie, T>> { + match self.header.trie_type { + TrieType::Fast => Typed::Fast(FastCodePointTrie { inner: self }), + TrieType::Small => Typed::Small(SmallCodePointTrie { inner: self }), + } + } + + /// Obtains a reference to this trie as a Rust type that encodes the trie type in the Rust type. + #[inline] + pub fn as_typed_ref( + &self, + ) -> Typed<&FastCodePointTrie<'trie, T>, &SmallCodePointTrie<'trie, T>> { + // SAFETY: `FastCodePointTrie` and `SmallCodePointTrie` are `repr(transparent)` + // with `CodePointTrie`, so transmuting between the references is OK when the + // actual trie type agrees with the semantics of the typed wrapper. + match self.header.trie_type { + TrieType::Fast => Typed::Fast(unsafe { + core::mem::transmute::<&CodePointTrie<'trie, T>, &FastCodePointTrie<'trie, T>>(self) + }), + TrieType::Small => Typed::Small(unsafe { + core::mem::transmute::<&CodePointTrie<'trie, T>, &SmallCodePointTrie<'trie, T>>( + self, + ) + }), + } + } + /// Returns the position in the data array containing the trie's stored /// error value. - #[inline(always)] // `always` based on normalizer benchmarking + #[inline(always)] // `always` was based on previous normalizer benchmarking fn trie_error_val_index(&self) -> u32 { // We use wrapping_sub here to avoid panicky overflow checks. // len should always be > 1, but if it isn't this will just cause GIGO behavior of producing @@ -375,7 +519,6 @@ impl<'trie, T: TrieValue> CodePointTrie<'trie, T> { /// array for each block of code points in [0, `fastMax`), which in /// turn guarantees that those code points are represented and only need 1 /// lookup. - #[inline(always)] // `always` based on normalizer benchmarking fn fast_index(&self, code_point: u32) -> u32 { let index_array_pos: u32 = code_point >> FAST_TYPE_SHIFT; let index_array_val: u16 = @@ -390,6 +533,105 @@ impl<'trie, T: TrieValue> CodePointTrie<'trie, T> { fast_index_val } + /// Returns the value that is associated with `code_point` in this [`CodePointTrie`] + /// if `code_point` uses fast-path lookup or `None` if `code_point` + /// should use small-path lookup or is above the supported range. + #[inline(always)] // "always" to make the `Option` collapse away + fn get32_by_fast_index(&self, code_point: u32) -> Option { + let fast_max = match self.header.trie_type { + TrieType::Fast => FAST_TYPE_FAST_INDEXING_MAX, + TrieType::Small => SMALL_TYPE_FAST_INDEXING_MAX, + }; + if code_point <= fast_max { + // SAFETY: We just checked the invariant of + // `get32_assuming_fast_index`, + // which is + // "If `self.header.trie_type == TrieType::Small`, `code_point` must be at most + // `SMALL_TYPE_FAST_INDEXING_MAX`. If `self.header.trie_type == + // TrieType::Fast`, `code_point` must be at most `FAST_TYPE_FAST_INDEXING_MAX`." + Some(unsafe { self.get32_assuming_fast_index(code_point) }) + } else { + // The caller needs to call `get32_by_small_index` or determine + // that the argument is above the permitted range. + None + } + } + + /// Performs the actual fast-mode lookup + /// + /// # Safety + /// + /// If `self.header.trie_type == TrieType::Small`, `code_point` must be at most + /// `SMALL_TYPE_FAST_INDEXING_MAX`. If `self.header.trie_type == + /// TrieType::Fast`, `code_point` must be at most `FAST_TYPE_FAST_INDEXING_MAX`. + #[inline(always)] + unsafe fn get32_assuming_fast_index(&self, code_point: u32) -> T { + // Check the safety invariant of this method. + debug_assert!( + code_point + <= match self.header.trie_type { + TrieType::Fast => FAST_TYPE_FAST_INDEXING_MAX, + TrieType::Small => SMALL_TYPE_FAST_INDEXING_MAX, + } + ); + + let bit_prefix = (code_point as usize) >> FAST_TYPE_SHIFT; + debug_assert!(bit_prefix < self.index.len()); + // SAFETY: Relying on the length invariant of `self.index` having + // been checked and on the unchangedness invariant of `self.index` + // and `self.header.trie_type` after construction. + let base_offset_to_data: usize = usize::from(u16::from_unaligned(*unsafe { + self.index.as_ule_slice().get_unchecked(bit_prefix) + })); + let bit_suffix = (code_point & FAST_TYPE_DATA_MASK) as usize; + // SAFETY: Cannot overflow with supported (32-bit and 64-bit) `usize` + // sizes, since `base_offset_to_data` was extended from `u16` and + // `bit_suffix` is at most `FAST_TYPE_DATA_MASK`, which is well + // under what it takes to reach the 32-bit (or 64-bit) max with + // additon from the max of `u16`. + let offset_to_data = w!(base_offset_to_data + bit_suffix); + debug_assert!(offset_to_data < self.data.len()); + // SAFETY: Relying on the length invariant of `self.data` having + // been checked and on the unchangedness invariant of `self.data`, + // `self.index`, and `self.header.trie_type` after construction. + T::from_unaligned(*unsafe { self.data.as_ule_slice().get_unchecked(offset_to_data) }) + } + + /// Coldness wrapper for `get32_by_small_index` to also allow + /// calls without the effects of `#[cold]`. + #[cold] + #[inline(always)] + fn get32_by_small_index_cold(&self, code_point: u32) -> T { + self.get32_by_small_index(code_point) + } + + /// Returns the value that is associated with `code_point` in this [`CodePointTrie`] + /// assuming that the small index path should be used. + /// + /// # Intended Precondition + /// + /// `code_point` must be at most `CODE_POINT_MAX` AND greter than + /// `FAST_TYPE_FAST_INDEXING_MAX` if the trie type is fast or greater + /// than `SMALL_TYPE_FAST_INDEXING_MAX` if the trie type is small. + /// This is checked when debug assertions are enabled. If this + /// precondition is violated, the behavior of this method is + /// memory-safe, but the returned value may be bogus (not + /// necessarily the designated error value). + #[inline(never)] + fn get32_by_small_index(&self, code_point: u32) -> T { + debug_assert!(code_point <= CODE_POINT_MAX); + debug_assert!( + code_point + > match self.header.trie_type { + TrieType::Fast => FAST_TYPE_FAST_INDEXING_MAX, + TrieType::Small => SMALL_TYPE_FAST_INDEXING_MAX, + } + ); + self.data + .get(self.small_index(code_point) as usize) + .unwrap_or(self.error_value) + } + /// Returns the value that is associated with `code_point` in this [`CodePointTrie`]. /// /// # Examples @@ -404,11 +646,13 @@ impl<'trie, T: TrieValue> CodePointTrie<'trie, T> { /// ``` #[inline(always)] // `always` based on normalizer benchmarking pub fn get32(&self, code_point: u32) -> T { - // If we cannot read from the data array, then return the sentinel value - // self.error_value() for the instance type for T: TrieValue. - self.get32_ule(code_point) - .map(|t| T::from_unaligned(*t)) - .unwrap_or(self.error_value) + if let Some(v) = self.get32_by_fast_index(code_point) { + v + } else if code_point <= CODE_POINT_MAX { + self.get32_by_small_index_cold(code_point) + } else { + self.error_value + } } /// Returns the value that is associated with `char` in this [`CodePointTrie`]. @@ -425,7 +669,41 @@ impl<'trie, T: TrieValue> CodePointTrie<'trie, T> { /// ``` #[inline(always)] pub fn get(&self, c: char) -> T { - self.get32(u32::from(c)) + // LLVM's optimizations have been observed not to be 100% + // reliable around collapsing away unnecessary parts of + // `get32`, so not just calling `get32` here. + let code_point = u32::from(c); + if let Some(v) = self.get32_by_fast_index(code_point) { + v + } else { + self.get32_by_small_index_cold(code_point) + } + } + + /// Returns the value that is associated with `bmp` in this [`CodePointTrie`]. + #[inline(always)] + pub fn get16(&self, bmp: u16) -> T { + // LLVM's optimizations have been observed not to be 100% + // reliable around collapsing away unnecessary parts of + // `get32`, so not just calling `get32` here. + let code_point = u32::from(bmp); + if let Some(v) = self.get32_by_fast_index(code_point) { + v + } else { + self.get32_by_small_index_cold(code_point) + } + } + + /// Lookup trie value by non-Basic Multilingual Plane Scalar Value. + /// + /// The return value may be bogus (not necessarily `error_value`) is the argument is actually in + /// the Basic Multilingual Plane or above the Unicode Scalar Value + /// range (panics instead with debug assertions enabled). + #[inline(always)] + pub fn get32_supplementary(&self, supplementary: u32) -> T { + debug_assert!(supplementary > 0xFFFF); + debug_assert!(supplementary <= CODE_POINT_MAX); + self.get32_by_small_index(supplementary) } /// Returns a reference to the ULE of the value that is associated with `code_point` in this [`CodePointTrie`]. @@ -440,7 +718,7 @@ impl<'trie, T: TrieValue> CodePointTrie<'trie, T> { /// assert_eq!(Some(&0), trie.get32_ule(0x13E0)); // 'Ꮰ' as u32 /// assert_eq!(Some(&1), trie.get32_ule(0x10044)); // '𐁄' as u32 /// ``` - #[inline(always)] // `always` based on normalizer benchmarking + #[inline(always)] // `always` was based on previous normalizer benchmarking pub fn get32_ule(&self, code_point: u32) -> Option<&T::ULE> { // All code points up to the fast max limit are represented // individually in the `index` array to hold their `data` array position, and @@ -475,6 +753,8 @@ impl<'trie, T: TrieValue> CodePointTrie<'trie, T> { /// More specifically, panics if [`ZeroVec::try_into_converted()`] panics when converting /// `ZeroVec` into `ZeroVec

`, which happens if `T::ULE` and `P::ULE` differ in size. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* + /// /// # Examples /// /// ```no_run @@ -497,7 +777,7 @@ impl<'trie, T: TrieValue> CodePointTrie<'trie, T> { let slice = &[error_ule]; let error_vec = ZeroVec::::new_borrowed(slice); let error_converted = error_vec.try_into_converted::

()?; - #[allow(clippy::expect_used)] // we know this cannot fail + #[expect(clippy::expect_used)] // we know this cannot fail Ok(CodePointTrie { header: self.header, index: self.index, @@ -515,6 +795,8 @@ impl<'trie, T: TrieValue> CodePointTrie<'trie, T> { /// If the old and new types are the same size, use the more efficient /// [`CodePointTrie::try_into_converted`]. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* + /// /// # Examples /// /// ``` @@ -930,7 +1212,7 @@ impl<'trie, T: TrieValue> CodePointTrie<'trie, T> { /// assert_eq!(ranges.next(), None); /// assert_eq!(ranges.next(), None); /// ``` - pub fn iter_ranges(&self) -> CodePointMapRangeIterator { + pub fn iter_ranges(&self) -> CodePointMapRangeIterator<'_, T> { let init_range = Some(CodePointMapRange { range: u32::MAX..=u32::MAX, value: self.error_value(), @@ -1007,6 +1289,8 @@ impl<'trie, T: TrieValue> CodePointTrie<'trie, T> { /// Returns a [`CodePointInversionList`] for the code points that have the given /// [`TrieValue`] in the trie. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* + /// /// # Examples /// /// ``` @@ -1045,7 +1329,7 @@ impl databake::Bake for CodePointTrie<'_, T> { let index = self.index.bake(env); let data = self.data.bake(env); let error_value = self.error_value.bake(env); - databake::quote! { icu_collections::codepointtrie::CodePointTrie::from_parts(#header, #index, #data, #error_value) } + databake::quote! { unsafe { icu_collections::codepointtrie::CodePointTrie::from_parts_unstable_unchecked_v1(#header, #index, #data, #error_value) } } } } @@ -1138,6 +1422,255 @@ impl Iterator for CodePointMapRangeIterator<'_, T> { } } +/// For sealing `TypedCodePointTrie` +/// +/// # Safety Usable Invariant +/// +/// All implementations of `TypedCodePointTrie` are reviewable in this module. +trait Seal {} + +/// Trait for writing trait bounds for monomorphizing over either +/// `FastCodePointTrie` or `SmallCodePointTrie`. +#[allow(private_bounds)] // Permit sealing +pub trait TypedCodePointTrie<'trie, T: TrieValue>: Seal { + /// The `TrieType` associated with this `TypedCodePointTrie` + /// + /// # Safety Usable Invariant + /// + /// This constant matches `self.as_untyped_ref().header.trie_type`. + const TRIE_TYPE: TrieType; + + /// Lookup trie value as `u32` by Unicode Scalar Value without branching on trie type. + #[inline(always)] + fn get32_u32(&self, code_point: u32) -> u32 { + self.get32(code_point).to_u32() + } + + /// Lookup trie value by Basic Multilingual Plane Code Point without branching on trie type. + #[inline(always)] + fn get16(&self, bmp: u16) -> T { + // LLVM's optimizations have been observed not to be 100% + // reliable around collapsing away unnecessary parts of + // `get32`, so not just calling `get32` here. + let code_point = u32::from(bmp); + if let Some(v) = self.get32_by_fast_index(code_point) { + v + } else { + self.as_untyped_ref().get32_by_small_index_cold(code_point) + } + } + + /// Lookup trie value by non-Basic Multilingual Plane Scalar Value without branching on trie type. + #[inline(always)] + fn get32_supplementary(&self, supplementary: u32) -> T { + self.as_untyped_ref().get32_supplementary(supplementary) + } + + /// Lookup trie value by Unicode Scalar Value without branching on trie type. + #[inline(always)] + fn get(&self, c: char) -> T { + // LLVM's optimizations have been observed not to be 100% + // reliable around collapsing away unnecessary parts of + // `get32`, so not just calling `get32` here. + let code_point = u32::from(c); + if let Some(v) = self.get32_by_fast_index(code_point) { + v + } else { + self.as_untyped_ref().get32_by_small_index_cold(code_point) + } + } + + /// Lookup trie value by Unicode Code Point without branching on trie type. + #[inline(always)] + fn get32(&self, code_point: u32) -> T { + if let Some(v) = self.get32_by_fast_index(code_point) { + v + } else if code_point <= CODE_POINT_MAX { + self.as_untyped_ref().get32_by_small_index_cold(code_point) + } else { + self.as_untyped_ref().error_value + } + } + + /// Returns the value that is associated with `code_point` in this [`CodePointTrie`] + /// if `code_point` uses fast-path lookup or `None` if `code_point` + /// should use small-path lookup or is above the supported range. + #[inline(always)] // "always" to make the `Option` collapse away + fn get32_by_fast_index(&self, code_point: u32) -> Option { + debug_assert_eq!(Self::TRIE_TYPE, self.as_untyped_ref().header.trie_type); + let fast_max = match Self::TRIE_TYPE { + TrieType::Fast => FAST_TYPE_FAST_INDEXING_MAX, + TrieType::Small => SMALL_TYPE_FAST_INDEXING_MAX, + }; + if code_point <= fast_max { + // SAFETY: We just checked the invariant of + // `get32_assuming_fast_index`, + // which is + // "If `self.header.trie_type == TrieType::Small`, `code_point` must be at most + // `SMALL_TYPE_FAST_INDEXING_MAX`. If `self.header.trie_type == + // TrieType::Fast`, `code_point` must be at most `FAST_TYPE_FAST_INDEXING_MAX`." + // ... assuming that `Self::TRIE_TYPE` always matches + // `self.as_untyped_ref().header.trie_type`, i.e. we're relying on + // `CodePointTrie::to_typed` and `CodePointTrie::as_typed_ref` being correct + // and the exclusive ways of obtaining `Self`. + Some(unsafe { self.as_untyped_ref().get32_assuming_fast_index(code_point) }) + } else { + // The caller needs to call `get32_by_small_index` or determine + // that the argument is above the permitted range. + None + } + } + + /// Returns a reference to the wrapped `CodePointTrie`. + fn as_untyped_ref(&self) -> &CodePointTrie<'trie, T>; + + /// Extracts the wrapped `CodePointTrie`. + fn to_untyped(self) -> CodePointTrie<'trie, T>; +} + +/// Type-safe wrapper for a fast trie guaranteeing +/// the the getters don't branch on the trie type +/// and for guarenteeing that `get16` is branchless +/// in release builds. +#[derive(Debug)] +#[repr(transparent)] +pub struct FastCodePointTrie<'trie, T: TrieValue> { + inner: CodePointTrie<'trie, T>, +} + +impl<'trie, T: TrieValue> TypedCodePointTrie<'trie, T> for FastCodePointTrie<'trie, T> { + const TRIE_TYPE: TrieType = TrieType::Fast; + + /// Returns a reference to the wrapped `CodePointTrie`. + #[inline(always)] + fn as_untyped_ref(&self) -> &CodePointTrie<'trie, T> { + &self.inner + } + + /// Extracts the wrapped `CodePointTrie`. + #[inline(always)] + fn to_untyped(self) -> CodePointTrie<'trie, T> { + self.inner + } + + /// Lookup trie value by Basic Multilingual Plane Code Point without branching on trie type. + #[inline(always)] + fn get16(&self, bmp: u16) -> T { + debug_assert!(u32::from(u16::MAX) <= FAST_TYPE_FAST_INDEXING_MAX); + debug_assert_eq!(Self::TRIE_TYPE, TrieType::Fast); + debug_assert_eq!(self.as_untyped_ref().header.trie_type, TrieType::Fast); + let code_point = u32::from(bmp); + // SAFETY: With `TrieType::Fast`, the `u16` range satisfies + // the invariant of `get32_assuming_fast_index`, which is + // "If `self.header.trie_type == TrieType::Small`, `code_point` must be at most + // `SMALL_TYPE_FAST_INDEXING_MAX`. If `self.header.trie_type == + // TrieType::Fast`, `code_point` must be at most `FAST_TYPE_FAST_INDEXING_MAX`." + // + // We're relying on `CodePointTrie::to_typed` and `CodePointTrie::as_typed_ref` + // being correct and the exclusive ways of obtaining `Self`. + unsafe { self.as_untyped_ref().get32_assuming_fast_index(code_point) } + } +} + +impl<'trie, T: TrieValue> Seal for FastCodePointTrie<'trie, T> {} + +impl<'trie, T: TrieValue> TryFrom<&'trie CodePointTrie<'trie, T>> + for &'trie FastCodePointTrie<'trie, T> +{ + type Error = TypedCodePointTrieError; + + fn try_from( + reference: &'trie CodePointTrie<'trie, T>, + ) -> Result<&'trie FastCodePointTrie<'trie, T>, TypedCodePointTrieError> { + match reference.as_typed_ref() { + Typed::Fast(trie) => Ok(trie), + Typed::Small(_) => Err(TypedCodePointTrieError), + } + } +} + +impl<'trie, T: TrieValue> TryFrom> for FastCodePointTrie<'trie, T> { + type Error = TypedCodePointTrieError; + + fn try_from( + value: CodePointTrie<'trie, T>, + ) -> Result, TypedCodePointTrieError> { + match value.to_typed() { + Typed::Fast(trie) => Ok(trie), + Typed::Small(_) => Err(TypedCodePointTrieError), + } + } +} + +/// Type-safe wrapper for a small trie guaranteeing +/// the the getters don't branch on the trie type. +#[derive(Debug)] +#[repr(transparent)] +pub struct SmallCodePointTrie<'trie, T: TrieValue> { + inner: CodePointTrie<'trie, T>, +} + +impl<'trie, T: TrieValue> TypedCodePointTrie<'trie, T> for SmallCodePointTrie<'trie, T> { + const TRIE_TYPE: TrieType = TrieType::Small; + + /// Returns a reference to the wrapped `CodePointTrie`. + #[inline(always)] + fn as_untyped_ref(&self) -> &CodePointTrie<'trie, T> { + &self.inner + } + + /// Extracts the wrapped `CodePointTrie`. + #[inline(always)] + fn to_untyped(self) -> CodePointTrie<'trie, T> { + self.inner + } +} + +impl<'trie, T: TrieValue> Seal for SmallCodePointTrie<'trie, T> {} + +impl<'trie, T: TrieValue> TryFrom<&'trie CodePointTrie<'trie, T>> + for &'trie SmallCodePointTrie<'trie, T> +{ + type Error = TypedCodePointTrieError; + + fn try_from( + reference: &'trie CodePointTrie<'trie, T>, + ) -> Result<&'trie SmallCodePointTrie<'trie, T>, TypedCodePointTrieError> { + match reference.as_typed_ref() { + Typed::Fast(_) => Err(TypedCodePointTrieError), + Typed::Small(trie) => Ok(trie), + } + } +} + +impl<'trie, T: TrieValue> TryFrom> for SmallCodePointTrie<'trie, T> { + type Error = TypedCodePointTrieError; + + fn try_from( + value: CodePointTrie<'trie, T>, + ) -> Result, TypedCodePointTrieError> { + match value.to_typed() { + Typed::Fast(_) => Err(TypedCodePointTrieError), + Typed::Small(trie) => Ok(trie), + } + } +} + +/// Error indicating that the `TrieType` of an untyped trie +/// does not match the requested typed trie type. +#[derive(Debug)] +#[non_exhaustive] +pub struct TypedCodePointTrieError; + +/// Holder for either fast or small trie with the trie +/// type encoded into the Rust type. +pub enum Typed { + /// The trie type is fast. + Fast(F), + /// The trie type is small. + Small(S), +} + #[cfg(test)] mod tests { use super::*; @@ -1279,6 +1812,17 @@ mod tests { Ok(()) } + #[test] + fn test_typed() { + let untyped = planes::get_planes_trie(); + assert_eq!(untyped.get('\u{10000}'), 1); + let small_ref = <&SmallCodePointTrie<_>>::try_from(&untyped).unwrap(); + assert_eq!(small_ref.get('\u{10000}'), 1); + let _ = <&FastCodePointTrie<_>>::try_from(&untyped).is_err(); + let small = >::try_from(untyped).unwrap(); + assert_eq!(small.get('\u{10000}'), 1); + } + #[test] fn test_get_range() { let planes_trie = planes::get_planes_trie(); @@ -1321,23 +1865,26 @@ mod tests { } #[test] + #[allow(unused_unsafe)] // `unsafe` below is both necessary and unnecessary fn databake() { databake::test_bake!( CodePointTrie<'static, u32>, const, - crate::codepointtrie::CodePointTrie::from_parts( - crate::codepointtrie::CodePointTrieHeader { - high_start: 1u32, - shifted12_high_start: 2u16, - index3_null_offset: 3u16, - data_null_offset: 4u32, - null_value: 5u32, - trie_type: crate::codepointtrie::TrieType::Small, - }, - zerovec::ZeroVec::new(), - zerovec::ZeroVec::new(), - 0u32, - ), + unsafe { + crate::codepointtrie::CodePointTrie::from_parts_unstable_unchecked_v1( + crate::codepointtrie::CodePointTrieHeader { + high_start: 1u32, + shifted12_high_start: 2u16, + index3_null_offset: 3u16, + data_null_offset: 4u32, + null_value: 5u32, + trie_type: crate::codepointtrie::TrieType::Small, + }, + zerovec::ZeroVec::new(), + zerovec::ZeroVec::new(), + 0u32, + ) + }, icu_collections, [zerovec], ); diff --git a/deps/crates/vendor/icu_collections/src/codepointtrie/error.rs b/deps/crates/vendor/icu_collections/src/codepointtrie/error.rs index 4cd157fc3f2762..383949d9561142 100644 --- a/deps/crates/vendor/icu_collections/src/codepointtrie/error.rs +++ b/deps/crates/vendor/icu_collections/src/codepointtrie/error.rs @@ -19,6 +19,12 @@ pub enum Error { /// [`CodePointTrie`](super::CodePointTrie) must be constructed from data vector with at least one element #[displaydoc("CodePointTrie must be constructed from data vector with at least one element")] EmptyDataVector, + /// [`CodePointTrie`](super::CodePointTrie) must be constructed from index vector long enough to accommodate fast-path access + #[displaydoc("CodePointTrie must be constructed from index vector long enough to accommodate fast-path access")] + IndexTooShortForFastAccess, + /// [`CodePointTrie`](super::CodePointTrie) must be constructed from data vector long enough to accommodate fast-path access + #[displaydoc("CodePointTrie must be constructed from data vector long enough to accommodate fast-path access")] + DataTooShortForFastAccess, } impl core::error::Error for Error {} diff --git a/deps/crates/vendor/icu_collections/src/codepointtrie/mod.rs b/deps/crates/vendor/icu_collections/src/codepointtrie/mod.rs index 970eab4fbfd570..dfc5a29ffc21a6 100644 --- a/deps/crates/vendor/icu_collections/src/codepointtrie/mod.rs +++ b/deps/crates/vendor/icu_collections/src/codepointtrie/mod.rs @@ -29,8 +29,6 @@ //! //! [`ICU4X`]: ../icu/index.html -extern crate alloc; - mod cptrie; mod error; mod impl_const; @@ -46,6 +44,10 @@ pub use cptrie::CodePointMapRange; pub use cptrie::CodePointMapRangeIterator; pub use cptrie::CodePointTrie; pub use cptrie::CodePointTrieHeader; +pub use cptrie::FastCodePointTrie; +pub use cptrie::SmallCodePointTrie; pub use cptrie::TrieType; pub use cptrie::TrieValue; +pub use cptrie::Typed; +pub use cptrie::TypedCodePointTrie; pub use error::Error as CodePointTrieError; diff --git a/deps/crates/vendor/icu_collections/src/codepointtrie/planes.rs b/deps/crates/vendor/icu_collections/src/codepointtrie/planes.rs index 70ab1629d8b731..a806632992fe55 100644 --- a/deps/crates/vendor/icu_collections/src/codepointtrie/planes.rs +++ b/deps/crates/vendor/icu_collections/src/codepointtrie/planes.rs @@ -172,9 +172,9 @@ pub fn get_planes_trie() -> CodePointTrie<'static, u8> { 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xe, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x10, 0x10, 0x10, 0, ]; - #[allow(clippy::unwrap_used)] // valid bytes + #[expect(clippy::unwrap_used)] // valid bytes let index: ZeroVec = ZeroVec::parse_bytes(index_array_as_bytes).unwrap(); - #[allow(clippy::unwrap_used)] // valid bytes + #[expect(clippy::unwrap_used)] // valid bytes let data: ZeroVec = ZeroVec::parse_bytes(data_8_array).unwrap(); let high_start = 0x100000; let shifted12_high_start = 0x100; @@ -192,7 +192,7 @@ pub fn get_planes_trie() -> CodePointTrie<'static, u8> { trie_type, }; - #[allow(clippy::unwrap_used)] // valid data + #[expect(clippy::unwrap_used)] // valid data CodePointTrie::try_new(trie_header, index, data).unwrap() } diff --git a/deps/crates/vendor/icu_collections/src/codepointtrie/serde.rs b/deps/crates/vendor/icu_collections/src/codepointtrie/serde.rs index 74b9e7bb3ed1b6..adfb2d8aa08e06 100644 --- a/deps/crates/vendor/icu_collections/src/codepointtrie/serde.rs +++ b/deps/crates/vendor/icu_collections/src/codepointtrie/serde.rs @@ -39,9 +39,31 @@ where D: Deserializer<'de>, { let de = CodePointTrieSerde::deserialize(deserializer)?; - let error_value = de.data.last().ok_or_else(|| { - D::Error::custom("CodePointTrie vector must have at least one element") - })?; + // SAFETY: + // `validate_fields` upholds the invariants for the fields that + // fast-path access without bound checks relies on. + let error_value = match CodePointTrie::validate_fields(&de.header, &de.index, &de.data) { + Ok(v) => v, + Err(e) => { + match e { + super::CodePointTrieError::FromDeserialized { reason } => { + // Not supposed to be returned by `validate_fields`. + debug_assert!(false); + return Err(D::Error::custom(reason)); + } + super::CodePointTrieError::EmptyDataVector => { + return Err(D::Error::custom("CodePointTrie must be constructed from data vector with at least one element")); + } + super::CodePointTrieError::IndexTooShortForFastAccess => { + return Err(D::Error::custom("CodePointTrie must be constructed from index vector long enough to accommodate fast-path access")); + } + super::CodePointTrieError::DataTooShortForFastAccess => { + return Err(D::Error::custom("CodePointTrie must be constructed from data vector long enough to accommodate fast-path access")); + } + } + } + }; + // Field invariants upheld: Checked by `validate_fields` above. Ok(CodePointTrie { header: de.header, index: de.index, diff --git a/deps/crates/vendor/icu_collections/src/codepointtrie/toml.rs b/deps/crates/vendor/icu_collections/src/codepointtrie/toml.rs index f8b0f7b4638e1e..af54098e1f21ad 100644 --- a/deps/crates/vendor/icu_collections/src/codepointtrie/toml.rs +++ b/deps/crates/vendor/icu_collections/src/codepointtrie/toml.rs @@ -18,7 +18,6 @@ use zerovec::ZeroVec; /// generated by ICU4C. /// /// Use `TryInto` to convert [`CodePointTrieToml`] to a proper [`CodePointTrie`]. -#[allow(clippy::upper_case_acronyms)] #[derive(serde::Deserialize)] pub struct CodePointTrieToml { #[serde(skip)] @@ -72,7 +71,7 @@ impl CodePointTrieToml { } /// Gets the `data` slice. - pub fn data_slice(&self) -> Result { + pub fn data_slice(&self) -> Result, Error> { if let Some(data_8) = &self.data_8 { Ok(CodePointDataSlice::U8(data_8.as_slice())) } else if let Some(data_16) = &self.data_16 { diff --git a/deps/crates/vendor/icu_collections/src/iterator_utils.rs b/deps/crates/vendor/icu_collections/src/iterator_utils.rs index 701a77eea31da8..0701f32ffd748e 100644 --- a/deps/crates/vendor/icu_collections/src/iterator_utils.rs +++ b/deps/crates/vendor/icu_collections/src/iterator_utils.rs @@ -39,7 +39,7 @@ where }; // Keep pulling ranges - #[allow(clippy::while_let_on_iterator)] + #[expect(clippy::while_let_on_iterator)] // can't move the iterator, also we want it to be explicit that we're not draining the iterator while let Some(next) = self.iter.next() { if *next.range.start() == ret.range.end() + 1 && next.value == ret.value { diff --git a/deps/crates/vendor/icu_collections/tests/cpt.rs b/deps/crates/vendor/icu_collections/tests/cpt.rs index 210277cf40f72c..f4b04d55963b09 100644 --- a/deps/crates/vendor/icu_collections/tests/cpt.rs +++ b/deps/crates/vendor/icu_collections/tests/cpt.rs @@ -255,7 +255,7 @@ pub fn check_trie>(trie: &CodePointTrie, check_range let range_value = range_tuple[1]; // Check all values in this range, one-by-one while i < range_limit { - assert_eq!(range_value, trie.get32(i).into(), "trie_get({})", i,); + assert_eq!(range_value, trie.get32(i).into(), "trie_get({i})",); i += 1; } } @@ -335,7 +335,6 @@ pub struct EnumPropCodePointMapData { pub ranges: Vec<(u32, u32, u32)>, } -#[allow(clippy::upper_case_acronyms)] #[cfg_attr(any(feature = "serde", test), derive(serde::Deserialize))] pub struct EnumPropSerializedCPT { #[cfg_attr(any(feature = "serde", test), serde(rename = "struct"))] @@ -347,7 +346,6 @@ pub struct EnumPropSerializedCPT { // using similar functions, some of these structs may be useful to refactor // into main code at a later point. -#[allow(clippy::upper_case_acronyms)] #[cfg_attr(any(feature = "serde", test), derive(serde::Deserialize))] pub struct EnumPropSerializedCPTStruct { #[cfg_attr(any(feature = "serde", test), serde(skip))] diff --git a/deps/crates/vendor/icu_locale/.cargo-checksum.json b/deps/crates/vendor/icu_locale/.cargo-checksum.json index 6a5d8438d2631c..6fb690bcbf0fb7 100644 --- a/deps/crates/vendor/icu_locale/.cargo-checksum.json +++ b/deps/crates/vendor/icu_locale/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"805f67596f172ac7494771909ebf7b32211d9d6b69010798fe0741e78fc0845d","LICENSE":"f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2","README.md":"3eabddc961d47b3205baacf44113fc4aa414d8429ae0b045a6a7e264af980747","benches/fixtures/locales.json":"9846601a29874baf140cac1252d4624fadc30182fec106d17f008ece886b9185","benches/fixtures/uncanonicalized-locales.json":"a866ed318b92f79d8853567e79b373c02984967023f5f39161140544e71b0c72","benches/locale_canonicalizer.rs":"3b6599352c88d2c039d083f91b5b7e222614946c55a77e3ccb1ae0b5fa2ae346","src/canonicalizer.rs":"a1266f265ea51e724496e1d789c9fc8768dd83ea6653a056bcd71b09cee7e774","src/directionality.rs":"af2e0421cf36d08232c1cf6b6d7e08824132128559fc69b888974c2ae007e8f5","src/exemplar_chars.rs":"70f37cde5153f27a4f112b908354d584a00daa6047ef9901569ef64f1a1da5f6","src/expander.rs":"6e865c782717fc3f1a5d16054142aa3cfb443e2ee4ebc1eb432070355f7f1a0e","src/fallback/algorithms.rs":"8141ff08b43b20275b54f97e5a890e52dca3c293d9a8dad42d48ca43c2304b35","src/fallback/mod.rs":"a4d802f9a06440f97784449b28da49ba349b8402f2b96dfebb7611c982b6fcf6","src/lib.rs":"683b67c0352bab45eb38c0aa249532a16168edac33ec278c9aed60be8aa5df9f","src/provider.rs":"6ff47585fda0d8f60db3c34492890b1bf0fcf8354cfe2b80ebce884bf78f1179","tests/fixtures/canonicalize.json":"3dc2f661b04e4c9ecced70fc1b98a504eb5f5a0067b38665b10e50c25174bc4a","tests/fixtures/maximize.json":"bc38baf34858d6000e617a63bb30d07c439e838aaac493e2d6513cd36b222c3c","tests/fixtures/minimize.json":"efe180ddaf299670a900cf1d676c5f97caa97f7827d10a2e436ce959d637ba7f","tests/fixtures/mod.rs":"98ee70076a3554bb5043ecb1e3643fd47c6bac126724ee207b0633017b8763ed","tests/locale_canonicalizer.rs":"db8f560a0a8591aca4bd8713c13e5bf705b08f8ea184efdf64e240218188b767"},"package":"6ae5921528335e91da1b6c695dbf1ec37df5ac13faa3f91e5640be93aa2fbefd"} \ No newline at end of file +{"files":{".cargo_vcs_info.json":"75f8e5fb1d26d5b74f3aa5d09b4aced17b8ab9a9155ecf57bc5f528445916547","Cargo.lock":"b3f2f2eed3b6035323161be0b43ff6f66864420afe482c7f9d1c3689489ef790","Cargo.toml":"2f55d17536899327b3f4b59f44f20c8d932c84bc4c7016270c49992c081273a4","Cargo.toml.orig":"9cf2a1729c32b9736763644d8af2ab09a4971a6f0fc3d932dfb9d7e03b650594","LICENSE":"f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2","README.md":"3eabddc961d47b3205baacf44113fc4aa414d8429ae0b045a6a7e264af980747","benches/fixtures/locales.json":"9846601a29874baf140cac1252d4624fadc30182fec106d17f008ece886b9185","benches/fixtures/uncanonicalized-locales.json":"a866ed318b92f79d8853567e79b373c02984967023f5f39161140544e71b0c72","benches/locale_canonicalizer.rs":"3b6599352c88d2c039d083f91b5b7e222614946c55a77e3ccb1ae0b5fa2ae346","src/canonicalizer.rs":"88255bae6b4f2799ff9d3f644ec6de8dbd558b5a9f6634e5c5390caa7ec758f2","src/directionality.rs":"af2e0421cf36d08232c1cf6b6d7e08824132128559fc69b888974c2ae007e8f5","src/exemplar_chars.rs":"70f37cde5153f27a4f112b908354d584a00daa6047ef9901569ef64f1a1da5f6","src/expander.rs":"f74f35d1b58b3086cd1d992c35238831057c9063c6afc6bc4dd0ef702bf8cf4b","src/fallback/algorithms.rs":"93c0bdc427570dc2899ccdd2f82ad5e3237e5afe6890c3e7a09ef92dcf63661b","src/fallback/mod.rs":"fd51cb417d0918df4c9f02da3095430e236af7dd9ab87df7fa683fdf2e83b011","src/lib.rs":"683b67c0352bab45eb38c0aa249532a16168edac33ec278c9aed60be8aa5df9f","src/provider.rs":"6ff47585fda0d8f60db3c34492890b1bf0fcf8354cfe2b80ebce884bf78f1179","tests/fixtures/canonicalize.json":"3dc2f661b04e4c9ecced70fc1b98a504eb5f5a0067b38665b10e50c25174bc4a","tests/fixtures/maximize.json":"bc38baf34858d6000e617a63bb30d07c439e838aaac493e2d6513cd36b222c3c","tests/fixtures/minimize.json":"efe180ddaf299670a900cf1d676c5f97caa97f7827d10a2e436ce959d637ba7f","tests/fixtures/mod.rs":"98ee70076a3554bb5043ecb1e3643fd47c6bac126724ee207b0633017b8763ed","tests/locale_canonicalizer.rs":"dc00a426018d2c5ffec6077f962ce6da1f458ff2df14ba53f2cc390ab2fc622e"},"package":"532b11722e350ab6bf916ba6eb0efe3ee54b932666afec989465f9243fe6dd60"} \ No newline at end of file diff --git a/deps/crates/vendor/icu_locale/.cargo_vcs_info.json b/deps/crates/vendor/icu_locale/.cargo_vcs_info.json new file mode 100644 index 00000000000000..82f90aa2fb05c6 --- /dev/null +++ b/deps/crates/vendor/icu_locale/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "38a49da495248dd1ded84cf306e4ca42e64d5bb3" + }, + "path_in_vcs": "components/locale" +} \ No newline at end of file diff --git a/deps/crates/vendor/icu_locale/Cargo.lock b/deps/crates/vendor/icu_locale/Cargo.lock new file mode 100644 index 00000000000000..921a35c9b3426b --- /dev/null +++ b/deps/crates/vendor/icu_locale/Cargo.lock @@ -0,0 +1,845 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clap" +version = "4.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror", +] + +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "databake" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6ee9e2d2afb173bcdeee45934c89ec341ab26f91c9933774fc15c2b58f83ef" +dependencies = [ + "databake-derive", + "proc-macro2", + "quote", +] + +[[package]] +name = "databake-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6834770958c7b84223607e49758ec0dde273c4df915e734aad50f62968a4c134" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "erased-serde" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "259d404d09818dec19332e31d94558aeb442fea04c817006456c24b5460bbd4b" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "databake", + "displaydoc", + "potential_utf", + "serde", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale" +version = "2.1.1" +dependencies = [ + "criterion", + "databake", + "icu_collections", + "icu_locale_core", + "icu_locale_data", + "icu_provider", + "potential_utf", + "serde", + "serde_json", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "databake", + "displaydoc", + "litemap", + "serde", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locale_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f03e2fcaefecdf05619f3d6f91740e79ab969b4dd54f77cbf546b1d0d28e3147" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "databake", + "displaydoc", + "erased-serde", + "icu_locale_core", + "postcard", + "serde", + "stable_deref_trait", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "is-terminal" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "js-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.177" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "oorandom" +version = "11.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" + +[[package]] +name = "plotters" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" + +[[package]] +name = "plotters-svg" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "serde", +] + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "serde_core", + "writeable", + "zerovec", +] + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.145" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", + "serde_core", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "syn" +version = "2.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "databake", + "displaydoc", + "serde_core", + "zerovec", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "unicode-ident" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "databake", + "serde", + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/deps/crates/vendor/icu_locale/Cargo.toml b/deps/crates/vendor/icu_locale/Cargo.toml index 7c1c38bb74c4f5..270bc9bfc418a9 100644 --- a/deps/crates/vendor/icu_locale/Cargo.toml +++ b/deps/crates/vendor/icu_locale/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.82" +rust-version = "1.83" name = "icu_locale" -version = "2.0.0" +version = "2.1.1" authors = ["The ICU4X Project Developers"] build = false include = [ @@ -91,16 +91,12 @@ features = ["derive"] optional = true default-features = false -[dependencies.displaydoc] -version = "0.2.3" -default-features = false - [dependencies.icu_collections] -version = "~2.0.0" +version = "~2.1.1" default-features = false [dependencies.icu_locale_core] -version = "2.0.0" +version = "2.1.1" features = [ "alloc", "zerovec", @@ -108,16 +104,17 @@ features = [ default-features = false [dependencies.icu_locale_data] -version = "~2.0.0" +version = "~2.1.1" optional = true default-features = false [dependencies.icu_provider] -version = "2.0.0" +version = "2.1.1" +features = ["alloc"] default-features = false [dependencies.potential_utf] -version = "0.1.1" +version = "0.1.3" features = [ "alloc", "zerovec", @@ -125,7 +122,7 @@ features = [ default-features = false [dependencies.serde] -version = "1.0.110" +version = "1.0.220" features = [ "derive", "alloc", @@ -142,7 +139,7 @@ features = [ default-features = false [dependencies.zerovec] -version = "0.11.1" +version = "0.11.3" features = [ "alloc", "yoke", @@ -150,7 +147,7 @@ features = [ default-features = false [dev-dependencies.serde] -version = "1.0.110" +version = "1.0.220" features = ["derive"] default-features = false diff --git a/deps/crates/vendor/icu_locale/Cargo.toml.orig b/deps/crates/vendor/icu_locale/Cargo.toml.orig new file mode 100644 index 00000000000000..1d96b0151d25e3 --- /dev/null +++ b/deps/crates/vendor/icu_locale/Cargo.toml.orig @@ -0,0 +1,62 @@ +# This file is part of ICU4X. For terms of use, please see the file +# called LICENSE at the top level of the ICU4X source tree +# (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +[package] +name = "icu_locale" +description = "API for Unicode Language and Locale Identifiers canonicalization" + +authors.workspace = true +categories.workspace = true +edition.workspace = true +homepage.workspace = true +include.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true +version.workspace = true + +[package.metadata.cargo-all-features] +skip_optional_dependencies = true + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +databake = { workspace = true, optional = true, features = ["derive"] } +icu_locale_core = { workspace = true, features = ["alloc", "zerovec"] } +icu_provider = { workspace = true, features = ["alloc"] } +serde = { workspace = true, features = ["derive", "alloc"], optional = true } +tinystr = { workspace = true, features = ["alloc", "zerovec"] } +potential_utf = { workspace = true, features = ["alloc", "zerovec"] } +zerovec = { workspace = true, features = ["alloc", "yoke"] } + +icu_collections = { workspace = true } + +icu_locale_data = { workspace = true, optional = true } + +[dev-dependencies] +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +icu = { path = "../../components/icu", default-features = false } +writeable = { path = "../../utils/writeable" } + +[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] +criterion = { workspace = true } + +[lib] +bench = false # This option is required for Benchmark CI + +[features] +default = ["compiled_data"] +serde = ["dep:serde", "icu_locale_core/serde", "tinystr/serde", "zerovec/serde", "icu_provider/serde", "potential_utf/serde", "icu_collections/serde"] +datagen = ["serde", "dep:databake", "zerovec/databake", "icu_locale_core/databake", "tinystr/databake", "icu_collections/databake", "icu_provider/export"] +compiled_data = ["dep:icu_locale_data", "icu_provider/baked"] + +[[bench]] +name = "locale_canonicalizer" +harness = false + +[[test]] +name = "locale_canonicalizer" +required-features = ["serde"] diff --git a/deps/crates/vendor/icu_locale/src/canonicalizer.rs b/deps/crates/vendor/icu_locale/src/canonicalizer.rs index c8320cc1d447fe..ea6a14a3d4374e 100644 --- a/deps/crates/vendor/icu_locale/src/canonicalizer.rs +++ b/deps/crates/vendor/icu_locale/src/canonicalizer.rs @@ -450,7 +450,7 @@ impl> LocaleCanonicalizer { if modified.is_empty() { modified = locale.id.variants.to_vec(); } - #[allow(clippy::indexing_slicing)] + #[expect(clippy::indexing_slicing)] let _ = core::mem::replace(&mut modified[idx], updated); } } @@ -589,8 +589,7 @@ mod test { rule.variants.iter().map(Variant::as_str), ), result, - "{}", - source + "{source}" ); } } diff --git a/deps/crates/vendor/icu_locale/src/expander.rs b/deps/crates/vendor/icu_locale/src/expander.rs index 25291a6649013d..f1d6684dd4a6ac 100644 --- a/deps/crates/vendor/icu_locale/src/expander.rs +++ b/deps/crates/vendor/icu_locale/src/expander.rs @@ -310,7 +310,7 @@ impl LocaleExpander { }) } - fn as_borrowed(&self) -> LocaleExpanderBorrowed { + fn as_borrowed(&self) -> LocaleExpanderBorrowed<'_> { LocaleExpanderBorrowed { likely_subtags_l: self.likely_subtags_l.get(), likely_subtags_sr: self.likely_subtags_sr.get(), diff --git a/deps/crates/vendor/icu_locale/src/fallback/algorithms.rs b/deps/crates/vendor/icu_locale/src/fallback/algorithms.rs index 58f2352cc6e860..7e9e5f0419cf23 100644 --- a/deps/crates/vendor/icu_locale/src/fallback/algorithms.rs +++ b/deps/crates/vendor/icu_locale/src/fallback/algorithms.rs @@ -204,7 +204,6 @@ impl LocaleFallbackIteratorInner<'_> { locale.variant = self.backup_variant.take(); } // needed if more fallback is added at the end - #[allow(clippy::needless_return)] return; } else { // 3. Remove the language and apply the maximized script @@ -215,7 +214,6 @@ impl LocaleFallbackIteratorInner<'_> { locale.variant = self.backup_variant.take(); } // needed if more fallback is added at the end - #[allow(clippy::needless_return)] return; } } diff --git a/deps/crates/vendor/icu_locale/src/fallback/mod.rs b/deps/crates/vendor/icu_locale/src/fallback/mod.rs index d1266831f65401..8f13a620493ab3 100644 --- a/deps/crates/vendor/icu_locale/src/fallback/mod.rs +++ b/deps/crates/vendor/icu_locale/src/fallback/mod.rs @@ -104,8 +104,7 @@ impl LocaleFallbacker { /// /// [📚 Help choosing a constructor](icu_provider::constructors) #[cfg(feature = "compiled_data")] - #[allow(clippy::new_ret_no_self)] // keeping constructors together - #[allow(clippy::new_without_default)] // Deliberate choice, see #5554 + #[expect(clippy::new_ret_no_self)] // keeping constructors together pub const fn new<'a>() -> LocaleFallbackerBorrowed<'a> { // Safety: we're transmuting down from LocaleFallbackerBorrowed<'static> to LocaleFallbackerBorrowed<'a> // ZeroMaps use associated types in a way that confuse the compiler which gives up and marks them @@ -157,12 +156,12 @@ impl LocaleFallbacker { /// Associates a configuration with this fallbacker. #[inline] - pub fn for_config(&self, config: LocaleFallbackConfig) -> LocaleFallbackerWithConfig { + pub fn for_config(&self, config: LocaleFallbackConfig) -> LocaleFallbackerWithConfig<'_> { self.as_borrowed().for_config(config) } /// Creates a borrowed version of this fallbacker for performance. - pub fn as_borrowed(&self) -> LocaleFallbackerBorrowed { + pub fn as_borrowed(&self) -> LocaleFallbackerBorrowed<'_> { LocaleFallbackerBorrowed { likely_subtags: self.likely_subtags.get(), parents: self.parents.get(), @@ -189,7 +188,7 @@ impl LocaleFallbackerBorrowed<'static> { /// /// [📚 Help choosing a constructor](icu_provider::constructors) #[cfg(feature = "compiled_data")] - #[allow(clippy::new_without_default)] + #[expect(clippy::new_without_default)] pub const fn new() -> Self { Self { likely_subtags: crate::provider::Baked::SINGLETON_LOCALE_LIKELY_SUBTAGS_LANGUAGE_V1, diff --git a/deps/crates/vendor/icu_locale/tests/locale_canonicalizer.rs b/deps/crates/vendor/icu_locale/tests/locale_canonicalizer.rs index aa91070fcf3a89..b5dceed85568dd 100644 --- a/deps/crates/vendor/icu_locale/tests/locale_canonicalizer.rs +++ b/deps/crates/vendor/icu_locale/tests/locale_canonicalizer.rs @@ -25,9 +25,9 @@ fn test_maximize() { let result = lc.maximize(&mut locale.id); assert_writeable_eq!(locale, case.output, "{:?}", case); if result == TransformResult::Modified { - assert_ne!(locale, unmodified, "{:?}", case); + assert_ne!(locale, unmodified, "{case:?}"); } else { - assert_eq!(locale, unmodified, "{:?}", case); + assert_eq!(locale, unmodified, "{case:?}"); } } } @@ -49,9 +49,9 @@ fn test_minimize() { let result = lc.minimize(&mut locale.id); assert_writeable_eq!(locale, case.output, "{:?}", case); if result == TransformResult::Modified { - assert_ne!(locale, unmodified, "{:?}", case); + assert_ne!(locale, unmodified, "{case:?}"); } else { - assert_eq!(locale, unmodified, "{:?}", case); + assert_eq!(locale, unmodified, "{case:?}"); } } } @@ -73,9 +73,9 @@ fn test_canonicalize() { let result = lc.canonicalize(&mut locale); assert_writeable_eq!(locale, case.output, "{:?}", case); if result == TransformResult::Modified { - assert_ne!(locale, unmodified, "{:?}", case); + assert_ne!(locale, unmodified, "{case:?}"); } else { - assert_eq!(locale, unmodified, "{:?}", case); + assert_eq!(locale, unmodified, "{case:?}"); } } } diff --git a/deps/crates/vendor/icu_locale_core/.cargo-checksum.json b/deps/crates/vendor/icu_locale_core/.cargo-checksum.json index 93787cc80f4487..c60bf2a096b473 100644 --- a/deps/crates/vendor/icu_locale_core/.cargo-checksum.json +++ b/deps/crates/vendor/icu_locale_core/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"1410e3b8b7992dc36ace635a935718887ee70908121633151e9ae31fff773e81","LICENSE":"f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2","README.md":"3e30d773b84c9682a0f03fbfae067edca276b16a2ed0f0ab99c31f6a53aa68b2","benches/fixtures/langid.json":"373c11527653c63c685c9e229a8de5ae2b557c25b686a9d891c59e1f603232d8","benches/fixtures/locale.json":"669b19db933094290a45bf856559920f4e92401072e364ac82c482119dc9233a","benches/fixtures/mod.rs":"d59ae0ebb4d42c5b9a89376bb20d400145eeb8edcd4e93dcd07adfd55f1db8c0","benches/fixtures/subtags.json":"28be3a639e452d713e807d5779b6819e06277e2dbbf67801ef34964fb9b074b6","benches/helpers/macros.rs":"b9bf068a08156f8421ea39ca2a5b83351f9f9b63336b207706b75d1acb7697ac","benches/helpers/mod.rs":"9118aceb41badd98a6d3e07f79bf6328f3da1f93ae82ef99e6ca7e7229aa4c42","benches/iai_langid.rs":"256aa84228af9fd730a90ffc81b2adafaec131b338d786142b770fa45fc221f1","benches/langid.rs":"0203769d2c5ae9d5269344216b93d43c6cb9f58bf4e3b182247afe00f5bb0287","benches/locale.rs":"172d82598b2924515de72c731837d702ce2ff75fdc3655069288c9015ff30c56","benches/subtags.rs":"6ff85047f04896749dff12ed00060afc882ac2ff27f86a57c3afdcbba13f797a","src/data.rs":"bb36f7ed75cdabbfc54c7e108057d85583c712aaf1783b713ef71b5008493032","src/databake.rs":"b0cb3175eb2a919fe9d48d6c85635676a99d2474fc34b2b2ba503fd6d67fec3e","src/extensions/mod.rs":"b5982c55e099b4596371c2d7faed4086009c33d9fc6e10b475f5655bde6727fc","src/extensions/other/mod.rs":"5dc66dcde0263c1b9562f8ef90edcd616c49b118a40059458e314d45a672a337","src/extensions/private/mod.rs":"0a5271741722dbe0495713946c19d257e63dde3b4ab80d7c81c51c251557979d","src/extensions/private/other.rs":"050fba0eeb47b45c539ebda561cabe8f2d6b1cd6ab272bd8d25eb34b33466c96","src/extensions/transform/fields.rs":"88b968c260de0e7ee92efd044bb85392846db22acc19be3b9acfbad410ab1e5f","src/extensions/transform/key.rs":"7b44e1ccd95f3fcc0892a018effa054cd74d64a3667535eed2270d41baef1393","src/extensions/transform/mod.rs":"9072ebdb61afb5427d60855289a686dbf8debbee36feecdc034bdbac8593e97c","src/extensions/transform/value.rs":"5aa653c37cd7c2ae0aec9b37f102986095ec904bdac797c374cabad9059bd9a7","src/extensions/unicode/attribute.rs":"c2a6cfc920532c58023c40a9bd10632a73aedd4670a1562fa7caa15a500018e1","src/extensions/unicode/attributes.rs":"c644d7dcf310e4e24376351e45ec88db08c3d86f1c53d3d163ecc08cfcdda212","src/extensions/unicode/key.rs":"ad3c8844b6b55529d70a7d91889bf53703f92994b316d5c9052fe68b5350e530","src/extensions/unicode/keywords.rs":"73f563d887412ff4bc37947c1df9f361df6e34d1e82f2a4c906cf115844d7dd5","src/extensions/unicode/mod.rs":"a51ce421f1375d8c8108d09094951ccd44eb6488100c1ed57dbd2d2432f0da0f","src/extensions/unicode/subdivision.rs":"a1523c051f55833c94995d95920579a2c30cea98cba9e68cd1f90bc21ce2c9ea","src/extensions/unicode/value.rs":"ac158d119ef833a0b457405ffb792cc4eda7edf2e14906cfc1be737d5f69e444","src/helpers.rs":"20a7de315db2c0b48e343e81a9b45dc5548025facfe880ae81e00f59530259fc","src/langid.rs":"21bc904b0098c42817a271398afd2822b2cd5f87936f8cb676e5c91e05197bac","src/lib.rs":"8128cdc5057eed807e057d241f545b59e76b64e106938c4fc87aa558afcc72b6","src/locale.rs":"0ad643efa17d23ca68f6ce7edc4aee60e42486e5ac7448640d61f9488d162740","src/macros.rs":"ed064e4a5bec77706d3022d73e24a6d410b2e7cd395447b6bcb5822c4714bd1c","src/parser/errors.rs":"9959d6e1f00f89ce739d18d489cf7733865cb95a26e4a33b9651eda2e310d89d","src/parser/langid.rs":"f60fb31f7dea4d6090a411da15773135283b6ea8564f4f51be702ce3d40bacf6","src/parser/locale.rs":"81068dfdcc1e765d759df7eb964c8441a3e6e17be881b059be49af2cf802b4d4","src/parser/mod.rs":"7202edc3c6cea056d9172c0a18c1fa84ad2b9a1409809974da93ae9ab80080ae","src/preferences/extensions/mod.rs":"8055be6df84eac91b2bb96603e022025ff80b8f6594b5a82c2b0fb95f0367043","src/preferences/extensions/unicode/errors.rs":"9f6e2edfaecd1b8679aa011c1d35250be8d0aac9ea5558b1e0fa58f5f9527ead","src/preferences/extensions/unicode/keywords/calendar.rs":"472defc4a3574b56496c8d2542ef98584cc1f2f33c3b0903131983158e19f768","src/preferences/extensions/unicode/keywords/collation.rs":"9c60a1156c8e20f4a0fdfa6a544f047ca0710fc116a9e8bdcbaa8d8fdc743f87","src/preferences/extensions/unicode/keywords/currency.rs":"92335724649b7ce1f840fe8f0b02f1896a7dab495d36fc45e7858bfa645420bd","src/preferences/extensions/unicode/keywords/currency_format.rs":"03c94e5dd3253c4cb1c8a4d5a2708be3d77cae9c334985649213440b8bac42c0","src/preferences/extensions/unicode/keywords/dictionary_break.rs":"a13ad0985a98dbf7cea96e2c50db1b6f9513d099a5b15f8bd55edc1e922699cc","src/preferences/extensions/unicode/keywords/emoji.rs":"0c79aa3b90cc228580204807d82809587e00204bc3d09783e4dfc2c302bec984","src/preferences/extensions/unicode/keywords/first_day.rs":"16471ad310624f059f1c280f3aa518f379d746feb892b6a8533631557d5ce690","src/preferences/extensions/unicode/keywords/hour_cycle.rs":"531e959c95a8289c56050e8b5e6ae899277c49b4c8a7f04f99cebf436db25fd6","src/preferences/extensions/unicode/keywords/line_break.rs":"5380f187ea22ea24576c15507a1b1275c947f374c9ec05ac4ba6576ba26122e2","src/preferences/extensions/unicode/keywords/line_break_word.rs":"7aae1d07ffaa6c2a44617b99c8bc1ba19df048cc3ec7aac10ccff89a6d84304b","src/preferences/extensions/unicode/keywords/measurement_system.rs":"b41bb9ce40c310e7370b11f211ca22cb07b08e8c7a8f0aab2dc99a766ff2b22e","src/preferences/extensions/unicode/keywords/measurement_unit_override.rs":"6670167cd9942cfc1c6c1b45d954ae3acc8c69f0609eefe1e33532fb02cdb8fd","src/preferences/extensions/unicode/keywords/mod.rs":"1ca967da8529fe3f7d1943da6e853d753ba2dd94ac5a86f496c80b3ff22b7df7","src/preferences/extensions/unicode/keywords/numbering_system.rs":"47105a6613fca0f9306f1db3f0ce9b5b29416218144af5596ed392ab552521f1","src/preferences/extensions/unicode/keywords/region_override.rs":"65590219d58dcf466f48f07f94d6fc0ce1433182e5acd8e926ad01f6a7d245be","src/preferences/extensions/unicode/keywords/regional_subdivision.rs":"0e54659cfc99c416fc108580c34c4710fbf32b9183422635b6c766d6a47e0d05","src/preferences/extensions/unicode/keywords/sentence_supression.rs":"31942a4bedc3e247bbd73740baf32e3b95bb4c91522dbc55f97c3374eee8669e","src/preferences/extensions/unicode/keywords/timezone.rs":"1d7f7ba02728919d57e793fe1d695e7d47bd5c173d72e518b7e35f0e724c77d9","src/preferences/extensions/unicode/keywords/variant.rs":"3d96c4da532d59965d81761fdf7aa78ec3bbd316bf72ec23e7d19d292850bc76","src/preferences/extensions/unicode/macros/enum_keyword.rs":"70c3185eacd51a1698c14ff98f68a49a788729893f6975b83cf6ccc8aae8d0e0","src/preferences/extensions/unicode/macros/mod.rs":"7a62888e12399959469a39c7f353e7b5d00988302f78b44df5e3b7fd22e442c7","src/preferences/extensions/unicode/macros/struct_keyword.rs":"dba324f98c3e108b7add972cbf2a9586486e560350d736a4e7034834177472d6","src/preferences/extensions/unicode/mod.rs":"9ce8a095b63724f124798a0f7e4b7dcc60bd0e7bfb2523d0f9e11883a81f904d","src/preferences/locale.rs":"67ae458b6c8cbaa9fbec2f602fe3b33f6a82f9b5a3968c0b45a80ee9aae4a812","src/preferences/mod.rs":"36940ac6a6476276fff513fef174bc45eda3487507e14adeab2bc1794f763376","src/serde.rs":"0a9c35d10714376621bf15e1f12d00bf05fc30f20c1e53be17d67bc64c03d63a","src/shortvec/litemap.rs":"e3970c8984ff951d613a951bc372a67ec4410bb49e209979181e8aedb2eaebee","src/shortvec/mod.rs":"be860b8574ca081a14e4dcf63344c259f0e31b2f11c4ddd75c7fb21c81b4e7c3","src/subtags/language.rs":"94757472cfb54f2f583c79ea6ad7c7662240868a2bc04e4b938998e32a8de394","src/subtags/mod.rs":"29e68217c2a47aa70db941467631eee7343bec96d823cf79eb70fcb8975abfd9","src/subtags/region.rs":"1157ea7f2defb86233ee86f4522e494d6dfe4776a2b5f853008c75cbbcc312f0","src/subtags/script.rs":"f562cc5607b5acec4ba5fc14dddf5d7eff1d19129535f3a309fd0fb31607b714","src/subtags/variant.rs":"6230b1bb252b0782c9cb015be8f583e8b2d8ab7ffff79789bb6df600e2b0eb5c","src/subtags/variants.rs":"c8caa29a442f527f657bee41fb2179c3eb01f30fde9bf80198bc54bc273732ed","src/zerovec.rs":"89442aa13615cfd3d92d9079249f8432e33b7739401dda3266b4c2a9d4a5ff7b","tests/fixtures/canonicalize.json":"5414bd4972eb80ba46c727b407a8ed48a6e12e3639db034033586813c872f59c","tests/fixtures/invalid-extensions.json":"36eb5966085a1c9e966689af504cfbf8ea9b78b741675fe033ec9b6153e63ea6","tests/fixtures/invalid.json":"109169258632bd23d06827dfae6509f02a8127ffec25f48281ed61d795c67765","tests/fixtures/langid.json":"960fd01722217ef1ea9077e2e0821d7089fe318a241bd7fb7918f50bf8f3f5c3","tests/fixtures/locale.json":"df1b195b18780758a6b1c0264206b9cd9ac8c4741c5d6b0cc2b92f8e17991c17","tests/fixtures/mod.rs":"12e5815ba46229304aa8234eb537faa568f10576815739beaa3f815134d7e7ac","tests/langid.rs":"d79f33c1f536bec7a0eb1c466842afd61e15098f5039ea6a8085cdf31128199c","tests/locale.rs":"a7ffc4e9d1ebc70e9d915994033b3853285764953c6f0416f07e30520852b17f"},"package":"93cca704c2d63cf8a91f5c2c5f88e027940dede132319b85a52939db9758f7e5"} \ No newline at end of file +{"files":{".cargo_vcs_info.json":"87472294cb1b942324597b25d40baa022967be22454f8c2172de6089d9ff8d32","Cargo.lock":"060041080fd4db117c6f5604ac650c14f88eedbc28b5169a30f3337d40b4313f","Cargo.toml":"4dd1fdf5dcd1517c4f6339872f8589f2074090ede054ba1f38259ad7d6abb7af","Cargo.toml.orig":"1953cfdf680ff8b4f33d2602aee3a0e8c5dc11c8936325953fb254bf2c3b4840","LICENSE":"f367c1b8e1aa262435251e442901da4607b4650e0e63a026f5044473ecfb90f2","README.md":"3e30d773b84c9682a0f03fbfae067edca276b16a2ed0f0ab99c31f6a53aa68b2","benches/fixtures/langid.json":"373c11527653c63c685c9e229a8de5ae2b557c25b686a9d891c59e1f603232d8","benches/fixtures/locale.json":"669b19db933094290a45bf856559920f4e92401072e364ac82c482119dc9233a","benches/fixtures/mod.rs":"d59ae0ebb4d42c5b9a89376bb20d400145eeb8edcd4e93dcd07adfd55f1db8c0","benches/fixtures/subtags.json":"28be3a639e452d713e807d5779b6819e06277e2dbbf67801ef34964fb9b074b6","benches/helpers/macros.rs":"b9bf068a08156f8421ea39ca2a5b83351f9f9b63336b207706b75d1acb7697ac","benches/helpers/mod.rs":"9118aceb41badd98a6d3e07f79bf6328f3da1f93ae82ef99e6ca7e7229aa4c42","benches/iai_langid.rs":"256aa84228af9fd730a90ffc81b2adafaec131b338d786142b770fa45fc221f1","benches/langid.rs":"0203769d2c5ae9d5269344216b93d43c6cb9f58bf4e3b182247afe00f5bb0287","benches/locale.rs":"172d82598b2924515de72c731837d702ce2ff75fdc3655069288c9015ff30c56","benches/subtags.rs":"6ff85047f04896749dff12ed00060afc882ac2ff27f86a57c3afdcbba13f797a","src/data.rs":"29274b5276adeb92d91a2da4a37cc9216e131e1d8f7984d50d6899f5e71e9d20","src/databake.rs":"b0cb3175eb2a919fe9d48d6c85635676a99d2474fc34b2b2ba503fd6d67fec3e","src/extensions/mod.rs":"93c2d618750068e4f724fc3389330115daae93fdff54f13d3c6d81852127a417","src/extensions/other/mod.rs":"7548cca590f16f04db3245e322b0ba3596eff26c129f89bb554fc2c7d3e97c16","src/extensions/private/mod.rs":"0063cd169fa42285c331a8c4d9c3a24a60a79d9217bebb4b105523fde678faba","src/extensions/private/other.rs":"050fba0eeb47b45c539ebda561cabe8f2d6b1cd6ab272bd8d25eb34b33466c96","src/extensions/transform/fields.rs":"06ba3c3baec94b76f8120bdb8e76ceeb5cdab4e9dba6852f10965e8af8e76dd3","src/extensions/transform/key.rs":"7b44e1ccd95f3fcc0892a018effa054cd74d64a3667535eed2270d41baef1393","src/extensions/transform/mod.rs":"1a24f18770f870985501069d760b0ab26a071c4fb32738fb5a81e309eacd16eb","src/extensions/transform/value.rs":"6ee1205b7576d7d49d9d2b983e7bea7e8b92db9f2a70cd940c1f61bf94e14eef","src/extensions/unicode/attribute.rs":"c2a6cfc920532c58023c40a9bd10632a73aedd4670a1562fa7caa15a500018e1","src/extensions/unicode/attributes.rs":"5fe26de18edf670e93aeff51a1d95f29a2117d4f965796126c6c99baf2640683","src/extensions/unicode/key.rs":"ad3c8844b6b55529d70a7d91889bf53703f92994b316d5c9052fe68b5350e530","src/extensions/unicode/keywords.rs":"25028c190011c26ff98c1f41d756b832c5077d47bc3cda16619080c0ea9256f5","src/extensions/unicode/mod.rs":"c3d96faca4cfbb2097ee163adf7d2284f3bdf809a74aa5465f96af9f8a3b2d1d","src/extensions/unicode/subdivision.rs":"ee1c7d0e4b0e4fe3124dafaafef24356f661077201a6a16269b0315374f0bf7a","src/extensions/unicode/value.rs":"d30a4708c7cc0867bd863ad40b49419116786cc39eedd06205088af1b60a10ee","src/helpers.rs":"b157f722e09e3da2bc1920cb964638940207173c5bcfcc271c3086a8a70cfb77","src/langid.rs":"d37dc4aaf8d07bf2dc21a028ea117295f37f46afefe98845e65740692bdf317c","src/lib.rs":"0f38bc043dd3f9ee84c0934f91aa32a739f0b5f839e32869180f94270c284bc6","src/locale.rs":"c595ec154ea306359c92a4b5bc7e6f42fc0b8cbc1bb3a1d145ce9ba36fe63c4e","src/macros.rs":"c2d9fa8a671561d7e9b8082439d56450a1d87039fa5040742a95bd3ab85e9288","src/parser/errors.rs":"9959d6e1f00f89ce739d18d489cf7733865cb95a26e4a33b9651eda2e310d89d","src/parser/langid.rs":"32b4950254793f77d0d5873cba17d6e134b0c3772cbddf559c9e52f4af80d57f","src/parser/locale.rs":"3ba0374f8af82c3751974c4007cd167753153dc3bca9f0cd70d0b0cd17b36fe0","src/parser/mod.rs":"56430a72c3c407f9661e9b6062b7bb13627c508838330482a1a6630de3169d94","src/preferences/extensions/mod.rs":"8055be6df84eac91b2bb96603e022025ff80b8f6594b5a82c2b0fb95f0367043","src/preferences/extensions/unicode/errors.rs":"9f6e2edfaecd1b8679aa011c1d35250be8d0aac9ea5558b1e0fa58f5f9527ead","src/preferences/extensions/unicode/keywords/calendar.rs":"e78abd46c4488776e720e6e4fbef4cf7d2c0e7a5a73a5897b5a0a43c497c0609","src/preferences/extensions/unicode/keywords/collation.rs":"2fbdf8d32967afa80ae35eb33555fb390d96c8690efcfd0d61e30d09f945781c","src/preferences/extensions/unicode/keywords/currency.rs":"92335724649b7ce1f840fe8f0b02f1896a7dab495d36fc45e7858bfa645420bd","src/preferences/extensions/unicode/keywords/currency_format.rs":"69ca7166d19a3d90953bd898e00ad76db89570b7973f251d930d5b5f090ef3ef","src/preferences/extensions/unicode/keywords/dictionary_break.rs":"2489abf09a017c419de5e443ac4bf014476c27c6d31b84a2b55cf6fa53740826","src/preferences/extensions/unicode/keywords/emoji.rs":"0b34acbba058050452d7b4d0b538cd784d5bb76b54cac7b2acd1f946b3ae04c5","src/preferences/extensions/unicode/keywords/first_day.rs":"65e7be67e62b0f5de16508001d2a9d902361eb630df1be5ef4d0ea4f24713e0e","src/preferences/extensions/unicode/keywords/hour_cycle.rs":"01d36e9066b4c6a8db0bf224f0877fa9f4414217484267fff183779b492a11e5","src/preferences/extensions/unicode/keywords/line_break.rs":"0292b4e9c6dadf9759f7371e1a4b6db0b917211026b7dde1983a1726e1d89206","src/preferences/extensions/unicode/keywords/line_break_word.rs":"6fef4aef3dc44541bb1cbeefc0a8cdb9b97f0a26ad9c4f9be057cb4fb3f1c45b","src/preferences/extensions/unicode/keywords/measurement_system.rs":"ddcadb5c654f6dd253ea70a095534978588788979f03796fa128354d349bf909","src/preferences/extensions/unicode/keywords/measurement_unit_override.rs":"ee3a9417050f6b7d6e5c987ece779218e006a19136fea705485bf080c0865dde","src/preferences/extensions/unicode/keywords/mod.rs":"18c6384f19567e7865b48963eb43f34cb53e4eb52dfa9e6592e3af64a4b4b687","src/preferences/extensions/unicode/keywords/numbering_system.rs":"47105a6613fca0f9306f1db3f0ce9b5b29416218144af5596ed392ab552521f1","src/preferences/extensions/unicode/keywords/region_override.rs":"65590219d58dcf466f48f07f94d6fc0ce1433182e5acd8e926ad01f6a7d245be","src/preferences/extensions/unicode/keywords/regional_subdivision.rs":"77866d9824b3b4569b63c4bfeac26f2d2025d1eab3d2ea147961f6773ee270e9","src/preferences/extensions/unicode/keywords/sentence_supression.rs":"8e991966dd9e4a6de441fdd03f8075a70c544741c76e8e076923159a107b6689","src/preferences/extensions/unicode/keywords/timezone.rs":"1d7f7ba02728919d57e793fe1d695e7d47bd5c173d72e518b7e35f0e724c77d9","src/preferences/extensions/unicode/keywords/variant.rs":"8598a4dd392c32ad08db700a3500a218b5c0674444675a4ca84da8be81b2bcb7","src/preferences/extensions/unicode/macros/enum_keyword.rs":"45cd0ace21a363b813a1bbb571a2b22f93839549ba1a96f776dc442b08b2bdd9","src/preferences/extensions/unicode/macros/mod.rs":"fc4212e6a62a402eebbaba29cec5e0f91109d3aa1d962039e50dd633a7ecc70d","src/preferences/extensions/unicode/macros/struct_keyword.rs":"dba324f98c3e108b7add972cbf2a9586486e560350d736a4e7034834177472d6","src/preferences/extensions/unicode/mod.rs":"9ce8a095b63724f124798a0f7e4b7dcc60bd0e7bfb2523d0f9e11883a81f904d","src/preferences/locale.rs":"759466d81773a853d87f2f8288d096a001fa208a2b6752ee767ec63c4f80e605","src/preferences/mod.rs":"e563ebc4594e54da8f60bcd6a3aefc77677163c7b847db67f576a1680da979e9","src/serde.rs":"a1a3439a0cc2e9ff754784d355ac8daf885cc5f3f210460b6781ff6d0ae2e7a3","src/shortvec/litemap.rs":"51af8e84fa010492ec44938eb65fbef23486267bb4d6c6a03154497b38ba35b1","src/shortvec/mod.rs":"e4ff29488b509354d80f8d75f6468cf68eda4a1de1cfaa54e8f1c9f9dc0b9f6a","src/subtags/language.rs":"94757472cfb54f2f583c79ea6ad7c7662240868a2bc04e4b938998e32a8de394","src/subtags/mod.rs":"f998571e80229552aa0aedcae35d0918a9aff261a58e488cfcc6d67d1f696b8d","src/subtags/region.rs":"1157ea7f2defb86233ee86f4522e494d6dfe4776a2b5f853008c75cbbcc312f0","src/subtags/script.rs":"f562cc5607b5acec4ba5fc14dddf5d7eff1d19129535f3a309fd0fb31607b714","src/subtags/variant.rs":"6230b1bb252b0782c9cb015be8f583e8b2d8ab7ffff79789bb6df600e2b0eb5c","src/subtags/variants.rs":"c3af767be128fa4bcab6efd65188f428e3a6b66ac3c69cb3e6489938cbb7094d","src/zerovec.rs":"a63c99e0ef6d38f4b4903b42b1e800aa821c7cbfd817b07d313dcdf4d377823d","tests/fixtures/canonicalize.json":"5414bd4972eb80ba46c727b407a8ed48a6e12e3639db034033586813c872f59c","tests/fixtures/invalid-extensions.json":"36eb5966085a1c9e966689af504cfbf8ea9b78b741675fe033ec9b6153e63ea6","tests/fixtures/invalid.json":"109169258632bd23d06827dfae6509f02a8127ffec25f48281ed61d795c67765","tests/fixtures/langid.json":"960fd01722217ef1ea9077e2e0821d7089fe318a241bd7fb7918f50bf8f3f5c3","tests/fixtures/locale.json":"df1b195b18780758a6b1c0264206b9cd9ac8c4741c5d6b0cc2b92f8e17991c17","tests/fixtures/mod.rs":"448fcf033391285b2f7ed2d73195a80a1342007083708b0786dc7d822df5831c","tests/langid.rs":"d79f33c1f536bec7a0eb1c466842afd61e15098f5039ea6a8085cdf31128199c","tests/locale.rs":"a7ffc4e9d1ebc70e9d915994033b3853285764953c6f0416f07e30520852b17f"},"package":"edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"} \ No newline at end of file diff --git a/deps/crates/vendor/icu_locale_core/.cargo_vcs_info.json b/deps/crates/vendor/icu_locale_core/.cargo_vcs_info.json new file mode 100644 index 00000000000000..c1582af2bc43cc --- /dev/null +++ b/deps/crates/vendor/icu_locale_core/.cargo_vcs_info.json @@ -0,0 +1,7 @@ +{ + "git": { + "sha1": "38a49da495248dd1ded84cf306e4ca42e64d5bb3", + "dirty": true + }, + "path_in_vcs": "components/locale_core" +} \ No newline at end of file diff --git a/deps/crates/vendor/icu_locale_core/Cargo.lock b/deps/crates/vendor/icu_locale_core/Cargo.lock new file mode 100644 index 00000000000000..77a22263621536 --- /dev/null +++ b/deps/crates/vendor/icu_locale_core/Cargo.lock @@ -0,0 +1,165 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "databake" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6ee9e2d2afb173bcdeee45934c89ec341ab26f91c9933774fc15c2b58f83ef" +dependencies = [ + "databake-derive", + "proc-macro2", + "quote", +] + +[[package]] +name = "databake-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6834770958c7b84223607e49758ec0dde273c4df915e734aad50f62968a4c134" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +dependencies = [ + "databake", + "displaydoc", + "litemap", + "serde", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "proc-macro2" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "2.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "serde_core", + "zerovec", +] + +[[package]] +name = "unicode-ident" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "462eeb75aeb73aea900253ce739c8e18a67423fadf006037cd3ff27e82748a06" + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "serde", + "zerofrom", +] diff --git a/deps/crates/vendor/icu_locale_core/Cargo.toml b/deps/crates/vendor/icu_locale_core/Cargo.toml index 924ab0d1863b42..99eb6b9dd720ae 100644 --- a/deps/crates/vendor/icu_locale_core/Cargo.toml +++ b/deps/crates/vendor/icu_locale_core/Cargo.toml @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.82" +rust-version = "1.83" name = "icu_locale_core" -version = "2.0.1" +version = "2.1.1" authors = ["The ICU4X Project Developers"] build = false include = [ @@ -43,7 +43,12 @@ repository = "https://github.com/unicode-org/icu4x" all-features = true [features] -alloc = [] +alloc = [ + "litemap/alloc", + "tinystr/alloc", + "writeable/alloc", + "serde?/alloc", +] databake = [ "dep:databake", "alloc", @@ -51,7 +56,6 @@ databake = [ serde = [ "dep:serde", "tinystr/serde", - "alloc", ] zerovec = [ "dep:zerovec", @@ -103,57 +107,22 @@ default-features = false [dependencies.litemap] version = "0.8.0" -features = ["alloc"] default-features = false [dependencies.serde] -version = "1.0.110" -features = [ - "alloc", - "derive", -] +version = "1.0.220" optional = true default-features = false [dependencies.tinystr] version = "0.8.0" -features = ["alloc"] default-features = false [dependencies.writeable] version = "0.6.0" -features = ["alloc"] default-features = false [dependencies.zerovec] -version = "0.11.1" +version = "0.11.3" optional = true default-features = false - -[dev-dependencies.iai] -version = "0.1.1" - -[dev-dependencies.litemap] -version = "0.8.0" -features = ["testing"] -default-features = false - -[dev-dependencies.postcard] -version = "1.0.3" -features = ["use-std"] -default-features = false - -[dev-dependencies.potential_utf] -version = "0.1.1" -default-features = false - -[dev-dependencies.serde] -version = "1.0.110" -features = ["derive"] -default-features = false - -[dev-dependencies.serde_json] -version = "1.0.45" - -[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies.criterion] -version = "0.5.0" diff --git a/deps/crates/vendor/icu_locale_core/Cargo.toml.orig b/deps/crates/vendor/icu_locale_core/Cargo.toml.orig new file mode 100644 index 00000000000000..94d03fa7a7354a --- /dev/null +++ b/deps/crates/vendor/icu_locale_core/Cargo.toml.orig @@ -0,0 +1,55 @@ +# This file is part of ICU4X. For terms of use, please see the file +# called LICENSE at the top level of the ICU4X source tree +# (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). + +[package] +name = "icu_locale_core" +description = "API for managing Unicode Language and Locale Identifiers" + +authors.workspace = true +categories.workspace = true +edition.workspace = true +homepage.workspace = true +include.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true +version.workspace = true + +[package.metadata.docs.rs] +all-features = true + +[dependencies] +displaydoc = { workspace = true } +litemap = { workspace = true } +tinystr = { workspace = true } +writeable = { workspace = true } + +databake = { workspace = true, features = ["derive"], optional = true } +serde = { workspace = true, optional = true } +zerovec = { workspace = true, optional = true } + +[features] +databake = ["dep:databake", "alloc"] +serde = ["dep:serde", "tinystr/serde"] +zerovec = ["dep:zerovec", "tinystr/zerovec"] +alloc = ["litemap/alloc", "tinystr/alloc", "writeable/alloc", "serde?/alloc"] + +[lib] +bench = false # This option is required for Benchmark CI + +[[bench]] +name = "subtags" +harness = false + +[[bench]] +name = "langid" +harness = false + +[[bench]] +name = "locale" +harness = false + +[[bench]] +name = "iai_langid" +harness = false diff --git a/deps/crates/vendor/icu_locale_core/src/data.rs b/deps/crates/vendor/icu_locale_core/src/data.rs index 5bf0e971bb3d7a..5143bf23b1fa25 100644 --- a/deps/crates/vendor/icu_locale_core/src/data.rs +++ b/deps/crates/vendor/icu_locale_core/src/data.rs @@ -101,7 +101,7 @@ impl fmt::Debug for DataLocale { } } -impl_writeable_for_each_subtag_str_no_test!(DataLocale, selff, selff.script.is_none() && selff.region.is_none() && selff.variant.is_none() && selff.subdivision.is_none() => selff.language.write_to_string()); +impl_writeable_for_each_subtag_str_no_test!(DataLocale, selff, selff.script.is_none() && selff.region.is_none() && selff.variant.is_none() && selff.subdivision.is_none() => Some(selff.language.as_str())); impl From for DataLocale { fn from(langid: LanguageIdentifier) -> Self { @@ -141,6 +141,7 @@ impl From<&Locale> for DataLocale { } } +/// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] impl FromStr for DataLocale { type Err = ParseError; @@ -153,12 +154,16 @@ impl FromStr for DataLocale { impl DataLocale { #[inline] /// Parses a [`DataLocale`]. + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] pub fn try_from_str(s: &str) -> Result { Self::try_from_utf8(s.as_bytes()) } /// Parses a [`DataLocale`] from a UTF-8 byte slice. + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { let locale = Locale::try_from_utf8(code_units)?; diff --git a/deps/crates/vendor/icu_locale_core/src/extensions/mod.rs b/deps/crates/vendor/icu_locale_core/src/extensions/mod.rs index 1893ad7349e02c..134921a3b96134 100644 --- a/deps/crates/vendor/icu_locale_core/src/extensions/mod.rs +++ b/deps/crates/vendor/icu_locale_core/src/extensions/mod.rs @@ -194,7 +194,7 @@ impl Extensions { && self.other.is_empty() } - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] pub(crate) fn as_tuple( &self, ) -> ( @@ -231,6 +231,8 @@ impl Extensions { /// Retains the specified extension types, clearing all others. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* + /// /// # Examples /// /// ``` @@ -252,6 +254,7 @@ impl Extensions { /// }); /// assert_eq!(only_t_z, "und-t-mul-z-zzz".parse().unwrap()); /// ``` + #[cfg(feature = "alloc")] pub fn retain_by_type(&mut self, mut predicate: F) where F: FnMut(ExtensionType) -> bool, @@ -360,7 +363,6 @@ impl Extensions { } } -#[cfg(feature = "alloc")] impl_writeable_for_each_subtag_str_no_test!(Extensions); #[test] diff --git a/deps/crates/vendor/icu_locale_core/src/extensions/other/mod.rs b/deps/crates/vendor/icu_locale_core/src/extensions/other/mod.rs index 050b379c6da0d3..8934c4dff76fa7 100644 --- a/deps/crates/vendor/icu_locale_core/src/extensions/other/mod.rs +++ b/deps/crates/vendor/icu_locale_core/src/extensions/other/mod.rs @@ -64,6 +64,8 @@ pub struct Other { impl Other { /// A constructor which takes a str slice, parses it and /// produces a well-formed [`Other`]. + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[inline] #[cfg(feature = "alloc")] pub fn try_from_str(s: &str) -> Result { @@ -71,6 +73,8 @@ impl Other { } /// See [`Self::try_from_str`] + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { let mut iter = SubtagIterator::new(code_units); @@ -85,6 +89,8 @@ impl Other { /// A constructor which takes a pre-sorted list of [`Subtag`]. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* + /// /// # Panics /// /// Panics if `ext` is not ASCII alphabetic. @@ -200,6 +206,7 @@ impl Other { } } +/// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] impl FromStr for Other { type Err = ParseError; @@ -210,7 +217,7 @@ impl FromStr for Other { } } -writeable::impl_display_with_writeable!(Other); +writeable::impl_display_with_writeable!(Other, #[cfg(feature = "alloc")]); impl writeable::Writeable for Other { fn write_to(&self, sink: &mut W) -> core::fmt::Result { @@ -236,17 +243,6 @@ impl writeable::Writeable for Other { } result } - - #[cfg(feature = "alloc")] - fn write_to_string(&self) -> alloc::borrow::Cow { - if self.keys.is_empty() { - return alloc::borrow::Cow::Borrowed(""); - } - let mut string = - alloc::string::String::with_capacity(self.writeable_length_hint().capacity()); - let _ = self.write_to(&mut string); - alloc::borrow::Cow::Owned(string) - } } #[cfg(test)] diff --git a/deps/crates/vendor/icu_locale_core/src/extensions/private/mod.rs b/deps/crates/vendor/icu_locale_core/src/extensions/private/mod.rs index ee9852921af51d..458259c26e15fa 100644 --- a/deps/crates/vendor/icu_locale_core/src/extensions/private/mod.rs +++ b/deps/crates/vendor/icu_locale_core/src/extensions/private/mod.rs @@ -89,6 +89,8 @@ impl Private { /// A constructor which takes a str slice, parses it and /// produces a well-formed [`Private`]. + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[inline] #[cfg(feature = "alloc")] pub fn try_from_str(s: &str) -> Result { @@ -96,6 +98,8 @@ impl Private { } /// See [`Self::try_from_str`] + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { let mut iter = SubtagIterator::new(code_units); @@ -110,6 +114,8 @@ impl Private { /// A constructor which takes a pre-sorted list of [`Subtag`]. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* + /// /// # Examples /// /// ``` @@ -190,6 +196,7 @@ impl Private { } } +/// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] impl FromStr for Private { type Err = ParseError; @@ -200,7 +207,7 @@ impl FromStr for Private { } } -writeable::impl_display_with_writeable!(Private); +writeable::impl_display_with_writeable!(Private, #[cfg(feature = "alloc")]); impl writeable::Writeable for Private { fn write_to(&self, sink: &mut W) -> core::fmt::Result { diff --git a/deps/crates/vendor/icu_locale_core/src/extensions/transform/fields.rs b/deps/crates/vendor/icu_locale_core/src/extensions/transform/fields.rs index d5d9cf72484124..d7a027d9210093 100644 --- a/deps/crates/vendor/icu_locale_core/src/extensions/transform/fields.rs +++ b/deps/crates/vendor/icu_locale_core/src/extensions/transform/fields.rs @@ -3,7 +3,6 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use core::borrow::Borrow; -use core::iter::FromIterator; use litemap::LiteMap; use super::Key; @@ -32,7 +31,12 @@ use super::Value; /// assert_eq!(&fields.to_string(), "h0-hybrid"); /// ``` #[derive(Clone, PartialEq, Eq, Debug, Default, Hash, PartialOrd, Ord)] -pub struct Fields(LiteMap); +pub struct Fields(Inner); + +#[cfg(feature = "alloc")] +type Inner = LiteMap; +#[cfg(not(feature = "alloc"))] +type Inner = LiteMap; impl Fields { /// Returns a new empty list of key-value pairs. Same as [`default()`](Default::default()), but is `const`. @@ -137,6 +141,8 @@ impl Fields { /// Sets the specified keyword, returning the old value if it already existed. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* + /// /// # Examples /// /// ``` @@ -154,12 +160,15 @@ impl Fields { /// assert_eq!(old_value, Some(casefold)); /// assert_eq!(loc, "en-t-hi-d0-lower".parse().unwrap()); /// ``` + #[cfg(feature = "alloc")] pub fn set(&mut self, key: Key, value: Value) -> Option { self.0.insert(key, value) } /// Retains a subset of fields as specified by the predicate function. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* + /// /// # Examples /// /// ``` @@ -180,6 +189,7 @@ impl Fields { /// .retain_by_key(|&k| k == key!("d0")); /// assert_eq!(loc, Locale::UNKNOWN); /// ``` + #[cfg(feature = "alloc")] pub fn retain_by_key(&mut self, mut predicate: F) where F: FnMut(&Key) -> bool, @@ -205,13 +215,17 @@ impl Fields { } } +/// ✨ *Enabled with the `alloc` Cargo feature.* +#[cfg(feature = "alloc")] impl From> for Fields { fn from(map: LiteMap) -> Self { Self(map) } } -impl FromIterator<(Key, Value)> for Fields { +/// ✨ *Enabled with the `alloc` Cargo feature.* +#[cfg(feature = "alloc")] +impl core::iter::FromIterator<(Key, Value)> for Fields { fn from_iter>(iter: I) -> Self { LiteMap::from_iter(iter).into() } diff --git a/deps/crates/vendor/icu_locale_core/src/extensions/transform/mod.rs b/deps/crates/vendor/icu_locale_core/src/extensions/transform/mod.rs index 8f3094f1bf2145..712009954f127f 100644 --- a/deps/crates/vendor/icu_locale_core/src/extensions/transform/mod.rs +++ b/deps/crates/vendor/icu_locale_core/src/extensions/transform/mod.rs @@ -117,6 +117,8 @@ impl Transform { /// A constructor which takes a str slice, parses it and /// produces a well-formed [`Transform`]. + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[inline] #[cfg(feature = "alloc")] pub fn try_from_str(s: &str) -> Result { @@ -124,6 +126,8 @@ impl Transform { } /// See [`Self::try_from_str`] + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { let mut iter = SubtagIterator::new(code_units); @@ -167,7 +171,7 @@ impl Transform { self.fields.clear(); } - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] pub(crate) fn as_tuple( &self, ) -> ( @@ -270,6 +274,7 @@ impl Transform { } } +/// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] impl FromStr for Transform { type Err = ParseError; @@ -280,7 +285,7 @@ impl FromStr for Transform { } } -writeable::impl_display_with_writeable!(Transform); +writeable::impl_display_with_writeable!(Transform, #[cfg(feature = "alloc")]); impl writeable::Writeable for Transform { fn write_to(&self, sink: &mut W) -> core::fmt::Result { diff --git a/deps/crates/vendor/icu_locale_core/src/extensions/transform/value.rs b/deps/crates/vendor/icu_locale_core/src/extensions/transform/value.rs index 3a54f739dd1b92..2d59476ec37ed5 100644 --- a/deps/crates/vendor/icu_locale_core/src/extensions/transform/value.rs +++ b/deps/crates/vendor/icu_locale_core/src/extensions/transform/value.rs @@ -40,6 +40,8 @@ impl Value { /// A constructor which takes a str slice, parses it and /// produces a well-formed [`Value`]. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* + /// /// # Examples /// /// ``` @@ -54,6 +56,8 @@ impl Value { } /// See [`Self::try_from_str`] + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { let mut v = ShortBoxSlice::default(); @@ -115,6 +119,7 @@ impl Value { } } +/// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] impl FromStr for Value { type Err = ParseError; @@ -125,7 +130,7 @@ impl FromStr for Value { } } -impl_writeable_for_each_subtag_str_no_test!(Value, selff, selff.0.is_empty() => alloc::borrow::Cow::Borrowed("true")); +impl_writeable_for_each_subtag_str_no_test!(Value, selff, selff.0.is_empty() => Some("true")); #[test] fn test_writeable() { diff --git a/deps/crates/vendor/icu_locale_core/src/extensions/unicode/attributes.rs b/deps/crates/vendor/icu_locale_core/src/extensions/unicode/attributes.rs index 7ca0fecfcfc212..fe0b1ef14c8522 100644 --- a/deps/crates/vendor/icu_locale_core/src/extensions/unicode/attributes.rs +++ b/deps/crates/vendor/icu_locale_core/src/extensions/unicode/attributes.rs @@ -57,6 +57,8 @@ impl Attributes { /// A constructor which takes a str slice, parses it and /// produces a well-formed [`Attributes`]. + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[inline] #[cfg(feature = "alloc")] pub fn try_from_str(s: &str) -> Result { @@ -64,6 +66,8 @@ impl Attributes { } /// See [`Self::try_from_str`] + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { let mut iter = SubtagIterator::new(code_units); @@ -72,6 +76,7 @@ impl Attributes { /// A constructor which takes a pre-sorted list of [`Attribute`] elements. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* /// /// # Examples /// @@ -143,8 +148,32 @@ impl Attributes { { self.deref().iter().map(|t| t.as_str()).try_for_each(f) } + + /// Extends the `Attributes` with values from another `Attributes`. + /// + /// # Example + /// + /// ``` + /// use icu::locale::extensions::unicode::Attributes; + /// + /// let mut attrs: Attributes = "foobar-foobaz".parse().unwrap(); + /// let attrs2: Attributes = "foobar-fooqux".parse().unwrap(); + /// + /// attrs.extend_from_attributes(attrs2); + /// + /// assert_eq!(attrs, "foobar-foobaz-fooqux".parse().unwrap()); + /// ``` + #[cfg(feature = "alloc")] + pub fn extend_from_attributes(&mut self, other: Attributes) { + for attr in other.0 { + if let Err(idx) = self.binary_search(&attr) { + self.0.insert(idx, attr); + } + } + } } +/// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] impl FromStr for Attributes { type Err = ParseError; diff --git a/deps/crates/vendor/icu_locale_core/src/extensions/unicode/keywords.rs b/deps/crates/vendor/icu_locale_core/src/extensions/unicode/keywords.rs index 726b5490efc52b..c7287fc66c7979 100644 --- a/deps/crates/vendor/icu_locale_core/src/extensions/unicode/keywords.rs +++ b/deps/crates/vendor/icu_locale_core/src/extensions/unicode/keywords.rs @@ -96,6 +96,8 @@ impl Keywords { /// A constructor which takes a str slice, parses it and /// produces a well-formed [`Keywords`]. + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[inline] #[cfg(feature = "alloc")] pub fn try_from_str(s: &str) -> Result { @@ -103,6 +105,8 @@ impl Keywords { } /// See [`Self::try_from_str`] + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { let mut iter = SubtagIterator::new(code_units); @@ -175,6 +179,8 @@ impl Keywords { /// /// Returns `None` if the key doesn't exist or if the key has no value. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* + /// /// # Examples /// /// ``` @@ -200,6 +206,8 @@ impl Keywords { /// Sets the specified keyword, returning the old value if it already existed. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* + /// /// # Examples /// /// ``` @@ -225,6 +233,8 @@ impl Keywords { /// Removes the specified keyword, returning the old value if it existed. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* + /// /// # Examples /// /// ``` @@ -261,6 +271,8 @@ impl Keywords { /// Retains a subset of keywords as specified by the predicate function. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* + /// /// # Examples /// /// ``` @@ -374,6 +386,27 @@ impl Keywords { Ok(()) } + /// Extends the `Keywords` with values from another `Keywords`. + /// + /// # Example + /// + /// ``` + /// use icu::locale::extensions::unicode::Keywords; + /// + /// let mut kw: Keywords = "ab-cd-ca-buddhist".parse().unwrap(); + /// let kw2: Keywords = "ca-gregory-hc-h12".parse().unwrap(); + /// + /// kw.extend_from_keywords(kw2); + /// + /// assert_eq!(kw, "ab-cd-ca-gregory-hc-h12".parse().unwrap()); + /// ``` + #[cfg(feature = "alloc")] + pub fn extend_from_keywords(&mut self, other: Keywords) { + for (key, value) in other.0 { + self.0.insert(key, value); + } + } + /// This needs to be its own method to help with type inference in helpers.rs #[cfg(test)] pub(crate) fn from_tuple_vec(v: Vec<(Key, Value)>) -> Self { @@ -387,6 +420,7 @@ impl From>> for Keywords { } } +/// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] impl FromIterator<(Key, Value)> for Keywords { fn from_iter>(iter: I) -> Self { @@ -394,6 +428,7 @@ impl FromIterator<(Key, Value)> for Keywords { } } +/// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] impl FromStr for Keywords { type Err = ParseError; diff --git a/deps/crates/vendor/icu_locale_core/src/extensions/unicode/mod.rs b/deps/crates/vendor/icu_locale_core/src/extensions/unicode/mod.rs index f51593548ba3b5..1a2d984312f787 100644 --- a/deps/crates/vendor/icu_locale_core/src/extensions/unicode/mod.rs +++ b/deps/crates/vendor/icu_locale_core/src/extensions/unicode/mod.rs @@ -115,6 +115,8 @@ impl Unicode { /// A constructor which takes a str slice, parses it and /// produces a well-formed [`Unicode`]. + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[inline] #[cfg(feature = "alloc")] pub fn try_from_str(s: &str) -> Result { @@ -122,6 +124,8 @@ impl Unicode { } /// See [`Self::try_from_str`] + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { let mut iter = SubtagIterator::new(code_units); @@ -210,8 +214,29 @@ impl Unicode { } Ok(()) } + + /// Extends the `Unicode` with values from another `Unicode`. + /// + /// # Example + /// + /// ``` + /// use icu::locale::extensions::unicode::Unicode; + /// + /// let mut ue: Unicode = "u-foobar-ca-buddhist".parse().unwrap(); + /// let ue2: Unicode = "u-ca-gregory-hc-h12".parse().unwrap(); + /// + /// ue.extend(ue2); + /// + /// assert_eq!(ue, "u-foobar-ca-gregory-hc-h12".parse().unwrap()); + /// ``` + #[cfg(feature = "alloc")] + pub fn extend(&mut self, other: Unicode) { + self.keywords.extend_from_keywords(other.keywords); + self.attributes.extend_from_attributes(other.attributes); + } } +/// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] impl FromStr for Unicode { type Err = ParseError; @@ -222,7 +247,7 @@ impl FromStr for Unicode { } } -writeable::impl_display_with_writeable!(Unicode); +writeable::impl_display_with_writeable!(Unicode, #[cfg(feature = "alloc")]); impl writeable::Writeable for Unicode { fn write_to(&self, sink: &mut W) -> core::fmt::Result { diff --git a/deps/crates/vendor/icu_locale_core/src/extensions/unicode/subdivision.rs b/deps/crates/vendor/icu_locale_core/src/extensions/unicode/subdivision.rs index 5855fed7fc09d4..26e0436e3b0795 100644 --- a/deps/crates/vendor/icu_locale_core/src/extensions/unicode/subdivision.rs +++ b/deps/crates/vendor/icu_locale_core/src/extensions/unicode/subdivision.rs @@ -151,7 +151,7 @@ impl writeable::Writeable for SubdivisionId { } } -writeable::impl_display_with_writeable!(SubdivisionId); +writeable::impl_display_with_writeable!(SubdivisionId, #[cfg(feature = "alloc")]); impl FromStr for SubdivisionId { type Err = ParseError; @@ -175,7 +175,7 @@ mod tests { for sample in ["", "gb", "o"] { let oe: Result = sample.parse(); - assert!(oe.is_err(), "Should fail: {}", sample); + assert!(oe.is_err(), "Should fail: {sample}"); } } } diff --git a/deps/crates/vendor/icu_locale_core/src/extensions/unicode/value.rs b/deps/crates/vendor/icu_locale_core/src/extensions/unicode/value.rs index c2f3381078da5a..41beb43915bea3 100644 --- a/deps/crates/vendor/icu_locale_core/src/extensions/unicode/value.rs +++ b/deps/crates/vendor/icu_locale_core/src/extensions/unicode/value.rs @@ -3,7 +3,6 @@ // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). use crate::parser::ParseError; -#[cfg(feature = "alloc")] use crate::parser::SubtagIterator; use crate::shortvec::{ShortBoxSlice, ShortBoxSliceIntoIter}; use crate::subtags::{subtag, Subtag}; @@ -51,14 +50,18 @@ impl Value { /// /// Value::try_from_str("buddhist").expect("Parsing failed."); /// ``` + /// + /// # `alloc` Cargo feature + /// + /// Without the `alloc` Cargo feature, this only supports parsing + /// up to two (non-`true`) subtags, and will return an error for + /// longer strings. #[inline] - #[cfg(feature = "alloc")] pub fn try_from_str(s: &str) -> Result { Self::try_from_utf8(s.as_bytes()) } /// See [`Self::try_from_str`] - #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { let mut v = ShortBoxSlice::new(); @@ -66,7 +69,16 @@ impl Value { for chunk in SubtagIterator::new(code_units) { let subtag = Subtag::try_from_utf8(chunk)?; if subtag != TRUE_VALUE { + #[cfg(feature = "alloc")] v.push(subtag); + #[cfg(not(feature = "alloc"))] + if v.is_empty() { + v = ShortBoxSlice::new_single(subtag); + } else if let &[prev] = &*v { + v = ShortBoxSlice::new_double(prev, subtag); + } else { + return Err(ParseError::InvalidSubtag); + } } } } @@ -118,6 +130,8 @@ impl Value { /// Appends a subtag to the back of a [`Value`]. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* + /// /// # Examples /// /// ``` @@ -170,7 +184,7 @@ impl Value { /// use icu::locale::{extensions::unicode::Value, subtags::subtag}; /// /// let mut v = Value::default(); - /// assert_eq!(v.is_empty(), true); + /// assert!(v.is_empty()); /// ``` pub fn is_empty(&self) -> bool { self.0.is_empty() @@ -226,8 +240,14 @@ impl Value { } } + #[doc(hidden)] + pub fn from_two_subtags(f: Subtag, s: Subtag) -> Self { + Self(ShortBoxSlice::new_double(f, s)) + } + /// A constructor which takes a pre-sorted list of [`Value`] elements. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* /// /// # Examples /// @@ -283,6 +303,7 @@ impl IntoIterator for Value { } } +/// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] impl FromIterator for Value { fn from_iter>(iter: T) -> Self { @@ -290,6 +311,7 @@ impl FromIterator for Value { } } +/// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] impl Extend for Value { fn extend>(&mut self, iter: T) { @@ -299,6 +321,7 @@ impl Extend for Value { } } +/// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] impl FromStr for Value { type Err = ParseError; diff --git a/deps/crates/vendor/icu_locale_core/src/helpers.rs b/deps/crates/vendor/icu_locale_core/src/helpers.rs index 48522f4bb1277a..c4ad9c78620c33 100644 --- a/deps/crates/vendor/icu_locale_core/src/helpers.rs +++ b/deps/crates/vendor/icu_locale_core/src/helpers.rs @@ -19,7 +19,6 @@ macro_rules! impl_tinystr_subtag { [$bad_example:literal $(, $more_bad_examples:literal)*], ) => { #[derive(Debug, PartialEq, Eq, Clone, Hash, PartialOrd, Ord, Copy)] - #[cfg_attr(feature = "serde", derive(serde::Serialize))] #[repr(transparent)] $(#[$doc])* pub struct $name(tinystr::TinyAsciiStr<$len_end>); @@ -45,7 +44,6 @@ macro_rules! impl_tinystr_subtag { pub const fn try_from_utf8( code_units: &[u8], ) -> Result { - #[allow(clippy::double_comparisons)] // if code_units.len() === 0 if code_units.len() < $len_start || code_units.len() > $len_end { return Err(crate::parser::errors::ParseError::$error); } @@ -157,14 +155,12 @@ macro_rules! impl_tinystr_subtag { fn writeable_length_hint(&self) -> writeable::LengthHint { writeable::LengthHint::exact(self.0.len()) } - #[inline] - #[cfg(feature = "alloc")] - fn write_to_string(&self) -> alloc::borrow::Cow { - alloc::borrow::Cow::Borrowed(self.0.as_str()) + fn writeable_borrow(&self) -> Option<&str> { + Some(self.0.as_str()) } } - writeable::impl_display_with_writeable!($name); + writeable::impl_display_with_writeable!($name, #[cfg(feature = "alloc")]); #[doc = concat!("A macro allowing for compile-time construction of valid [`", stringify!($name), "`] subtags.")] /// @@ -191,7 +187,6 @@ macro_rules! impl_tinystr_subtag { use $crate::$($path ::)+ $name; match $name::try_from_utf8($string.as_bytes()) { Ok(r) => r, - #[allow(clippy::panic)] // const context _ => panic!(concat!("Invalid ", $(stringify!($path), "::",)+ stringify!($name), ": ", $string)), } }}; @@ -241,6 +236,16 @@ macro_rules! impl_tinystr_subtag { )* } + #[cfg(feature = "serde")] + impl serde::Serialize for $name { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.0.serialize(serializer) + } + } + #[cfg(feature = "serde")] impl<'de> serde::Deserialize<'de> for $name { fn deserialize(deserializer: D) -> Result @@ -317,6 +322,7 @@ macro_rules! impl_tinystr_subtag { } #[cfg(feature = "zerovec")] + #[cfg(feature = "alloc")] impl<'a> zerovec::maps::ZeroMapKV<'a> for $name { type Container = zerovec::ZeroVec<'a, $name>; type Slice = zerovec::ZeroSlice<$name>; @@ -361,28 +367,24 @@ macro_rules! impl_writeable_for_each_subtag_str_no_test { } $( - #[cfg(feature = "alloc")] - fn write_to_string(&self) -> alloc::borrow::Cow { - #[allow(clippy::unwrap_used)] // impl_writeable_for_subtag_list's $borrow uses unwrap + fn writeable_borrow(&self) -> Option<&str> { let $self = self; if $borrow_cond { $borrow } else { - let mut output = alloc::string::String::with_capacity(self.writeable_length_hint().capacity()); - let _ = self.write_to(&mut output); - alloc::borrow::Cow::Owned(output) + None } } )? } - writeable::impl_display_with_writeable!($type); + writeable::impl_display_with_writeable!($type, #[cfg(feature = "alloc")]); }; } macro_rules! impl_writeable_for_subtag_list { ($type:tt, $sample1:literal, $sample2:literal) => { - impl_writeable_for_each_subtag_str_no_test!($type, selff, selff.0.len() == 1 => alloc::borrow::Cow::Borrowed(selff.0.get(0).unwrap().as_str())); + impl_writeable_for_each_subtag_str_no_test!($type, selff, selff.0.len() == 1 => #[allow(clippy::unwrap_used)] { Some(selff.0.get(0).unwrap().as_str()) } ); #[test] fn test_writeable() { diff --git a/deps/crates/vendor/icu_locale_core/src/langid.rs b/deps/crates/vendor/icu_locale_core/src/langid.rs index 82ef5e0d44bb7f..0f8001c0126bb7 100644 --- a/deps/crates/vendor/icu_locale_core/src/langid.rs +++ b/deps/crates/vendor/icu_locale_core/src/langid.rs @@ -40,6 +40,14 @@ use alloc::borrow::Cow; /// This operation normalizes syntax to be well-formed. No legacy subtag replacements is performed. /// For validation and canonicalization, see `LocaleCanonicalizer`. /// +/// # Serde +/// +/// This type implements `serde::Serialize` and `serde::Deserialize` if the +/// `"serde"` Cargo feature is enabled on the crate. +/// +/// The value will be serialized as a string and parsed when deserialized. +/// For tips on efficient storage and retrieval of locales, see [`crate::zerovec`]. +/// /// # Examples /// /// Simple example: @@ -71,7 +79,7 @@ use alloc::borrow::Cow; /// assert_eq!(li.language, language!("en")); /// assert_eq!(li.script, Some(script!("Latn"))); /// assert_eq!(li.region, Some(region!("US"))); -/// assert_eq!(li.variants.get(0), Some(&variant!("valencia"))); +/// assert_eq!(li.variants.first(), Some(&variant!("valencia"))); /// ``` /// /// [`Unicode BCP47 Language Identifier`]: https://unicode.org/reports/tr35/tr35.html#Unicode_language_identifier @@ -95,6 +103,8 @@ impl LanguageIdentifier { /// A constructor which takes a utf8 slice, parses it and /// produces a well-formed [`LanguageIdentifier`]. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* + /// /// # Examples /// /// ``` @@ -109,13 +119,15 @@ impl LanguageIdentifier { } /// See [`Self::try_from_str`] + /// + /// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] pub fn try_from_utf8(code_units: &[u8]) -> Result { crate::parser::parse_language_identifier(code_units, parser::ParserMode::LanguageIdentifier) } #[doc(hidden)] // macro use - #[allow(clippy::type_complexity)] + #[expect(clippy::type_complexity)] // The return type should be `Result` once the `const_precise_live_drops` // is stabilized ([rust-lang#73255](https://github.com/rust-lang/rust/issues/73255)). pub const fn try_from_utf8_with_single_variant( @@ -138,6 +150,8 @@ impl LanguageIdentifier { /// A constructor which takes a utf8 slice which may contain extension keys, /// parses it and produces a well-formed [`LanguageIdentifier`]. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* + /// /// # Examples /// /// ``` @@ -168,6 +182,8 @@ impl LanguageIdentifier { /// /// This operation will normalize casing and the separator. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* + /// /// # Examples /// /// ``` @@ -179,7 +195,7 @@ impl LanguageIdentifier { /// ); /// ``` #[cfg(feature = "alloc")] - pub fn normalize_utf8(input: &[u8]) -> Result, ParseError> { + pub fn normalize_utf8(input: &[u8]) -> Result, ParseError> { let lang_id = Self::try_from_utf8(input)?; Ok(writeable::to_string_or_borrow(&lang_id, input)) } @@ -188,6 +204,8 @@ impl LanguageIdentifier { /// /// This operation will normalize casing and the separator. /// + /// ✨ *Enabled with the `alloc` Cargo feature.* + /// /// # Examples /// /// ``` @@ -199,7 +217,7 @@ impl LanguageIdentifier { /// ); /// ``` #[cfg(feature = "alloc")] - pub fn normalize(input: &str) -> Result, ParseError> { + pub fn normalize(input: &str) -> Result, ParseError> { Self::normalize_utf8(input.as_bytes()) } @@ -495,6 +513,7 @@ impl core::fmt::Debug for LanguageIdentifier { } } +/// ✨ *Enabled with the `alloc` Cargo feature.* #[cfg(feature = "alloc")] impl FromStr for LanguageIdentifier { type Err = ParseError; @@ -505,7 +524,7 @@ impl FromStr for LanguageIdentifier { } } -impl_writeable_for_each_subtag_str_no_test!(LanguageIdentifier, selff, selff.script.is_none() && selff.region.is_none() && selff.variants.is_empty() => selff.language.write_to_string()); +impl_writeable_for_each_subtag_str_no_test!(LanguageIdentifier, selff, selff.script.is_none() && selff.region.is_none() && selff.variants.is_empty() => Some(selff.language.as_str())); #[test] fn test_writeable() { diff --git a/deps/crates/vendor/icu_locale_core/src/lib.rs b/deps/crates/vendor/icu_locale_core/src/lib.rs index 8e8a130411c1a5..b465710e9525f4 100644 --- a/deps/crates/vendor/icu_locale_core/src/lib.rs +++ b/deps/crates/vendor/icu_locale_core/src/lib.rs @@ -89,7 +89,7 @@ pub mod subtags; pub mod preferences; pub mod zerovec; -#[cfg(feature = "serde")] +#[cfg(all(feature = "alloc", feature = "serde"))] mod serde; #[cfg(feature = "databake")] diff --git a/deps/crates/vendor/icu_locale_core/src/locale.rs b/deps/crates/vendor/icu_locale_core/src/locale.rs index a3435f215f9b28..31af244c243ad6 100644 --- a/deps/crates/vendor/icu_locale_core/src/locale.rs +++ b/deps/crates/vendor/icu_locale_core/src/locale.rs @@ -46,6 +46,14 @@ use core::str::FromStr; /// ICU4X's Locale parsing does not allow for non-BCP-47-compatible locales [allowed by UTS 35 for backwards compatability][tr35-bcp]. /// Furthermore, it currently does not allow for language tags to have more than three characters. /// +/// # Serde +/// +/// This type implements `serde::Serialize` and `serde::Deserialize` if the +/// `"serde"` Cargo feature is enabled on the crate. +/// +/// The value will be serialized as a string and parsed when deserialized. +/// For tips on efficient storage and retrieval of locales, see [`crate::zerovec`]. +/// /// # Examples /// /// Simple example: @@ -82,7 +90,7 @@ use core::str::FromStr; /// assert_eq!(loc.id.script, "Latn".parse::