diff --git a/Cargo.lock b/Cargo.lock index 0cdef8c..e239b6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,9 +54,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "android_system_properties" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" dependencies = [ "libc", ] @@ -113,9 +113,18 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "ar_archive_writer" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523e5e187fff36fcb8d1d19ccf0ca4ca43ec3d158316057f66dc6f72716bc5ec" +dependencies = [ + "object 0.39.1", +] [[package]] name = "arraydeque" @@ -155,18 +164,18 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] name = "async-trait" -version = "0.1.89" +version = "0.1.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.10", ] [[package]] @@ -192,13 +201,14 @@ dependencies = [ "edgezero-cli", "edgezero-core", "futures", + "hex", "log", "serde", "serde_json", - "sha2 0.10.9", + "sha2 0.11.1", "simple_logger", "tokio", - "toml 0.8.23", + "toml", "tracing", "url", ] @@ -220,7 +230,7 @@ dependencies = [ "log", "serde_json", "time", - "toml 0.8.23", + "toml", "worker", ] @@ -242,7 +252,7 @@ dependencies = [ "once_cell", "serde_json", "time", - "toml 0.8.23", + "toml", ] [[package]] @@ -263,7 +273,7 @@ dependencies = [ "serde_json", "spin-sdk", "time", - "toml 0.8.23", + "toml", ] [[package]] @@ -278,10 +288,11 @@ dependencies = [ "auctioneer-runtime", "flate2", "gimli", + "hex", "jsonschema", "jsonschema-macros-core", "mime", - "object", + "object 0.41.0", "percent-encoding", "proc-macro2", "quote", @@ -292,16 +303,16 @@ dependencies = [ "serde", "serde_json", "serde_yaml_ng", - "sha2 0.10.9", - "syn 2.0.118", + "sha2 0.11.1", + "syn 3.0.10", "tar", "tempfile", - "toml 0.8.23", + "toml", "url", "uuid-simd", "validator", - "wasm-encoder 0.247.0", - "wasmparser 0.247.0", + "wasm-encoder 0.263.0", + "wasmparser 0.263.0", ] [[package]] @@ -347,14 +358,14 @@ dependencies = [ "serde", "serde_json", "serde_yaml_ng", - "sha2 0.10.9", - "syn 2.0.118", + "sha2 0.11.1", + "syn 3.0.10", "tar", "tempfile", "time", "tokio", "tokio-rustls", - "toml 0.8.23", + "toml", "url", "validator", "yaml-rust2", @@ -377,11 +388,11 @@ dependencies = [ "rustix", "serde", "serde_json", - "sha2 0.10.9", - "syn 2.0.118", + "sha2 0.11.1", + "syn 3.0.10", "tempfile", "time", - "toml 0.8.23", + "toml", "unicode-case-mapping", "url", "validator", @@ -405,10 +416,10 @@ dependencies = [ "quote", "serde", "serde_json", - "sha2 0.10.9", - "syn 2.0.118", + "sha2 0.11.1", + "syn 3.0.10", "time", - "toml 0.8.23", + "toml", "unicode-case-mapping", "url", "validator", @@ -435,18 +446,19 @@ dependencies = [ "edgezero-core", "flate2", "futures", + "hex", "hmac", "http", "log", "png", "serde", "serde_json", - "sha2 0.10.9", + "sha2 0.11.1", "subtle", "testing_logger", - "thiserror 1.0.69", + "thiserror 2.0.21", "time", - "toml 0.8.23", + "toml", "url", "validator", "zeroize", @@ -468,7 +480,7 @@ dependencies = [ "serde", "serde_json", "testing_logger", - "thiserror 1.0.69", + "thiserror 2.0.21", "time", "url", ] @@ -480,7 +492,7 @@ dependencies = [ "serde", "serde_json", "serde_path_to_error", - "thiserror 1.0.69", + "thiserror 2.0.21", "time", ] @@ -492,7 +504,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.118", + "syn 3.0.10", "trybuild", ] @@ -506,7 +518,7 @@ dependencies = [ "psl", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.21", "time", "url", ] @@ -518,10 +530,10 @@ dependencies = [ "hex", "pulldown-cmark", "serde", - "sha2 0.10.9", - "thiserror 1.0.69", + "sha2 0.11.1", + "thiserror 2.0.21", "time", - "toml 0.8.23", + "toml", ] [[package]] @@ -533,14 +545,14 @@ dependencies = [ "auctioneer-openrtb", "auctioneer-privacy", "auctioneer-runtime", - "getrandom 0.3.4", + "getrandom 0.4.3", "log", "lru", "once_cell", "proptest", "serde_json", "testing_logger", - "thiserror 1.0.69", + "thiserror 2.0.21", "time", ] @@ -556,7 +568,7 @@ dependencies = [ "serde_json", "tempfile", "time", - "toml 0.8.23", + "toml", "web-time", ] @@ -568,9 +580,9 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "aws-lc-rs" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00" +checksum = "048006790404103c488e6c5616b3e7e702a71292aadda08e8f7698a9e0d2eb53" dependencies = [ "aws-lc-sys", "zeroize", @@ -578,14 +590,15 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.41.0" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4" +checksum = "8bfbe32ac36b3c428696ce315464181bc4029d689fd58e3f2a4e58c252242f52" dependencies = [ "cc", "cmake", "dunce", "fs_extra", + "pkg-config", ] [[package]] @@ -664,7 +677,16 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ - "bit-vec", + "bit-vec 0.8.0", +] + +[[package]] +name = "bit-set" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56d87354e4229f54a44f7bf2435906a4656dba36026ab6eaca629a2c436a691c" +dependencies = [ + "bit-vec 0.10.2", ] [[package]] @@ -673,6 +695,16 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" +[[package]] +name = "bit-vec" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72503af1e72be411d74ca45cd6b309878fcb35354e252fc2a3a8bda3a97082a0" +dependencies = [ + "borsh", + "serde", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -681,9 +713,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.13.0" +version = "2.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" [[package]] name = "block-buffer" @@ -694,15 +726,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - [[package]] name = "block-buffer" version = "0.12.1" @@ -718,6 +741,30 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc0b364ead1874514c8c2855ab558056ebfeb775653e7ae45ff72f28f8f3166c" +[[package]] +name = "borsh" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "553c5d846a6ba5150c65e3b1b8ec073bcf1abc20f9b7220de384a4443ea4e20a" +dependencies = [ + "borsh-derive", + "bytes", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cdfe656708a01f89b451a7d36466e6fe6c414de0aa18fc54f864f6f9ca9f56" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 3.0.10", +] + [[package]] name = "brotli" version = "8.0.4" @@ -769,9 +816,9 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "cc" -version = "1.2.65" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" +checksum = "4ff2a8126fff0f8c839080d619675a585e61720bb12d2baceae45769fd66f155" dependencies = [ "find-msvc-tools", "jobserver", @@ -781,15 +828,26 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" [[package]] name = "cfg_aliases" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + +[[package]] +name = "chacha20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "rand_core", +] [[package]] name = "chrono" @@ -807,9 +865,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.1" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" dependencies = [ "clap_builder", "clap_derive", @@ -817,9 +875,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.6.0" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" dependencies = [ "anstream", "anstyle", @@ -829,21 +887,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.6.1" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" +checksum = "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.10", ] [[package]] name = "clap_lex" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" [[package]] name = "cmake" @@ -854,6 +912,12 @@ dependencies = [ "cc", ] +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + [[package]] name = "colorchoice" version = "1.0.5" @@ -871,9 +935,9 @@ dependencies = [ [[package]] name = "combine" -version = "4.6.7" +version = "4.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +checksum = "4356eba6976435498d05a311ee9fc486da3bc81c200d3f0d7dd9703b41913f92" dependencies = [ "bytes", "memchr", @@ -899,9 +963,9 @@ checksum = "cc14f565cf027a105f7a44ccf9e5b424348421a1d8952a8fc9d499d313107789" [[package]] name = "const-oid" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" +checksum = "be95d4a884358a21a199689323c29e9256b4a1b315e22f183d155422041d3a9a" [[package]] name = "cookie" @@ -939,6 +1003,12 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "core_detect" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f8f80099a98041a3d1622845c271458a2d73e688351bf3cb999266764b81d48" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -966,16 +1036,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crypto-common" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" -dependencies = [ - "generic-array", - "typenum", -] - [[package]] name = "crypto-common" version = "0.2.2" @@ -995,14 +1055,33 @@ dependencies = [ "linktime-proc-macro", ] +[[package]] +name = "ctutils" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261af4dc7a06ea8a527a8717d8cbba3417530d6ea14e1edb3de6b67806be474f" +dependencies = [ + "cmov", +] + [[package]] name = "darling" version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.11", + "darling_macro 0.20.11", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core 0.23.0", + "darling_macro 0.23.0", ] [[package]] @@ -1016,7 +1095,20 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.118", + "syn 2.0.119", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.119", ] [[package]] @@ -1025,9 +1117,20 @@ version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ - "darling_core", + "darling_core 0.20.11", "quote", - "syn 2.0.118", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core 0.23.0", + "quote", + "syn 2.0.119", ] [[package]] @@ -1038,9 +1141,9 @@ checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" [[package]] name = "deranged" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +checksum = "9e9de72ce2ad1f90dc62fa25f0f430ef85eb4b0d8fa0be4f30373bc40a21d28e" dependencies = [ "serde_core", ] @@ -1060,10 +1163,10 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" dependencies = [ - "darling", + "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -1073,7 +1176,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -1085,17 +1188,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer 0.10.4", - "crypto-common 0.1.7", - "subtle", -] - [[package]] name = "digest" version = "0.11.3" @@ -1104,18 +1196,19 @@ checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ "block-buffer 0.12.1", "const-oid", - "crypto-common 0.2.2", + "crypto-common", + "ctutils", ] [[package]] name = "displaydoc" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.10", ] [[package]] @@ -1140,7 +1233,7 @@ dependencies = [ "serde", "serde_json", "sha2 0.11.1", - "toml 1.1.2+spec-1.1.0", + "toml", "walkdir", ] @@ -1170,9 +1263,9 @@ dependencies = [ "serde", "serde_json", "simple_logger", - "thiserror 2.0.18", + "thiserror 2.0.21", "tokio", - "toml 1.1.2+spec-1.1.0", + "toml", "tower", "tracing", "walkdir", @@ -1197,7 +1290,7 @@ dependencies = [ "log", "serde_json", "tempfile", - "toml_edit 0.25.12+spec-1.1.0", + "toml_edit", "walkdir", "wasm-streams", "web-sys", @@ -1231,8 +1324,8 @@ dependencies = [ "serde", "serde_json", "sha2 0.11.1", - "thiserror 2.0.18", - "toml_edit 0.25.12+spec-1.1.0", + "thiserror 2.0.21", + "toml_edit", "walkdir", ] @@ -1256,9 +1349,9 @@ dependencies = [ "serde_json", "spin-sdk", "subtle", - "thiserror 2.0.18", - "toml 1.1.2+spec-1.1.0", - "toml_edit 0.25.12+spec-1.1.0", + "thiserror 2.0.21", + "toml", + "toml_edit", "walkdir", ] @@ -1282,8 +1375,8 @@ dependencies = [ "serde_json", "similar", "simple_logger", - "thiserror 2.0.18", - "toml 1.1.2+spec-1.1.0", + "thiserror 2.0.21", + "toml", "validator", ] @@ -1322,8 +1415,8 @@ dependencies = [ "serde_urlencoded", "sha2 0.11.1", "simd-adler32", - "thiserror 2.0.18", - "toml 1.1.2+spec-1.1.0", + "thiserror 2.0.21", + "toml", "tower-service", "tracing", "url", @@ -1341,16 +1434,16 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 3.0.9", - "toml 1.1.2+spec-1.1.0", + "syn 3.0.10", + "toml", "validator", ] [[package]] name = "either" -version = "1.16.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" +checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" [[package]] name = "elsa" @@ -1373,24 +1466,29 @@ dependencies = [ [[package]] name = "encoding_rs" -version = "0.8.35" +version = "0.8.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +checksum = "89253175e704ab869b04f9db224d38630e0211a53841a79181deae0889e169f5" dependencies = [ "cfg-if", + "core_detect", + "multiversion_no_op", + "rustversion", + "scopeguard", + "simdutf8", ] [[package]] name = "equivalent" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "00d174d5400e5e8fd687ad1049e2f578285fa914201b1af7e8b112a4546bd826" [[package]] name = "errno" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +checksum = "e35d6e78f4cebb90e51d543db8fe41528851d6deeef6ef21ebd4bfdc1e784776" dependencies = [ "libc", "windows-sys 0.61.2", @@ -1410,11 +1508,11 @@ checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "fancy-regex" -version = "0.19.2" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d301f5bf187b3c295fce6468d3875037a0bccc5f6b151c63cac2f85babf21912" +checksum = "0a2e16b9a584b602f1e0e5e22c30ca0906786088c27500653e432d086def8b53" dependencies = [ - "bit-set", + "bit-set 0.8.0", "regex-automata", "regex-syntax", ] @@ -1482,9 +1580,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" [[package]] name = "fdeflate" @@ -1516,9 +1614,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.9" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "1c66915cc5391097de7a2b0b972e8505aa33c0df401fd3a6811dbdb32881ba48" [[package]] name = "flate2" @@ -1547,12 +1645,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - [[package]] name = "foldhash" version = "0.2.0" @@ -1665,7 +1757,7 @@ checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" dependencies = [ "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -1699,9 +1791,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", @@ -1741,17 +1833,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi 6.0.0", + "rand_core", + "wasm-bindgen", ] [[package]] name = "gimli" -version = "0.32.3" +version = "0.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" +checksum = "1033caf0b349c518623b5396bfb2cf0bddf44f0306d543a250e5743297aafd10" dependencies = [ - "fallible-iterator", + "fnv", + "hashbrown", "indexmap", "stable_deref_trait", ] @@ -1764,9 +1860,9 @@ checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" [[package]] name = "h2" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8e5e5a340588f4452631496976cf8636d4a7ecf600239fdc27615d2530bc16" +checksum = "7d29020232d6aa3fb1daca64c1127cf662cf97f254ae16c18c05b8ab635fc118" dependencies = [ "atomic-waker", "bytes", @@ -1794,18 +1890,7 @@ dependencies = [ "pest_derive", "serde", "serde_json", - "thiserror 2.0.18", -] - -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash 0.1.5", + "thiserror 2.0.21", ] [[package]] @@ -1816,7 +1901,7 @@ checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" dependencies = [ "allocator-api2", "equivalent", - "foldhash 0.2.0", + "foldhash", ] [[package]] @@ -1825,7 +1910,7 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a596f1b20ed2cc5ecac41a164aaebc7258057060f06c0cf7a2ba3991ee7990fb" dependencies = [ - "hashbrown 0.17.1", + "hashbrown", ] [[package]] @@ -1842,11 +1927,11 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hmac" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" dependencies = [ - "digest 0.10.7", + "digest 0.11.3", ] [[package]] @@ -1861,9 +1946,9 @@ dependencies = [ [[package]] name = "http-body" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" dependencies = [ "bytes", "http", @@ -1871,9 +1956,9 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +checksum = "23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" dependencies = [ "bytes", "futures-core", @@ -1927,9 +2012,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.9" +version = "0.27.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +checksum = "dfa8e654703247911e29c23fbeaa261834bd9bb74efba2f9acddc37bfb127f53" dependencies = [ "http", "hyper", @@ -1958,16 +2043,17 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +checksum = "ddc03d96684f9226b8a787cdb71488417b53ab5ea8fdb1dac946cb9431cc8bff" dependencies = [ - "base64 0.22.1", + "base64 0.23.1", "bytes", "futures-channel", "futures-util", "http", "http-body", + "httparse", "hyper", "ipnet", "libc", @@ -2007,9 +2093,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +checksum = "fe090a42a0d3140fed8c63263ed1fecc02422cb2f4bfe55cd8de2de1b8e105dd" dependencies = [ "displaydoc", "potential_utf", @@ -2021,9 +2107,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +checksum = "25d29b57c17c6528d0dc4c2141cfa2d08200465acb537a3909c8b9b8a4a984c0" dependencies = [ "displaydoc", "litemap", @@ -2034,9 +2120,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +checksum = "404a3b8c486f205c87fe7f23ab6894d84a4ad76d6e4671ae1981ba7def87c599" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -2048,16 +2134,17 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" +checksum = "20f0088bfb7441f7a37fa0c9e20cb1e9cba1cac6b9ce8cd2a6dc44294f8e8cbc" [[package]] name = "icu_properties" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +checksum = "2ea83d991c56158f7cf898bf86436c1dfe7c07ee82fe88951f2695c9f37a379f" dependencies = [ + "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", @@ -2068,15 +2155,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" +checksum = "b98f29af82d02b163fe50161388350e743bb3107cc8e8c2f7314cb505faddfcf" [[package]] name = "icu_provider" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +checksum = "413099315636c588ee8f011190b329b971a09a8fae9d157e01dcae8379468514" dependencies = [ "displaydoc", "icu_locale_core", @@ -2122,27 +2209,27 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.14.0" +version = "2.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" dependencies = [ "equivalent", - "hashbrown 0.17.1", + "hashbrown", "serde", "serde_core", ] [[package]] name = "ipnet" -version = "2.12.0" +version = "2.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" +checksum = "791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0" [[package]] name = "ipnetwork" -version = "0.20.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" +checksum = "cf370abdafd54d13e54a620e8c3e1145f28e46cc9d704bc6d94414559df41763" [[package]] name = "is_terminal_polyfill" @@ -2161,9 +2248,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +checksum = "3bd1574e617a9a6c1f8f8181bd7e841e1f20e4277607ef28945765188d6284d4" [[package]] name = "jni" @@ -2177,7 +2264,7 @@ dependencies = [ "jni-sys", "log", "simd_cesu8", - "thiserror 2.0.18", + "thiserror 2.0.21", "walkdir", "windows-link", ] @@ -2192,7 +2279,7 @@ dependencies = [ "quote", "rustc_version", "simd_cesu8", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -2211,24 +2298,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" dependencies = [ "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] name = "jobserver" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.3", "libc", ] [[package]] name = "js-sys" -version = "0.3.103" +version = "0.3.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +checksum = "8dc09d2154098bbf4ef54eab6b117a3c24cbbffe94046b16ee6d6d4510584d3a" dependencies = [ "cfg-if", "futures-util", @@ -2237,9 +2324,9 @@ dependencies = [ [[package]] name = "jsonschema" -version = "0.58.6" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f622c574a29fb3034a0a90645afee194dfedc75fc124228801b6e77041075bd1" +checksum = "0e37f27df77c7887edbc5f5a59ecd8e5ec4a669319266ec1b61068667a603183" dependencies = [ "ahash", "bytecount", @@ -2266,9 +2353,9 @@ dependencies = [ [[package]] name = "jsonschema-macros" -version = "0.58.6" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5553b59276ad81f2f49c80cd381a6d6d873e74139cdeb2bef0f9eb28a2ded2b6" +checksum = "e3467cc02f0e5de53d77834726a4744c61bdd239336ae49902ff0cbf1842d930" dependencies = [ "jsonschema-macros-core", "proc-macro2", @@ -2276,7 +2363,7 @@ dependencies = [ [[package]] name = "jsonschema-macros-core" -version = "0.58.6" +version = "0.61.2" dependencies = [ "fancy-regex", "indexmap", @@ -2288,28 +2375,29 @@ dependencies = [ "referencing", "regex", "serde_json", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] name = "jsonschema-regex" -version = "0.58.6" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a968fffd387b2ab005bf00c1851f5d26e90df05b6f7ad609ed0d620033cca5e7" +checksum = "7e41151614b6c927e21982be8bef5a26741ae5a0ae6a781eedee2aa930a980e6" dependencies = [ "regex-syntax", ] [[package]] name = "jsonschema-value" -version = "0.58.6" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39b7670345e5ce87371339d13705dbb9276b7e3e934bbe1efa2c6734a1f65a96" +checksum = "1515b9a91134ef67d7bac95c2d76fbc7e383c4c55ee544204ceec8088f881fef" dependencies = [ "ahash", "bytecount", "fraction", "getrandom 0.3.4", + "memchr", "num-cmp", "num-traits", "serde_json", @@ -2324,9 +2412,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.186" +version = "0.2.191" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a" [[package]] name = "libsqlite3-sys" @@ -2359,9 +2447,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" [[package]] name = "lock_api" @@ -2391,18 +2479,18 @@ dependencies = [ [[package]] name = "lru" -version = "0.12.5" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +checksum = "4a9f71e3591c7ec44d3e563e87bf14ddc2bada8519dca046e5b0e560cd004e2d" dependencies = [ - "hashbrown 0.15.5", + "hashbrown", ] [[package]] name = "lru-slab" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +checksum = "4050469837a6ff301cd14c1f8f24f88549e6d548f24f64e2148eb0f72cebc51f" [[package]] name = "matchit" @@ -2424,9 +2512,9 @@ checksum = "8863b587001c1b9a8a4e36008cebc6b3612cb1226fe2de94858e06092687b608" [[package]] name = "memchr" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "micromap" @@ -2436,9 +2524,9 @@ checksum = "c2a86d3146ed3995b5913c414f6664344b9617457320782e64f0bb44afd49d74" [[package]] name = "mime" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +checksum = "d5848f5a9e8117cf94f2f90faac24a87ff81600ff8628c1e3deaab572e76bfa1" [[package]] name = "miniz_oxide" @@ -2452,15 +2540,21 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.1" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" +checksum = "1788edb87fdc09c7e26304471e2f5be8cdefb1b6930d6e3985fc02ff53bf86ee" dependencies = [ "libc", "wasi", "windows-sys 0.61.2", ] +[[package]] +name = "multiversion_no_op" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743fb55ba31b18fb1ecef6bdc9aa2743314978ac084044301a7eee33fb99a20d" + [[package]] name = "native-tls" version = "0.2.18" @@ -2579,21 +2673,30 @@ dependencies = [ [[package]] name = "num_threads" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +checksum = "cabcc654086861f9e1bc5115258de62ef92c79b20f4615a1b0cc57c4e82027d4" dependencies = [ "libc", ] [[package]] name = "object" -version = "0.37.3" +version = "0.39.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b" +dependencies = [ + "memchr", +] + +[[package]] +name = "object" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" +checksum = "11dbdb66876026054e4ffc8d757d862bdf5df5aebd5c0b95a41f17832a94f7d2" dependencies = [ "crc32fast", - "hashbrown 0.15.5", + "hashbrown", "indexmap", "memchr", ] @@ -2618,11 +2721,11 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.81" +version = "0.10.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" +checksum = "4de8111e94a56adca7ebfe6c365b6d42f99deb69b74b6becacd4204e2f193aa2" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.2", "cfg-if", "foreign-types", "libc", @@ -2638,20 +2741,20 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] name = "openssl-probe" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" +checksum = "7e036b411754132fd6b74e94b74e9a13c5cf606fa93d1885c35860d3060820b1" [[package]] name = "openssl-sys" -version = "0.9.117" +version = "0.9.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" +checksum = "19c413d6ec9ebaf5e1c829d355cb3e9f783778d700f135be0921d52fce3c60ae" dependencies = [ "cc", "libc", @@ -2696,19 +2799,20 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.9.2" +version = "2.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45d3aca230fad2e6f6317ca0a72724338c4960cb97168a85cdee66df4a9a21a8" +checksum = "5ec53fd1d256900a9a771bf2720d42cef6f8bc91b4e25065fbd291e3e7222576" dependencies = [ "memchr", + "pest_stack_guard", "ucd-trie", ] [[package]] name = "pest_derive" -version = "2.9.2" +version = "2.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284b60557f2c4a2e72ad3f2d34d42685a2fa4a6a61d0d2a10c0ae2a5e916c2cf" +checksum = "adcf794fd301ddc20818a6b4de85ed507f4b45300245cec948982e69e12e3bd7" dependencies = [ "pest", "pest_generator", @@ -2716,26 +2820,36 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.9.2" +version = "2.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d9d1f08a115309ee99268cf85e5228e0e56aa9caf8841ec12866b6be07c3109" +checksum = "c3073afae5db334c25dea9fc3e230a4f191e920c1df080cb9c0b37c9ce1dbb41" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.10", ] [[package]] name = "pest_meta" -version = "2.9.2" +version = "2.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed93ba1a9ffcca32130a5188701c81c0c49cf00d4b7c5007d5148951d743adcb" +checksum = "7bc7f614b3742541642af1685faaa910bf6333e3cd3729c2cccd118146a57327" dependencies = [ "pest", ] +[[package]] +name = "pest_stack_guard" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ac6154fd4418b8f0b82532c59c26f303f9ca59a64c883e8ce3971fd82733439" +dependencies = [ + "psm", + "stacker", +] + [[package]] name = "pin-project" version = "1.1.13" @@ -2753,7 +2867,7 @@ checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -2764,17 +2878,17 @@ checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkg-config" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" [[package]] name = "png" -version = "0.17.16" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.13.2", "crc32fast", "fdeflate", "flate2", @@ -2783,27 +2897,18 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" dependencies = [ "zerovec", ] [[package]] name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.21" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] +checksum = "4a6394b9e965e73d0a289ee54f589087e2c676aedf60885baf52c76b771e4958" [[package]] name = "prettyplease" @@ -2812,7 +2917,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bfe0f4c752e450fc2faf62654f1c134747922825d5b04ca717b8874f41a40c0" dependencies = [ "proc-macro2", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] @@ -2821,52 +2926,53 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit 0.25.12+spec-1.1.0", + "toml_edit", ] [[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" +name = "proc-macro-error-attr3" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +checksum = "9e564d14133360e1ae169ffde5da25881b5fa47261665b8e5713c212c27799da" dependencies = [ "proc-macro2", "quote", ] [[package]] -name = "proc-macro-error2" -version = "2.0.1" +name = "proc-macro-error3" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +checksum = "8f0d4471b3436c22106b21913b1dda531558918ae9b7ec55d58aa84b43552233" dependencies = [ - "proc-macro-error-attr2", + "proc-macro-error-attr3", "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.10", ] [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" +checksum = "b8530004ccb15eae51c7e40009fbe317f341f804db54dc033eec1c50be28cfa0" dependencies = [ - "bit-set", - "bit-vec", - "bitflags 2.13.0", + "bit-set 0.11.1", + "bit-vec 0.10.2", + "bitflags 2.13.2", + "chacha20", + "core_detect", "num-traits", "rand", - "rand_chacha", "rand_xorshift", "regex-syntax", "unarray", @@ -2874,9 +2980,9 @@ dependencies = [ [[package]] name = "psl" -version = "2.1.215" +version = "2.1.252" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caff7403e06671f170c65dc7bf475ed31d6e108c7e0d2440fb4df8ba56cfded6" +checksum = "efefe9aafbc2e8fd9157db7eb16c61a86cbf0ead714adf510a7ae662470fe369" dependencies = [ "psl-types", ] @@ -2887,22 +2993,32 @@ version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" +[[package]] +name = "psm" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd034599e63b970727f70d79e02d62390a4a84f7c6b827c27c46d5ac3fa622" +dependencies = [ + "ar_archive_writer", + "cc", +] + [[package]] name = "pulldown-cmark" version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3db2be46835f013dd3f4fa7f5f7402c537787b54ebb6fe2b94bbdd7e2669bb7b" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.2", "memchr", "unicase", ] [[package]] name = "quinn" -version = "0.11.11" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" +checksum = "4051e23e9185c255a7e33ef59cdbca87a22d359052eecd22fc6b901fb37d9d11" dependencies = [ "bytes", "cfg_aliases", @@ -2912,7 +3028,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror 2.0.18", + "thiserror 2.0.21", "tokio", "tracing", "web-time", @@ -2920,21 +3036,22 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.15" +version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fcb935c5bec503c2f0e306bdd3e58bb9029dcb14fa8d9ac76e3a5256ac0763e" +checksum = "0e750cca55fe4f0439a15d0bb529da9651e79993e8e72c61a899a36d462befbe" dependencies = [ "aws-lc-rs", "bytes", - "getrandom 0.3.4", + "getrandom 0.4.3", "lru-slab", "rand", + "rand_pcg", "ring", "rustc-hash", "rustls", "rustls-pki-types", "slab", - "thiserror 2.0.18", + "thiserror 2.0.21", "tinyvec", "tracing", "web-time", @@ -2942,23 +3059,23 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.14" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +checksum = "af66907df18639dcf4db56ca65490cabc4b27a97dbadd96f2926cca73298f016" dependencies = [ "cfg_aliases", "libc", "once_cell", "socket2", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "quote" -version = "1.0.46" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] @@ -2977,47 +3094,44 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.9.4" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" dependencies = [ - "rand_chacha", + "chacha20", + "getrandom 0.4.3", "rand_core", ] [[package]] -name = "rand_chacha" -version = "0.9.0" +name = "rand_core" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core", -] +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] -name = "rand_core" -version = "0.9.5" +name = "rand_pcg" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" dependencies = [ - "getrandom 0.3.4", + "rand_core", ] [[package]] name = "rand_xorshift" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +checksum = "60aa6af80be32871323012e02e6e65f8a7cc7890931ae421d217ad8fe0df2ccf" dependencies = [ "rand_core", ] [[package]] name = "redb" -version = "4.4.0" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39178e0a867f9e3eaa6292a4ab1dd3613f2519c5b564341e1e7b29b270736cc4" +checksum = "8b317ef681e18f6091efbfab532eaf924a135c492d9d0299d0fbfae07e92a39b" dependencies = [ "libc", ] @@ -3028,7 +3142,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.2", ] [[package]] @@ -3048,19 +3162,19 @@ checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" dependencies = [ "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", ] [[package]] name = "referencing" -version = "0.58.6" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558f3855529c0a7e78a48e409fa653456e55f1b167eab4109c16a255b7727e3f" +checksum = "a028057ef852c58a42d75e09da87b5e733f4030f4c7411728955e4f87203a577" dependencies = [ "ahash", "fluent-uri", "getrandom 0.3.4", - "hashbrown 0.17.1", + "hashbrown", "itoa", "micromap", "parking_lot", @@ -3070,9 +3184,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.12.4" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" dependencies = [ "aho-corasick", "memchr", @@ -3196,7 +3310,7 @@ version = "0.40.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23f2a97da3e3873c73cb2a2e71b35c40ff95e0b1eefa8d72d8499a6928c3b5b3" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.2", "fallible-iterator", "fallible-streaming-iterator", "libsqlite3-sys", @@ -3205,9 +3319,9 @@ dependencies = [ [[package]] name = "rustc-hash" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" [[package]] name = "rustc_version" @@ -3220,11 +3334,11 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.4" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +checksum = "e5e76742e5294153d4dde1207dbec5bdd81eef6fabdc0d2118babadabfd858aa" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.2", "errno", "libc", "linux-raw-sys", @@ -3233,9 +3347,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.41" +version = "0.23.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" +checksum = "48e13bd8c0e9365c43cfa5c9e8f9ad49d3c8444926c9aac819e0e4dc503c8fdf" dependencies = [ "aws-lc-rs", "once_cell", @@ -3247,9 +3361,9 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" +checksum = "4a073f5dc7469f984c52ad2752b63b0807745133b6de880b7b64c1ac4c48aec4" dependencies = [ "openssl-probe", "rustls-pki-types", @@ -3259,9 +3373,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.14.1" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +checksum = "102f35f7de7b06d8c61f1cff6592f5253e0dea431c74867aad5dfd70f44663fb" dependencies = [ "web-time", "zeroize", @@ -3269,9 +3383,9 @@ dependencies = [ [[package]] name = "rustls-platform-verifier" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" +checksum = "1167586491e2b18b8bfbb293e8180ec17c201c4f076d7cb3070ca964e7598f98" dependencies = [ "core-foundation 0.10.1", "core-foundation-sys", @@ -3290,15 +3404,15 @@ dependencies = [ [[package]] name = "rustls-platform-verifier-android" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" +checksum = "eec689c0bc40ff2458a5977b6619cb718087084a18e02a131c599b62d05e1a5f" [[package]] name = "rustls-webpki" -version = "0.103.13" +version = "0.103.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +checksum = "e3a0760a887c14823fca5a1c970b01d47c328c696c0c64829d1df50e8f853fd5" dependencies = [ "aws-lc-rs", "ring", @@ -3308,9 +3422,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "ryu" @@ -3329,9 +3443,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +checksum = "9cb23c424d8ee841bb4d813677ca237e2a610067d594fec130f87d6093495ab5" dependencies = [ "windows-sys 0.61.2", ] @@ -3348,7 +3462,7 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.2", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -3373,9 +3487,9 @@ checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" [[package]] name = "serde" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", "serde_derive", @@ -3394,22 +3508,22 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.10", ] [[package]] @@ -3438,29 +3552,20 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.10", ] [[package]] name = "serde_spanned" -version = "0.6.9" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_spanned" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +checksum = "9c187e0a369471c550af028cba56d4f4fa2a489ad28151ae95a4d340a2a8b782" dependencies = [ "serde_core", ] @@ -3503,17 +3608,6 @@ dependencies = [ "opaque-debug", ] -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "digest 0.10.7", -] - [[package]] name = "sha2" version = "0.11.1" @@ -3549,9 +3643,9 @@ checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" [[package]] name = "simd_cesu8" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" dependencies = [ "rustc_version", "simdutf8", @@ -3565,9 +3659,9 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "similar" -version = "3.2.0" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f66ca1f7aca2474dc10c942eb22feffc897735f54cd1db90138c2fddb490987" +checksum = "d2f8bec09ae8fae0f4f265a4559a9334be3929d8504e9b536df0a41302bd1733" dependencies = [ "bstr", ] @@ -3592,15 +3686,15 @@ checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.15.2" +version = "1.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" +checksum = "149309498a5f7334b12ddae0cad8aba81ce785fe91755068867e017cf98fee46" [[package]] name = "socket2" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", "windows-sys 0.61.2", @@ -3628,7 +3722,7 @@ dependencies = [ "http-body", "http-body-util", "spin-macro", - "thiserror 2.0.18", + "thiserror 2.0.21", "wasip3", ] @@ -3638,6 +3732,19 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "stacker" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707f49d46706bacf8a2b00d51dace3f9de527c13eec3778f570c411f89e69967" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys 0.61.2", +] + [[package]] name = "strsim" version = "0.11.1" @@ -3671,7 +3778,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -3683,7 +3790,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -3705,9 +3812,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.118" +version = "2.0.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" dependencies = [ "proc-macro2", "quote", @@ -3716,9 +3823,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.9" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78c8dee4c7bf0e14673097256fed6142ce9d3b85a408189d07482442145823b" +checksum = "4ae9ccbea3a7b0b09443036490c8f34a8b1b760fd345e5c0dae0aac718faea79" dependencies = [ "proc-macro2", "quote", @@ -3736,13 +3843,13 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.2" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +checksum = "901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.10", ] [[package]] @@ -3751,7 +3858,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.2", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -3824,11 +3931,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" dependencies = [ - "thiserror-impl 2.0.18", + "thiserror-impl 2.0.21", ] [[package]] @@ -3839,25 +3946,25 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.10", ] [[package]] name = "time" -version = "0.3.51" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c17d80feb7334b40c484e45ed1a5273dfd8bfda537c3be2e74a06a6686f327" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" dependencies = [ "deranged", "libc", @@ -3877,9 +3984,9 @@ checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.30" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcef1a61bdb119096e153208ec5cbec23944ce8bca13be5c7f60c634f7403935" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" dependencies = [ "num-conv", "time-core", @@ -3887,9 +3994,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +checksum = "abc840c238154d58f9e86b2792261edfde565a17696e1cda1a449de27979801a" dependencies = [ "displaydoc", "zerovec", @@ -3897,24 +4004,15 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.11.0" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +checksum = "fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" [[package]] name = "tokio" -version = "1.52.3" +version = "1.54.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" +checksum = "b52fd3255258d26fac7264ab5a76b53c13367136dc011d3d6ad4f8ed070396a3" dependencies = [ "bytes", "libc", @@ -3928,13 +4026,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.7.0" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.10", ] [[package]] @@ -3949,9 +4047,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.4" +version = "0.26.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +checksum = "c9cc2678c2cdd569ef8215e2afd7954ada2ae20b4fdd2c5fe6139a3b02d105db" dependencies = [ "rustls", "tokio", @@ -3959,9 +4057,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.19" +version = "0.7.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" +checksum = "e464cf451ba96ebfc6f9b6542f17ee8b8956e33f1e40d9690624e59d7a7f8a4b" dependencies = [ "bytes", "futures-core", @@ -3973,96 +4071,55 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" -dependencies = [ - "serde", - "serde_spanned 0.6.9", - "toml_datetime 0.6.11", - "toml_edit 0.22.27", -] - -[[package]] -name = "toml" -version = "1.1.2+spec-1.1.0" +version = "1.2.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +checksum = "d5755c51863cdac711f1956baf8eb9588e060755f7d3c4c979e70ea1e1f32cd7" dependencies = [ "indexmap", "serde_core", - "serde_spanned 1.1.1", - "toml_datetime 1.1.1+spec-1.1.0", + "serde_spanned", + "toml_datetime", "toml_parser", "toml_writer", - "winnow 1.0.3", + "winnow", ] [[package]] name = "toml_datetime" -version = "0.6.11" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_datetime" -version = "1.1.1+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +checksum = "173f25c883cd2176a2d8212155638c0a60d484a9d84546d270866f40f56b6e49" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.22.27" +version = "0.25.19+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +checksum = "dd43688c4858d7264ae1cf9a9f874a67c3feb74a883b1cd7bebd6a4ea8307218" dependencies = [ "indexmap", - "serde", - "serde_spanned 0.6.9", - "toml_datetime 0.6.11", - "toml_write", - "winnow 0.7.15", -] - -[[package]] -name = "toml_edit" -version = "0.25.12+spec-1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" -dependencies = [ - "indexmap", - "toml_datetime 1.1.1+spec-1.1.0", + "toml_datetime", "toml_parser", "toml_writer", - "winnow 1.0.3", + "winnow", ] [[package]] name = "toml_parser" -version = "1.1.2+spec-1.1.0" +version = "1.1.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +checksum = "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c" dependencies = [ - "winnow 1.0.3", + "winnow", ] -[[package]] -name = "toml_write" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" - [[package]] name = "toml_writer" -version = "1.1.1+spec-1.1.0" +version = "1.2.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" +checksum = "009dbb7700f11c55ef83aebbe4c0e9cf1f1ac0844bd8d6f00dc38f302026e13a" [[package]] name = "tower" @@ -4087,7 +4144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ "async-compression", - "bitflags 2.13.0", + "bitflags 2.13.2", "bytes", "futures-core", "futures-util", @@ -4135,7 +4192,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -4165,7 +4222,7 @@ dependencies = [ "serde_json", "target-tuple", "termcolor", - "toml 1.1.2+spec-1.1.0", + "toml", ] [[package]] @@ -4188,15 +4245,15 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicase" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" +checksum = "357cc3acc6a036009fd6c973ed009037c732d60d0b4f6c673e9041497482a28f" [[package]] name = "unicode-case-mapping" -version = "0.5.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b92e07ac57786e12073609c8a91417884306b753d974108ca48c8434ed9b99cb" +checksum = "4e9026503b74f3207a4c04e6bf4ea735daa8edf6c0bbfa044cae597bb947a9db" [[package]] name = "unicode-general-category" @@ -4206,9 +4263,9 @@ checksum = "0b993bddc193ae5bd0d623b49ec06ac3e9312875fdae725a975c51db1cc1677f" [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" [[package]] name = "unsafe-libyaml" @@ -4236,9 +4293,12 @@ dependencies = [ [[package]] name = "utf8_iter" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +checksum = "af3bd9d3e571c26fcce9d033b87ea5ab061b8d2ffe9b7a5675d810d68f03edf0" +dependencies = [ + "utf_types", +] [[package]] name = "utf8parse" @@ -4246,6 +4306,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "utf_types" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3b425286980a367278453f3b6d28cdcb134b574e5a35824a6ff5eebad50bb6" + [[package]] name = "uuid-simd" version = "0.8.0" @@ -4273,16 +4339,15 @@ dependencies = [ [[package]] name = "validator_derive" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7df16e474ef958526d1205f6dda359fdfab79d9aa6d54bafcb92dcd07673dca" +checksum = "240e4b81c20a1d6d50d1d7265c658dfbd204e8b9ac4d80f3c931f39462196335" dependencies = [ - "darling", - "once_cell", - "proc-macro-error2", + "darling 0.23.0", + "proc-macro-error3", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -4346,18 +4411,17 @@ dependencies = [ "bytes", "http", "http-body", - "thiserror 2.0.18", + "thiserror 2.0.21", "wit-bindgen 0.63.0", ] [[package]] name = "wasm-bindgen" -version = "0.2.126" +version = "0.2.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +checksum = "a0181c14ddd6c7b8b0b0132a5f1ea2f32be0d893cd3ea97b6e3b28886b8a3d1c" dependencies = [ "cfg-if", - "once_cell", "rustversion", "wasm-bindgen-macro", "wasm-bindgen-shared", @@ -4365,19 +4429,20 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.76" +version = "0.4.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" +checksum = "5e14e0327cb5368ad60ccb22d04a9827a693c95a926d8d125e9fa39e0baec501" dependencies = [ "js-sys", + "tokio", "wasm-bindgen", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.126" +version = "0.2.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +checksum = "6e931a02a39abdbf66966fc35902b5ed58344750a70885bed4ebb3d8eaf28ed9" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4385,44 +4450,44 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.126" +version = "0.2.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +checksum = "2ca4b54280e455bd831e33a6b8e734baf432fe63fbc35c42ac14ce67a043a53a" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.10", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.126" +version = "0.2.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" +checksum = "3b1f9c3798725016c6ee5f2f57869ec0831e8bbc0ab0310a86e787e97f41389e" dependencies = [ "unicode-ident", ] [[package]] name = "wasm-encoder" -version = "0.247.0" +version = "0.262.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b6733b8b91d010a6ac5b0fb237dc46a19650bc4c67db66857e2e787d437204" +checksum = "4495a6f85dd94c411c749303efcbc5defade0b0cbdbc0541495241ab917a9b5a" dependencies = [ "leb128fmt", - "wasmparser 0.247.0", + "wasmparser 0.262.0", ] [[package]] name = "wasm-encoder" -version = "0.262.0" +version = "0.263.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4495a6f85dd94c411c749303efcbc5defade0b0cbdbc0541495241ab917a9b5a" +checksum = "0b883a26aea02eaabe2d2c3fba7eb039ef5cdcb5d5201ae5551e73d5e251a81f" dependencies = [ "leb128fmt", - "wasmparser 0.262.0", + "wasmparser 0.263.0", ] [[package]] @@ -4452,32 +4517,32 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.247.0" +version = "0.262.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6fb4c2bee46c5ea4d40f8cdb5c131725cd976718ec56f1c8e82fbde5fa2a80" +checksum = "974d643b125b272607e2fff8012ea14a8328acd7621e4bafa7afb32500052b1b" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.2", + "hashbrown", "indexmap", "semver", ] [[package]] name = "wasmparser" -version = "0.262.0" +version = "0.263.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "974d643b125b272607e2fff8012ea14a8328acd7621e4bafa7afb32500052b1b" +checksum = "4f5fa0a054ae153606df820eb0a84213e28cda41bbe04ba2628e71b6ba100fcb" dependencies = [ - "bitflags 2.13.0", - "hashbrown 0.17.1", + "bitflags 2.13.2", "indexmap", "semver", ] [[package]] name = "web-sys" -version = "0.3.103" +version = "0.3.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" +checksum = "d7d179596ff5ec0f6de4db64d54011bde6289cc49603d3a6e4ce3f329207ab88" dependencies = [ "js-sys", "wasm-bindgen", @@ -4495,9 +4560,9 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "1.0.8" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d46a5a140e6f7afeccd8eae97eff335163939eac8b929834875168b29b3d267" +checksum = "293198dcebfb821155b5092ab94b5a82ff180eddd7241df3bd6e66a4ffd1a585" dependencies = [ "rustls-pki-types", ] @@ -4554,7 +4619,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -4565,7 +4630,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -4609,16 +4674,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", + "windows-targets", ] [[package]] @@ -4636,31 +4692,14 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", + "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]] @@ -4669,110 +4708,53 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - [[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_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - [[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_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - [[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_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - [[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_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - [[package]] name = "winnow" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +checksum = "8c3b93199df0ab874cdf0c6a94f0a0dc3423fe41f1cafb62b8bd7b1deb277aef" dependencies = [ "memchr", ] @@ -4783,7 +4765,7 @@ version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.2", ] [[package]] @@ -4792,7 +4774,7 @@ version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.2", ] [[package]] @@ -4801,7 +4783,7 @@ version = "0.63.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b85a987ab61d365382d25c7d47e26edd48941b3bf6e3fbf76eff918bc71dab06" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.2", "futures", "wit-bindgen-rust-macro", ] @@ -4827,7 +4809,7 @@ dependencies = [ "heck", "indexmap", "prettyplease", - "syn 3.0.9", + "syn 3.0.10", "wasm-metadata", "wit-bindgen-core", "wit-component", @@ -4843,7 +4825,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 3.0.9", + "syn 3.0.10", "wit-bindgen-core", "wit-bindgen-rust", ] @@ -4855,7 +4837,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "078def49fdb49cab405c3006e05793b3fdaf7069126ba6b9c97d01ec8c98fe4c" dependencies = [ "anyhow", - "bitflags 2.13.0", + "bitflags 2.13.2", "indexmap", "log", "serde", @@ -4874,7 +4856,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00f0dc051466ffe46787721fca3d088536f158ae400be044f1b1c386ba9397ad" dependencies = [ "anyhow", - "hashbrown 0.17.1", + "hashbrown", "id-arena", "indexmap", "log", @@ -4919,15 +4901,15 @@ dependencies = [ [[package]] name = "worker-macros" -version = "0.8.5" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d908735d273dd7f9c325a842623f4e5a745e0686187ce465b34dc162ad348df" +checksum = "f3d7389670b55aab89760be149007aeff773cdad7b650d807f7fb556d04bb304" dependencies = [ "async-trait", "proc-macro2", "quote", - "strum 0.27.2", - "syn 2.0.118", + "strum 0.28.0", + "syn 3.0.10", "wasm-bindgen", "wasm-bindgen-macro-support", "worker-sys", @@ -4935,9 +4917,9 @@ dependencies = [ [[package]] name = "worker-sys" -version = "0.8.5" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33faa1a8fa6c7eec67b196e008859c44d468a5ad4f991855cdc856f119e0e98f" +checksum = "6a440092e7ae7c5feb5507fbdc6aee0cc241d132757c83e1729766a24cddff82" dependencies = [ "cfg-if", "js-sys", @@ -4947,9 +4929,9 @@ dependencies = [ [[package]] name = "writeable" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" [[package]] name = "yaml-rust2" @@ -4963,9 +4945,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +checksum = "417ef3fcf6c300b7dbd25c85531a746931c02ad536f3cf4786ed1e88223340b3" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -4974,34 +4956,34 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +checksum = "ec8ebde2db3681e8c9980cc27822030e68752690ddfa9473e739aeb4dbde6d71" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.10", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.52" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" +checksum = "e5fe1f8f1b06191a00962174c61aa5005e0bb391a6d80d07e24d115c01a92ed8" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.52" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" +checksum = "863ad3ac83293fb4d740aedbfdc9240dd8d1a50c1099acd76ce80ce7c7230c7f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -5015,27 +4997,27 @@ dependencies = [ [[package]] name = "zerofrom-derive" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +checksum = "f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.10", "synstructure", ] [[package]] name = "zeroize" -version = "1.9.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" +checksum = "e13084392c5e4bc371903e2935a5eaeed24905a7511356b883835e18a78f6879" [[package]] name = "zerotrie" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" dependencies = [ "displaydoc", "yoke", @@ -5044,9 +5026,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.6" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +checksum = "f58a2799cfe9a1670c7ea8edbd52ef8edb93cb37a7f83bf31ba9e35d9dae6a40" dependencies = [ "yoke", "zerofrom", @@ -5055,13 +5037,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.3" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +checksum = "c3743ddbf47738d929cd1ae2e199d40d0162979dfe31aef8ae646d2bf00bf97a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.10", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 1c2254e..9f311b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,14 +46,14 @@ axum = "0.8" base64 = { version = "=0.23.1", default-features = false, features = ["std"] } bytes = "=1.12.1" cookie = { version = "=0.18.2", default-features = false } -hmac = { version = "=0.12.1", default-features = false } +hmac = { version = "=0.13.0", default-features = false } # Native HTTP version entries. The adapter's real-socket fixtures use Tokio TCP; # production crates route HTTP through EdgeZero, not directly through hyper. hyper = { version = "1", default-features = false } hyper-util = { version = "0.1", default-features = false } # Qualification-only candidate; do not add to deployed dependencies before its gate passes. -jsonschema = { version = "=0.58.6", default-features = false, features = ["macros"] } -jsonschema-macros-core = "=0.58.6" +jsonschema = { version = "=0.61.2", default-features = false, features = ["macros"] } +jsonschema-macros-core = "=0.61.2" # Dev-only log-capture helper used by regression tests that inspect # `log::warn!` output. Idempotent global setup — no cross-test # serialisation lock. @@ -82,16 +82,16 @@ hex = "0.4" # `executor` adds the single-threaded LocalPool used in synchronous test # contexts. No async runtime is added — `block_on` here is test-only. futures = { version = "0.3", default-features = false, features = ["std", "executor"] } -getrandom = { version = "0.3", default-features = false } +getrandom = { version = "0.4", default-features = false } # Native qualification reads compiler-emitted DWARF layout facts, never guesses # private dependency layouts. Write support is for synthetic conformance input. -gimli = { version = "=0.32.3", default-features = false, features = ["read", "write", "std"] } +gimli = { version = "=0.34.0", default-features = false, features = ["read", "write", "std"] } http = "1" http-body-util = "0.1" -ipnetwork = { version = "0.20", default-features = false } +ipnetwork = { version = "0.21", default-features = false } log = "0.4" # Entry-count-bounded parse cache behind auctioneer-privacy's GvlStore. -lru = "0.12" +lru = "0.19" auctioneer-bidder = { path = "crates/auctioneer-bidder" } auctioneer-cli = { path = "crates/auctioneer-cli", default-features = false } auctioneer-config-data = { path = "crates/auctioneer-config-data" } @@ -104,13 +104,13 @@ auctioneer-openrtb = { path = "crates/auctioneer-openrtb" } auctioneer-openrtb-catalogue = { path = "crates/auctioneer-openrtb-catalogue" } auctioneer-privacy = { path = "crates/auctioneer-privacy" } auctioneer-runtime = { path = "crates/auctioneer-runtime" } -mime = "0.3.17" +mime = "0.3.18" once_cell = "1" # Native-only application artifact inspection and synthetic object controls. -object = { version = "=0.37.3", default-features = false, features = ["read", "write", "std"] } +object = { version = "=0.41.0", default-features = false, features = ["read", "write", "std"] } percent-encoding = "2" # Test-only decoder for the original Prebid tracking pixel. -png = { version = "=0.17.16", default-features = false } +png = { version = "=0.18.1", default-features = false } # Dev-only property testing (auctioneer-privacy TCF parser: never-panic + # round-trip properties). # Property tests run in-process on native and WASM; no test uses fork/timeout. @@ -120,7 +120,7 @@ quote = "1" psl = "2" # Native maintenance fetches retain the archive tool's existing HTTP policy. reqwest = { version = "0.12", features = ["blocking", "json", "gzip"] } -regex = "=1.12.4" +regex = "=1.13.1" # Qualification-only direct API; this is the existing regex feature closure. regex-automata = { version = "=0.4.18", default-features = false, features = ["std", "meta", "nfa", "dfa-onepass", "dfa-search", "hybrid", "perf", "unicode"] } # Structured HIR inspection in native schema qualification only. @@ -133,27 +133,27 @@ yaml-rust2 = { version = "=0.13.0", default-features = false } # Dotted-field-path retention for GVL/GCL schema errors # (`MalformedEntry { path }` diagnostics in auctioneer-gvl-schema). serde_path_to_error = "0.1" -sha2 = "0.10" +sha2 = "0.11" rustix = { version = "1.1", features = ["fs", "process", "system"] } rustls = { version = "0.23", default-features = false, features = ["std", "aws_lc_rs", "tls12"] } tempfile = "3" tar = { version = "0.4.46", default-features = false } tokio-rustls = { version = "0.26", default-features = false, features = ["aws_lc_rs", "tls12"] } -zeroize = { version = "1.8", default-features = false, features = ["alloc"] } +zeroize = { version = "1.9", default-features = false, features = ["alloc"] } simple_logger = "5" spin-sdk = { version = "=7.0.0", git = "https://github.com/stackpop/spin-rust-sdk.git", rev = "6c59ed5b4fcb377072763aee0b27a3abdd8edb72", default-features = false, features = ["http", "key-value", "variables"] } # Constant-time comparison for the health-endpoint bearer digest — # wasm-compatible, no timing side channel on token verification. subtle = "2" -syn = { version = "2", features = ["full"] } -thiserror = "1" +syn = { version = "3", features = ["full"] } +thiserror = "2" time = { version = "0.3", default-features = false, features = ["std", "macros", "parsing", "formatting"] } tokio = { version = "1", features = ["macros", "rt-multi-thread"] } -toml = "0.8" +toml = "1.2" trybuild = "=1.0.122" tracing = "0.1" -# Unicode 15 simple folding, qualified against Go 1.23.12 over every scalar. -unicode-case-mapping = "=0.5.0" +# Unicode 16 C/S folding, qualified over every scalar with the frozen Go delta. +unicode-case-mapping = "=1.0.0" # `url` is needed by auctioneer-exchange::validate_endpoint. url = { version = "2", default-features = false } uuid-simd = { version = "=0.8.0", default-features = false, features = ["std", "detect"] } @@ -164,9 +164,9 @@ uuid-simd = { version = "=0.8.0", default-features = false, features = ["std", " # they have arguments validator's per-field derive cannot pass # (e.g. `allow_insecure: bool` for the URL gate). validator = { version = "0.21", features = ["derive"] } -wasmparser = { version = "=0.247.0", default-features = false, features = ["std", "validate", "features", "component-model", "simd"] } +wasmparser = { version = "=0.263.0", default-features = false, features = ["std", "validate", "features", "component-model", "simd"] } # Native-only artifact conformance fixtures use the matching standard encoder. -wasm-encoder = { version = "=0.247.0", default-features = false, features = ["std", "component-model"] } +wasm-encoder = { version = "=0.263.0", default-features = false, features = ["std", "component-model"] } # Portable monotonic clock. The SAME major as EdgeZero's own pin, so # Cargo unifies both on one `web-time` crate and # `auctioneer_runtime::MonotonicInstant` IS diff --git a/NOTICE b/NOTICE index 164d616..be8af06 100644 --- a/NOTICE +++ b/NOTICE @@ -40,3 +40,12 @@ affiliation or endorsement, and do not grant trademark rights. Other third-party components and data retain their own licenses and notices. This attribution record is not a complete dependency or data-license inventory. + +Unicode Character Database 16.0.0 +https://www.unicode.org/versions/Unicode16.0.0/ +Copyright 2024 Unicode, Inc. + +The case-folding conformance tests retain original Unicode data and notices +under crates/auctioneer-config-data/tests/fixtures/unicode/, including the +Unicode License v3 permission notice. These are test data, not a new runtime +Unicode implementation. diff --git a/crates/auctioneer-adapter-axum/Cargo.toml b/crates/auctioneer-adapter-axum/Cargo.toml index e34179e..5f65c16 100644 --- a/crates/auctioneer-adapter-axum/Cargo.toml +++ b/crates/auctioneer-adapter-axum/Cargo.toml @@ -56,6 +56,7 @@ simple_logger = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } sha2 = { workspace = true } +hex = { workspace = true } # The "time" feature is what provides `tokio::time::sleep`; the base # workspace entry enables only macros + rt-multi-thread. tokio = { workspace = true, features = ["macros", "rt-multi-thread", "time"] } diff --git a/crates/auctioneer-adapter-axum/src/resource_profile.rs b/crates/auctioneer-adapter-axum/src/resource_profile.rs index f995588..9c65bc5 100644 --- a/crates/auctioneer-adapter-axum/src/resource_profile.rs +++ b/crates/auctioneer-adapter-axum/src/resource_profile.rs @@ -277,7 +277,7 @@ struct Profile { } fn digest(value: &T) -> anyhow::Result { - Ok(format!("{:x}", Sha256::digest(serde_json::to_vec(value)?))) + Ok(hex::encode(Sha256::digest(serde_json::to_vec(value)?))) } fn reference_digest() -> anyhow::Result { diff --git a/crates/auctioneer-adapter-axum/tests/resource_profile.rs b/crates/auctioneer-adapter-axum/tests/resource_profile.rs index 3a04311..2e094ac 100644 --- a/crates/auctioneer-adapter-axum/tests/resource_profile.rs +++ b/crates/auctioneer-adapter-axum/tests/resource_profile.rs @@ -482,7 +482,7 @@ mod tests { } fn sha256(bytes: &[u8]) -> String { - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) } #[test] diff --git a/crates/auctioneer-bidder/Cargo.toml b/crates/auctioneer-bidder/Cargo.toml index 30b80b5..37b7cf2 100644 --- a/crates/auctioneer-bidder/Cargo.toml +++ b/crates/auctioneer-bidder/Cargo.toml @@ -49,7 +49,7 @@ test = false # Forwards into auctioneer-config-data so build.rs's syncer-URL template-validation # pass also relaxes its scheme rule under the feature. insecure-bidders = ["auctioneer-config-data/insecure-bidders"] -test-support = ["dep:toml"] +test-support = ["dep:hex", "dep:toml"] # Inspection only; enables the unqualified build, never serving admission. # Guest graphs include the candidate only in this inspection lane. Normal native # serving uses the approved tested-reservation contract, not bound qualification. @@ -78,6 +78,7 @@ validator = { workspace = true } uuid-simd = { workspace = true, optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] +hex = { workspace = true, optional = true } jsonschema = { workspace = true } regex-automata = { workspace = true } uuid-simd = { workspace = true } @@ -92,6 +93,7 @@ quote = { workspace = true } toml = { workspace = true } [build-dependencies] +hex = { workspace = true } # Data-only declarations let discovery compare inactive feature ownership. # Configuration generation must never depend on bidder implementations. auctioneer-config-data = { workspace = true } @@ -106,6 +108,7 @@ url = { workspace = true } [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] aho-corasick = { workspace = true } +hex = { workspace = true } gimli = { workspace = true } jsonschema = { workspace = true } jsonschema-macros-core = { workspace = true } diff --git a/crates/auctioneer-bidder/src/bidders/aps/tests/conformance.rs b/crates/auctioneer-bidder/src/bidders/aps/tests/conformance.rs index 2d8d7fa..b8cf5eb 100644 --- a/crates/auctioneer-bidder/src/bidders/aps/tests/conformance.rs +++ b/crates/auctioneer-bidder/src/bidders/aps/tests/conformance.rs @@ -917,7 +917,7 @@ mod tests { } fn sha256(bytes: &[u8]) -> String { - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) } fn source_pin(pin: SourcePin) -> Source { diff --git a/crates/auctioneer-bidder/src/bidders/criteo/tests/conformance.rs b/crates/auctioneer-bidder/src/bidders/criteo/tests/conformance.rs index d998891..e6cb58c 100644 --- a/crates/auctioneer-bidder/src/bidders/criteo/tests/conformance.rs +++ b/crates/auctioneer-bidder/src/bidders/criteo/tests/conformance.rs @@ -186,7 +186,7 @@ mod tests { #[test] fn capture_membership_and_literal_parameter_cases_have_frozen_witnesses() { - assert_eq!(format!("{:x}", Sha256::digest(MANIFEST)), MANIFEST_SHA256); + assert_eq!(hex::encode(Sha256::digest(MANIFEST)), MANIFEST_SHA256); let manifest: toml::Value = toml::from_str(MANIFEST).unwrap(); assert_eq!(manifest["native_only"].as_bool(), Some(true)); let definitions = manifest["definitions"].as_table().unwrap(); @@ -251,7 +251,7 @@ mod tests { ); assert_eq!( rows[0]["retained"]["source_sha256"].as_str().unwrap(), - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) ); } let cases: Value = @@ -349,7 +349,7 @@ mod tests { row["source_bytes"].as_integer().unwrap() ); assert_eq!( - format!("{:x}", Sha256::digest(&bytes.stdout)), + hex::encode(Sha256::digest(&bytes.stdout)), row["source_sha256"].as_str().unwrap() ); let blob = Command::new("git") diff --git a/crates/auctioneer-bidder/src/bidders/mod.rs b/crates/auctioneer-bidder/src/bidders/mod.rs index f97fe22..f0f78f3 100644 --- a/crates/auctioneer-bidder/src/bidders/mod.rs +++ b/crates/auctioneer-bidder/src/bidders/mod.rs @@ -89,7 +89,7 @@ pub(crate) mod harness { source: &str, ) -> Result<(), &'static str> { use sha2::{Digest as _, Sha256}; - let digest = |bytes: &str| format!("{:x}", Sha256::digest(bytes.as_bytes())); + let digest = |bytes: &str| hex::encode(Sha256::digest(bytes.as_bytes())); if digest(manifest) != manifest_sha256 { return Err("protocol manifest digest mismatch"); } @@ -446,7 +446,7 @@ pub(crate) mod harness { } fn sha256(source: &str) -> String { - format!("{:x}", Sha256::digest(source.as_bytes())) + hex::encode(Sha256::digest(source.as_bytes())) } fn fixture() -> (String, String, String) { diff --git a/crates/auctioneer-bidder/src/bidders/msft/mod.rs b/crates/auctioneer-bidder/src/bidders/msft/mod.rs index 6760221..7982d4b 100644 --- a/crates/auctioneer-bidder/src/bidders/msft/mod.rs +++ b/crates/auctioneer-bidder/src/bidders/msft/mod.rs @@ -161,7 +161,7 @@ mod tests { use sha2::{Digest as _, Sha256}; let manifest_source = include_str!("bidder.toml"); assert_eq!( - format!("{:x}", Sha256::digest(manifest_source.as_bytes())), + hex::encode(Sha256::digest(manifest_source.as_bytes())), CAPTURE_MANIFEST_SHA256 ); let manifest: toml::Value = toml::from_str(manifest_source).unwrap(); @@ -182,7 +182,7 @@ mod tests { assert_eq!(retained.bytes, u64::try_from(source.len()).unwrap()); assert_eq!( retained.sha256, - format!("{:x}", Sha256::digest(source.as_bytes())) + hex::encode(Sha256::digest(source.as_bytes())) ); serde_json::from_str(source).unwrap() } diff --git a/crates/auctioneer-bidder/src/bidders/msft/tests/conformance.rs b/crates/auctioneer-bidder/src/bidders/msft/tests/conformance.rs index 9b3839c..c55a833 100644 --- a/crates/auctioneer-bidder/src/bidders/msft/tests/conformance.rs +++ b/crates/auctioneer-bidder/src/bidders/msft/tests/conformance.rs @@ -257,7 +257,7 @@ mod tests { assert_eq!(row.bytes, literal.len()); assert_eq!( row.sha256, - format!("{:x}", Sha256::digest(literal.as_bytes())) + hex::encode(Sha256::digest(literal.as_bytes())) ); let end = row.source_offset.checked_add(row.bytes).unwrap(); assert_eq!(text.get(row.source_offset..end), Some(row.input.as_str())); diff --git a/crates/auctioneer-bidder/src/bidders/openx/tests/conformance.rs b/crates/auctioneer-bidder/src/bidders/openx/tests/conformance.rs index 0a18479..69b901a 100644 --- a/crates/auctioneer-bidder/src/bidders/openx/tests/conformance.rs +++ b/crates/auctioneer-bidder/src/bidders/openx/tests/conformance.rs @@ -211,7 +211,7 @@ mod tests { #[test] fn exact_capture_membership_and_parameter_literals_have_frozen_witnesses() { - assert_eq!(format!("{:x}", Sha256::digest(MANIFEST)), MANIFEST_SHA256); + assert_eq!(hex::encode(Sha256::digest(MANIFEST)), MANIFEST_SHA256); let manifest: toml::Value = toml::from_str(MANIFEST).unwrap(); assert_eq!(manifest["factory"].as_bool(), Some(true)); assert_eq!(manifest["native_only"].as_bool(), Some(true)); @@ -288,7 +288,7 @@ mod tests { ); assert_eq!( witnesses[0]["retained"]["source_sha256"].as_str().unwrap(), - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) ); } let cases: Value = @@ -364,7 +364,7 @@ mod tests { row["source_bytes"].as_integer().unwrap() ); assert_eq!( - format!("{:x}", Sha256::digest(&bytes)), + hex::encode(Sha256::digest(&bytes)), row["source_sha256"].as_str().unwrap() ); assert_eq!( diff --git a/crates/auctioneer-bidder/src/bidders/pubmatic/tests/conformance.rs b/crates/auctioneer-bidder/src/bidders/pubmatic/tests/conformance.rs index 6dd9cd8..4f3c446 100644 --- a/crates/auctioneer-bidder/src/bidders/pubmatic/tests/conformance.rs +++ b/crates/auctioneer-bidder/src/bidders/pubmatic/tests/conformance.rs @@ -604,7 +604,7 @@ mod tests { #[test] fn exact_capture_membership_and_parameter_literals_have_frozen_witnesses() { - assert_eq!(format!("{:x}", Sha256::digest(MANIFEST)), MANIFEST_SHA256); + assert_eq!(hex::encode(Sha256::digest(MANIFEST)), MANIFEST_SHA256); let manifest: TomlValue = toml::from_str(MANIFEST).unwrap(); assert_eq!(manifest["factory"].as_bool(), Some(true)); let artifacts = manifest["provenance"]["artifacts"].as_array().unwrap(); @@ -671,7 +671,7 @@ mod tests { ); assert_eq!( witnesses[0]["retained"]["source_sha256"].as_str().unwrap(), - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) ); } assert_parameter_literals(); @@ -754,7 +754,7 @@ mod tests { assert!(output.status.success()); output.stdout }; - assert_eq!(format!("{:x}", Sha256::digest(MANIFEST)), MANIFEST_SHA256); + assert_eq!(hex::encode(Sha256::digest(MANIFEST)), MANIFEST_SHA256); let manifest: TomlValue = toml::from_str(MANIFEST).unwrap(); assert_eq!( manifest["provenance"]["sources"]["upstream"]["revision"].as_str(), @@ -797,7 +797,7 @@ mod tests { row["source_bytes"].as_integer().unwrap() ); assert_eq!( - format!("{:x}", Sha256::digest(&bytes)), + hex::encode(Sha256::digest(&bytes)), row["source_sha256"].as_str().unwrap() ); let fields = source_object_info(&checkout, &object); diff --git a/crates/auctioneer-bidder/src/bidders/rubicon/tests/conformance.rs b/crates/auctioneer-bidder/src/bidders/rubicon/tests/conformance.rs index 7ee5d16..f7b0567 100644 --- a/crates/auctioneer-bidder/src/bidders/rubicon/tests/conformance.rs +++ b/crates/auctioneer-bidder/src/bidders/rubicon/tests/conformance.rs @@ -226,7 +226,7 @@ protocol_fixtures!(run_fixture, "../fixtures/protocol/"; #[test] fn exact_capture_membership_and_retained_bytes_are_independently_frozen() { - assert_eq!(format!("{:x}", Sha256::digest(MANIFEST)), MANIFEST_SHA256); + assert_eq!(hex::encode(Sha256::digest(MANIFEST)), MANIFEST_SHA256); let manifest: toml::Value = toml::from_str(MANIFEST).unwrap(); assert_eq!(manifest["native_only"].as_bool(), Some(true)); let definitions = manifest["definitions"].as_table().unwrap(); @@ -288,7 +288,7 @@ fn exact_capture_membership_and_retained_bytes_are_independently_frozen() { ); assert_eq!( schema_row["source_sha256"].as_str().unwrap(), - format!("{:x}", Sha256::digest(schema)) + hex::encode(Sha256::digest(schema)) ); } @@ -351,7 +351,7 @@ fn source_objects_match_pinned_rubicon_tree_and_all_artifacts() { ); assert_eq!( row["source_sha256"].as_str().unwrap(), - format!("{:x}", Sha256::digest(&bytes)) + hex::encode(Sha256::digest(&bytes)) ); assert_eq!( from_utf8(&git("rev-parse", &object)).unwrap().trim(), diff --git a/crates/auctioneer-bidder/src/bidders/sharethrough/tests/conformance.rs b/crates/auctioneer-bidder/src/bidders/sharethrough/tests/conformance.rs index 17ea436..fbeec31 100644 --- a/crates/auctioneer-bidder/src/bidders/sharethrough/tests/conformance.rs +++ b/crates/auctioneer-bidder/src/bidders/sharethrough/tests/conformance.rs @@ -161,7 +161,7 @@ mod tests { #[test] fn exact_capture_membership_retained_bytes_and_parameter_literals_are_frozen() { - assert_eq!(format!("{:x}", Sha256::digest(MANIFEST)), MANIFEST_SHA256); + assert_eq!(hex::encode(Sha256::digest(MANIFEST)), MANIFEST_SHA256); let manifest: toml::Value = toml::from_str(MANIFEST).unwrap(); assert_eq!(manifest["factory"].as_bool(), Some(true)); assert_eq!(manifest["native_only"].as_bool(), Some(true)); @@ -229,7 +229,7 @@ mod tests { ); assert_eq!( retained["source_sha256"].as_str().unwrap(), - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) ); retained_count = retained_count.checked_add(1).unwrap(); } @@ -318,7 +318,7 @@ mod tests { ); assert_eq!( row["source_sha256"].as_str().unwrap(), - format!("{:x}", Sha256::digest(&bytes)) + hex::encode(Sha256::digest(&bytes)) ); assert_eq!( from_utf8(&git("rev-parse", &object)).unwrap().trim(), diff --git a/crates/auctioneer-bidder/src/bidders/thetradedesk/tests/conformance.rs b/crates/auctioneer-bidder/src/bidders/thetradedesk/tests/conformance.rs index 3c1f974..88ba570 100644 --- a/crates/auctioneer-bidder/src/bidders/thetradedesk/tests/conformance.rs +++ b/crates/auctioneer-bidder/src/bidders/thetradedesk/tests/conformance.rs @@ -441,7 +441,7 @@ mod tests { fn retained_witness(category: &str, source: &str, bytes: &[u8]) { assert_eq!( - format!("{:x}", Sha256::digest(MANIFEST.as_bytes())), + hex::encode(Sha256::digest(MANIFEST.as_bytes())), MANIFEST_SHA256 ); let manifest: toml::Value = toml::from_str(MANIFEST).unwrap(); @@ -457,7 +457,7 @@ mod tests { assert_eq!(matches.len(), 1); let retained: Retained = matches[0]["retained"].clone().try_into().unwrap(); assert_eq!(retained.bytes, bytes.len()); - assert_eq!(retained.sha256, format!("{:x}", Sha256::digest(bytes))); + assert_eq!(retained.sha256, hex::encode(Sha256::digest(bytes))); assert_eq!( retained.path, if category == "schema" { @@ -502,7 +502,7 @@ mod tests { #[test] fn source_capture_membership_and_counts_cannot_silently_shrink() { assert_eq!( - format!("{:x}", Sha256::digest(MANIFEST.as_bytes())), + hex::encode(Sha256::digest(MANIFEST.as_bytes())), MANIFEST_SHA256 ); let manifest: toml::Value = toml::from_str(MANIFEST).unwrap(); @@ -585,7 +585,7 @@ mod tests { u64::try_from(row["source_bytes"].as_integer().unwrap()).unwrap() ); assert_eq!( - format!("{:x}", Sha256::digest(&bytes.stdout)), + hex::encode(Sha256::digest(&bytes.stdout)), row["source_sha256"].as_str().unwrap() ); let blob = Command::new("git") diff --git a/crates/auctioneer-bidder/src/bidders/yahoo_ads/tests/conformance.rs b/crates/auctioneer-bidder/src/bidders/yahoo_ads/tests/conformance.rs index c45f2b3..48f13a2 100644 --- a/crates/auctioneer-bidder/src/bidders/yahoo_ads/tests/conformance.rs +++ b/crates/auctioneer-bidder/src/bidders/yahoo_ads/tests/conformance.rs @@ -382,7 +382,7 @@ mod tests { ); assert_eq!( row["source_sha256"].as_str(), - Some(format!("{:x}", Sha256::digest(source.as_bytes())).as_str()) + Some(hex::encode(Sha256::digest(source.as_bytes())).as_str()) ); } diff --git a/crates/auctioneer-bidder/src/test_support/factory_contract.rs b/crates/auctioneer-bidder/src/test_support/factory_contract.rs index ea517cc..39df78c 100644 --- a/crates/auctioneer-bidder/src/test_support/factory_contract.rs +++ b/crates/auctioneer-bidder/src/test_support/factory_contract.rs @@ -145,7 +145,7 @@ pub(crate) fn assert_factory_contract(key: &str, source: &str) { .join(key) .join("bidder.toml"); assert_eq!( - format!("{:x}", Sha256::digest(fs::read(manifest).unwrap())), + hex::encode(Sha256::digest(fs::read(manifest).unwrap())), fixture.manifest_sha256, "factory manifest digest" ); diff --git a/crates/auctioneer-bidder/tests/native_schema_resources.rs b/crates/auctioneer-bidder/tests/native_schema_resources.rs index 475aa4c..e79909e 100644 --- a/crates/auctioneer-bidder/tests/native_schema_resources.rs +++ b/crates/auctioneer-bidder/tests/native_schema_resources.rs @@ -196,7 +196,7 @@ mod tests { u64::try_from(retained["source_bytes"].as_integer().unwrap()).unwrap() ); assert_eq!( - format!("{:x}", Sha256::digest(&bytes)), + hex::encode(Sha256::digest(&bytes)), retained["source_sha256"].as_str().unwrap(), "{relative}: captured source digest" ); @@ -250,7 +250,7 @@ mod tests { let document: toml::Value = toml::from_str(&fs::read_to_string(path).unwrap()).unwrap(); assert_eq!( document["schema_sha256"].as_str().unwrap(), - format!("{:x}", Sha256::digest(schema_bytes)), + hex::encode(Sha256::digest(schema_bytes)), "{}: authored expectation schema pin", path.display() ); @@ -661,7 +661,7 @@ mod tests { .unwrap(); assert_eq!( factory["manifest_sha256"].as_str().unwrap(), - format!("{:x}", Sha256::digest(manifest_bytes)), + hex::encode(Sha256::digest(manifest_bytes)), "{}: first factory case manifest pin", row.name() ); diff --git a/crates/auctioneer-bidder/tests/registry_inventory/mod.rs b/crates/auctioneer-bidder/tests/registry_inventory/mod.rs index 5510801..dc8f7cf 100644 --- a/crates/auctioneer-bidder/tests/registry_inventory/mod.rs +++ b/crates/auctioneer-bidder/tests/registry_inventory/mod.rs @@ -257,7 +257,7 @@ pub(crate) fn check_canonical_schema( return Err(SchemaError::Source); } let actual_length = u64::try_from(bytes.len()).map_err(|_error| SchemaError::Witness)?; - let digest = format!("{:x}", Sha256::digest(bytes)); + let digest = hex::encode(Sha256::digest(bytes)); let source_length = schema .get("source_bytes") .and_then(toml::Value::as_integer) diff --git a/crates/auctioneer-bidder/tests/registry_join.rs b/crates/auctioneer-bidder/tests/registry_join.rs index 69d7034..d5aa5e4 100644 --- a/crates/auctioneer-bidder/tests/registry_join.rs +++ b/crates/auctioneer-bidder/tests/registry_join.rs @@ -126,7 +126,7 @@ mod tests { let (mut manifest, mut bytes, inventory) = schema_fixture(); bytes.push(b'\n'); let length = i64::try_from(bytes.len()).unwrap(); - let digest = format!("{:x}", Sha256::digest(&bytes)); + let digest = hex::encode(Sha256::digest(&bytes)); let schema = manifest.provenance["artifacts"] .as_array_mut() .unwrap() diff --git a/crates/auctioneer-bidder/tests/registry_source_conformance.rs b/crates/auctioneer-bidder/tests/registry_source_conformance.rs index 193398b..10bbf34 100644 --- a/crates/auctioneer-bidder/tests/registry_source_conformance.rs +++ b/crates/auctioneer-bidder/tests/registry_source_conformance.rs @@ -241,10 +241,9 @@ mod tests { assert!(!fixture["cases"].as_array().unwrap().is_empty()); // Frozen bidder-owned expectations pin all effective metadata and provenance, // including supplemental sources, inactive factories and schema-less owners. - let digest = format!( - "{:x}", - Sha256::digest(fs::read(directory.join("bidder.toml")).unwrap()) - ); + let digest = hex::encode(Sha256::digest( + fs::read(directory.join("bidder.toml")).unwrap(), + )); assert_eq!( fixture["manifest_sha256"].as_str(), Some(digest.as_str()), diff --git a/crates/auctioneer-bidder/tests/schema_build/application.rs b/crates/auctioneer-bidder/tests/schema_build/application.rs index de2d6a7..cd54e75 100644 --- a/crates/auctioneer-bidder/tests/schema_build/application.rs +++ b/crates/auctioneer-bidder/tests/schema_build/application.rs @@ -83,7 +83,7 @@ struct ExpectedBuild<'a> { } fn digest(bytes: &[u8]) -> String { - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) } fn enabled_features(development: bool) -> Vec<&'static str> { @@ -733,13 +733,17 @@ fn imports(bytes: &[u8], guest: bool) -> Result, String> { use object::Object as _; let file = object::File::parse(bytes).map_err(|_error| "invalid native application imports")?; - for import in file + for import_result in file .imports() .map_err(|_error| "invalid native application imports")? { + let import = import_result.map_err(|_error| "invalid native application imports")?; + let object::NameOrOrdinal::Name(name) = import.name() else { + return Err("unsupported native application import ordinal".into()); + }; imports.push(json!({"encoding":"native", "library":from_utf8(import.library()).map_err(|_error| "invalid native import library")?, - "name":from_utf8(import.name()).map_err(|_error| "invalid native import name")?})); + "name":from_utf8(name).map_err(|_error| "invalid native import name")?})); if imports.len() > 0x4000 { return Err("application imports exceed count cap".into()); } diff --git a/crates/auctioneer-bidder/tests/schema_build/compiler_layout.rs b/crates/auctioneer-bidder/tests/schema_build/compiler_layout.rs index 171c5b8..9447552 100644 --- a/crates/auctioneer-bidder/tests/schema_build/compiler_layout.rs +++ b/crates/auctioneer-bidder/tests/schema_build/compiler_layout.rs @@ -750,7 +750,7 @@ fn profile(target: &str) -> &'static str { } fn digest(bytes: &[u8]) -> String { - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) } fn verify_compiler_pin(tool_versions: &str, compiler: &str) -> Result { @@ -1374,13 +1374,12 @@ fn debug_producers( } let unit = dwarf.unit(header).map_err(|error| error.to_string())?; let mut entries = unit.entries(); - let (_, root) = entries + let root = entries .next_dfs() .map_err(|error| error.to_string())? .ok_or("compiler layout compile unit missing")?; let producer_attribute = root .attr_value(gimli::DW_AT_producer) - .map_err(|error| error.to_string())? .ok_or("compiler layout DWARF producer missing")?; let producer_reader = dwarf .attr_string(&unit, producer_attribute) diff --git a/crates/auctioneer-bidder/tests/schema_build/guest.rs b/crates/auctioneer-bidder/tests/schema_build/guest.rs index 8f8fe3b..a03facb 100644 --- a/crates/auctioneer-bidder/tests/schema_build/guest.rs +++ b/crates/auctioneer-bidder/tests/schema_build/guest.rs @@ -107,7 +107,7 @@ impl Runtime { "expected_version": pinned_version(TOOL_VERSIONS).unwrap(), "invoked_program": self.path, "invoked_program_bytes": self.identity.0, "invoked_program_sha256": self.identity.1, - "tool_versions_sha256": format!("{:x}", Sha256::digest(TOOL_VERSIONS.as_bytes())), + "tool_versions_sha256": hex::encode(Sha256::digest(TOOL_VERSIONS.as_bytes())), "host_arch": env::consts::ARCH, "host_os": env::consts::OS, "code_cache": false, "filesystem_preopens": [], "inherited_guest_environment": false, "network": false, "debugger": false, @@ -345,7 +345,7 @@ fn file_identity(path: &Path, limit: u64) -> Result<(u64, String), String> { if metadata.len() != bytes { return Err("guest identity changed while reading".to_owned()); } - Ok((bytes, format!("{:x}", hash.finalize()))) + Ok((bytes, hex::encode(hash.finalize()))) } fn empty_config(root: &Path) -> Result { @@ -705,7 +705,7 @@ mod tests { target: "wasm32-wasip1".to_owned(), validators: 1, artifact_bytes: u64::try_from(bytes.len()).unwrap(), - sha256: format!("{:x}", Sha256::digest(bytes)), + sha256: hex::encode(Sha256::digest(bytes)), names: vec!["fake_bidder".to_owned()], results: vec![false], wasm: None, diff --git a/crates/auctioneer-bidder/tests/schema_build/inspection.rs b/crates/auctioneer-bidder/tests/schema_build/inspection.rs index b20a985..70ffa09 100644 --- a/crates/auctioneer-bidder/tests/schema_build/inspection.rs +++ b/crates/auctioneer-bidder/tests/schema_build/inspection.rs @@ -141,15 +141,15 @@ impl NativeRelocations { fn check_native_relocation_encodings(file: &ObjectFile<'_>) -> Result<(), &'static str> { use object::read::elf::SectionHeader as _; - let unsupported = |kind: u32, flags: u64| { - flags & u64::from(elf::SHF_ALLOC) != 0 + let unsupported = |kind: elf::SectionType, flags: elf::SectionFlags| { + flags.contains(elf::SHF_ALLOC) && matches!(kind, elf::SHT_REL | elf::SHT_RELR | elf::SHT_CREL) }; let unaccounted = if let ObjectFile::Elf32(elf_file) = file { elf_file.elf_section_table().iter().any(|header| { unsupported( header.sh_type(elf_file.endian()), - u64::from(header.sh_flags(elf_file.endian())), + header.sh_flags(elf_file.endian()), ) }) } else if let ObjectFile::Elf64(elf_file) = file { @@ -1039,7 +1039,7 @@ mod tests { fake_linked_elf_for_machine(relocations, elf::EM_X86_64) } - fn fake_linked_elf_for_machine(relocations: Option<&[Rel]>, machine: u16) -> Vec { + fn fake_linked_elf_for_machine(relocations: Option<&[Rel]>, machine: elf::Machine) -> Vec { fake_linked_elf_with_extra_encoding(relocations, machine, None) } @@ -1049,8 +1049,8 @@ mod tests { )] fn fake_linked_elf_with_extra_encoding( relocations: Option<&[Rel]>, - machine: u16, - extra_encoding: Option, + machine: elf::Machine, + extra_encoding: Option, ) -> Vec { use object::write::elf::{FileHeader, ProgramHeader, SectionHeader, Sym, Writer}; use object::{Endianness, elf}; @@ -1092,24 +1092,24 @@ mod tests { } writer.reserve_null_dynamic_symbol_index(); - let text_offset = writer.reserve(text.len(), 16); - let data_offset = writer.reserve(data.len(), 8); - let dynstr_offset = writer.reserve_dynstr(); + let text_offset = writer.reserve(u64::try_from(text.len()).unwrap(), 16); + let data_offset = writer.reserve(u64::try_from(data.len()).unwrap(), 8); + let dynstr_offset = writer.reserve_dynstr().unwrap(); let dynsym_offset = writer.reserve_dynsym(); let rela_offset = relocations.map(|rows| writer.reserve_relocations(rows.len(), true)); let extra_offset = extra_encoding.map(|_| writer.reserve(0, 8)); let allocated_end = writer.reserved_len(); writer.reserve_symtab(); - writer.reserve_strtab(); - writer.reserve_shstrtab(); + writer.reserve_strtab().unwrap(); + writer.reserve_shstrtab().unwrap(); writer.reserve_section_headers(); let reserved_end = writer.reserved_len(); - let data_address = |offset: usize| { + let data_address = |offset: u64| { 0x2000_u64 - .checked_add(u64::try_from(offset.checked_sub(data_offset).unwrap()).unwrap()) + .checked_add(offset.checked_sub(data_offset).unwrap()) .unwrap() }; - let data_size = u64::try_from(allocated_end.checked_sub(data_offset).unwrap()).unwrap(); + let data_size = allocated_end.checked_sub(data_offset).unwrap(); writer .write_file_header(&FileHeader { @@ -1118,14 +1118,14 @@ mod tests { e_type: elf::ET_DYN, e_machine: machine, e_entry: 0x1010, - e_flags: 0, + e_flags: elf::FileFlags::default(), }) .unwrap(); writer.write_align_program_headers(); writer.write_program_header(&ProgramHeader { p_type: elf::PT_LOAD, p_flags: elf::PF_R | elf::PF_X, - p_offset: u64::try_from(text_offset).unwrap(), + p_offset: text_offset, p_vaddr: 0x1000, p_paddr: 0x1000, p_filesz: u64::try_from(text.len()).unwrap(), @@ -1135,7 +1135,7 @@ mod tests { writer.write_program_header(&ProgramHeader { p_type: elf::PT_LOAD, p_flags: elf::PF_R | elf::PF_W, - p_offset: u64::try_from(data_offset).unwrap(), + p_offset: data_offset, p_vaddr: 0x2000, p_paddr: 0x2000, p_filesz: data_size, @@ -1158,11 +1158,11 @@ mod tests { writer.write_null_symbol(); for (name, address) in function_symbols.into_iter().zip([0x1010, 0x1020, 0x1030]) { writer.write_symbol(&Sym { - name: Some(name), - section: Some(text_section), - st_info: (elf::STB_GLOBAL << 4) | elf::STT_FUNC, - st_other: elf::STV_DEFAULT, - st_shndx: 0, + st_name: writer.string_offset(Some(name)), + section: Some(text_section.0), + st_info: elf::SymbolInfo::new(elf::STB_GLOBAL, elf::STT_FUNC), + st_other: elf::STV_DEFAULT.into(), + st_shndx: elf::SHN_UNDEF, st_value: address, st_size: 1, }); @@ -1172,11 +1172,11 @@ mod tests { writer.write_null_section_header(); writer.write_section_header(&SectionHeader { - name: Some(text_name), + sh_name: writer.section_name_offset(Some(text_name)), sh_type: elf::SHT_PROGBITS, - sh_flags: u64::from(elf::SHF_ALLOC | elf::SHF_EXECINSTR), + sh_flags: elf::SHF_ALLOC | elf::SHF_EXECINSTR, sh_addr: 0x1000, - sh_offset: u64::try_from(text_offset).unwrap(), + sh_offset: text_offset, sh_size: u64::try_from(text.len()).unwrap(), sh_link: 0, sh_info: 0, @@ -1184,11 +1184,11 @@ mod tests { sh_entsize: 0, }); writer.write_section_header(&SectionHeader { - name: Some(data_name), + sh_name: writer.section_name_offset(Some(data_name)), sh_type: elf::SHT_PROGBITS, - sh_flags: u64::from(elf::SHF_ALLOC | elf::SHF_WRITE), + sh_flags: elf::SHF_ALLOC | elf::SHF_WRITE, sh_addr: 0x2000, - sh_offset: u64::try_from(data_offset).unwrap(), + sh_offset: data_offset, sh_size: u64::try_from(data.len()).unwrap(), sh_link: 0, sh_info: 0, @@ -1200,11 +1200,11 @@ mod tests { if let (Some(name), Some(offset), Some(rows)) = (rela_name, rela_offset, relocations) { let entry_size = size_of::>(); writer.write_section_header(&SectionHeader { - name: Some(name), + sh_name: writer.section_name_offset(Some(name)), sh_type: elf::SHT_RELA, - sh_flags: u64::from(elf::SHF_ALLOC), + sh_flags: elf::SHF_ALLOC, sh_addr: data_address(offset), - sh_offset: u64::try_from(offset).unwrap(), + sh_offset: offset, sh_size: u64::try_from(rows.len().checked_mul(entry_size).unwrap()).unwrap(), // object discovers dynamic relocations through this .dynsym link. sh_link: dynsym_section.0, @@ -1215,11 +1215,11 @@ mod tests { } if let (Some(kind), Some(name), Some(offset)) = (extra_encoding, extra_name, extra_offset) { writer.write_section_header(&SectionHeader { - name: Some(name), + sh_name: writer.section_name_offset(Some(name)), sh_type: kind, - sh_flags: u64::from(elf::SHF_ALLOC), + sh_flags: elf::SHF_ALLOC, sh_addr: data_address(offset), - sh_offset: u64::try_from(offset).unwrap(), + sh_offset: offset, sh_size: 0, sh_link: dynsym_section.0, sh_info: 0, @@ -1530,7 +1530,7 @@ mod tests { unbounded.push(Rel { r_offset: offset, r_sym: 0, - r_type: u32::MAX, + r_type: elf::RelocationType(u32::MAX), r_addend: 0, }); let bytes = fake_linked_elf_for_machine(Some(&unbounded), machine); diff --git a/crates/auctioneer-bidder/tests/schema_build/mod.rs b/crates/auctioneer-bidder/tests/schema_build/mod.rs index bc3c870..7ada175 100644 --- a/crates/auctioneer-bidder/tests/schema_build/mod.rs +++ b/crates/auctioneer-bidder/tests/schema_build/mod.rs @@ -459,7 +459,7 @@ pub fn verify_lock(child: &str, workspace: &str) -> Result<(), String> { own = own.checked_add(1).ok_or("package overflow")?; continue; } - if identity == ("jsonschema-macros-core".into(), "0.58.6".into(), None, None) + if identity == ("jsonschema-macros-core".into(), "0.61.2".into(), None, None) && reviewed.contains(&identity) { compiler = true; @@ -513,7 +513,7 @@ pub fn verify_compiler_metadata(bytes: &[u8], vendor: &Path) -> Result<(), Strin }); let package = matching.next().ok_or("missing patched compiler")?; if matching.next().is_some() - || package.get("version").and_then(Json::as_str) != Some("0.58.6") + || package.get("version").and_then(Json::as_str) != Some("0.61.2") || !package.get("source").is_some_and(Json::is_null) || package.get("manifest_path").and_then(Json::as_str) != vendor.join("Cargo.toml").to_str() { @@ -1048,7 +1048,7 @@ fn artifact_with_count( { return Err("linked artifact lost schema membership".into()); } - let sha256 = format!("{:x}", Sha256::digest(&bytes)); + let sha256 = hex::encode(Sha256::digest(&bytes)); Ok(LinkReport { target: target.into(), validators, @@ -1891,7 +1891,7 @@ mod tests { item.attrs.is_empty(), "both guest and native must typecheck the queries" ); - let syn::Type::BareFn(signature) = item.ty.as_ref() else { + let syn::Type::FnPtr(signature) = item.ty.as_ref() else { panic!("query witness must be a function pointer"); }; assert_eq!(signature.inputs.len(), 2); @@ -2580,15 +2580,18 @@ mod tests { }) .unwrap(); dispatch.arms.iter().find(|arm| { - let Some((_, guard)) = &arm.guard else { return false; }; - let syn::Expr::Binary(and) = guard.as_ref() else { return false; }; + let syn::Pat::Guard(guard) = &arm.pat else { return false; }; + let syn::Expr::Binary(and) = guard.guard.as_ref() else { return false; }; let syn::Expr::Binary(equal) = and.left.as_ref() else { return false; }; matches!(equal.right.as_ref(), syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Str(operation), .. }) if operation.value() == "sequence") }).unwrap() } fn assert_sequence_byte_limit(sequence: &syn::Arm) { - let syn::Expr::Binary(guard) = sequence.guard.as_ref().unwrap().1.as_ref() else { + let syn::Pat::Guard(pattern) = &sequence.pat else { + panic!("sequence must bound its input"); + }; + let syn::Expr::Binary(guard) = pattern.guard.as_ref() else { panic!("sequence must bound its input"); }; assert!(matches!(guard.op, syn::BinOp::And(_))); diff --git a/crates/auctioneer-bidder/tests/schema_build/native_dwarf.rs b/crates/auctioneer-bidder/tests/schema_build/native_dwarf.rs index dc6d8db..9924f1e 100644 --- a/crates/auctioneer-bidder/tests/schema_build/native_dwarf.rs +++ b/crates/auctioneer-bidder/tests/schema_build/native_dwarf.rs @@ -562,7 +562,8 @@ pub(crate) mod tests { }; assert_eq!(object.section(target).flags, SectionFlags::None); object.section_mut(target).flags = SectionFlags::Elf { - sh_flags: u64::from(elf::SHF_ALLOC | elf::SHF_WRITE), + sh_type: elf::SHT_PROGBITS, + sh_flags: elf::SHF_ALLOC | elf::SHF_WRITE, }; }); let file = object::File::parse(bytes.as_slice()).unwrap(); diff --git a/crates/auctioneer-bidder/tests/schema_build/schema_artifact.rs b/crates/auctioneer-bidder/tests/schema_build/schema_artifact.rs index 2fd30d7..830d608 100644 --- a/crates/auctioneer-bidder/tests/schema_build/schema_artifact.rs +++ b/crates/auctioneer-bidder/tests/schema_build/schema_artifact.rs @@ -132,9 +132,10 @@ fn record_payload(artifact: &mut WasmArtifact, payload: Payload<'_>) -> Result<( } Payload::CodeSectionEntry(body) => { add(&mut artifact.code_bodies, 1)?; + let range = body.range(); add( &mut artifact.code_body_bytes, - u64::try_from(body.range().len()).map_err(|_error| OVERFLOW)?, + range.end.checked_sub(range.start).ok_or(OVERFLOW)?, )?; } Payload::DataSection(section) => { @@ -265,41 +266,35 @@ pub(super) fn native_program_data<'data>( { return Ok(false); } - match section.flags() { - SectionFlags::Elf { sh_flags } => Ok(sh_flags & u64::from(elf::SHF_ALLOC) != 0 - && sh_flags & u64::from(elf::SHF_EXECINSTR) == 0), - SectionFlags::MachO { flags } => { - if flags - & (macho::S_ATTR_DEBUG - | macho::S_ATTR_PURE_INSTRUCTIONS - | macho::S_ATTR_SOME_INSTRUCTIONS) - != 0 - { - return Ok(false); - } - let start = section.address(); - let end = start - .checked_add(section.size()) + let section_flags = section.flags(); + if let SectionFlags::Elf { sh_flags, .. } = section_flags { + return Ok(sh_flags.contains(elf::SHF_ALLOC) && !sh_flags.intersects(elf::SHF_EXECINSTR)); + } + let SectionFlags::MachO { flags, .. } = section_flags else { + return Err("unsupported native inspection section"); + }; + if flags.intersects( + macho::S_ATTR_DEBUG | macho::S_ATTR_PURE_INSTRUCTIONS | macho::S_ATTR_SOME_INSTRUCTIONS, + ) { + return Ok(false); + } + let start = section.address(); + let end = start + .checked_add(section.size()) + .ok_or("native inspection address overflow")?; + for segment in file.segments() { + if matches!(segment.flags(), SegmentFlags::MachO {initprot, ..} if initprot.contains(macho::VM_PROT_READ)) + { + let segment_end = segment + .address() + .checked_add(segment.size()) .ok_or("native inspection address overflow")?; - for segment in file.segments() { - if matches!(segment.flags(), SegmentFlags::MachO {initprot, ..} if initprot & macho::VM_PROT_READ != 0) - { - let segment_end = segment - .address() - .checked_add(segment.size()) - .ok_or("native inspection address overflow")?; - if segment.address() <= start && end <= segment_end { - return Ok(true); - } - } + if segment.address() <= start && end <= segment_end { + return Ok(true); } - Ok(false) - } - SectionFlags::None | SectionFlags::Coff { .. } | SectionFlags::Xcoff { .. } => { - Err("unsupported native inspection section") } - _ => Err("unsupported native inspection section"), } + Ok(false) } #[cfg(test)] @@ -320,7 +315,20 @@ mod tests { let bytes = fake_stream_component(wasm_encoder::ComponentValType::Primitive( wasm_encoder::PrimitiveValType::U8, )); - assert!(wasmparser::Validator::new().validate_all(&bytes).is_err()); + // New parser releases enable async components by default. The negative + // control must actually disable the proposal instead of relying on that default. + let mut features = wasmparser::WasmFeatures::default(); + features.remove(wasmparser::WasmFeatures::CM_ASYNC); + assert!( + wasmparser::Validator::new_with_features(features) + .validate_all(&bytes) + .is_err() + ); + assert!( + super::validator() + .features() + .contains(wasmparser::WasmFeatures::CM_ASYNC) + ); let measured = measure(&bytes).expect("valid stream type used by the Spin component"); assert_eq!(measured.format, ArtifactFormat::Component); assert_eq!(measured.components, 1); diff --git a/crates/auctioneer-bidder/tests/schema_build/schema_regex_vendor/mod.rs b/crates/auctioneer-bidder/tests/schema_build/schema_regex_vendor/mod.rs index c83beb6..e47636b 100644 --- a/crates/auctioneer-bidder/tests/schema_build/schema_regex_vendor/mod.rs +++ b/crates/auctioneer-bidder/tests/schema_build/schema_regex_vendor/mod.rs @@ -84,7 +84,7 @@ impl fmt::Display for VerifyError { type SourceFiles = BTreeMap>; fn digest(bytes: &[u8]) -> String { - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) } fn directory(path: &Path) -> Result<(), ()> { @@ -274,7 +274,7 @@ fn tree_digest(files: &SourceFiles) -> Result { ); checksum.update(bytes); } - Ok(format!("{:x}", checksum.finalize())) + Ok(hex::encode(checksum.finalize())) } pub fn verify(root: &Path) -> Result { @@ -552,7 +552,7 @@ mod tests { fn metadata() -> serde_json::Value { json!({"packages": [ - {"name": "jsonschema-macros-core", "version": "0.58.6", "source": null, "manifest_path": "/reviewed/compiler/Cargo.toml"}, + {"name": "jsonschema-macros-core", "version": "0.61.2", "source": null, "manifest_path": "/reviewed/compiler/Cargo.toml"}, {"name": "regex-automata", "version": "0.4.18", "source": null, "manifest_path": "/reviewed/engine/Cargo.toml", "id": "path+file:///reviewed/engine#regex-automata@0.4.18"} ], "resolve": {"nodes": [{"id": "path+file:///reviewed/engine#regex-automata@0.4.18", "features": FEATURES}]}}) } diff --git a/crates/auctioneer-bidder/tests/schema_build/selected.rs b/crates/auctioneer-bidder/tests/schema_build/selected.rs index bec4fa3..b989573 100644 --- a/crates/auctioneer-bidder/tests/schema_build/selected.rs +++ b/crates/auctioneer-bidder/tests/schema_build/selected.rs @@ -15,7 +15,7 @@ use std::time::Duration; use std::{fs, path::Path}; fn digest(bytes: &[u8]) -> String { - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) } fn membership(schemas: &[SchemaInventory], binding: &Value) -> Result { diff --git a/crates/auctioneer-bidder/tests/schema_build_cases/mod.rs b/crates/auctioneer-bidder/tests/schema_build_cases/mod.rs index a0c593a..ceacb9b 100644 --- a/crates/auctioneer-bidder/tests/schema_build_cases/mod.rs +++ b/crates/auctioneer-bidder/tests/schema_build_cases/mod.rs @@ -20,14 +20,15 @@ mod tests { const ROOT: &str = include_str!("../../../../Cargo.toml"); const LOCK: &str = include_str!("../../../../Cargo.lock"); - const ARCHIVE_SHA256: &str = "bf3ebe067f2c25a981a7d1b2f696fc213e10dbf80ba5fe997f7dc2e4fe261f26"; + const ARCHIVE_SHA256: &str = "75afa4b5e6986cc221f5339d7d6149360f0bf8e65bcb23617dc0f92900b576d2"; const TYPE_CHECK_SHA256: &str = "c5fe64170d5154c5967280d28c2fcb269c24d49ef756322d269ac8eb8998d912"; const INITIALIZATION_SHA256: &str = - "0fe3dfb41dd37dab3fa8fe7613fb20084b91550b100798da2c21adbcd21a6730"; - const EXPLICIT_CACHE_PATCH: &str = "jsonschema-macros-core-explicit-cache.patch"; + "5a757b0f4d360fcc9fb8dce7af0031b107067be9f5c451321ec94d49ff3fb2f8"; + const EXPLICIT_CACHE_PATCH: &str = + "jsonschema-macros-core-0.61.2-explicit-cache-all-modes.patch"; const EXPLICIT_CACHE_PATCH_SHA256: &str = - "32d16bb697447d2158b0b40da829fc1e93d16527b2b7c1b42345ae5689a18993"; + "846658280e27162d5ea8334ba347eb86e0cf9ff05d22f701e632ce648868befe"; // Source tables fix accepts/refusals; lexical inputs distinguish JSON // refusals from schema refusals independently of the generated validator. @@ -246,7 +247,7 @@ mod tests { fn compiler_metadata_requires_the_exact_local_package_and_manifest() { let vendor = Path::new("/reviewed/compiler"); let original = json!({"packages": [{ - "name": "jsonschema-macros-core", "version": "0.58.6", + "name": "jsonschema-macros-core", "version": "0.61.2", "source": null, "manifest_path": "/reviewed/compiler/Cargo.toml" }, {"name": "unrelated"}]}); assert_eq!( @@ -308,8 +309,8 @@ mod tests { .join("../..") .canonicalize() .unwrap(); - let raw = fs::read(workspace.join("vendor/jsonschema-macros-core-0.58.6.crate")).unwrap(); - assert_eq!(format!("{:x}", Sha256::digest(&raw)), ARCHIVE_SHA256); + let raw = fs::read(workspace.join("vendor/jsonschema-macros-core-0.61.2.crate")).unwrap(); + assert_eq!(hex::encode(Sha256::digest(&raw)), ARCHIVE_SHA256); let mut archive = tar::Archive::new(GzDecoder::new(raw.as_slice())); let mut files = BTreeMap::new(); for entry_result in archive.entries().unwrap() { @@ -318,7 +319,7 @@ mod tests { let relative = entry .path() .unwrap() - .strip_prefix("jsonschema-macros-core-0.58.6") + .strip_prefix("jsonschema-macros-core-0.61.2") .unwrap() .to_owned(); assert!(!relative.as_os_str().is_empty()); @@ -362,17 +363,17 @@ mod tests { let workspace = Path::new(env!("CARGO_MANIFEST_DIR")).join("../.."); let patch = workspace.join("vendor/patches").join(patch_name); let checksum = match patch_name { - "jsonschema-macros-core-type-check.patch" => { + "jsonschema-macros-core-0.61.2-type-check.patch" => { "1d1ed4cdfdd21abbd2c469bbee6f7aa3ea8079c736dd22b9abe5d08e76265358" } - "jsonschema-macros-core-regex-initialization.patch" => { - "a3a0e791aeedd859835cb97e8a36d9c5c6cdb1db523c6348a21f41d1876a65f2" + "jsonschema-macros-core-0.61.2-regex-initialization.patch" => { + "b21e13915ba100b27a8db5c1b765b5f81c302be806d763359f73e0ca5a5be798" } EXPLICIT_CACHE_PATCH => EXPLICIT_CACHE_PATCH_SHA256, _ => panic!("unreviewed portable patch: {patch_name}"), }; assert_eq!( - format!("{:x}", Sha256::digest(fs::read(&patch).unwrap())), + hex::encode(Sha256::digest(fs::read(&patch).unwrap())), checksum ); let original = compiler_tree(directory); @@ -415,7 +416,7 @@ mod tests { fs::write(&file, original).unwrap(); apply_portable_compiler_patch(temporary.path(), patch_name); assert_eq!( - format!("{:x}", Sha256::digest(fs::read(file).unwrap())), + hex::encode(Sha256::digest(fs::read(file).unwrap())), expected_sha256 ); } @@ -424,7 +425,7 @@ mod tests { fn portable_type_check_patch_recreates_the_reviewed_object_schema_file() { assert_portable_patch_recreates_historical_file( "src/codegen/object_schema.rs", - "jsonschema-macros-core-type-check.patch", + "jsonschema-macros-core-0.61.2-type-check.patch", TYPE_CHECK_SHA256, ); } @@ -433,7 +434,7 @@ mod tests { fn portable_regex_initialization_patch_recreates_the_reviewed_emit_root_file() { assert_portable_patch_recreates_historical_file( "src/codegen/emit_root.rs", - "jsonschema-macros-core-regex-initialization.patch", + "jsonschema-macros-core-0.61.2-regex-initialization.patch", INITIALIZATION_SHA256, ); } @@ -452,23 +453,20 @@ mod tests { // The separately pinned license is not part of any compiler patch. let license = fs::read(workspace.join("vendor/jsonschema-macros-core/LICENSE")).unwrap(); assert_eq!( - format!("{:x}", Sha256::digest(&license)), + hex::encode(Sha256::digest(&license)), "117829c3ca21efb132d81a44b55363d395ab8eea18526873bc828da4c0e5f038" ); fs::write(temporary.path().join("LICENSE"), license).unwrap(); for patch in [ - "jsonschema-macros-core-type-check.patch", - "jsonschema-macros-core-regex-initialization.patch", + "jsonschema-macros-core-0.61.2-type-check.patch", + "jsonschema-macros-core-0.61.2-regex-initialization.patch", ] { apply_portable_compiler_patch(temporary.path(), patch); } assert_eq!( - format!( - "{:x}", - Sha256::digest( - fs::read(temporary.path().join("src/codegen/emit_root.rs")).unwrap() - ) - ), + hex::encode(Sha256::digest( + fs::read(temporary.path().join("src/codegen/emit_root.rs")).unwrap() + )), INITIALIZATION_SHA256 ); let two_patch_base = compiler_tree(temporary.path()); diff --git a/crates/auctioneer-bidder/tests/schema_cache_controls.rs b/crates/auctioneer-bidder/tests/schema_cache_controls.rs index 70f6037..99ea703 100644 --- a/crates/auctioneer-bidder/tests/schema_cache_controls.rs +++ b/crates/auctioneer-bidder/tests/schema_cache_controls.rs @@ -57,6 +57,59 @@ mod tests { errors.into_iter().next().unwrap() } + #[test] + fn repeated_and_collapsed_patterns_cannot_bypass_engine_construction_limits() { + use quote::quote; + + struct Refusals(Vec); + impl VisitMut for Refusals { + fn visit_macro_mut(&mut self, i: &mut syn::Macro) { + if i.path.is_ident("compile_error") { + self.0.push(i.parse_body::().unwrap().value()); + } + visit_mut::visit_macro_mut(self, i); + } + } + + for pattern in ["^[a-z]{1,10000000}$", "a{1,10000000}"] { + for explicit in [false, true] { + for configured in [false, true] { + let mut builder = regex::RegexBuilder::new(pattern); + let limits = if configured { + builder.size_limit(0x0001_0000).dfa_size_limit(0x0001_0000); + quote!(size_limit = 65_536, dfa_size_limit = 65_536,) + } else { + quote!() + }; + assert!(builder.build().is_err(), "engine must refuse {pattern}"); + let cache = explicit.then(|| quote!(cache = explicit,)); + let schema = syn::LitStr::new( + &json!({"type": "string", "pattern": pattern}).to_string(), + proc_macro2::Span::call_site(), + ); + let mut syntax: syn::File = syn::parse2(jsonschema_macros_core::expand( + quote!( + schema = #schema, draft = Draft4, + pattern_options = { engine = regex, #cache #limits }, + methods = { is_valid = true, validate = false, iter_errors = false } + ), + quote!( + pub struct BoundedPattern; + ), + )) + .unwrap(); + let mut errors = Refusals(Vec::new()); + errors.visit_file_mut(&mut syntax); + assert_eq!( + errors.0, + [format!("Invalid `pattern` regular expression: {pattern}")], + "pattern={pattern}, explicit={explicit}, configured={configured}" + ); + } + } + } + } + #[test] fn direct_automata_dependency_preserves_the_locked_engine_feature_closure() { let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../.."); diff --git a/crates/auctioneer-bidder/tests/schema_compiler_controls.rs b/crates/auctioneer-bidder/tests/schema_compiler_controls.rs index e32a663..54b0d94 100644 --- a/crates/auctioneer-bidder/tests/schema_compiler_controls.rs +++ b/crates/auctioneer-bidder/tests/schema_compiler_controls.rs @@ -410,7 +410,7 @@ mod tests { fn compiler_is_pinned_without_retrieval_for_native_serving_and_explicit_guest_staging() { let root: Value = toml::from_str(include_str!("../../../Cargo.toml")).unwrap(); let candidate = &root["workspace"]["dependencies"]["jsonschema"]; - assert_eq!(candidate["version"].as_str(), Some("=0.58.6")); + assert_eq!(candidate["version"].as_str(), Some("=0.61.2")); assert_eq!(candidate["default-features"].as_bool(), Some(false)); assert_eq!( candidate["features"].as_array().unwrap(), diff --git a/crates/auctioneer-bidder/tests/schema_compiler_layout/mod.rs b/crates/auctioneer-bidder/tests/schema_compiler_layout/mod.rs index e0eefdb..d680ad5 100644 --- a/crates/auctioneer-bidder/tests/schema_compiler_layout/mod.rs +++ b/crates/auctioneer-bidder/tests/schema_compiler_layout/mod.rs @@ -328,16 +328,14 @@ fn read_unit>( ) -> Result<(), Error> { let mut entries = unit.entries(); let mut scopes = Vec::new(); - let mut depth = 0_isize; - while let Some((delta, entry)) = entries.next_dfs().map_err(|_error| Error::MalformedDwarf)? { + while let Some(entry) = entries.next_dfs().map_err(|_error| Error::MalformedDwarf)? { spend( &mut budget.entries, 1, budget.limits.entries, Limit::Entries, )?; - depth = depth.checked_add(delta).ok_or(Error::MalformedDwarf)?; - let level = usize::try_from(depth).map_err(|_error| Error::MalformedDwarf)?; + let level = usize::try_from(entry.depth()).map_err(|_error| Error::MalformedDwarf)?; if level > budget.limits.depth { return Err(Error::Limit(Limit::Depth)); } @@ -374,13 +372,10 @@ fn read_unit>( fn entry_name>( dwarf: &Dwarf, unit: &Unit, - entry: &DebuggingInformationEntry<'_, '_, R>, + entry: &DebuggingInformationEntry, budget: &mut ReadBudget, ) -> Result, Error> { - let Some(value) = entry - .attr_value(gimli::DW_AT_name) - .map_err(|_error| Error::MalformedDwarf)? - else { + let Some(value) = entry.attr_value(gimli::DW_AT_name) else { return Ok(None); }; let raw_name = dwarf @@ -428,12 +423,9 @@ fn qualified_name( } fn declaration>( - entry: &DebuggingInformationEntry<'_, '_, R>, + entry: &DebuggingInformationEntry, ) -> Result { - match entry - .attr_value(gimli::DW_AT_declaration) - .map_err(|_error| Error::MalformedDwarf)? - { + match entry.attr_value(gimli::DW_AT_declaration) { None | Some(AttributeValue::Flag(false)) => Ok(false), Some(AttributeValue::Flag(true)) => Ok(true), _ => Err(Error::MalformedDwarf), @@ -441,17 +433,15 @@ fn declaration>( } fn type_field>( - entry: &DebuggingInformationEntry<'_, '_, R>, + entry: &DebuggingInformationEntry, name: &str, ) -> Result { let size = entry .attr_value(gimli::DW_AT_byte_size) - .map_err(|_error| Error::MalformedDwarf)? .and_then(|value| value.udata_value()) .ok_or_else(|| Error::MissingByteSize(name.to_owned()))?; let encoded_alignment = entry .attr_value(gimli::DW_AT_alignment) - .map_err(|_error| Error::MalformedDwarf)? .and_then(|value| value.udata_value()) .ok_or_else(|| Error::MissingAlignment(name.to_owned()))?; let bytes = usize::try_from(size).map_err(|_error| Error::InvalidLayout(name.to_owned()))?; diff --git a/crates/auctioneer-bidder/tests/schema_matchers/mod.rs b/crates/auctioneer-bidder/tests/schema_matchers/mod.rs index cc09f31..46e2304 100644 --- a/crates/auctioneer-bidder/tests/schema_matchers/mod.rs +++ b/crates/auctioneer-bidder/tests/schema_matchers/mod.rs @@ -612,7 +612,7 @@ fn gather(value: &Value, origin: &str, output: &mut BTreeMap String { - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) } fn check_deadline(deadline: Instant) -> Result<(), &'static str> { @@ -677,7 +677,7 @@ fn metadata() -> Value { "rustc":String::from_utf8(rustc.stdout).unwrap(),"profile":"release","debug_assertions":cfg!(debug_assertions), "engine_version":engine["version"].as_str(),"engine_checksum":engine.get("checksum").and_then(toml::Value::as_str), "engine_source_identity":engine_identity, - "compiler_version":"0.58.6 with existing pinned patches","os":env::consts::OS, + "compiler_version":"0.61.2 with existing pinned patches","os":env::consts::OS, "arch":env::consts::ARCH,"word_bytes":size_of::(), "test_binary_sha256":digest(&binary),"test_binary_bytes":binary.len(),"host_exclusive":false, "method_revision":2_u32,"samples":7_u32,"iterations_rule":"clamp(65536 / max(input_bytes, 64), 64, 1024)", diff --git a/crates/auctioneer-bidder/tests/schema_qualification/fixture.rs b/crates/auctioneer-bidder/tests/schema_qualification/fixture.rs index 7d7242a..b528f15 100644 --- a/crates/auctioneer-bidder/tests/schema_qualification/fixture.rs +++ b/crates/auctioneer-bidder/tests/schema_qualification/fixture.rs @@ -70,7 +70,7 @@ pub fn pins() -> (String, String) { assert_eq!(implementations.len(), OWNERS); let schemas: Vec<_> = ROWS.iter().enumerate().map(|(index, (name, _, build_schema))| { let schema = build_schema().to_string(); - json!({"name": name, "path": format!("static/bidder-params/{name}.json"), "blob": format!("{:040x}", index.checked_add(1).unwrap()), "bytes": schema.len(), "sha256": format!("{:x}", Sha256::digest(schema.as_bytes()))}) + json!({"name": name, "path": format!("static/bidder-params/{name}.json"), "blob": format!("{:040x}", index.checked_add(1).unwrap()), "bytes": schema.len(), "sha256": hex::encode(Sha256::digest(schema.as_bytes()))}) }).collect(); let source = json!({"schema_version": 2_i32, "kind": "reference_inventory_only", "revision": REVISION, "counts": {"schemas": SCHEMAS, "schema_bytes": schema_bytes(), "largest_schema_bytes": largest_bytes()}, "implementations": implementations, "schema": schemas}); // Public source identities may differ from their filesystem implementation key. @@ -109,7 +109,7 @@ pub fn inventory(bidders: &Path, source: &Path) -> Result String { let schema = (ROWS[2].2)().to_string(); - let sha256 = format!("{:x}", Sha256::digest(schema.as_bytes())); + let sha256 = hex::encode(Sha256::digest(schema.as_bytes())); toml::to_string(&json!({"schema_version":1_i32,"kind":"supplemental_schema_reference_only","require_all":false,"schema":[{ "key":"fake_supplemental","name":"fake_supplemental","repository":REPOSITORY,"revision":"2222222222222222222222222222222222222222", "source_path":"static/bidder-params/fake_supplemental.json","source_blob":format!("{:040x}", 3_usize),"source_bytes":schema.len(),"source_sha256":sha256, @@ -142,7 +142,7 @@ impl Fixture { fs::create_dir_all(path.parent().unwrap())?; fs::write(path, &schema)?; let artifacts = manifests.entry(*key).or_insert_with(Vec::new); - artifacts.push(json!({"category": "schema", "source": "upstream", "source_path": format!("static/bidder-params/{name}.json"), "source_blob": format!("{:040x}", index.checked_add(1).unwrap()), "source_bytes": schema.len(), "source_sha256": format!("{:x}", Sha256::digest(schema.as_bytes())), "retained": {"source_path": retained, "source_bytes": schema.len(), "source_sha256": format!("{:x}", Sha256::digest(schema.as_bytes()))}})); + artifacts.push(json!({"category": "schema", "source": "upstream", "source_path": format!("static/bidder-params/{name}.json"), "source_blob": format!("{:040x}", index.checked_add(1).unwrap()), "source_bytes": schema.len(), "source_sha256": hex::encode(Sha256::digest(schema.as_bytes())), "retained": {"source_path": retained, "source_bytes": schema.len(), "source_sha256": hex::encode(Sha256::digest(schema.as_bytes()))}})); } for (key, artifacts) in manifests { let manifest = json!({"key": key, "factory": false, "provenance": {"origin": "reference", "sources": {"upstream": {"repository": REPOSITORY, "revision": REVISION}}, "artifacts": artifacts}}); diff --git a/crates/auctioneer-bidder/tests/schema_qualification/mod.rs b/crates/auctioneer-bidder/tests/schema_qualification/mod.rs index 9022483..9c2ee29 100644 --- a/crates/auctioneer-bidder/tests/schema_qualification/mod.rs +++ b/crates/auctioneer-bidder/tests/schema_qualification/mod.rs @@ -518,17 +518,17 @@ fn owned_witnesses( /// Verify committed witnesses before auditing every raw schema. Neither input is optional. pub fn inventory(bidders_root: &Path, source_path: &Path) -> Result { - if format!("{:x}", Sha256::digest(COMMITTED_SOURCE.as_bytes())) + if hex::encode(Sha256::digest(COMMITTED_SOURCE.as_bytes())) != "b22f74407fd081cd7d073b8724ba8f74e1385163b9bc30c2277342adc38bb6c6" { return Err(InventoryError::Witness); } - if format!("{:x}", Sha256::digest(COMMITTED_BINDINGS.as_bytes())) + if hex::encode(Sha256::digest(COMMITTED_BINDINGS.as_bytes())) != "d1a0f18d99f53cbd4f62fe74c5d1e5580f8688fce95a29b1b05ee934dbe9ff0c" { return Err(InventoryError::Witness); } - if format!("{:x}", Sha256::digest(COMMITTED_SUPPLEMENTAL.as_bytes())) + if hex::encode(Sha256::digest(COMMITTED_SUPPLEMENTAL.as_bytes())) != "2022d18b8e5580824111a2a3781039b701c7c6df85a0456206ce2b370775ebbb" { return Err(InventoryError::Witness); @@ -642,7 +642,7 @@ fn verify_exclusion( } let bytes = read_bounded(&root.join(key).join(&retained.path), MAX_SCHEMA_BYTES)?; if u64::try_from(bytes.len()).map_err(|_error| InventoryError::Limit)? != pin.retained.bytes - || format!("{:x}", Sha256::digest(&bytes)) != pin.retained.sha256 + || hex::encode(Sha256::digest(&bytes)) != pin.retained.sha256 { return Err(InventoryError::Witness); } @@ -712,7 +712,7 @@ pub fn inventory_with_pins( for witness in actual.into_values() { let bytes = read_bounded(&bidders_root.join(&witness.path), MAX_SCHEMA_BYTES)?; let length = u64::try_from(bytes.len()).map_err(|_error| InventoryError::Limit)?; - if length != witness.bytes || format!("{:x}", Sha256::digest(&bytes)) != witness.sha256 { + if length != witness.bytes || hex::encode(Sha256::digest(&bytes)) != witness.sha256 { return Err(InventoryError::Witness); } schema_bytes = schema_bytes @@ -1988,8 +1988,7 @@ mod tests { &mut *row }; target["source_bytes"] = toml::Value::Integer(i64::try_from(bytes.len())?); - target["source_sha256"] = - toml::Value::String(format!("{:x}", Sha256::digest(&bytes))); + target["source_sha256"] = toml::Value::String(hex::encode(Sha256::digest(&bytes))); } fs::write( fixture.bidders.join("fake_supplemental/parameters.json"), @@ -2307,7 +2306,7 @@ mod tests { assert_eq!(bytes.len(), original.len()); assert_ne!(bytes, original); assert_eq!(serde_json::from_slice::(&bytes).unwrap(), schema); - let digest = format!("{:x}", Sha256::digest(&bytes)); + let digest = hex::encode(Sha256::digest(&bytes)); fs::write(path, bytes).unwrap(); fixture .manifest("fake_base", |manifest| { diff --git a/crates/auctioneer-bidder/tests/schema_reference/mod.rs b/crates/auctioneer-bidder/tests/schema_reference/mod.rs index 32df311..f07d864 100644 --- a/crates/auctioneer-bidder/tests/schema_reference/mod.rs +++ b/crates/auctioneer-bidder/tests/schema_reference/mod.rs @@ -149,7 +149,7 @@ pub(crate) enum CaptureError { } fn digest(bytes: &[u8]) -> String { - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) } pub(crate) fn captured() -> Result { diff --git a/crates/auctioneer-bidder/tests/schema_selected_semantics/mod.rs b/crates/auctioneer-bidder/tests/schema_selected_semantics/mod.rs index 0525e71..1514a20 100644 --- a/crates/auctioneer-bidder/tests/schema_selected_semantics/mod.rs +++ b/crates/auctioneer-bidder/tests/schema_selected_semantics/mod.rs @@ -128,7 +128,7 @@ where } fn digest(bytes: &[u8]) -> String { - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) } fn hex(value: &str, length: usize) -> bool { diff --git a/crates/auctioneer-bidder/tests/schema_selection_source/mod.rs b/crates/auctioneer-bidder/tests/schema_selection_source/mod.rs index b0e5e53..73ceaec 100644 --- a/crates/auctioneer-bidder/tests/schema_selection_source/mod.rs +++ b/crates/auctioneer-bidder/tests/schema_selection_source/mod.rs @@ -111,7 +111,7 @@ struct LaneReport { } fn digest(bytes: &[u8]) -> String { - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) } fn pinned(text: &str, sha256: &str) -> Result { diff --git a/crates/auctioneer-bidder/tests/schema_source_conformance.rs b/crates/auctioneer-bidder/tests/schema_source_conformance.rs index d45d3ce..bc9756d 100644 --- a/crates/auctioneer-bidder/tests/schema_source_conformance.rs +++ b/crates/auctioneer-bidder/tests/schema_source_conformance.rs @@ -253,7 +253,7 @@ mod tests { ); assert_eq!( record["source_sha256"].as_str(), - Some(format!("{:x}", Sha256::digest(bytes)).as_str()) + Some(hex::encode(Sha256::digest(bytes)).as_str()) ); } } @@ -386,7 +386,7 @@ mod tests { assert!(certificate.work_upper_bound > 0); certificates.push(json!({"owner":owner, "pattern":pattern, "lane":cohort.manifest["lane"], - "cohort_sha256":format!("{:x}", Sha256::digest(serde_json::to_vec(&cohort.manifest).unwrap())), + "cohort_sha256":hex::encode(Sha256::digest(serde_json::to_vec(&cohort.manifest).unwrap())), "peak_requested_bytes":certificate.peak_requested_bytes, "source_record_visit_upper_bound":certificate.work_upper_bound, "bound_class":"conditional_target_syntax_component", @@ -475,7 +475,7 @@ mod tests { assert!(certificate.requested_heap_bytes > 0); certificates.push(json!({"owner":owner,"pattern":pattern,"reverse":reverse, "lane":cohort.manifest["lane"], - "cohort_sha256":format!("{:x}", Sha256::digest(serde_json::to_vec(&cohort.manifest).unwrap())), + "cohort_sha256":hex::encode(Sha256::digest(serde_json::to_vec(&cohort.manifest).unwrap())), "target":report["binding"]["target"],"states":certificate.states, "arc_bytes":certificate.arc_bytes,"states_bytes":certificate.states_bytes, "start_patterns_bytes":certificate.start_patterns_bytes, @@ -510,18 +510,18 @@ mod tests { fn attach_target_components(report: &mut Value, package: &str) { if package == "regex-syntax" { report["target_syntax_model_sources"] = json!({ - "syntax_construction": format!("{:x}", Sha256::digest(include_bytes!("schema_syntax_construction/mod.rs"))), - "heap_layout": format!("{:x}", Sha256::digest(include_bytes!("schema_heap_layout/mod.rs"))), - "producer": format!("{:x}", Sha256::digest(include_bytes!("schema_source_conformance.rs"))), + "syntax_construction": hex::encode(Sha256::digest(include_bytes!("schema_syntax_construction/mod.rs"))), + "heap_layout": hex::encode(Sha256::digest(include_bytes!("schema_heap_layout/mod.rs"))), + "producer": hex::encode(Sha256::digest(include_bytes!("schema_source_conformance.rs"))), }); report["target_syntax_components"] = syntax_components(report); } else { assert_eq!(package, "regex-automata"); report["target_nfa_model_sources"] = json!({ - "target_projection": format!("{:x}", Sha256::digest(include_bytes!("schema_nfa_heap/target.rs"))), - "native_owner_source": format!("{:x}", Sha256::digest(include_bytes!("schema_nfa_heap/mod.rs"))), - "topology_constructor": format!("{:x}", Sha256::digest(include_bytes!("schema_cache_model/mod.rs"))), - "producer": format!("{:x}", Sha256::digest(include_bytes!("schema_source_conformance.rs"))), + "target_projection": hex::encode(Sha256::digest(include_bytes!("schema_nfa_heap/target.rs"))), + "native_owner_source": hex::encode(Sha256::digest(include_bytes!("schema_nfa_heap/mod.rs"))), + "topology_constructor": hex::encode(Sha256::digest(include_bytes!("schema_cache_model/mod.rs"))), + "producer": hex::encode(Sha256::digest(include_bytes!("schema_source_conformance.rs"))), }); report["target_nfa_layout_names"] = json!(nfa_layout_requests()); report["target_nfa_components"] = nfa_components(report); @@ -1488,8 +1488,8 @@ mod tests { "probe_enum_inline_bytes": observed["owner_inline_bytes"], "probe_enum_storage": "outside measurement windows; not the production owner representation", "derivation_sources_sha256": { - "cache": format!("{:x}", Sha256::digest(include_bytes!("schema_meta_heap/mod.rs"))), - "bundle": format!("{:x}", Sha256::digest(include_bytes!("schema_bundle_heap/mod.rs")))}, + "cache": hex::encode(Sha256::digest(include_bytes!("schema_meta_heap/mod.rs"))), + "bundle": hex::encode(Sha256::digest(include_bytes!("schema_bundle_heap/mod.rs")))}, "observations": observed, "excludes": ["constructor_peak_and_work", "compiled_programs_and_other_schema_state", "complete_call_frames", "work_bound", "allocator_and_physical_memory", "guest_layouts", "serving_profile_qualification"]}) @@ -1598,7 +1598,7 @@ mod tests { .expect("selected serial native cache owner"); peaks.push(heap.peak); rows.push(json!({"helper": helper, - "pattern_sha256": format!("{:x}", Sha256::digest(pattern.as_bytes())), + "pattern_sha256": hex::encode(Sha256::digest(pattern.as_bytes())), "eager_bytes": heap.eager_bytes, "forward_bytes": heap.forward_bytes, "reverse_bytes": heap.reverse_bytes, "optional_prefix_peak_bytes": heap.prefix_peak_bytes, "fallback_bytes": heap.fallback_bytes, "growth_overlap_bytes": heap.growth_overlap, @@ -1910,7 +1910,7 @@ mod tests { } }; rows.push(json!({"owner": owner, "helper": name, - "pattern_sha256": format!("{:x}", Sha256::digest(pattern.as_bytes())), + "pattern_sha256": hex::encode(Sha256::digest(pattern.as_bytes())), "metadata_bytes": heap.metadata_bytes, "strategy_arc_bytes": heap.strategy_arc_bytes, "nfa_bytes": heap.nfa_bytes, "onepass_tables_bytes": heap.onepass_tables_bytes, "automatic_prefilter": disposition, "automatic_prefilter_bytes": heap.automatic_prefilter_bytes, @@ -1933,13 +1933,13 @@ mod tests { "layout_profile_correspondence_with_child": "not_established", "owners": rows, "requested_heap_bytes": total, "static_inline_bytes": inline, "derivation_sources_sha256": { - "program": format!("{:x}", Sha256::digest(include_bytes!("schema_program_heap/mod.rs"))), - "literal": format!("{:x}", Sha256::digest(include_bytes!("schema_literal_heap/mod.rs"))), - "metadata": format!("{:x}", Sha256::digest(include_bytes!("schema_metadata_heap/mod.rs"))), - "nfa": format!("{:x}", Sha256::digest(include_bytes!("schema_nfa_heap/mod.rs"))), - "onepass": format!("{:x}", Sha256::digest(include_bytes!("schema_onepass_bounds/mod.rs"))), - "pool": format!("{:x}", Sha256::digest(include_bytes!("schema_pool_heap/mod.rs"))), - "arc": format!("{:x}", Sha256::digest(include_bytes!("schema_heap_layout/mod.rs")))}, + "program": hex::encode(Sha256::digest(include_bytes!("schema_program_heap/mod.rs"))), + "literal": hex::encode(Sha256::digest(include_bytes!("schema_literal_heap/mod.rs"))), + "metadata": hex::encode(Sha256::digest(include_bytes!("schema_metadata_heap/mod.rs"))), + "nfa": hex::encode(Sha256::digest(include_bytes!("schema_nfa_heap/mod.rs"))), + "onepass": hex::encode(Sha256::digest(include_bytes!("schema_onepass_bounds/mod.rs"))), + "pool": hex::encode(Sha256::digest(include_bytes!("schema_pool_heap/mod.rs"))), + "arc": hex::encode(Sha256::digest(include_bytes!("schema_heap_layout/mod.rs")))}, "constructor_observations": observed, "excludes": ["non_regex_schema_state", "compiled_code_and_data_residency", "constructor_peak_and_work", "search_cache_and_work", "allocator_and_physical_memory", "guest_layouts", "serving_profile_qualification"]}) @@ -2930,29 +2930,21 @@ mod tests { .map(|(name, pattern)| ExpectedOwner { name: name.clone(), kind: OwnerKind::Regex, - pattern_config_digest: format!( - "{:x}", - Sha256::digest( - serde_json::to_vec( - &json!({"pattern": pattern, "constructor": constructor}) - ) - .unwrap() - ) - ), + pattern_config_digest: hex::encode(Sha256::digest( + serde_json::to_vec(&json!({"pattern": pattern, "constructor": constructor})) + .unwrap(), + )), }) .collect(); owners.push(ExpectedOwner { name: "fake_public_prefilter".to_owned(), kind: OwnerKind::PublicPrefilter, - pattern_config_digest: format!( - "{:x}", - Sha256::digest( - serde_json::to_vec( - &json!({"match_kind": "leftmost_first", "needles": ["fake_layout_literal"]}) - ) - .unwrap() + pattern_config_digest: hex::encode(Sha256::digest( + serde_json::to_vec( + &json!({"match_kind": "leftmost_first", "needles": ["fake_layout_literal"]}), ) - ), + .unwrap(), + )), }); owners } @@ -3871,7 +3863,7 @@ mod tests { .join(filename), ) .unwrap(); - assert_eq!(format!("{:x}", Sha256::digest(&bytes)), expected_sha256); + assert_eq!(hex::encode(Sha256::digest(&bytes)), expected_sha256); let record: Value = serde_json::from_slice(&bytes).unwrap(); assert_eq!( record["metadata"]["scope"], @@ -3925,7 +3917,7 @@ mod tests { let inventory_bytes = include_bytes!("conformance/fixtures/reference/catalog/source-inventory.toml"); assert_eq!( - format!("{:x}", Sha256::digest(inventory_bytes)), + hex::encode(Sha256::digest(inventory_bytes)), "b22f74407fd081cd7d073b8724ba8f74e1385163b9bc30c2277342adc38bb6c6" ); let frozen_inventory: toml::Value = @@ -3953,7 +3945,7 @@ mod tests { let capture_bytes = include_bytes!("conformance/fixtures/reference/schema-reference/parameters.json"); assert_eq!( - format!("{:x}", Sha256::digest(capture_bytes)), + hex::encode(Sha256::digest(capture_bytes)), "6efc0eaea62063f86d391df46265e1df2fb06789cfe2e746f53c3c9e4c41863e" ); let frozen_capture: serde_json::Value = serde_json::from_slice(capture_bytes).unwrap(); diff --git a/crates/auctioneer-bidder/tests/schema_syntax_construction/mod.rs b/crates/auctioneer-bidder/tests/schema_syntax_construction/mod.rs index 12fb9ea..bd77ac6 100644 --- a/crates/auctioneer-bidder/tests/schema_syntax_construction/mod.rs +++ b/crates/auctioneer-bidder/tests/schema_syntax_construction/mod.rs @@ -210,7 +210,7 @@ fn verify_source_bytes( expected: &str, bytes: &[u8], ) -> Result<(), ConstructionError> { - if format!("{:x}", Sha256::digest(bytes)) != expected { + if hex::encode(Sha256::digest(bytes)) != expected { return Err(ConstructionError::Source(relative)); } Ok(()) @@ -1230,7 +1230,7 @@ mod tests { fn syntax_construction_source_digest_checks_refuse_changed_bytes() { use sha2::{Digest as _, Sha256}; let bytes = b"fake_reviewed_source"; - let expected = format!("{:x}", Sha256::digest(bytes)); + let expected = hex::encode(Sha256::digest(bytes)); assert_eq!( super::verify_source_bytes("fake_source.rs", &expected, bytes), Ok(()) diff --git a/crates/auctioneer-bidder/tests/schema_vendor/mod.rs b/crates/auctioneer-bidder/tests/schema_vendor/mod.rs index 9592f0d..149b1ed 100644 --- a/crates/auctioneer-bidder/tests/schema_vendor/mod.rs +++ b/crates/auctioneer-bidder/tests/schema_vendor/mod.rs @@ -1,5 +1,5 @@ //! Checks the approved crates.io payload from revision -//! 55ac1664384793c5d3b20745d3f9c169dfe2c06f, with exact patched and added files. +//! 0e82636fde8b2afb5e712ede6c261166ea10fc17, with exact patched and added files. use flate2::read::GzDecoder; use sha2::{Digest as _, Sha256}; @@ -9,30 +9,30 @@ use std::io::Read as _; use std::path::{Path, PathBuf}; use std::str::from_utf8; -const ARCHIVE_PATH: &str = "vendor/jsonschema-macros-core-0.58.6.crate"; +const ARCHIVE_PATH: &str = "vendor/jsonschema-macros-core-0.61.2.crate"; const VENDOR_PATH: &str = "vendor/jsonschema-macros-core"; -const ARCHIVE_PREFIX: &str = "jsonschema-macros-core-0.58.6/"; -const ARCHIVE_SHA256: &str = "bf3ebe067f2c25a981a7d1b2f696fc213e10dbf80ba5fe997f7dc2e4fe261f26"; -const PATCHED_FILES: [(&str, &str); 8] = [ +const ARCHIVE_PREFIX: &str = "jsonschema-macros-core-0.61.2/"; +const ARCHIVE_SHA256: &str = "75afa4b5e6986cc221f5339d7d6149360f0bf8e65bcb23617dc0f92900b576d2"; +const PATCHED_FILES: [(&str, &str); 9] = [ ( "Cargo.toml", - "4f5e5fae8a57a8f400542804fba6199b969deaeb0519b1f1aa6d84b005a7363e", + "7e20e3d63945bdeed04afb10a8763be91419577c510891e87a5bbbd1eaf559c3", ), ( "Cargo.toml.orig", - "8084eeeaa19a83442d0fc29325c5861ead328886021bbb6a0abb13415d7faefb", + "467286fa79c0c70a4952e386a960af50874868ff40caaf1e44722daf97436d6d", ), ( "src/lib.rs", - "9411c0283761acfb41305686bba260e723235e6620713893b3efaf1b9dd09623", + "8fdaf9996475baf95ad42a820d2f9e1a8b7d3fe80e3bb9144b624507c150e5cd", ), ( "src/context.rs", - "c6191b58242eda136efc7e498ff2a8ac217066416e2f8da10f5aec1ffb637d2b", + "ce580d3bcb085388ed8c11cd20e32c00789c972f461402d36233d799d93f6da5", ), ( "src/codegen.rs", - "df60bb9e815bf5568696c3c9930c1132ae3bd10b8a88bbdb0b7bc06117899511", + "68d9a7a692f6f9891ab9e19077ec24d22b45cb884a9281664a0c947c0c9ab35f", ), ( "src/codegen/object_schema.rs", @@ -40,7 +40,11 @@ const PATCHED_FILES: [(&str, &str); 8] = [ ), ( "src/codegen/emit_root.rs", - "0fe3dfb41dd37dab3fa8fe7613fb20084b91550b100798da2c21adbcd21a6730", + "5a757b0f4d360fcc9fb8dce7af0031b107067be9f5c451321ec94d49ff3fb2f8", + ), + ( + "src/codegen/regex.rs", + "bb2103f10ab1f5a14ed490401dc74f24ddcb6a875146f35eaed581de25c4994b", ), ( "src/tests.rs", @@ -57,7 +61,7 @@ const MAX_MEMBER_BYTES: u64 = 512 * 1024; const MAX_MEMBERS: usize = 512; fn sha256(bytes: &[u8]) -> String { - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) } fn directory(path: &Path) -> Result<(), String> { @@ -296,7 +300,11 @@ mod tests { #[test] fn rejects_edits_to_unpatched_source_lock_and_vcs_provenance() { let temporary = fixture(); - for name in ["src/codegen/regex.rs", "Cargo.lock", ".cargo_vcs_info.json"] { + for name in [ + "src/codegen/dispatch.rs", + "Cargo.lock", + ".cargo_vcs_info.json", + ] { let path = temporary.path().join(VENDOR_PATH).join(name); let original = fs::read(&path).unwrap(); let mut changed = original.clone(); @@ -437,7 +445,9 @@ mod tests { .map(|(name, _)| (*name, fs::read(vendor.join(name)).unwrap())) .collect(); let patch = Path::new(env!("CARGO_MANIFEST_DIR")) - .join("../../vendor/patches/jsonschema-macros-core-explicit-cache.patch") + .join( + "../../vendor/patches/jsonschema-macros-core-0.61.2-explicit-cache-all-modes.patch", + ) .canonicalize() .unwrap(); let mut child = Command::new("git") @@ -478,7 +488,7 @@ mod tests { ), "src/codegen/emit_root.rs" => assert_eq!( sha256(&actual), - "0fe3dfb41dd37dab3fa8fe7613fb20084b91550b100798da2c21adbcd21a6730" + "5a757b0f4d360fcc9fb8dce7af0031b107067be9f5c451321ec94d49ff3fb2f8" ), _ => assert_eq!(actual, original, "{}", name.display()), } diff --git a/crates/auctioneer-bidder/tests/test_isolation.rs b/crates/auctioneer-bidder/tests/test_isolation.rs index 9f34734..aea9199 100644 --- a/crates/auctioneer-bidder/tests/test_isolation.rs +++ b/crates/auctioneer-bidder/tests/test_isolation.rs @@ -255,7 +255,7 @@ mod tests { let syn::Item::Impl(implementation) = item else { continue; }; - if implementation.trait_.as_ref().is_none_or(|(_, path, _)| { + if implementation.trait_.as_ref().is_none_or(|(path, _)| { path.segments .last() .is_none_or(|segment| segment.ident != "Bidder") diff --git a/crates/auctioneer-cli/src/bidders/check.rs b/crates/auctioneer-cli/src/bidders/check.rs index 6c0de29..8503906 100644 --- a/crates/auctioneer-cli/src/bidders/check.rs +++ b/crates/auctioneer-cli/src/bidders/check.rs @@ -114,7 +114,7 @@ fn parse_inventory(bytes: &[u8]) -> Result { } pub(super) fn parse_factory_bindings(bytes: &[u8]) -> Result { - if format!("{:x}", Sha256::digest(bytes)) != FACTORY_CAPTURE_SHA256 { + if hex::encode(Sha256::digest(bytes)) != FACTORY_CAPTURE_SHA256 { return Err(Error::InvalidSource); } parse_inventory(bytes).map_err(|_error| Error::InvalidSource) @@ -215,7 +215,7 @@ pub(super) async fn run_bytes( report.scope = "wave_design_only"; report.wave = Some(WaveSummary { id: design.id, - sha256: format!("{:x}", Sha256::digest(&bytes)), + sha256: hex::encode(Sha256::digest(&bytes)), review_status: "pending", operations, drivers, diff --git a/crates/auctioneer-cli/src/bidders/import_packages.rs b/crates/auctioneer-cli/src/bidders/import_packages.rs index f9469cb..e6fa339 100644 --- a/crates/auctioneer-cli/src/bidders/import_packages.rs +++ b/crates/auctioneer-cli/src/bidders/import_packages.rs @@ -156,7 +156,7 @@ impl Package { } fn digest(bytes: &[u8]) -> String { - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) } fn artifact( diff --git a/crates/auctioneer-cli/src/bidders/import_projection/mod.rs b/crates/auctioneer-cli/src/bidders/import_projection/mod.rs index 7f17b28..bd98afe 100644 --- a/crates/auctioneer-cli/src/bidders/import_projection/mod.rs +++ b/crates/auctioneer-cli/src/bidders/import_projection/mod.rs @@ -102,7 +102,7 @@ fn retained_inputs( let path = Path::new(&manifest.key).join(relative); let bytes = actual.get(&path).ok_or(Error::ImportInput)?; if u64::try_from(bytes.len()).ok() != Some(retained.bytes) - || format!("{:x}", Sha256::digest(bytes)) != retained.sha256 + || hex::encode(Sha256::digest(bytes)) != retained.sha256 { return Err(Error::ImportInput); } diff --git a/crates/auctioneer-cli/src/bidders/inventory.rs b/crates/auctioneer-cli/src/bidders/inventory.rs index d2e4e40..5573a08 100644 --- a/crates/auctioneer-cli/src/bidders/inventory.rs +++ b/crates/auctioneer-cli/src/bidders/inventory.rs @@ -24,7 +24,7 @@ impl Inventory { fn validate_source_pin(&self) -> Result<(), Error> { // Independently frozen source inventory, not a digest learned from this scan. let bytes = toml::to_string_pretty(self).map_err(|_error| Error::Output)?; - if format!("{:x}", Sha256::digest(bytes.as_bytes())) + if hex::encode(Sha256::digest(bytes.as_bytes())) != "b22f74407fd081cd7d073b8724ba8f74e1385163b9bc30c2277342adc38bb6c6" { return Err(Error::InvalidSource); @@ -126,7 +126,7 @@ fn artifact(entry: &Entry, bytes: &[u8], root: &str, suffix: &str) -> Result( /// Return the lowercase SHA-256 digest of the supplied bytes. #[must_use] pub fn sha256(bytes: &[u8]) -> String { - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) } /// Hash compact JSON with canonically ordered object keys. @@ -244,7 +244,7 @@ fn hash_open_file(mut file: File, cap: usize) -> Result { } digest.update(chunk.get(..count).ok_or(HarnessError::new("input_io"))?); } - Ok(format!("{:x}", digest.finalize())) + Ok(hex::encode(digest.finalize())) } /// Hash a bounded regular file, refusing final symlinks and hardlinks on Unix. diff --git a/crates/auctioneer-cli/src/native_control/process.rs b/crates/auctioneer-cli/src/native_control/process.rs index 64f138f..2ab36d1 100644 --- a/crates/auctioneer-cli/src/native_control/process.rs +++ b/crates/auctioneer-cli/src/native_control/process.rs @@ -564,7 +564,7 @@ impl ManagedProcess { let output = self.inner.output.lock().await; ProcessSummary { output_bytes: output.bytes, - output_sha256: format!("{:x}", output.digest.clone().finalize()), + output_sha256: hex::encode(output.digest.clone().finalize()), closed: self.closed(), } } diff --git a/crates/auctioneer-cli/src/qualification/evaluate.rs b/crates/auctioneer-cli/src/qualification/evaluate.rs index d86a266..582c87c 100644 --- a/crates/auctioneer-cli/src/qualification/evaluate.rs +++ b/crates/auctioneer-cli/src/qualification/evaluate.rs @@ -647,7 +647,7 @@ pub mod tests { }) }) .collect(); - json!({"schema_version":2,"profile_sha256":format!("{:x}",Sha256::digest(serde_json::to_vec(p).unwrap())), + json!({"schema_version":2,"profile_sha256":hex::encode(Sha256::digest(serde_json::to_vec(p).unwrap())), "identity":p["identity"],"resources":p["resources"],"hardware":p["hardware"],"platform":p["platform"], "backend":p["backend"],"variants":variants,"capabilities":capabilities,"scenarios":rows}) } diff --git a/crates/auctioneer-cli/src/qualification/harness/native/snapshots.rs b/crates/auctioneer-cli/src/qualification/harness/native/snapshots.rs index 9fe5d2f..e24104c 100644 --- a/crates/auctioneer-cli/src/qualification/harness/native/snapshots.rs +++ b/crates/auctioneer-cli/src/qualification/harness/native/snapshots.rs @@ -505,7 +505,7 @@ fn copy_stream(input: &mut File, output: &mut File) -> Result { .write_all(chunk) .map_err(|_error| HarnessError::new("output_io"))?; } - Digest::try_from(format!("{:x}", digest.finalize())) + Digest::try_from(hex::encode(digest.finalize())) .map_err(|_error| HarnessError::new("invalid_input")) } diff --git a/crates/auctioneer-cli/src/qualification/harness/stdio.rs b/crates/auctioneer-cli/src/qualification/harness/stdio.rs index 524f465..5f34549 100644 --- a/crates/auctioneer-cli/src/qualification/harness/stdio.rs +++ b/crates/auctioneer-cli/src/qualification/harness/stdio.rs @@ -38,9 +38,17 @@ mod unix { let flags = fcntl_getfl(&file).map_err(|_error| HarnessError::new("output_io"))?; fcntl_setfl(&file, flags | OFlags::NONBLOCK) .map_err(|_error| HarnessError::new("output_io"))?; - Ok(Output::Ready( - AsyncFd::new(file).map_err(|_error| HarnessError::new("output_io"))?, - )) + #[expect( + unsafe_code, + reason = "the private writer retains exclusive ownership of its duplicated descriptor" + )] + // SAFETY: File owns a valid duplicated descriptor. Output never exposes + // or replaces it, and retains it across readiness waits and timeout. + // AsyncFd unregisters before dropping the owned File; forgetting it + // would retain both the registration and descriptor instead of closing it. + let output = + unsafe { AsyncFd::register(file) }.map_err(|_error| HarnessError::new("output_io"))?; + Ok(Output::Ready(output)) } async fn ready_write(output: &AsyncFd, mut bytes: &[u8]) -> io::Result<()> { diff --git a/crates/auctioneer-cli/src/qualification/profile.rs b/crates/auctioneer-cli/src/qualification/profile.rs index 2c1132d..1fd0f91 100644 --- a/crates/auctioneer-cli/src/qualification/profile.rs +++ b/crates/auctioneer-cli/src/qualification/profile.rs @@ -51,7 +51,7 @@ pub type Revision = Hex<40>; impl Digest { pub fn of(bytes: &[u8]) -> Self { - Self(format!("{:x}", Sha256::digest(bytes))) + Self(hex::encode(Sha256::digest(bytes))) } /// Compact sorted-key JSON is shared with the offline fixture reviewer. diff --git a/crates/auctioneer-cli/tests/bidders_import.rs b/crates/auctioneer-cli/tests/bidders_import.rs index c39a5d8..f89290c 100644 --- a/crates/auctioneer-cli/tests/bidders_import.rs +++ b/crates/auctioneer-cli/tests/bidders_import.rs @@ -45,7 +45,7 @@ mod tests { "../../auctioneer-bidder/tests/conformance/fixtures/reference/catalog/source-inventory.toml" ); assert_eq!( - format!("{:x}", Sha256::digest(bytes)), + hex::encode(Sha256::digest(bytes)), "b22f74407fd081cd7d073b8724ba8f74e1385163b9bc30c2277342adc38bb6c6" ); toml::from_str(from_utf8(bytes).unwrap()).unwrap() @@ -56,7 +56,7 @@ mod tests { "../../auctioneer-bidder/tests/conformance/fixtures/reference/catalog/source-bindings.toml" ); assert_eq!( - format!("{:x}", Sha256::digest(bytes)), + hex::encode(Sha256::digest(bytes)), "d1a0f18d99f53cbd4f62fe74c5d1e5580f8688fce95a29b1b05ee934dbe9ff0c" ); toml::from_str(from_utf8(bytes).unwrap()).unwrap() @@ -124,7 +124,7 @@ mod tests { ); assert_eq!( artifact["source_sha256"].as_str().unwrap(), - format!("{:x}", Sha256::digest(&original)) + hex::encode(Sha256::digest(&original)) ); original } @@ -139,7 +139,7 @@ mod tests { ); assert_eq!( retained["source_sha256"].as_str().unwrap(), - format!("{:x}", Sha256::digest(original)) + hex::encode(Sha256::digest(original)) ); } diff --git a/crates/auctioneer-cli/tests/bidders_source.rs b/crates/auctioneer-cli/tests/bidders_source.rs index cdc5ed2..bc69863 100644 --- a/crates/auctioneer-cli/tests/bidders_source.rs +++ b/crates/auctioneer-cli/tests/bidders_source.rs @@ -80,7 +80,7 @@ mod tests { fn pinned_inventory() -> Value { assert_eq!( - format!("{:x}", Sha256::digest(committed_inventory().as_bytes())), + hex::encode(Sha256::digest(committed_inventory().as_bytes())), "b22f74407fd081cd7d073b8724ba8f74e1385163b9bc30c2277342adc38bb6c6" ); let reference: Value = toml::from_str(committed_inventory()).unwrap(); @@ -93,7 +93,7 @@ mod tests { "../../auctioneer-bidder/tests/conformance/fixtures/reference/catalog/supplemental-schemas.toml" ); assert_eq!( - format!("{:x}", Sha256::digest(capture.as_bytes())), + hex::encode(Sha256::digest(capture.as_bytes())), "2022d18b8e5580824111a2a3781039b701c7c6df85a0456206ce2b370775ebbb", "frozen supplemental source pins" ); @@ -125,7 +125,7 @@ mod tests { fn verify_manifest_snapshot(bytes: &[u8], fixture: &serde_json::Value) { assert_eq!(fixture["schema_version"].as_u64(), Some(1)); assert_eq!( - format!("{:x}", Sha256::digest(bytes)), + hex::encode(Sha256::digest(bytes)), fixture["manifest_sha256"].as_str().unwrap(), "bidder-owned frozen manifest" ); @@ -320,7 +320,7 @@ mod tests { "retained length {object}" ); assert_eq!( - format!("{:x}", Sha256::digest(&retained_bytes)), + hex::encode(Sha256::digest(&retained_bytes)), retained["source_sha256"].as_str().unwrap(), "retained digest {object}" ); @@ -389,7 +389,7 @@ mod tests { "source length {object}" ); assert_eq!( - format!("{:x}", Sha256::digest(&bytes)), + hex::encode(Sha256::digest(&bytes)), artifact["source_sha256"].as_str().unwrap(), "source digest {object}" ); @@ -581,7 +581,7 @@ mod tests { let bytes = toml::to_string(&manifest).unwrap().into_bytes(); let fixture = serde_json::json!({ "schema_version": 1_u8, - "manifest_sha256": format!("{:x}", Sha256::digest(&bytes)), + "manifest_sha256": hex::encode(Sha256::digest(&bytes)), }); verify_manifest_snapshot(&bytes, &fixture); for hash in [ @@ -847,7 +847,7 @@ mod tests { ); let mut repinned = schema.clone(); repinned["retained"]["source_sha256"] = - Value::String(format!("{:x}", Sha256::digest(&corrupt))); + Value::String(hex::encode(Sha256::digest(&corrupt))); assert!( catch_unwind(|| verify_retained_artifact(&repinned, directory.path(), Some(&bytes))) .is_err(), @@ -1138,7 +1138,7 @@ mod tests { "../../auctioneer-bidder/tests/conformance/fixtures/reference/catalog/source-bindings.toml" ); assert_eq!( - format!("{:x}", Sha256::digest(bytes)), + hex::encode(Sha256::digest(bytes)), "d1a0f18d99f53cbd4f62fe74c5d1e5580f8688fce95a29b1b05ee934dbe9ff0c" ); let capture: Value = toml::from_str(from_utf8(bytes).unwrap()).unwrap(); diff --git a/crates/auctioneer-cli/tests/bidders_wave.rs b/crates/auctioneer-cli/tests/bidders_wave.rs index 656cd10..6312c96 100644 --- a/crates/auctioneer-cli/tests/bidders_wave.rs +++ b/crates/auctioneer-cli/tests/bidders_wave.rs @@ -20,7 +20,7 @@ mod tests { fn pinned_manifest() -> toml::Value { let bytes = fs::read(manifest()).unwrap(); assert_eq!( - format!("{:x}", Sha256::digest(&bytes)), + hex::encode(Sha256::digest(&bytes)), "aa9d38e3e6221c13d13b28ba18684e041f48e3c15608aa60ee11db86924a0c24", "complete frozen priority contract, including membership and per-owner operations" ); diff --git a/crates/auctioneer-cli/tests/qualification_cli.rs b/crates/auctioneer-cli/tests/qualification_cli.rs index 5d9e91f..4622490 100644 --- a/crates/auctioneer-cli/tests/qualification_cli.rs +++ b/crates/auctioneer-cli/tests/qualification_cli.rs @@ -210,7 +210,7 @@ mod tests { "capability":c,"status":"verified","evidence_sha256":d}) }) .collect(); - let mut o = json!({"schema_version":2_i32,"profile_sha256":format!("{:x}",Sha256::digest(serde_json::to_vec(&p).unwrap())), + let mut o = json!({"schema_version":2_i32,"profile_sha256":hex::encode(Sha256::digest(serde_json::to_vec(&p).unwrap())), "identity":p["identity"],"resources":p["resources"],"platform":p["platform"],"hardware":p["hardware"],"backend":p["backend"], "variants":variant_rows,"capabilities":capabilities,"scenarios":rows}); bind_debug(&mut p, &mut o); @@ -218,7 +218,7 @@ mod tests { } fn hash(value: &Value) -> String { - format!("{:x}", Sha256::digest(serde_json::to_vec(value).unwrap())) + hex::encode(Sha256::digest(serde_json::to_vec(value).unwrap())) } fn bind_debug(p: &mut Value, o: &mut Value) { diff --git a/crates/auctioneer-cli/tests/qualification_evidence.rs b/crates/auctioneer-cli/tests/qualification_evidence.rs index ed59201..34e7a7b 100644 --- a/crates/auctioneer-cli/tests/qualification_evidence.rs +++ b/crates/auctioneer-cli/tests/qualification_evidence.rs @@ -61,7 +61,7 @@ mod tests { } fn digest(bytes: &[u8]) -> String { - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) } fn exact_members(actual: &BTreeSet<&str>, expected: &[&str]) -> Result<(), String> { diff --git a/crates/auctioneer-config-data/tests/fixtures/unicode/CaseFolding-16.0.0.txt b/crates/auctioneer-config-data/tests/fixtures/unicode/CaseFolding-16.0.0.txt new file mode 100644 index 0000000..1b7a9c1 --- /dev/null +++ b/crates/auctioneer-config-data/tests/fixtures/unicode/CaseFolding-16.0.0.txt @@ -0,0 +1,1654 @@ +# CaseFolding-16.0.0.txt +# Date: 2024-04-30, 21:48:11 GMT +# © 2024 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use and license, see https://www.unicode.org/terms_of_use.html +# +# Unicode Character Database +# For documentation, see https://www.unicode.org/reports/tr44/ +# +# Case Folding Properties +# +# This file is a supplement to the UnicodeData file. +# It provides a case folding mapping generated from the Unicode Character Database. +# If all characters are mapped according to the full mapping below, then +# case differences (according to UnicodeData.txt and SpecialCasing.txt) +# are eliminated. +# +# The data supports both implementations that require simple case foldings +# (where string lengths don't change), and implementations that allow full case folding +# (where string lengths may grow). Note that where they can be supported, the +# full case foldings are superior: for example, they allow "MASSE" and "Maße" to match. +# +# All code points not listed in this file map to themselves. +# +# NOTE: case folding does not preserve normalization formats! +# +# For information on case folding, including how to have case folding +# preserve normalization formats, see Section 3.13 Default Case Algorithms in +# The Unicode Standard. +# +# ================================================================================ +# Format +# ================================================================================ +# The entries in this file are in the following machine-readable format: +# +# ; ; ; # +# +# The status field is: +# C: common case folding, common mappings shared by both simple and full mappings. +# F: full case folding, mappings that cause strings to grow in length. Multiple characters are separated by spaces. +# S: simple case folding, mappings to single characters where different from F. +# T: special case for uppercase I and dotted uppercase I +# - For non-Turkic languages, this mapping is normally not used. +# - For Turkic languages (tr, az), this mapping can be used instead of the normal mapping for these characters. +# Note that the Turkic mappings do not maintain canonical equivalence without additional processing. +# See the discussions of case mapping in the Unicode Standard for more information. +# +# Usage: +# A. To do a simple case folding, use the mappings with status C + S. +# B. To do a full case folding, use the mappings with status C + F. +# +# The mappings with status T can be used or omitted depending on the desired case-folding +# behavior. (The default option is to exclude them.) +# +# ================================================================= + +# Property: Case_Folding + +# All code points not explicitly listed for Case_Folding +# have the value C for the status field, and the code point itself for the mapping field. + +# ================================================================= +0041; C; 0061; # LATIN CAPITAL LETTER A +0042; C; 0062; # LATIN CAPITAL LETTER B +0043; C; 0063; # LATIN CAPITAL LETTER C +0044; C; 0064; # LATIN CAPITAL LETTER D +0045; C; 0065; # LATIN CAPITAL LETTER E +0046; C; 0066; # LATIN CAPITAL LETTER F +0047; C; 0067; # LATIN CAPITAL LETTER G +0048; C; 0068; # LATIN CAPITAL LETTER H +0049; C; 0069; # LATIN CAPITAL LETTER I +0049; T; 0131; # LATIN CAPITAL LETTER I +004A; C; 006A; # LATIN CAPITAL LETTER J +004B; C; 006B; # LATIN CAPITAL LETTER K +004C; C; 006C; # LATIN CAPITAL LETTER L +004D; C; 006D; # LATIN CAPITAL LETTER M +004E; C; 006E; # LATIN CAPITAL LETTER N +004F; C; 006F; # LATIN CAPITAL LETTER O +0050; C; 0070; # LATIN CAPITAL LETTER P +0051; C; 0071; # LATIN CAPITAL LETTER Q +0052; C; 0072; # LATIN CAPITAL LETTER R +0053; C; 0073; # LATIN CAPITAL LETTER S +0054; C; 0074; # LATIN CAPITAL LETTER T +0055; C; 0075; # LATIN CAPITAL LETTER U +0056; C; 0076; # LATIN CAPITAL LETTER V +0057; C; 0077; # LATIN CAPITAL LETTER W +0058; C; 0078; # LATIN CAPITAL LETTER X +0059; C; 0079; # LATIN CAPITAL LETTER Y +005A; C; 007A; # LATIN CAPITAL LETTER Z +00B5; C; 03BC; # MICRO SIGN +00C0; C; 00E0; # LATIN CAPITAL LETTER A WITH GRAVE +00C1; C; 00E1; # LATIN CAPITAL LETTER A WITH ACUTE +00C2; C; 00E2; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX +00C3; C; 00E3; # LATIN CAPITAL LETTER A WITH TILDE +00C4; C; 00E4; # LATIN CAPITAL LETTER A WITH DIAERESIS +00C5; C; 00E5; # LATIN CAPITAL LETTER A WITH RING ABOVE +00C6; C; 00E6; # LATIN CAPITAL LETTER AE +00C7; C; 00E7; # LATIN CAPITAL LETTER C WITH CEDILLA +00C8; C; 00E8; # LATIN CAPITAL LETTER E WITH GRAVE +00C9; C; 00E9; # LATIN CAPITAL LETTER E WITH ACUTE +00CA; C; 00EA; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX +00CB; C; 00EB; # LATIN CAPITAL LETTER E WITH DIAERESIS +00CC; C; 00EC; # LATIN CAPITAL LETTER I WITH GRAVE +00CD; C; 00ED; # LATIN CAPITAL LETTER I WITH ACUTE +00CE; C; 00EE; # LATIN CAPITAL LETTER I WITH CIRCUMFLEX +00CF; C; 00EF; # LATIN CAPITAL LETTER I WITH DIAERESIS +00D0; C; 00F0; # LATIN CAPITAL LETTER ETH +00D1; C; 00F1; # LATIN CAPITAL LETTER N WITH TILDE +00D2; C; 00F2; # LATIN CAPITAL LETTER O WITH GRAVE +00D3; C; 00F3; # LATIN CAPITAL LETTER O WITH ACUTE +00D4; C; 00F4; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX +00D5; C; 00F5; # LATIN CAPITAL LETTER O WITH TILDE +00D6; C; 00F6; # LATIN CAPITAL LETTER O WITH DIAERESIS +00D8; C; 00F8; # LATIN CAPITAL LETTER O WITH STROKE +00D9; C; 00F9; # LATIN CAPITAL LETTER U WITH GRAVE +00DA; C; 00FA; # LATIN CAPITAL LETTER U WITH ACUTE +00DB; C; 00FB; # LATIN CAPITAL LETTER U WITH CIRCUMFLEX +00DC; C; 00FC; # LATIN CAPITAL LETTER U WITH DIAERESIS +00DD; C; 00FD; # LATIN CAPITAL LETTER Y WITH ACUTE +00DE; C; 00FE; # LATIN CAPITAL LETTER THORN +00DF; F; 0073 0073; # LATIN SMALL LETTER SHARP S +0100; C; 0101; # LATIN CAPITAL LETTER A WITH MACRON +0102; C; 0103; # LATIN CAPITAL LETTER A WITH BREVE +0104; C; 0105; # LATIN CAPITAL LETTER A WITH OGONEK +0106; C; 0107; # LATIN CAPITAL LETTER C WITH ACUTE +0108; C; 0109; # LATIN CAPITAL LETTER C WITH CIRCUMFLEX +010A; C; 010B; # LATIN CAPITAL LETTER C WITH DOT ABOVE +010C; C; 010D; # LATIN CAPITAL LETTER C WITH CARON +010E; C; 010F; # LATIN CAPITAL LETTER D WITH CARON +0110; C; 0111; # LATIN CAPITAL LETTER D WITH STROKE +0112; C; 0113; # LATIN CAPITAL LETTER E WITH MACRON +0114; C; 0115; # LATIN CAPITAL LETTER E WITH BREVE +0116; C; 0117; # LATIN CAPITAL LETTER E WITH DOT ABOVE +0118; C; 0119; # LATIN CAPITAL LETTER E WITH OGONEK +011A; C; 011B; # LATIN CAPITAL LETTER E WITH CARON +011C; C; 011D; # LATIN CAPITAL LETTER G WITH CIRCUMFLEX +011E; C; 011F; # LATIN CAPITAL LETTER G WITH BREVE +0120; C; 0121; # LATIN CAPITAL LETTER G WITH DOT ABOVE +0122; C; 0123; # LATIN CAPITAL LETTER G WITH CEDILLA +0124; C; 0125; # LATIN CAPITAL LETTER H WITH CIRCUMFLEX +0126; C; 0127; # LATIN CAPITAL LETTER H WITH STROKE +0128; C; 0129; # LATIN CAPITAL LETTER I WITH TILDE +012A; C; 012B; # LATIN CAPITAL LETTER I WITH MACRON +012C; C; 012D; # LATIN CAPITAL LETTER I WITH BREVE +012E; C; 012F; # LATIN CAPITAL LETTER I WITH OGONEK +0130; F; 0069 0307; # LATIN CAPITAL LETTER I WITH DOT ABOVE +0130; T; 0069; # LATIN CAPITAL LETTER I WITH DOT ABOVE +0132; C; 0133; # LATIN CAPITAL LIGATURE IJ +0134; C; 0135; # LATIN CAPITAL LETTER J WITH CIRCUMFLEX +0136; C; 0137; # LATIN CAPITAL LETTER K WITH CEDILLA +0139; C; 013A; # LATIN CAPITAL LETTER L WITH ACUTE +013B; C; 013C; # LATIN CAPITAL LETTER L WITH CEDILLA +013D; C; 013E; # LATIN CAPITAL LETTER L WITH CARON +013F; C; 0140; # LATIN CAPITAL LETTER L WITH MIDDLE DOT +0141; C; 0142; # LATIN CAPITAL LETTER L WITH STROKE +0143; C; 0144; # LATIN CAPITAL LETTER N WITH ACUTE +0145; C; 0146; # LATIN CAPITAL LETTER N WITH CEDILLA +0147; C; 0148; # LATIN CAPITAL LETTER N WITH CARON +0149; F; 02BC 006E; # LATIN SMALL LETTER N PRECEDED BY APOSTROPHE +014A; C; 014B; # LATIN CAPITAL LETTER ENG +014C; C; 014D; # LATIN CAPITAL LETTER O WITH MACRON +014E; C; 014F; # LATIN CAPITAL LETTER O WITH BREVE +0150; C; 0151; # LATIN CAPITAL LETTER O WITH DOUBLE ACUTE +0152; C; 0153; # LATIN CAPITAL LIGATURE OE +0154; C; 0155; # LATIN CAPITAL LETTER R WITH ACUTE +0156; C; 0157; # LATIN CAPITAL LETTER R WITH CEDILLA +0158; C; 0159; # LATIN CAPITAL LETTER R WITH CARON +015A; C; 015B; # LATIN CAPITAL LETTER S WITH ACUTE +015C; C; 015D; # LATIN CAPITAL LETTER S WITH CIRCUMFLEX +015E; C; 015F; # LATIN CAPITAL LETTER S WITH CEDILLA +0160; C; 0161; # LATIN CAPITAL LETTER S WITH CARON +0162; C; 0163; # LATIN CAPITAL LETTER T WITH CEDILLA +0164; C; 0165; # LATIN CAPITAL LETTER T WITH CARON +0166; C; 0167; # LATIN CAPITAL LETTER T WITH STROKE +0168; C; 0169; # LATIN CAPITAL LETTER U WITH TILDE +016A; C; 016B; # LATIN CAPITAL LETTER U WITH MACRON +016C; C; 016D; # LATIN CAPITAL LETTER U WITH BREVE +016E; C; 016F; # LATIN CAPITAL LETTER U WITH RING ABOVE +0170; C; 0171; # LATIN CAPITAL LETTER U WITH DOUBLE ACUTE +0172; C; 0173; # LATIN CAPITAL LETTER U WITH OGONEK +0174; C; 0175; # LATIN CAPITAL LETTER W WITH CIRCUMFLEX +0176; C; 0177; # LATIN CAPITAL LETTER Y WITH CIRCUMFLEX +0178; C; 00FF; # LATIN CAPITAL LETTER Y WITH DIAERESIS +0179; C; 017A; # LATIN CAPITAL LETTER Z WITH ACUTE +017B; C; 017C; # LATIN CAPITAL LETTER Z WITH DOT ABOVE +017D; C; 017E; # LATIN CAPITAL LETTER Z WITH CARON +017F; C; 0073; # LATIN SMALL LETTER LONG S +0181; C; 0253; # LATIN CAPITAL LETTER B WITH HOOK +0182; C; 0183; # LATIN CAPITAL LETTER B WITH TOPBAR +0184; C; 0185; # LATIN CAPITAL LETTER TONE SIX +0186; C; 0254; # LATIN CAPITAL LETTER OPEN O +0187; C; 0188; # LATIN CAPITAL LETTER C WITH HOOK +0189; C; 0256; # LATIN CAPITAL LETTER AFRICAN D +018A; C; 0257; # LATIN CAPITAL LETTER D WITH HOOK +018B; C; 018C; # LATIN CAPITAL LETTER D WITH TOPBAR +018E; C; 01DD; # LATIN CAPITAL LETTER REVERSED E +018F; C; 0259; # LATIN CAPITAL LETTER SCHWA +0190; C; 025B; # LATIN CAPITAL LETTER OPEN E +0191; C; 0192; # LATIN CAPITAL LETTER F WITH HOOK +0193; C; 0260; # LATIN CAPITAL LETTER G WITH HOOK +0194; C; 0263; # LATIN CAPITAL LETTER GAMMA +0196; C; 0269; # LATIN CAPITAL LETTER IOTA +0197; C; 0268; # LATIN CAPITAL LETTER I WITH STROKE +0198; C; 0199; # LATIN CAPITAL LETTER K WITH HOOK +019C; C; 026F; # LATIN CAPITAL LETTER TURNED M +019D; C; 0272; # LATIN CAPITAL LETTER N WITH LEFT HOOK +019F; C; 0275; # LATIN CAPITAL LETTER O WITH MIDDLE TILDE +01A0; C; 01A1; # LATIN CAPITAL LETTER O WITH HORN +01A2; C; 01A3; # LATIN CAPITAL LETTER OI +01A4; C; 01A5; # LATIN CAPITAL LETTER P WITH HOOK +01A6; C; 0280; # LATIN LETTER YR +01A7; C; 01A8; # LATIN CAPITAL LETTER TONE TWO +01A9; C; 0283; # LATIN CAPITAL LETTER ESH +01AC; C; 01AD; # LATIN CAPITAL LETTER T WITH HOOK +01AE; C; 0288; # LATIN CAPITAL LETTER T WITH RETROFLEX HOOK +01AF; C; 01B0; # LATIN CAPITAL LETTER U WITH HORN +01B1; C; 028A; # LATIN CAPITAL LETTER UPSILON +01B2; C; 028B; # LATIN CAPITAL LETTER V WITH HOOK +01B3; C; 01B4; # LATIN CAPITAL LETTER Y WITH HOOK +01B5; C; 01B6; # LATIN CAPITAL LETTER Z WITH STROKE +01B7; C; 0292; # LATIN CAPITAL LETTER EZH +01B8; C; 01B9; # LATIN CAPITAL LETTER EZH REVERSED +01BC; C; 01BD; # LATIN CAPITAL LETTER TONE FIVE +01C4; C; 01C6; # LATIN CAPITAL LETTER DZ WITH CARON +01C5; C; 01C6; # LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON +01C7; C; 01C9; # LATIN CAPITAL LETTER LJ +01C8; C; 01C9; # LATIN CAPITAL LETTER L WITH SMALL LETTER J +01CA; C; 01CC; # LATIN CAPITAL LETTER NJ +01CB; C; 01CC; # LATIN CAPITAL LETTER N WITH SMALL LETTER J +01CD; C; 01CE; # LATIN CAPITAL LETTER A WITH CARON +01CF; C; 01D0; # LATIN CAPITAL LETTER I WITH CARON +01D1; C; 01D2; # LATIN CAPITAL LETTER O WITH CARON +01D3; C; 01D4; # LATIN CAPITAL LETTER U WITH CARON +01D5; C; 01D6; # LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON +01D7; C; 01D8; # LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE +01D9; C; 01DA; # LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON +01DB; C; 01DC; # LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE +01DE; C; 01DF; # LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON +01E0; C; 01E1; # LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON +01E2; C; 01E3; # LATIN CAPITAL LETTER AE WITH MACRON +01E4; C; 01E5; # LATIN CAPITAL LETTER G WITH STROKE +01E6; C; 01E7; # LATIN CAPITAL LETTER G WITH CARON +01E8; C; 01E9; # LATIN CAPITAL LETTER K WITH CARON +01EA; C; 01EB; # LATIN CAPITAL LETTER O WITH OGONEK +01EC; C; 01ED; # LATIN CAPITAL LETTER O WITH OGONEK AND MACRON +01EE; C; 01EF; # LATIN CAPITAL LETTER EZH WITH CARON +01F0; F; 006A 030C; # LATIN SMALL LETTER J WITH CARON +01F1; C; 01F3; # LATIN CAPITAL LETTER DZ +01F2; C; 01F3; # LATIN CAPITAL LETTER D WITH SMALL LETTER Z +01F4; C; 01F5; # LATIN CAPITAL LETTER G WITH ACUTE +01F6; C; 0195; # LATIN CAPITAL LETTER HWAIR +01F7; C; 01BF; # LATIN CAPITAL LETTER WYNN +01F8; C; 01F9; # LATIN CAPITAL LETTER N WITH GRAVE +01FA; C; 01FB; # LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE +01FC; C; 01FD; # LATIN CAPITAL LETTER AE WITH ACUTE +01FE; C; 01FF; # LATIN CAPITAL LETTER O WITH STROKE AND ACUTE +0200; C; 0201; # LATIN CAPITAL LETTER A WITH DOUBLE GRAVE +0202; C; 0203; # LATIN CAPITAL LETTER A WITH INVERTED BREVE +0204; C; 0205; # LATIN CAPITAL LETTER E WITH DOUBLE GRAVE +0206; C; 0207; # LATIN CAPITAL LETTER E WITH INVERTED BREVE +0208; C; 0209; # LATIN CAPITAL LETTER I WITH DOUBLE GRAVE +020A; C; 020B; # LATIN CAPITAL LETTER I WITH INVERTED BREVE +020C; C; 020D; # LATIN CAPITAL LETTER O WITH DOUBLE GRAVE +020E; C; 020F; # LATIN CAPITAL LETTER O WITH INVERTED BREVE +0210; C; 0211; # LATIN CAPITAL LETTER R WITH DOUBLE GRAVE +0212; C; 0213; # LATIN CAPITAL LETTER R WITH INVERTED BREVE +0214; C; 0215; # LATIN CAPITAL LETTER U WITH DOUBLE GRAVE +0216; C; 0217; # LATIN CAPITAL LETTER U WITH INVERTED BREVE +0218; C; 0219; # LATIN CAPITAL LETTER S WITH COMMA BELOW +021A; C; 021B; # LATIN CAPITAL LETTER T WITH COMMA BELOW +021C; C; 021D; # LATIN CAPITAL LETTER YOGH +021E; C; 021F; # LATIN CAPITAL LETTER H WITH CARON +0220; C; 019E; # LATIN CAPITAL LETTER N WITH LONG RIGHT LEG +0222; C; 0223; # LATIN CAPITAL LETTER OU +0224; C; 0225; # LATIN CAPITAL LETTER Z WITH HOOK +0226; C; 0227; # LATIN CAPITAL LETTER A WITH DOT ABOVE +0228; C; 0229; # LATIN CAPITAL LETTER E WITH CEDILLA +022A; C; 022B; # LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON +022C; C; 022D; # LATIN CAPITAL LETTER O WITH TILDE AND MACRON +022E; C; 022F; # LATIN CAPITAL LETTER O WITH DOT ABOVE +0230; C; 0231; # LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON +0232; C; 0233; # LATIN CAPITAL LETTER Y WITH MACRON +023A; C; 2C65; # LATIN CAPITAL LETTER A WITH STROKE +023B; C; 023C; # LATIN CAPITAL LETTER C WITH STROKE +023D; C; 019A; # LATIN CAPITAL LETTER L WITH BAR +023E; C; 2C66; # LATIN CAPITAL LETTER T WITH DIAGONAL STROKE +0241; C; 0242; # LATIN CAPITAL LETTER GLOTTAL STOP +0243; C; 0180; # LATIN CAPITAL LETTER B WITH STROKE +0244; C; 0289; # LATIN CAPITAL LETTER U BAR +0245; C; 028C; # LATIN CAPITAL LETTER TURNED V +0246; C; 0247; # LATIN CAPITAL LETTER E WITH STROKE +0248; C; 0249; # LATIN CAPITAL LETTER J WITH STROKE +024A; C; 024B; # LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL +024C; C; 024D; # LATIN CAPITAL LETTER R WITH STROKE +024E; C; 024F; # LATIN CAPITAL LETTER Y WITH STROKE +0345; C; 03B9; # COMBINING GREEK YPOGEGRAMMENI +0370; C; 0371; # GREEK CAPITAL LETTER HETA +0372; C; 0373; # GREEK CAPITAL LETTER ARCHAIC SAMPI +0376; C; 0377; # GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA +037F; C; 03F3; # GREEK CAPITAL LETTER YOT +0386; C; 03AC; # GREEK CAPITAL LETTER ALPHA WITH TONOS +0388; C; 03AD; # GREEK CAPITAL LETTER EPSILON WITH TONOS +0389; C; 03AE; # GREEK CAPITAL LETTER ETA WITH TONOS +038A; C; 03AF; # GREEK CAPITAL LETTER IOTA WITH TONOS +038C; C; 03CC; # GREEK CAPITAL LETTER OMICRON WITH TONOS +038E; C; 03CD; # GREEK CAPITAL LETTER UPSILON WITH TONOS +038F; C; 03CE; # GREEK CAPITAL LETTER OMEGA WITH TONOS +0390; F; 03B9 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS +0391; C; 03B1; # GREEK CAPITAL LETTER ALPHA +0392; C; 03B2; # GREEK CAPITAL LETTER BETA +0393; C; 03B3; # GREEK CAPITAL LETTER GAMMA +0394; C; 03B4; # GREEK CAPITAL LETTER DELTA +0395; C; 03B5; # GREEK CAPITAL LETTER EPSILON +0396; C; 03B6; # GREEK CAPITAL LETTER ZETA +0397; C; 03B7; # GREEK CAPITAL LETTER ETA +0398; C; 03B8; # GREEK CAPITAL LETTER THETA +0399; C; 03B9; # GREEK CAPITAL LETTER IOTA +039A; C; 03BA; # GREEK CAPITAL LETTER KAPPA +039B; C; 03BB; # GREEK CAPITAL LETTER LAMDA +039C; C; 03BC; # GREEK CAPITAL LETTER MU +039D; C; 03BD; # GREEK CAPITAL LETTER NU +039E; C; 03BE; # GREEK CAPITAL LETTER XI +039F; C; 03BF; # GREEK CAPITAL LETTER OMICRON +03A0; C; 03C0; # GREEK CAPITAL LETTER PI +03A1; C; 03C1; # GREEK CAPITAL LETTER RHO +03A3; C; 03C3; # GREEK CAPITAL LETTER SIGMA +03A4; C; 03C4; # GREEK CAPITAL LETTER TAU +03A5; C; 03C5; # GREEK CAPITAL LETTER UPSILON +03A6; C; 03C6; # GREEK CAPITAL LETTER PHI +03A7; C; 03C7; # GREEK CAPITAL LETTER CHI +03A8; C; 03C8; # GREEK CAPITAL LETTER PSI +03A9; C; 03C9; # GREEK CAPITAL LETTER OMEGA +03AA; C; 03CA; # GREEK CAPITAL LETTER IOTA WITH DIALYTIKA +03AB; C; 03CB; # GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA +03B0; F; 03C5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS +03C2; C; 03C3; # GREEK SMALL LETTER FINAL SIGMA +03CF; C; 03D7; # GREEK CAPITAL KAI SYMBOL +03D0; C; 03B2; # GREEK BETA SYMBOL +03D1; C; 03B8; # GREEK THETA SYMBOL +03D5; C; 03C6; # GREEK PHI SYMBOL +03D6; C; 03C0; # GREEK PI SYMBOL +03D8; C; 03D9; # GREEK LETTER ARCHAIC KOPPA +03DA; C; 03DB; # GREEK LETTER STIGMA +03DC; C; 03DD; # GREEK LETTER DIGAMMA +03DE; C; 03DF; # GREEK LETTER KOPPA +03E0; C; 03E1; # GREEK LETTER SAMPI +03E2; C; 03E3; # COPTIC CAPITAL LETTER SHEI +03E4; C; 03E5; # COPTIC CAPITAL LETTER FEI +03E6; C; 03E7; # COPTIC CAPITAL LETTER KHEI +03E8; C; 03E9; # COPTIC CAPITAL LETTER HORI +03EA; C; 03EB; # COPTIC CAPITAL LETTER GANGIA +03EC; C; 03ED; # COPTIC CAPITAL LETTER SHIMA +03EE; C; 03EF; # COPTIC CAPITAL LETTER DEI +03F0; C; 03BA; # GREEK KAPPA SYMBOL +03F1; C; 03C1; # GREEK RHO SYMBOL +03F4; C; 03B8; # GREEK CAPITAL THETA SYMBOL +03F5; C; 03B5; # GREEK LUNATE EPSILON SYMBOL +03F7; C; 03F8; # GREEK CAPITAL LETTER SHO +03F9; C; 03F2; # GREEK CAPITAL LUNATE SIGMA SYMBOL +03FA; C; 03FB; # GREEK CAPITAL LETTER SAN +03FD; C; 037B; # GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL +03FE; C; 037C; # GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL +03FF; C; 037D; # GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL +0400; C; 0450; # CYRILLIC CAPITAL LETTER IE WITH GRAVE +0401; C; 0451; # CYRILLIC CAPITAL LETTER IO +0402; C; 0452; # CYRILLIC CAPITAL LETTER DJE +0403; C; 0453; # CYRILLIC CAPITAL LETTER GJE +0404; C; 0454; # CYRILLIC CAPITAL LETTER UKRAINIAN IE +0405; C; 0455; # CYRILLIC CAPITAL LETTER DZE +0406; C; 0456; # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I +0407; C; 0457; # CYRILLIC CAPITAL LETTER YI +0408; C; 0458; # CYRILLIC CAPITAL LETTER JE +0409; C; 0459; # CYRILLIC CAPITAL LETTER LJE +040A; C; 045A; # CYRILLIC CAPITAL LETTER NJE +040B; C; 045B; # CYRILLIC CAPITAL LETTER TSHE +040C; C; 045C; # CYRILLIC CAPITAL LETTER KJE +040D; C; 045D; # CYRILLIC CAPITAL LETTER I WITH GRAVE +040E; C; 045E; # CYRILLIC CAPITAL LETTER SHORT U +040F; C; 045F; # CYRILLIC CAPITAL LETTER DZHE +0410; C; 0430; # CYRILLIC CAPITAL LETTER A +0411; C; 0431; # CYRILLIC CAPITAL LETTER BE +0412; C; 0432; # CYRILLIC CAPITAL LETTER VE +0413; C; 0433; # CYRILLIC CAPITAL LETTER GHE +0414; C; 0434; # CYRILLIC CAPITAL LETTER DE +0415; C; 0435; # CYRILLIC CAPITAL LETTER IE +0416; C; 0436; # CYRILLIC CAPITAL LETTER ZHE +0417; C; 0437; # CYRILLIC CAPITAL LETTER ZE +0418; C; 0438; # CYRILLIC CAPITAL LETTER I +0419; C; 0439; # CYRILLIC CAPITAL LETTER SHORT I +041A; C; 043A; # CYRILLIC CAPITAL LETTER KA +041B; C; 043B; # CYRILLIC CAPITAL LETTER EL +041C; C; 043C; # CYRILLIC CAPITAL LETTER EM +041D; C; 043D; # CYRILLIC CAPITAL LETTER EN +041E; C; 043E; # CYRILLIC CAPITAL LETTER O +041F; C; 043F; # CYRILLIC CAPITAL LETTER PE +0420; C; 0440; # CYRILLIC CAPITAL LETTER ER +0421; C; 0441; # CYRILLIC CAPITAL LETTER ES +0422; C; 0442; # CYRILLIC CAPITAL LETTER TE +0423; C; 0443; # CYRILLIC CAPITAL LETTER U +0424; C; 0444; # CYRILLIC CAPITAL LETTER EF +0425; C; 0445; # CYRILLIC CAPITAL LETTER HA +0426; C; 0446; # CYRILLIC CAPITAL LETTER TSE +0427; C; 0447; # CYRILLIC CAPITAL LETTER CHE +0428; C; 0448; # CYRILLIC CAPITAL LETTER SHA +0429; C; 0449; # CYRILLIC CAPITAL LETTER SHCHA +042A; C; 044A; # CYRILLIC CAPITAL LETTER HARD SIGN +042B; C; 044B; # CYRILLIC CAPITAL LETTER YERU +042C; C; 044C; # CYRILLIC CAPITAL LETTER SOFT SIGN +042D; C; 044D; # CYRILLIC CAPITAL LETTER E +042E; C; 044E; # CYRILLIC CAPITAL LETTER YU +042F; C; 044F; # CYRILLIC CAPITAL LETTER YA +0460; C; 0461; # CYRILLIC CAPITAL LETTER OMEGA +0462; C; 0463; # CYRILLIC CAPITAL LETTER YAT +0464; C; 0465; # CYRILLIC CAPITAL LETTER IOTIFIED E +0466; C; 0467; # CYRILLIC CAPITAL LETTER LITTLE YUS +0468; C; 0469; # CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS +046A; C; 046B; # CYRILLIC CAPITAL LETTER BIG YUS +046C; C; 046D; # CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS +046E; C; 046F; # CYRILLIC CAPITAL LETTER KSI +0470; C; 0471; # CYRILLIC CAPITAL LETTER PSI +0472; C; 0473; # CYRILLIC CAPITAL LETTER FITA +0474; C; 0475; # CYRILLIC CAPITAL LETTER IZHITSA +0476; C; 0477; # CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT +0478; C; 0479; # CYRILLIC CAPITAL LETTER UK +047A; C; 047B; # CYRILLIC CAPITAL LETTER ROUND OMEGA +047C; C; 047D; # CYRILLIC CAPITAL LETTER OMEGA WITH TITLO +047E; C; 047F; # CYRILLIC CAPITAL LETTER OT +0480; C; 0481; # CYRILLIC CAPITAL LETTER KOPPA +048A; C; 048B; # CYRILLIC CAPITAL LETTER SHORT I WITH TAIL +048C; C; 048D; # CYRILLIC CAPITAL LETTER SEMISOFT SIGN +048E; C; 048F; # CYRILLIC CAPITAL LETTER ER WITH TICK +0490; C; 0491; # CYRILLIC CAPITAL LETTER GHE WITH UPTURN +0492; C; 0493; # CYRILLIC CAPITAL LETTER GHE WITH STROKE +0494; C; 0495; # CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK +0496; C; 0497; # CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER +0498; C; 0499; # CYRILLIC CAPITAL LETTER ZE WITH DESCENDER +049A; C; 049B; # CYRILLIC CAPITAL LETTER KA WITH DESCENDER +049C; C; 049D; # CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE +049E; C; 049F; # CYRILLIC CAPITAL LETTER KA WITH STROKE +04A0; C; 04A1; # CYRILLIC CAPITAL LETTER BASHKIR KA +04A2; C; 04A3; # CYRILLIC CAPITAL LETTER EN WITH DESCENDER +04A4; C; 04A5; # CYRILLIC CAPITAL LIGATURE EN GHE +04A6; C; 04A7; # CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK +04A8; C; 04A9; # CYRILLIC CAPITAL LETTER ABKHASIAN HA +04AA; C; 04AB; # CYRILLIC CAPITAL LETTER ES WITH DESCENDER +04AC; C; 04AD; # CYRILLIC CAPITAL LETTER TE WITH DESCENDER +04AE; C; 04AF; # CYRILLIC CAPITAL LETTER STRAIGHT U +04B0; C; 04B1; # CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE +04B2; C; 04B3; # CYRILLIC CAPITAL LETTER HA WITH DESCENDER +04B4; C; 04B5; # CYRILLIC CAPITAL LIGATURE TE TSE +04B6; C; 04B7; # CYRILLIC CAPITAL LETTER CHE WITH DESCENDER +04B8; C; 04B9; # CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE +04BA; C; 04BB; # CYRILLIC CAPITAL LETTER SHHA +04BC; C; 04BD; # CYRILLIC CAPITAL LETTER ABKHASIAN CHE +04BE; C; 04BF; # CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER +04C0; C; 04CF; # CYRILLIC LETTER PALOCHKA +04C1; C; 04C2; # CYRILLIC CAPITAL LETTER ZHE WITH BREVE +04C3; C; 04C4; # CYRILLIC CAPITAL LETTER KA WITH HOOK +04C5; C; 04C6; # CYRILLIC CAPITAL LETTER EL WITH TAIL +04C7; C; 04C8; # CYRILLIC CAPITAL LETTER EN WITH HOOK +04C9; C; 04CA; # CYRILLIC CAPITAL LETTER EN WITH TAIL +04CB; C; 04CC; # CYRILLIC CAPITAL LETTER KHAKASSIAN CHE +04CD; C; 04CE; # CYRILLIC CAPITAL LETTER EM WITH TAIL +04D0; C; 04D1; # CYRILLIC CAPITAL LETTER A WITH BREVE +04D2; C; 04D3; # CYRILLIC CAPITAL LETTER A WITH DIAERESIS +04D4; C; 04D5; # CYRILLIC CAPITAL LIGATURE A IE +04D6; C; 04D7; # CYRILLIC CAPITAL LETTER IE WITH BREVE +04D8; C; 04D9; # CYRILLIC CAPITAL LETTER SCHWA +04DA; C; 04DB; # CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS +04DC; C; 04DD; # CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS +04DE; C; 04DF; # CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS +04E0; C; 04E1; # CYRILLIC CAPITAL LETTER ABKHASIAN DZE +04E2; C; 04E3; # CYRILLIC CAPITAL LETTER I WITH MACRON +04E4; C; 04E5; # CYRILLIC CAPITAL LETTER I WITH DIAERESIS +04E6; C; 04E7; # CYRILLIC CAPITAL LETTER O WITH DIAERESIS +04E8; C; 04E9; # CYRILLIC CAPITAL LETTER BARRED O +04EA; C; 04EB; # CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS +04EC; C; 04ED; # CYRILLIC CAPITAL LETTER E WITH DIAERESIS +04EE; C; 04EF; # CYRILLIC CAPITAL LETTER U WITH MACRON +04F0; C; 04F1; # CYRILLIC CAPITAL LETTER U WITH DIAERESIS +04F2; C; 04F3; # CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE +04F4; C; 04F5; # CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS +04F6; C; 04F7; # CYRILLIC CAPITAL LETTER GHE WITH DESCENDER +04F8; C; 04F9; # CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS +04FA; C; 04FB; # CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK +04FC; C; 04FD; # CYRILLIC CAPITAL LETTER HA WITH HOOK +04FE; C; 04FF; # CYRILLIC CAPITAL LETTER HA WITH STROKE +0500; C; 0501; # CYRILLIC CAPITAL LETTER KOMI DE +0502; C; 0503; # CYRILLIC CAPITAL LETTER KOMI DJE +0504; C; 0505; # CYRILLIC CAPITAL LETTER KOMI ZJE +0506; C; 0507; # CYRILLIC CAPITAL LETTER KOMI DZJE +0508; C; 0509; # CYRILLIC CAPITAL LETTER KOMI LJE +050A; C; 050B; # CYRILLIC CAPITAL LETTER KOMI NJE +050C; C; 050D; # CYRILLIC CAPITAL LETTER KOMI SJE +050E; C; 050F; # CYRILLIC CAPITAL LETTER KOMI TJE +0510; C; 0511; # CYRILLIC CAPITAL LETTER REVERSED ZE +0512; C; 0513; # CYRILLIC CAPITAL LETTER EL WITH HOOK +0514; C; 0515; # CYRILLIC CAPITAL LETTER LHA +0516; C; 0517; # CYRILLIC CAPITAL LETTER RHA +0518; C; 0519; # CYRILLIC CAPITAL LETTER YAE +051A; C; 051B; # CYRILLIC CAPITAL LETTER QA +051C; C; 051D; # CYRILLIC CAPITAL LETTER WE +051E; C; 051F; # CYRILLIC CAPITAL LETTER ALEUT KA +0520; C; 0521; # CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK +0522; C; 0523; # CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK +0524; C; 0525; # CYRILLIC CAPITAL LETTER PE WITH DESCENDER +0526; C; 0527; # CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER +0528; C; 0529; # CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK +052A; C; 052B; # CYRILLIC CAPITAL LETTER DZZHE +052C; C; 052D; # CYRILLIC CAPITAL LETTER DCHE +052E; C; 052F; # CYRILLIC CAPITAL LETTER EL WITH DESCENDER +0531; C; 0561; # ARMENIAN CAPITAL LETTER AYB +0532; C; 0562; # ARMENIAN CAPITAL LETTER BEN +0533; C; 0563; # ARMENIAN CAPITAL LETTER GIM +0534; C; 0564; # ARMENIAN CAPITAL LETTER DA +0535; C; 0565; # ARMENIAN CAPITAL LETTER ECH +0536; C; 0566; # ARMENIAN CAPITAL LETTER ZA +0537; C; 0567; # ARMENIAN CAPITAL LETTER EH +0538; C; 0568; # ARMENIAN CAPITAL LETTER ET +0539; C; 0569; # ARMENIAN CAPITAL LETTER TO +053A; C; 056A; # ARMENIAN CAPITAL LETTER ZHE +053B; C; 056B; # ARMENIAN CAPITAL LETTER INI +053C; C; 056C; # ARMENIAN CAPITAL LETTER LIWN +053D; C; 056D; # ARMENIAN CAPITAL LETTER XEH +053E; C; 056E; # ARMENIAN CAPITAL LETTER CA +053F; C; 056F; # ARMENIAN CAPITAL LETTER KEN +0540; C; 0570; # ARMENIAN CAPITAL LETTER HO +0541; C; 0571; # ARMENIAN CAPITAL LETTER JA +0542; C; 0572; # ARMENIAN CAPITAL LETTER GHAD +0543; C; 0573; # ARMENIAN CAPITAL LETTER CHEH +0544; C; 0574; # ARMENIAN CAPITAL LETTER MEN +0545; C; 0575; # ARMENIAN CAPITAL LETTER YI +0546; C; 0576; # ARMENIAN CAPITAL LETTER NOW +0547; C; 0577; # ARMENIAN CAPITAL LETTER SHA +0548; C; 0578; # ARMENIAN CAPITAL LETTER VO +0549; C; 0579; # ARMENIAN CAPITAL LETTER CHA +054A; C; 057A; # ARMENIAN CAPITAL LETTER PEH +054B; C; 057B; # ARMENIAN CAPITAL LETTER JHEH +054C; C; 057C; # ARMENIAN CAPITAL LETTER RA +054D; C; 057D; # ARMENIAN CAPITAL LETTER SEH +054E; C; 057E; # ARMENIAN CAPITAL LETTER VEW +054F; C; 057F; # ARMENIAN CAPITAL LETTER TIWN +0550; C; 0580; # ARMENIAN CAPITAL LETTER REH +0551; C; 0581; # ARMENIAN CAPITAL LETTER CO +0552; C; 0582; # ARMENIAN CAPITAL LETTER YIWN +0553; C; 0583; # ARMENIAN CAPITAL LETTER PIWR +0554; C; 0584; # ARMENIAN CAPITAL LETTER KEH +0555; C; 0585; # ARMENIAN CAPITAL LETTER OH +0556; C; 0586; # ARMENIAN CAPITAL LETTER FEH +0587; F; 0565 0582; # ARMENIAN SMALL LIGATURE ECH YIWN +10A0; C; 2D00; # GEORGIAN CAPITAL LETTER AN +10A1; C; 2D01; # GEORGIAN CAPITAL LETTER BAN +10A2; C; 2D02; # GEORGIAN CAPITAL LETTER GAN +10A3; C; 2D03; # GEORGIAN CAPITAL LETTER DON +10A4; C; 2D04; # GEORGIAN CAPITAL LETTER EN +10A5; C; 2D05; # GEORGIAN CAPITAL LETTER VIN +10A6; C; 2D06; # GEORGIAN CAPITAL LETTER ZEN +10A7; C; 2D07; # GEORGIAN CAPITAL LETTER TAN +10A8; C; 2D08; # GEORGIAN CAPITAL LETTER IN +10A9; C; 2D09; # GEORGIAN CAPITAL LETTER KAN +10AA; C; 2D0A; # GEORGIAN CAPITAL LETTER LAS +10AB; C; 2D0B; # GEORGIAN CAPITAL LETTER MAN +10AC; C; 2D0C; # GEORGIAN CAPITAL LETTER NAR +10AD; C; 2D0D; # GEORGIAN CAPITAL LETTER ON +10AE; C; 2D0E; # GEORGIAN CAPITAL LETTER PAR +10AF; C; 2D0F; # GEORGIAN CAPITAL LETTER ZHAR +10B0; C; 2D10; # GEORGIAN CAPITAL LETTER RAE +10B1; C; 2D11; # GEORGIAN CAPITAL LETTER SAN +10B2; C; 2D12; # GEORGIAN CAPITAL LETTER TAR +10B3; C; 2D13; # GEORGIAN CAPITAL LETTER UN +10B4; C; 2D14; # GEORGIAN CAPITAL LETTER PHAR +10B5; C; 2D15; # GEORGIAN CAPITAL LETTER KHAR +10B6; C; 2D16; # GEORGIAN CAPITAL LETTER GHAN +10B7; C; 2D17; # GEORGIAN CAPITAL LETTER QAR +10B8; C; 2D18; # GEORGIAN CAPITAL LETTER SHIN +10B9; C; 2D19; # GEORGIAN CAPITAL LETTER CHIN +10BA; C; 2D1A; # GEORGIAN CAPITAL LETTER CAN +10BB; C; 2D1B; # GEORGIAN CAPITAL LETTER JIL +10BC; C; 2D1C; # GEORGIAN CAPITAL LETTER CIL +10BD; C; 2D1D; # GEORGIAN CAPITAL LETTER CHAR +10BE; C; 2D1E; # GEORGIAN CAPITAL LETTER XAN +10BF; C; 2D1F; # GEORGIAN CAPITAL LETTER JHAN +10C0; C; 2D20; # GEORGIAN CAPITAL LETTER HAE +10C1; C; 2D21; # GEORGIAN CAPITAL LETTER HE +10C2; C; 2D22; # GEORGIAN CAPITAL LETTER HIE +10C3; C; 2D23; # GEORGIAN CAPITAL LETTER WE +10C4; C; 2D24; # GEORGIAN CAPITAL LETTER HAR +10C5; C; 2D25; # GEORGIAN CAPITAL LETTER HOE +10C7; C; 2D27; # GEORGIAN CAPITAL LETTER YN +10CD; C; 2D2D; # GEORGIAN CAPITAL LETTER AEN +13F8; C; 13F0; # CHEROKEE SMALL LETTER YE +13F9; C; 13F1; # CHEROKEE SMALL LETTER YI +13FA; C; 13F2; # CHEROKEE SMALL LETTER YO +13FB; C; 13F3; # CHEROKEE SMALL LETTER YU +13FC; C; 13F4; # CHEROKEE SMALL LETTER YV +13FD; C; 13F5; # CHEROKEE SMALL LETTER MV +1C80; C; 0432; # CYRILLIC SMALL LETTER ROUNDED VE +1C81; C; 0434; # CYRILLIC SMALL LETTER LONG-LEGGED DE +1C82; C; 043E; # CYRILLIC SMALL LETTER NARROW O +1C83; C; 0441; # CYRILLIC SMALL LETTER WIDE ES +1C84; C; 0442; # CYRILLIC SMALL LETTER TALL TE +1C85; C; 0442; # CYRILLIC SMALL LETTER THREE-LEGGED TE +1C86; C; 044A; # CYRILLIC SMALL LETTER TALL HARD SIGN +1C87; C; 0463; # CYRILLIC SMALL LETTER TALL YAT +1C88; C; A64B; # CYRILLIC SMALL LETTER UNBLENDED UK +1C89; C; 1C8A; # CYRILLIC CAPITAL LETTER TJE +1C90; C; 10D0; # GEORGIAN MTAVRULI CAPITAL LETTER AN +1C91; C; 10D1; # GEORGIAN MTAVRULI CAPITAL LETTER BAN +1C92; C; 10D2; # GEORGIAN MTAVRULI CAPITAL LETTER GAN +1C93; C; 10D3; # GEORGIAN MTAVRULI CAPITAL LETTER DON +1C94; C; 10D4; # GEORGIAN MTAVRULI CAPITAL LETTER EN +1C95; C; 10D5; # GEORGIAN MTAVRULI CAPITAL LETTER VIN +1C96; C; 10D6; # GEORGIAN MTAVRULI CAPITAL LETTER ZEN +1C97; C; 10D7; # GEORGIAN MTAVRULI CAPITAL LETTER TAN +1C98; C; 10D8; # GEORGIAN MTAVRULI CAPITAL LETTER IN +1C99; C; 10D9; # GEORGIAN MTAVRULI CAPITAL LETTER KAN +1C9A; C; 10DA; # GEORGIAN MTAVRULI CAPITAL LETTER LAS +1C9B; C; 10DB; # GEORGIAN MTAVRULI CAPITAL LETTER MAN +1C9C; C; 10DC; # GEORGIAN MTAVRULI CAPITAL LETTER NAR +1C9D; C; 10DD; # GEORGIAN MTAVRULI CAPITAL LETTER ON +1C9E; C; 10DE; # GEORGIAN MTAVRULI CAPITAL LETTER PAR +1C9F; C; 10DF; # GEORGIAN MTAVRULI CAPITAL LETTER ZHAR +1CA0; C; 10E0; # GEORGIAN MTAVRULI CAPITAL LETTER RAE +1CA1; C; 10E1; # GEORGIAN MTAVRULI CAPITAL LETTER SAN +1CA2; C; 10E2; # GEORGIAN MTAVRULI CAPITAL LETTER TAR +1CA3; C; 10E3; # GEORGIAN MTAVRULI CAPITAL LETTER UN +1CA4; C; 10E4; # GEORGIAN MTAVRULI CAPITAL LETTER PHAR +1CA5; C; 10E5; # GEORGIAN MTAVRULI CAPITAL LETTER KHAR +1CA6; C; 10E6; # GEORGIAN MTAVRULI CAPITAL LETTER GHAN +1CA7; C; 10E7; # GEORGIAN MTAVRULI CAPITAL LETTER QAR +1CA8; C; 10E8; # GEORGIAN MTAVRULI CAPITAL LETTER SHIN +1CA9; C; 10E9; # GEORGIAN MTAVRULI CAPITAL LETTER CHIN +1CAA; C; 10EA; # GEORGIAN MTAVRULI CAPITAL LETTER CAN +1CAB; C; 10EB; # GEORGIAN MTAVRULI CAPITAL LETTER JIL +1CAC; C; 10EC; # GEORGIAN MTAVRULI CAPITAL LETTER CIL +1CAD; C; 10ED; # GEORGIAN MTAVRULI CAPITAL LETTER CHAR +1CAE; C; 10EE; # GEORGIAN MTAVRULI CAPITAL LETTER XAN +1CAF; C; 10EF; # GEORGIAN MTAVRULI CAPITAL LETTER JHAN +1CB0; C; 10F0; # GEORGIAN MTAVRULI CAPITAL LETTER HAE +1CB1; C; 10F1; # GEORGIAN MTAVRULI CAPITAL LETTER HE +1CB2; C; 10F2; # GEORGIAN MTAVRULI CAPITAL LETTER HIE +1CB3; C; 10F3; # GEORGIAN MTAVRULI CAPITAL LETTER WE +1CB4; C; 10F4; # GEORGIAN MTAVRULI CAPITAL LETTER HAR +1CB5; C; 10F5; # GEORGIAN MTAVRULI CAPITAL LETTER HOE +1CB6; C; 10F6; # GEORGIAN MTAVRULI CAPITAL LETTER FI +1CB7; C; 10F7; # GEORGIAN MTAVRULI CAPITAL LETTER YN +1CB8; C; 10F8; # GEORGIAN MTAVRULI CAPITAL LETTER ELIFI +1CB9; C; 10F9; # GEORGIAN MTAVRULI CAPITAL LETTER TURNED GAN +1CBA; C; 10FA; # GEORGIAN MTAVRULI CAPITAL LETTER AIN +1CBD; C; 10FD; # GEORGIAN MTAVRULI CAPITAL LETTER AEN +1CBE; C; 10FE; # GEORGIAN MTAVRULI CAPITAL LETTER HARD SIGN +1CBF; C; 10FF; # GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN +1E00; C; 1E01; # LATIN CAPITAL LETTER A WITH RING BELOW +1E02; C; 1E03; # LATIN CAPITAL LETTER B WITH DOT ABOVE +1E04; C; 1E05; # LATIN CAPITAL LETTER B WITH DOT BELOW +1E06; C; 1E07; # LATIN CAPITAL LETTER B WITH LINE BELOW +1E08; C; 1E09; # LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE +1E0A; C; 1E0B; # LATIN CAPITAL LETTER D WITH DOT ABOVE +1E0C; C; 1E0D; # LATIN CAPITAL LETTER D WITH DOT BELOW +1E0E; C; 1E0F; # LATIN CAPITAL LETTER D WITH LINE BELOW +1E10; C; 1E11; # LATIN CAPITAL LETTER D WITH CEDILLA +1E12; C; 1E13; # LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW +1E14; C; 1E15; # LATIN CAPITAL LETTER E WITH MACRON AND GRAVE +1E16; C; 1E17; # LATIN CAPITAL LETTER E WITH MACRON AND ACUTE +1E18; C; 1E19; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW +1E1A; C; 1E1B; # LATIN CAPITAL LETTER E WITH TILDE BELOW +1E1C; C; 1E1D; # LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE +1E1E; C; 1E1F; # LATIN CAPITAL LETTER F WITH DOT ABOVE +1E20; C; 1E21; # LATIN CAPITAL LETTER G WITH MACRON +1E22; C; 1E23; # LATIN CAPITAL LETTER H WITH DOT ABOVE +1E24; C; 1E25; # LATIN CAPITAL LETTER H WITH DOT BELOW +1E26; C; 1E27; # LATIN CAPITAL LETTER H WITH DIAERESIS +1E28; C; 1E29; # LATIN CAPITAL LETTER H WITH CEDILLA +1E2A; C; 1E2B; # LATIN CAPITAL LETTER H WITH BREVE BELOW +1E2C; C; 1E2D; # LATIN CAPITAL LETTER I WITH TILDE BELOW +1E2E; C; 1E2F; # LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE +1E30; C; 1E31; # LATIN CAPITAL LETTER K WITH ACUTE +1E32; C; 1E33; # LATIN CAPITAL LETTER K WITH DOT BELOW +1E34; C; 1E35; # LATIN CAPITAL LETTER K WITH LINE BELOW +1E36; C; 1E37; # LATIN CAPITAL LETTER L WITH DOT BELOW +1E38; C; 1E39; # LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON +1E3A; C; 1E3B; # LATIN CAPITAL LETTER L WITH LINE BELOW +1E3C; C; 1E3D; # LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW +1E3E; C; 1E3F; # LATIN CAPITAL LETTER M WITH ACUTE +1E40; C; 1E41; # LATIN CAPITAL LETTER M WITH DOT ABOVE +1E42; C; 1E43; # LATIN CAPITAL LETTER M WITH DOT BELOW +1E44; C; 1E45; # LATIN CAPITAL LETTER N WITH DOT ABOVE +1E46; C; 1E47; # LATIN CAPITAL LETTER N WITH DOT BELOW +1E48; C; 1E49; # LATIN CAPITAL LETTER N WITH LINE BELOW +1E4A; C; 1E4B; # LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW +1E4C; C; 1E4D; # LATIN CAPITAL LETTER O WITH TILDE AND ACUTE +1E4E; C; 1E4F; # LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS +1E50; C; 1E51; # LATIN CAPITAL LETTER O WITH MACRON AND GRAVE +1E52; C; 1E53; # LATIN CAPITAL LETTER O WITH MACRON AND ACUTE +1E54; C; 1E55; # LATIN CAPITAL LETTER P WITH ACUTE +1E56; C; 1E57; # LATIN CAPITAL LETTER P WITH DOT ABOVE +1E58; C; 1E59; # LATIN CAPITAL LETTER R WITH DOT ABOVE +1E5A; C; 1E5B; # LATIN CAPITAL LETTER R WITH DOT BELOW +1E5C; C; 1E5D; # LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON +1E5E; C; 1E5F; # LATIN CAPITAL LETTER R WITH LINE BELOW +1E60; C; 1E61; # LATIN CAPITAL LETTER S WITH DOT ABOVE +1E62; C; 1E63; # LATIN CAPITAL LETTER S WITH DOT BELOW +1E64; C; 1E65; # LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE +1E66; C; 1E67; # LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE +1E68; C; 1E69; # LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE +1E6A; C; 1E6B; # LATIN CAPITAL LETTER T WITH DOT ABOVE +1E6C; C; 1E6D; # LATIN CAPITAL LETTER T WITH DOT BELOW +1E6E; C; 1E6F; # LATIN CAPITAL LETTER T WITH LINE BELOW +1E70; C; 1E71; # LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW +1E72; C; 1E73; # LATIN CAPITAL LETTER U WITH DIAERESIS BELOW +1E74; C; 1E75; # LATIN CAPITAL LETTER U WITH TILDE BELOW +1E76; C; 1E77; # LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW +1E78; C; 1E79; # LATIN CAPITAL LETTER U WITH TILDE AND ACUTE +1E7A; C; 1E7B; # LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS +1E7C; C; 1E7D; # LATIN CAPITAL LETTER V WITH TILDE +1E7E; C; 1E7F; # LATIN CAPITAL LETTER V WITH DOT BELOW +1E80; C; 1E81; # LATIN CAPITAL LETTER W WITH GRAVE +1E82; C; 1E83; # LATIN CAPITAL LETTER W WITH ACUTE +1E84; C; 1E85; # LATIN CAPITAL LETTER W WITH DIAERESIS +1E86; C; 1E87; # LATIN CAPITAL LETTER W WITH DOT ABOVE +1E88; C; 1E89; # LATIN CAPITAL LETTER W WITH DOT BELOW +1E8A; C; 1E8B; # LATIN CAPITAL LETTER X WITH DOT ABOVE +1E8C; C; 1E8D; # LATIN CAPITAL LETTER X WITH DIAERESIS +1E8E; C; 1E8F; # LATIN CAPITAL LETTER Y WITH DOT ABOVE +1E90; C; 1E91; # LATIN CAPITAL LETTER Z WITH CIRCUMFLEX +1E92; C; 1E93; # LATIN CAPITAL LETTER Z WITH DOT BELOW +1E94; C; 1E95; # LATIN CAPITAL LETTER Z WITH LINE BELOW +1E96; F; 0068 0331; # LATIN SMALL LETTER H WITH LINE BELOW +1E97; F; 0074 0308; # LATIN SMALL LETTER T WITH DIAERESIS +1E98; F; 0077 030A; # LATIN SMALL LETTER W WITH RING ABOVE +1E99; F; 0079 030A; # LATIN SMALL LETTER Y WITH RING ABOVE +1E9A; F; 0061 02BE; # LATIN SMALL LETTER A WITH RIGHT HALF RING +1E9B; C; 1E61; # LATIN SMALL LETTER LONG S WITH DOT ABOVE +1E9E; F; 0073 0073; # LATIN CAPITAL LETTER SHARP S +1E9E; S; 00DF; # LATIN CAPITAL LETTER SHARP S +1EA0; C; 1EA1; # LATIN CAPITAL LETTER A WITH DOT BELOW +1EA2; C; 1EA3; # LATIN CAPITAL LETTER A WITH HOOK ABOVE +1EA4; C; 1EA5; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE +1EA6; C; 1EA7; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE +1EA8; C; 1EA9; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE +1EAA; C; 1EAB; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE +1EAC; C; 1EAD; # LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW +1EAE; C; 1EAF; # LATIN CAPITAL LETTER A WITH BREVE AND ACUTE +1EB0; C; 1EB1; # LATIN CAPITAL LETTER A WITH BREVE AND GRAVE +1EB2; C; 1EB3; # LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE +1EB4; C; 1EB5; # LATIN CAPITAL LETTER A WITH BREVE AND TILDE +1EB6; C; 1EB7; # LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW +1EB8; C; 1EB9; # LATIN CAPITAL LETTER E WITH DOT BELOW +1EBA; C; 1EBB; # LATIN CAPITAL LETTER E WITH HOOK ABOVE +1EBC; C; 1EBD; # LATIN CAPITAL LETTER E WITH TILDE +1EBE; C; 1EBF; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE +1EC0; C; 1EC1; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE +1EC2; C; 1EC3; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE +1EC4; C; 1EC5; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE +1EC6; C; 1EC7; # LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW +1EC8; C; 1EC9; # LATIN CAPITAL LETTER I WITH HOOK ABOVE +1ECA; C; 1ECB; # LATIN CAPITAL LETTER I WITH DOT BELOW +1ECC; C; 1ECD; # LATIN CAPITAL LETTER O WITH DOT BELOW +1ECE; C; 1ECF; # LATIN CAPITAL LETTER O WITH HOOK ABOVE +1ED0; C; 1ED1; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE +1ED2; C; 1ED3; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE +1ED4; C; 1ED5; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE +1ED6; C; 1ED7; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE +1ED8; C; 1ED9; # LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW +1EDA; C; 1EDB; # LATIN CAPITAL LETTER O WITH HORN AND ACUTE +1EDC; C; 1EDD; # LATIN CAPITAL LETTER O WITH HORN AND GRAVE +1EDE; C; 1EDF; # LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE +1EE0; C; 1EE1; # LATIN CAPITAL LETTER O WITH HORN AND TILDE +1EE2; C; 1EE3; # LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW +1EE4; C; 1EE5; # LATIN CAPITAL LETTER U WITH DOT BELOW +1EE6; C; 1EE7; # LATIN CAPITAL LETTER U WITH HOOK ABOVE +1EE8; C; 1EE9; # LATIN CAPITAL LETTER U WITH HORN AND ACUTE +1EEA; C; 1EEB; # LATIN CAPITAL LETTER U WITH HORN AND GRAVE +1EEC; C; 1EED; # LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE +1EEE; C; 1EEF; # LATIN CAPITAL LETTER U WITH HORN AND TILDE +1EF0; C; 1EF1; # LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW +1EF2; C; 1EF3; # LATIN CAPITAL LETTER Y WITH GRAVE +1EF4; C; 1EF5; # LATIN CAPITAL LETTER Y WITH DOT BELOW +1EF6; C; 1EF7; # LATIN CAPITAL LETTER Y WITH HOOK ABOVE +1EF8; C; 1EF9; # LATIN CAPITAL LETTER Y WITH TILDE +1EFA; C; 1EFB; # LATIN CAPITAL LETTER MIDDLE-WELSH LL +1EFC; C; 1EFD; # LATIN CAPITAL LETTER MIDDLE-WELSH V +1EFE; C; 1EFF; # LATIN CAPITAL LETTER Y WITH LOOP +1F08; C; 1F00; # GREEK CAPITAL LETTER ALPHA WITH PSILI +1F09; C; 1F01; # GREEK CAPITAL LETTER ALPHA WITH DASIA +1F0A; C; 1F02; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA +1F0B; C; 1F03; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA +1F0C; C; 1F04; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA +1F0D; C; 1F05; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA +1F0E; C; 1F06; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI +1F0F; C; 1F07; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI +1F18; C; 1F10; # GREEK CAPITAL LETTER EPSILON WITH PSILI +1F19; C; 1F11; # GREEK CAPITAL LETTER EPSILON WITH DASIA +1F1A; C; 1F12; # GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA +1F1B; C; 1F13; # GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA +1F1C; C; 1F14; # GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA +1F1D; C; 1F15; # GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA +1F28; C; 1F20; # GREEK CAPITAL LETTER ETA WITH PSILI +1F29; C; 1F21; # GREEK CAPITAL LETTER ETA WITH DASIA +1F2A; C; 1F22; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA +1F2B; C; 1F23; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA +1F2C; C; 1F24; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA +1F2D; C; 1F25; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA +1F2E; C; 1F26; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI +1F2F; C; 1F27; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI +1F38; C; 1F30; # GREEK CAPITAL LETTER IOTA WITH PSILI +1F39; C; 1F31; # GREEK CAPITAL LETTER IOTA WITH DASIA +1F3A; C; 1F32; # GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA +1F3B; C; 1F33; # GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA +1F3C; C; 1F34; # GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA +1F3D; C; 1F35; # GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA +1F3E; C; 1F36; # GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI +1F3F; C; 1F37; # GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI +1F48; C; 1F40; # GREEK CAPITAL LETTER OMICRON WITH PSILI +1F49; C; 1F41; # GREEK CAPITAL LETTER OMICRON WITH DASIA +1F4A; C; 1F42; # GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA +1F4B; C; 1F43; # GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA +1F4C; C; 1F44; # GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA +1F4D; C; 1F45; # GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA +1F50; F; 03C5 0313; # GREEK SMALL LETTER UPSILON WITH PSILI +1F52; F; 03C5 0313 0300; # GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA +1F54; F; 03C5 0313 0301; # GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA +1F56; F; 03C5 0313 0342; # GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI +1F59; C; 1F51; # GREEK CAPITAL LETTER UPSILON WITH DASIA +1F5B; C; 1F53; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA +1F5D; C; 1F55; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA +1F5F; C; 1F57; # GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI +1F68; C; 1F60; # GREEK CAPITAL LETTER OMEGA WITH PSILI +1F69; C; 1F61; # GREEK CAPITAL LETTER OMEGA WITH DASIA +1F6A; C; 1F62; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA +1F6B; C; 1F63; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA +1F6C; C; 1F64; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA +1F6D; C; 1F65; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA +1F6E; C; 1F66; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI +1F6F; C; 1F67; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI +1F80; F; 1F00 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI +1F81; F; 1F01 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI +1F82; F; 1F02 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1F83; F; 1F03 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1F84; F; 1F04 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1F85; F; 1F05 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1F86; F; 1F06 03B9; # GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1F87; F; 1F07 03B9; # GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1F88; F; 1F00 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI +1F88; S; 1F80; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI +1F89; F; 1F01 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI +1F89; S; 1F81; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI +1F8A; F; 1F02 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F8A; S; 1F82; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F8B; F; 1F03 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F8B; S; 1F83; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F8C; F; 1F04 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F8C; S; 1F84; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F8D; F; 1F05 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F8D; S; 1F85; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F8E; F; 1F06 03B9; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F8E; S; 1F86; # GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F8F; F; 1F07 03B9; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1F8F; S; 1F87; # GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1F90; F; 1F20 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI +1F91; F; 1F21 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI +1F92; F; 1F22 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1F93; F; 1F23 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1F94; F; 1F24 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1F95; F; 1F25 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1F96; F; 1F26 03B9; # GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1F97; F; 1F27 03B9; # GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1F98; F; 1F20 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI +1F98; S; 1F90; # GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI +1F99; F; 1F21 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI +1F99; S; 1F91; # GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI +1F9A; F; 1F22 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F9A; S; 1F92; # GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1F9B; F; 1F23 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F9B; S; 1F93; # GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1F9C; F; 1F24 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F9C; S; 1F94; # GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1F9D; F; 1F25 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F9D; S; 1F95; # GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1F9E; F; 1F26 03B9; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F9E; S; 1F96; # GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1F9F; F; 1F27 03B9; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1F9F; S; 1F97; # GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1FA0; F; 1F60 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI +1FA1; F; 1F61 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI +1FA2; F; 1F62 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI +1FA3; F; 1F63 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI +1FA4; F; 1F64 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI +1FA5; F; 1F65 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI +1FA6; F; 1F66 03B9; # GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI +1FA7; F; 1F67 03B9; # GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI +1FA8; F; 1F60 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI +1FA8; S; 1FA0; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI +1FA9; F; 1F61 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI +1FA9; S; 1FA1; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI +1FAA; F; 1F62 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1FAA; S; 1FA2; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI +1FAB; F; 1F63 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1FAB; S; 1FA3; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI +1FAC; F; 1F64 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1FAC; S; 1FA4; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI +1FAD; F; 1F65 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1FAD; S; 1FA5; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI +1FAE; F; 1F66 03B9; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1FAE; S; 1FA6; # GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI +1FAF; F; 1F67 03B9; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1FAF; S; 1FA7; # GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI +1FB2; F; 1F70 03B9; # GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI +1FB3; F; 03B1 03B9; # GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI +1FB4; F; 03AC 03B9; # GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI +1FB6; F; 03B1 0342; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI +1FB7; F; 03B1 0342 03B9; # GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI +1FB8; C; 1FB0; # GREEK CAPITAL LETTER ALPHA WITH VRACHY +1FB9; C; 1FB1; # GREEK CAPITAL LETTER ALPHA WITH MACRON +1FBA; C; 1F70; # GREEK CAPITAL LETTER ALPHA WITH VARIA +1FBB; C; 1F71; # GREEK CAPITAL LETTER ALPHA WITH OXIA +1FBC; F; 03B1 03B9; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI +1FBC; S; 1FB3; # GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI +1FBE; C; 03B9; # GREEK PROSGEGRAMMENI +1FC2; F; 1F74 03B9; # GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI +1FC3; F; 03B7 03B9; # GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI +1FC4; F; 03AE 03B9; # GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI +1FC6; F; 03B7 0342; # GREEK SMALL LETTER ETA WITH PERISPOMENI +1FC7; F; 03B7 0342 03B9; # GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI +1FC8; C; 1F72; # GREEK CAPITAL LETTER EPSILON WITH VARIA +1FC9; C; 1F73; # GREEK CAPITAL LETTER EPSILON WITH OXIA +1FCA; C; 1F74; # GREEK CAPITAL LETTER ETA WITH VARIA +1FCB; C; 1F75; # GREEK CAPITAL LETTER ETA WITH OXIA +1FCC; F; 03B7 03B9; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI +1FCC; S; 1FC3; # GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI +1FD2; F; 03B9 0308 0300; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA +1FD3; F; 03B9 0308 0301; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA +1FD3; S; 0390; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA +1FD6; F; 03B9 0342; # GREEK SMALL LETTER IOTA WITH PERISPOMENI +1FD7; F; 03B9 0308 0342; # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI +1FD8; C; 1FD0; # GREEK CAPITAL LETTER IOTA WITH VRACHY +1FD9; C; 1FD1; # GREEK CAPITAL LETTER IOTA WITH MACRON +1FDA; C; 1F76; # GREEK CAPITAL LETTER IOTA WITH VARIA +1FDB; C; 1F77; # GREEK CAPITAL LETTER IOTA WITH OXIA +1FE2; F; 03C5 0308 0300; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA +1FE3; F; 03C5 0308 0301; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA +1FE3; S; 03B0; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA +1FE4; F; 03C1 0313; # GREEK SMALL LETTER RHO WITH PSILI +1FE6; F; 03C5 0342; # GREEK SMALL LETTER UPSILON WITH PERISPOMENI +1FE7; F; 03C5 0308 0342; # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI +1FE8; C; 1FE0; # GREEK CAPITAL LETTER UPSILON WITH VRACHY +1FE9; C; 1FE1; # GREEK CAPITAL LETTER UPSILON WITH MACRON +1FEA; C; 1F7A; # GREEK CAPITAL LETTER UPSILON WITH VARIA +1FEB; C; 1F7B; # GREEK CAPITAL LETTER UPSILON WITH OXIA +1FEC; C; 1FE5; # GREEK CAPITAL LETTER RHO WITH DASIA +1FF2; F; 1F7C 03B9; # GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI +1FF3; F; 03C9 03B9; # GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI +1FF4; F; 03CE 03B9; # GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI +1FF6; F; 03C9 0342; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI +1FF7; F; 03C9 0342 03B9; # GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI +1FF8; C; 1F78; # GREEK CAPITAL LETTER OMICRON WITH VARIA +1FF9; C; 1F79; # GREEK CAPITAL LETTER OMICRON WITH OXIA +1FFA; C; 1F7C; # GREEK CAPITAL LETTER OMEGA WITH VARIA +1FFB; C; 1F7D; # GREEK CAPITAL LETTER OMEGA WITH OXIA +1FFC; F; 03C9 03B9; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI +1FFC; S; 1FF3; # GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI +2126; C; 03C9; # OHM SIGN +212A; C; 006B; # KELVIN SIGN +212B; C; 00E5; # ANGSTROM SIGN +2132; C; 214E; # TURNED CAPITAL F +2160; C; 2170; # ROMAN NUMERAL ONE +2161; C; 2171; # ROMAN NUMERAL TWO +2162; C; 2172; # ROMAN NUMERAL THREE +2163; C; 2173; # ROMAN NUMERAL FOUR +2164; C; 2174; # ROMAN NUMERAL FIVE +2165; C; 2175; # ROMAN NUMERAL SIX +2166; C; 2176; # ROMAN NUMERAL SEVEN +2167; C; 2177; # ROMAN NUMERAL EIGHT +2168; C; 2178; # ROMAN NUMERAL NINE +2169; C; 2179; # ROMAN NUMERAL TEN +216A; C; 217A; # ROMAN NUMERAL ELEVEN +216B; C; 217B; # ROMAN NUMERAL TWELVE +216C; C; 217C; # ROMAN NUMERAL FIFTY +216D; C; 217D; # ROMAN NUMERAL ONE HUNDRED +216E; C; 217E; # ROMAN NUMERAL FIVE HUNDRED +216F; C; 217F; # ROMAN NUMERAL ONE THOUSAND +2183; C; 2184; # ROMAN NUMERAL REVERSED ONE HUNDRED +24B6; C; 24D0; # CIRCLED LATIN CAPITAL LETTER A +24B7; C; 24D1; # CIRCLED LATIN CAPITAL LETTER B +24B8; C; 24D2; # CIRCLED LATIN CAPITAL LETTER C +24B9; C; 24D3; # CIRCLED LATIN CAPITAL LETTER D +24BA; C; 24D4; # CIRCLED LATIN CAPITAL LETTER E +24BB; C; 24D5; # CIRCLED LATIN CAPITAL LETTER F +24BC; C; 24D6; # CIRCLED LATIN CAPITAL LETTER G +24BD; C; 24D7; # CIRCLED LATIN CAPITAL LETTER H +24BE; C; 24D8; # CIRCLED LATIN CAPITAL LETTER I +24BF; C; 24D9; # CIRCLED LATIN CAPITAL LETTER J +24C0; C; 24DA; # CIRCLED LATIN CAPITAL LETTER K +24C1; C; 24DB; # CIRCLED LATIN CAPITAL LETTER L +24C2; C; 24DC; # CIRCLED LATIN CAPITAL LETTER M +24C3; C; 24DD; # CIRCLED LATIN CAPITAL LETTER N +24C4; C; 24DE; # CIRCLED LATIN CAPITAL LETTER O +24C5; C; 24DF; # CIRCLED LATIN CAPITAL LETTER P +24C6; C; 24E0; # CIRCLED LATIN CAPITAL LETTER Q +24C7; C; 24E1; # CIRCLED LATIN CAPITAL LETTER R +24C8; C; 24E2; # CIRCLED LATIN CAPITAL LETTER S +24C9; C; 24E3; # CIRCLED LATIN CAPITAL LETTER T +24CA; C; 24E4; # CIRCLED LATIN CAPITAL LETTER U +24CB; C; 24E5; # CIRCLED LATIN CAPITAL LETTER V +24CC; C; 24E6; # CIRCLED LATIN CAPITAL LETTER W +24CD; C; 24E7; # CIRCLED LATIN CAPITAL LETTER X +24CE; C; 24E8; # CIRCLED LATIN CAPITAL LETTER Y +24CF; C; 24E9; # CIRCLED LATIN CAPITAL LETTER Z +2C00; C; 2C30; # GLAGOLITIC CAPITAL LETTER AZU +2C01; C; 2C31; # GLAGOLITIC CAPITAL LETTER BUKY +2C02; C; 2C32; # GLAGOLITIC CAPITAL LETTER VEDE +2C03; C; 2C33; # GLAGOLITIC CAPITAL LETTER GLAGOLI +2C04; C; 2C34; # GLAGOLITIC CAPITAL LETTER DOBRO +2C05; C; 2C35; # GLAGOLITIC CAPITAL LETTER YESTU +2C06; C; 2C36; # GLAGOLITIC CAPITAL LETTER ZHIVETE +2C07; C; 2C37; # GLAGOLITIC CAPITAL LETTER DZELO +2C08; C; 2C38; # GLAGOLITIC CAPITAL LETTER ZEMLJA +2C09; C; 2C39; # GLAGOLITIC CAPITAL LETTER IZHE +2C0A; C; 2C3A; # GLAGOLITIC CAPITAL LETTER INITIAL IZHE +2C0B; C; 2C3B; # GLAGOLITIC CAPITAL LETTER I +2C0C; C; 2C3C; # GLAGOLITIC CAPITAL LETTER DJERVI +2C0D; C; 2C3D; # GLAGOLITIC CAPITAL LETTER KAKO +2C0E; C; 2C3E; # GLAGOLITIC CAPITAL LETTER LJUDIJE +2C0F; C; 2C3F; # GLAGOLITIC CAPITAL LETTER MYSLITE +2C10; C; 2C40; # GLAGOLITIC CAPITAL LETTER NASHI +2C11; C; 2C41; # GLAGOLITIC CAPITAL LETTER ONU +2C12; C; 2C42; # GLAGOLITIC CAPITAL LETTER POKOJI +2C13; C; 2C43; # GLAGOLITIC CAPITAL LETTER RITSI +2C14; C; 2C44; # GLAGOLITIC CAPITAL LETTER SLOVO +2C15; C; 2C45; # GLAGOLITIC CAPITAL LETTER TVRIDO +2C16; C; 2C46; # GLAGOLITIC CAPITAL LETTER UKU +2C17; C; 2C47; # GLAGOLITIC CAPITAL LETTER FRITU +2C18; C; 2C48; # GLAGOLITIC CAPITAL LETTER HERU +2C19; C; 2C49; # GLAGOLITIC CAPITAL LETTER OTU +2C1A; C; 2C4A; # GLAGOLITIC CAPITAL LETTER PE +2C1B; C; 2C4B; # GLAGOLITIC CAPITAL LETTER SHTA +2C1C; C; 2C4C; # GLAGOLITIC CAPITAL LETTER TSI +2C1D; C; 2C4D; # GLAGOLITIC CAPITAL LETTER CHRIVI +2C1E; C; 2C4E; # GLAGOLITIC CAPITAL LETTER SHA +2C1F; C; 2C4F; # GLAGOLITIC CAPITAL LETTER YERU +2C20; C; 2C50; # GLAGOLITIC CAPITAL LETTER YERI +2C21; C; 2C51; # GLAGOLITIC CAPITAL LETTER YATI +2C22; C; 2C52; # GLAGOLITIC CAPITAL LETTER SPIDERY HA +2C23; C; 2C53; # GLAGOLITIC CAPITAL LETTER YU +2C24; C; 2C54; # GLAGOLITIC CAPITAL LETTER SMALL YUS +2C25; C; 2C55; # GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL +2C26; C; 2C56; # GLAGOLITIC CAPITAL LETTER YO +2C27; C; 2C57; # GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS +2C28; C; 2C58; # GLAGOLITIC CAPITAL LETTER BIG YUS +2C29; C; 2C59; # GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS +2C2A; C; 2C5A; # GLAGOLITIC CAPITAL LETTER FITA +2C2B; C; 2C5B; # GLAGOLITIC CAPITAL LETTER IZHITSA +2C2C; C; 2C5C; # GLAGOLITIC CAPITAL LETTER SHTAPIC +2C2D; C; 2C5D; # GLAGOLITIC CAPITAL LETTER TROKUTASTI A +2C2E; C; 2C5E; # GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE +2C2F; C; 2C5F; # GLAGOLITIC CAPITAL LETTER CAUDATE CHRIVI +2C60; C; 2C61; # LATIN CAPITAL LETTER L WITH DOUBLE BAR +2C62; C; 026B; # LATIN CAPITAL LETTER L WITH MIDDLE TILDE +2C63; C; 1D7D; # LATIN CAPITAL LETTER P WITH STROKE +2C64; C; 027D; # LATIN CAPITAL LETTER R WITH TAIL +2C67; C; 2C68; # LATIN CAPITAL LETTER H WITH DESCENDER +2C69; C; 2C6A; # LATIN CAPITAL LETTER K WITH DESCENDER +2C6B; C; 2C6C; # LATIN CAPITAL LETTER Z WITH DESCENDER +2C6D; C; 0251; # LATIN CAPITAL LETTER ALPHA +2C6E; C; 0271; # LATIN CAPITAL LETTER M WITH HOOK +2C6F; C; 0250; # LATIN CAPITAL LETTER TURNED A +2C70; C; 0252; # LATIN CAPITAL LETTER TURNED ALPHA +2C72; C; 2C73; # LATIN CAPITAL LETTER W WITH HOOK +2C75; C; 2C76; # LATIN CAPITAL LETTER HALF H +2C7E; C; 023F; # LATIN CAPITAL LETTER S WITH SWASH TAIL +2C7F; C; 0240; # LATIN CAPITAL LETTER Z WITH SWASH TAIL +2C80; C; 2C81; # COPTIC CAPITAL LETTER ALFA +2C82; C; 2C83; # COPTIC CAPITAL LETTER VIDA +2C84; C; 2C85; # COPTIC CAPITAL LETTER GAMMA +2C86; C; 2C87; # COPTIC CAPITAL LETTER DALDA +2C88; C; 2C89; # COPTIC CAPITAL LETTER EIE +2C8A; C; 2C8B; # COPTIC CAPITAL LETTER SOU +2C8C; C; 2C8D; # COPTIC CAPITAL LETTER ZATA +2C8E; C; 2C8F; # COPTIC CAPITAL LETTER HATE +2C90; C; 2C91; # COPTIC CAPITAL LETTER THETHE +2C92; C; 2C93; # COPTIC CAPITAL LETTER IAUDA +2C94; C; 2C95; # COPTIC CAPITAL LETTER KAPA +2C96; C; 2C97; # COPTIC CAPITAL LETTER LAULA +2C98; C; 2C99; # COPTIC CAPITAL LETTER MI +2C9A; C; 2C9B; # COPTIC CAPITAL LETTER NI +2C9C; C; 2C9D; # COPTIC CAPITAL LETTER KSI +2C9E; C; 2C9F; # COPTIC CAPITAL LETTER O +2CA0; C; 2CA1; # COPTIC CAPITAL LETTER PI +2CA2; C; 2CA3; # COPTIC CAPITAL LETTER RO +2CA4; C; 2CA5; # COPTIC CAPITAL LETTER SIMA +2CA6; C; 2CA7; # COPTIC CAPITAL LETTER TAU +2CA8; C; 2CA9; # COPTIC CAPITAL LETTER UA +2CAA; C; 2CAB; # COPTIC CAPITAL LETTER FI +2CAC; C; 2CAD; # COPTIC CAPITAL LETTER KHI +2CAE; C; 2CAF; # COPTIC CAPITAL LETTER PSI +2CB0; C; 2CB1; # COPTIC CAPITAL LETTER OOU +2CB2; C; 2CB3; # COPTIC CAPITAL LETTER DIALECT-P ALEF +2CB4; C; 2CB5; # COPTIC CAPITAL LETTER OLD COPTIC AIN +2CB6; C; 2CB7; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE +2CB8; C; 2CB9; # COPTIC CAPITAL LETTER DIALECT-P KAPA +2CBA; C; 2CBB; # COPTIC CAPITAL LETTER DIALECT-P NI +2CBC; C; 2CBD; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI +2CBE; C; 2CBF; # COPTIC CAPITAL LETTER OLD COPTIC OOU +2CC0; C; 2CC1; # COPTIC CAPITAL LETTER SAMPI +2CC2; C; 2CC3; # COPTIC CAPITAL LETTER CROSSED SHEI +2CC4; C; 2CC5; # COPTIC CAPITAL LETTER OLD COPTIC SHEI +2CC6; C; 2CC7; # COPTIC CAPITAL LETTER OLD COPTIC ESH +2CC8; C; 2CC9; # COPTIC CAPITAL LETTER AKHMIMIC KHEI +2CCA; C; 2CCB; # COPTIC CAPITAL LETTER DIALECT-P HORI +2CCC; C; 2CCD; # COPTIC CAPITAL LETTER OLD COPTIC HORI +2CCE; C; 2CCF; # COPTIC CAPITAL LETTER OLD COPTIC HA +2CD0; C; 2CD1; # COPTIC CAPITAL LETTER L-SHAPED HA +2CD2; C; 2CD3; # COPTIC CAPITAL LETTER OLD COPTIC HEI +2CD4; C; 2CD5; # COPTIC CAPITAL LETTER OLD COPTIC HAT +2CD6; C; 2CD7; # COPTIC CAPITAL LETTER OLD COPTIC GANGIA +2CD8; C; 2CD9; # COPTIC CAPITAL LETTER OLD COPTIC DJA +2CDA; C; 2CDB; # COPTIC CAPITAL LETTER OLD COPTIC SHIMA +2CDC; C; 2CDD; # COPTIC CAPITAL LETTER OLD NUBIAN SHIMA +2CDE; C; 2CDF; # COPTIC CAPITAL LETTER OLD NUBIAN NGI +2CE0; C; 2CE1; # COPTIC CAPITAL LETTER OLD NUBIAN NYI +2CE2; C; 2CE3; # COPTIC CAPITAL LETTER OLD NUBIAN WAU +2CEB; C; 2CEC; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI +2CED; C; 2CEE; # COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA +2CF2; C; 2CF3; # COPTIC CAPITAL LETTER BOHAIRIC KHEI +A640; C; A641; # CYRILLIC CAPITAL LETTER ZEMLYA +A642; C; A643; # CYRILLIC CAPITAL LETTER DZELO +A644; C; A645; # CYRILLIC CAPITAL LETTER REVERSED DZE +A646; C; A647; # CYRILLIC CAPITAL LETTER IOTA +A648; C; A649; # CYRILLIC CAPITAL LETTER DJERV +A64A; C; A64B; # CYRILLIC CAPITAL LETTER MONOGRAPH UK +A64C; C; A64D; # CYRILLIC CAPITAL LETTER BROAD OMEGA +A64E; C; A64F; # CYRILLIC CAPITAL LETTER NEUTRAL YER +A650; C; A651; # CYRILLIC CAPITAL LETTER YERU WITH BACK YER +A652; C; A653; # CYRILLIC CAPITAL LETTER IOTIFIED YAT +A654; C; A655; # CYRILLIC CAPITAL LETTER REVERSED YU +A656; C; A657; # CYRILLIC CAPITAL LETTER IOTIFIED A +A658; C; A659; # CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS +A65A; C; A65B; # CYRILLIC CAPITAL LETTER BLENDED YUS +A65C; C; A65D; # CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS +A65E; C; A65F; # CYRILLIC CAPITAL LETTER YN +A660; C; A661; # CYRILLIC CAPITAL LETTER REVERSED TSE +A662; C; A663; # CYRILLIC CAPITAL LETTER SOFT DE +A664; C; A665; # CYRILLIC CAPITAL LETTER SOFT EL +A666; C; A667; # CYRILLIC CAPITAL LETTER SOFT EM +A668; C; A669; # CYRILLIC CAPITAL LETTER MONOCULAR O +A66A; C; A66B; # CYRILLIC CAPITAL LETTER BINOCULAR O +A66C; C; A66D; # CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O +A680; C; A681; # CYRILLIC CAPITAL LETTER DWE +A682; C; A683; # CYRILLIC CAPITAL LETTER DZWE +A684; C; A685; # CYRILLIC CAPITAL LETTER ZHWE +A686; C; A687; # CYRILLIC CAPITAL LETTER CCHE +A688; C; A689; # CYRILLIC CAPITAL LETTER DZZE +A68A; C; A68B; # CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK +A68C; C; A68D; # CYRILLIC CAPITAL LETTER TWE +A68E; C; A68F; # CYRILLIC CAPITAL LETTER TSWE +A690; C; A691; # CYRILLIC CAPITAL LETTER TSSE +A692; C; A693; # CYRILLIC CAPITAL LETTER TCHE +A694; C; A695; # CYRILLIC CAPITAL LETTER HWE +A696; C; A697; # CYRILLIC CAPITAL LETTER SHWE +A698; C; A699; # CYRILLIC CAPITAL LETTER DOUBLE O +A69A; C; A69B; # CYRILLIC CAPITAL LETTER CROSSED O +A722; C; A723; # LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF +A724; C; A725; # LATIN CAPITAL LETTER EGYPTOLOGICAL AIN +A726; C; A727; # LATIN CAPITAL LETTER HENG +A728; C; A729; # LATIN CAPITAL LETTER TZ +A72A; C; A72B; # LATIN CAPITAL LETTER TRESILLO +A72C; C; A72D; # LATIN CAPITAL LETTER CUATRILLO +A72E; C; A72F; # LATIN CAPITAL LETTER CUATRILLO WITH COMMA +A732; C; A733; # LATIN CAPITAL LETTER AA +A734; C; A735; # LATIN CAPITAL LETTER AO +A736; C; A737; # LATIN CAPITAL LETTER AU +A738; C; A739; # LATIN CAPITAL LETTER AV +A73A; C; A73B; # LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR +A73C; C; A73D; # LATIN CAPITAL LETTER AY +A73E; C; A73F; # LATIN CAPITAL LETTER REVERSED C WITH DOT +A740; C; A741; # LATIN CAPITAL LETTER K WITH STROKE +A742; C; A743; # LATIN CAPITAL LETTER K WITH DIAGONAL STROKE +A744; C; A745; # LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE +A746; C; A747; # LATIN CAPITAL LETTER BROKEN L +A748; C; A749; # LATIN CAPITAL LETTER L WITH HIGH STROKE +A74A; C; A74B; # LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY +A74C; C; A74D; # LATIN CAPITAL LETTER O WITH LOOP +A74E; C; A74F; # LATIN CAPITAL LETTER OO +A750; C; A751; # LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER +A752; C; A753; # LATIN CAPITAL LETTER P WITH FLOURISH +A754; C; A755; # LATIN CAPITAL LETTER P WITH SQUIRREL TAIL +A756; C; A757; # LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER +A758; C; A759; # LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE +A75A; C; A75B; # LATIN CAPITAL LETTER R ROTUNDA +A75C; C; A75D; # LATIN CAPITAL LETTER RUM ROTUNDA +A75E; C; A75F; # LATIN CAPITAL LETTER V WITH DIAGONAL STROKE +A760; C; A761; # LATIN CAPITAL LETTER VY +A762; C; A763; # LATIN CAPITAL LETTER VISIGOTHIC Z +A764; C; A765; # LATIN CAPITAL LETTER THORN WITH STROKE +A766; C; A767; # LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER +A768; C; A769; # LATIN CAPITAL LETTER VEND +A76A; C; A76B; # LATIN CAPITAL LETTER ET +A76C; C; A76D; # LATIN CAPITAL LETTER IS +A76E; C; A76F; # LATIN CAPITAL LETTER CON +A779; C; A77A; # LATIN CAPITAL LETTER INSULAR D +A77B; C; A77C; # LATIN CAPITAL LETTER INSULAR F +A77D; C; 1D79; # LATIN CAPITAL LETTER INSULAR G +A77E; C; A77F; # LATIN CAPITAL LETTER TURNED INSULAR G +A780; C; A781; # LATIN CAPITAL LETTER TURNED L +A782; C; A783; # LATIN CAPITAL LETTER INSULAR R +A784; C; A785; # LATIN CAPITAL LETTER INSULAR S +A786; C; A787; # LATIN CAPITAL LETTER INSULAR T +A78B; C; A78C; # LATIN CAPITAL LETTER SALTILLO +A78D; C; 0265; # LATIN CAPITAL LETTER TURNED H +A790; C; A791; # LATIN CAPITAL LETTER N WITH DESCENDER +A792; C; A793; # LATIN CAPITAL LETTER C WITH BAR +A796; C; A797; # LATIN CAPITAL LETTER B WITH FLOURISH +A798; C; A799; # LATIN CAPITAL LETTER F WITH STROKE +A79A; C; A79B; # LATIN CAPITAL LETTER VOLAPUK AE +A79C; C; A79D; # LATIN CAPITAL LETTER VOLAPUK OE +A79E; C; A79F; # LATIN CAPITAL LETTER VOLAPUK UE +A7A0; C; A7A1; # LATIN CAPITAL LETTER G WITH OBLIQUE STROKE +A7A2; C; A7A3; # LATIN CAPITAL LETTER K WITH OBLIQUE STROKE +A7A4; C; A7A5; # LATIN CAPITAL LETTER N WITH OBLIQUE STROKE +A7A6; C; A7A7; # LATIN CAPITAL LETTER R WITH OBLIQUE STROKE +A7A8; C; A7A9; # LATIN CAPITAL LETTER S WITH OBLIQUE STROKE +A7AA; C; 0266; # LATIN CAPITAL LETTER H WITH HOOK +A7AB; C; 025C; # LATIN CAPITAL LETTER REVERSED OPEN E +A7AC; C; 0261; # LATIN CAPITAL LETTER SCRIPT G +A7AD; C; 026C; # LATIN CAPITAL LETTER L WITH BELT +A7AE; C; 026A; # LATIN CAPITAL LETTER SMALL CAPITAL I +A7B0; C; 029E; # LATIN CAPITAL LETTER TURNED K +A7B1; C; 0287; # LATIN CAPITAL LETTER TURNED T +A7B2; C; 029D; # LATIN CAPITAL LETTER J WITH CROSSED-TAIL +A7B3; C; AB53; # LATIN CAPITAL LETTER CHI +A7B4; C; A7B5; # LATIN CAPITAL LETTER BETA +A7B6; C; A7B7; # LATIN CAPITAL LETTER OMEGA +A7B8; C; A7B9; # LATIN CAPITAL LETTER U WITH STROKE +A7BA; C; A7BB; # LATIN CAPITAL LETTER GLOTTAL A +A7BC; C; A7BD; # LATIN CAPITAL LETTER GLOTTAL I +A7BE; C; A7BF; # LATIN CAPITAL LETTER GLOTTAL U +A7C0; C; A7C1; # LATIN CAPITAL LETTER OLD POLISH O +A7C2; C; A7C3; # LATIN CAPITAL LETTER ANGLICANA W +A7C4; C; A794; # LATIN CAPITAL LETTER C WITH PALATAL HOOK +A7C5; C; 0282; # LATIN CAPITAL LETTER S WITH HOOK +A7C6; C; 1D8E; # LATIN CAPITAL LETTER Z WITH PALATAL HOOK +A7C7; C; A7C8; # LATIN CAPITAL LETTER D WITH SHORT STROKE OVERLAY +A7C9; C; A7CA; # LATIN CAPITAL LETTER S WITH SHORT STROKE OVERLAY +A7CB; C; 0264; # LATIN CAPITAL LETTER RAMS HORN +A7CC; C; A7CD; # LATIN CAPITAL LETTER S WITH DIAGONAL STROKE +A7D0; C; A7D1; # LATIN CAPITAL LETTER CLOSED INSULAR G +A7D6; C; A7D7; # LATIN CAPITAL LETTER MIDDLE SCOTS S +A7D8; C; A7D9; # LATIN CAPITAL LETTER SIGMOID S +A7DA; C; A7DB; # LATIN CAPITAL LETTER LAMBDA +A7DC; C; 019B; # LATIN CAPITAL LETTER LAMBDA WITH STROKE +A7F5; C; A7F6; # LATIN CAPITAL LETTER REVERSED HALF H +AB70; C; 13A0; # CHEROKEE SMALL LETTER A +AB71; C; 13A1; # CHEROKEE SMALL LETTER E +AB72; C; 13A2; # CHEROKEE SMALL LETTER I +AB73; C; 13A3; # CHEROKEE SMALL LETTER O +AB74; C; 13A4; # CHEROKEE SMALL LETTER U +AB75; C; 13A5; # CHEROKEE SMALL LETTER V +AB76; C; 13A6; # CHEROKEE SMALL LETTER GA +AB77; C; 13A7; # CHEROKEE SMALL LETTER KA +AB78; C; 13A8; # CHEROKEE SMALL LETTER GE +AB79; C; 13A9; # CHEROKEE SMALL LETTER GI +AB7A; C; 13AA; # CHEROKEE SMALL LETTER GO +AB7B; C; 13AB; # CHEROKEE SMALL LETTER GU +AB7C; C; 13AC; # CHEROKEE SMALL LETTER GV +AB7D; C; 13AD; # CHEROKEE SMALL LETTER HA +AB7E; C; 13AE; # CHEROKEE SMALL LETTER HE +AB7F; C; 13AF; # CHEROKEE SMALL LETTER HI +AB80; C; 13B0; # CHEROKEE SMALL LETTER HO +AB81; C; 13B1; # CHEROKEE SMALL LETTER HU +AB82; C; 13B2; # CHEROKEE SMALL LETTER HV +AB83; C; 13B3; # CHEROKEE SMALL LETTER LA +AB84; C; 13B4; # CHEROKEE SMALL LETTER LE +AB85; C; 13B5; # CHEROKEE SMALL LETTER LI +AB86; C; 13B6; # CHEROKEE SMALL LETTER LO +AB87; C; 13B7; # CHEROKEE SMALL LETTER LU +AB88; C; 13B8; # CHEROKEE SMALL LETTER LV +AB89; C; 13B9; # CHEROKEE SMALL LETTER MA +AB8A; C; 13BA; # CHEROKEE SMALL LETTER ME +AB8B; C; 13BB; # CHEROKEE SMALL LETTER MI +AB8C; C; 13BC; # CHEROKEE SMALL LETTER MO +AB8D; C; 13BD; # CHEROKEE SMALL LETTER MU +AB8E; C; 13BE; # CHEROKEE SMALL LETTER NA +AB8F; C; 13BF; # CHEROKEE SMALL LETTER HNA +AB90; C; 13C0; # CHEROKEE SMALL LETTER NAH +AB91; C; 13C1; # CHEROKEE SMALL LETTER NE +AB92; C; 13C2; # CHEROKEE SMALL LETTER NI +AB93; C; 13C3; # CHEROKEE SMALL LETTER NO +AB94; C; 13C4; # CHEROKEE SMALL LETTER NU +AB95; C; 13C5; # CHEROKEE SMALL LETTER NV +AB96; C; 13C6; # CHEROKEE SMALL LETTER QUA +AB97; C; 13C7; # CHEROKEE SMALL LETTER QUE +AB98; C; 13C8; # CHEROKEE SMALL LETTER QUI +AB99; C; 13C9; # CHEROKEE SMALL LETTER QUO +AB9A; C; 13CA; # CHEROKEE SMALL LETTER QUU +AB9B; C; 13CB; # CHEROKEE SMALL LETTER QUV +AB9C; C; 13CC; # CHEROKEE SMALL LETTER SA +AB9D; C; 13CD; # CHEROKEE SMALL LETTER S +AB9E; C; 13CE; # CHEROKEE SMALL LETTER SE +AB9F; C; 13CF; # CHEROKEE SMALL LETTER SI +ABA0; C; 13D0; # CHEROKEE SMALL LETTER SO +ABA1; C; 13D1; # CHEROKEE SMALL LETTER SU +ABA2; C; 13D2; # CHEROKEE SMALL LETTER SV +ABA3; C; 13D3; # CHEROKEE SMALL LETTER DA +ABA4; C; 13D4; # CHEROKEE SMALL LETTER TA +ABA5; C; 13D5; # CHEROKEE SMALL LETTER DE +ABA6; C; 13D6; # CHEROKEE SMALL LETTER TE +ABA7; C; 13D7; # CHEROKEE SMALL LETTER DI +ABA8; C; 13D8; # CHEROKEE SMALL LETTER TI +ABA9; C; 13D9; # CHEROKEE SMALL LETTER DO +ABAA; C; 13DA; # CHEROKEE SMALL LETTER DU +ABAB; C; 13DB; # CHEROKEE SMALL LETTER DV +ABAC; C; 13DC; # CHEROKEE SMALL LETTER DLA +ABAD; C; 13DD; # CHEROKEE SMALL LETTER TLA +ABAE; C; 13DE; # CHEROKEE SMALL LETTER TLE +ABAF; C; 13DF; # CHEROKEE SMALL LETTER TLI +ABB0; C; 13E0; # CHEROKEE SMALL LETTER TLO +ABB1; C; 13E1; # CHEROKEE SMALL LETTER TLU +ABB2; C; 13E2; # CHEROKEE SMALL LETTER TLV +ABB3; C; 13E3; # CHEROKEE SMALL LETTER TSA +ABB4; C; 13E4; # CHEROKEE SMALL LETTER TSE +ABB5; C; 13E5; # CHEROKEE SMALL LETTER TSI +ABB6; C; 13E6; # CHEROKEE SMALL LETTER TSO +ABB7; C; 13E7; # CHEROKEE SMALL LETTER TSU +ABB8; C; 13E8; # CHEROKEE SMALL LETTER TSV +ABB9; C; 13E9; # CHEROKEE SMALL LETTER WA +ABBA; C; 13EA; # CHEROKEE SMALL LETTER WE +ABBB; C; 13EB; # CHEROKEE SMALL LETTER WI +ABBC; C; 13EC; # CHEROKEE SMALL LETTER WO +ABBD; C; 13ED; # CHEROKEE SMALL LETTER WU +ABBE; C; 13EE; # CHEROKEE SMALL LETTER WV +ABBF; C; 13EF; # CHEROKEE SMALL LETTER YA +FB00; F; 0066 0066; # LATIN SMALL LIGATURE FF +FB01; F; 0066 0069; # LATIN SMALL LIGATURE FI +FB02; F; 0066 006C; # LATIN SMALL LIGATURE FL +FB03; F; 0066 0066 0069; # LATIN SMALL LIGATURE FFI +FB04; F; 0066 0066 006C; # LATIN SMALL LIGATURE FFL +FB05; F; 0073 0074; # LATIN SMALL LIGATURE LONG S T +FB05; S; FB06; # LATIN SMALL LIGATURE LONG S T +FB06; F; 0073 0074; # LATIN SMALL LIGATURE ST +FB13; F; 0574 0576; # ARMENIAN SMALL LIGATURE MEN NOW +FB14; F; 0574 0565; # ARMENIAN SMALL LIGATURE MEN ECH +FB15; F; 0574 056B; # ARMENIAN SMALL LIGATURE MEN INI +FB16; F; 057E 0576; # ARMENIAN SMALL LIGATURE VEW NOW +FB17; F; 0574 056D; # ARMENIAN SMALL LIGATURE MEN XEH +FF21; C; FF41; # FULLWIDTH LATIN CAPITAL LETTER A +FF22; C; FF42; # FULLWIDTH LATIN CAPITAL LETTER B +FF23; C; FF43; # FULLWIDTH LATIN CAPITAL LETTER C +FF24; C; FF44; # FULLWIDTH LATIN CAPITAL LETTER D +FF25; C; FF45; # FULLWIDTH LATIN CAPITAL LETTER E +FF26; C; FF46; # FULLWIDTH LATIN CAPITAL LETTER F +FF27; C; FF47; # FULLWIDTH LATIN CAPITAL LETTER G +FF28; C; FF48; # FULLWIDTH LATIN CAPITAL LETTER H +FF29; C; FF49; # FULLWIDTH LATIN CAPITAL LETTER I +FF2A; C; FF4A; # FULLWIDTH LATIN CAPITAL LETTER J +FF2B; C; FF4B; # FULLWIDTH LATIN CAPITAL LETTER K +FF2C; C; FF4C; # FULLWIDTH LATIN CAPITAL LETTER L +FF2D; C; FF4D; # FULLWIDTH LATIN CAPITAL LETTER M +FF2E; C; FF4E; # FULLWIDTH LATIN CAPITAL LETTER N +FF2F; C; FF4F; # FULLWIDTH LATIN CAPITAL LETTER O +FF30; C; FF50; # FULLWIDTH LATIN CAPITAL LETTER P +FF31; C; FF51; # FULLWIDTH LATIN CAPITAL LETTER Q +FF32; C; FF52; # FULLWIDTH LATIN CAPITAL LETTER R +FF33; C; FF53; # FULLWIDTH LATIN CAPITAL LETTER S +FF34; C; FF54; # FULLWIDTH LATIN CAPITAL LETTER T +FF35; C; FF55; # FULLWIDTH LATIN CAPITAL LETTER U +FF36; C; FF56; # FULLWIDTH LATIN CAPITAL LETTER V +FF37; C; FF57; # FULLWIDTH LATIN CAPITAL LETTER W +FF38; C; FF58; # FULLWIDTH LATIN CAPITAL LETTER X +FF39; C; FF59; # FULLWIDTH LATIN CAPITAL LETTER Y +FF3A; C; FF5A; # FULLWIDTH LATIN CAPITAL LETTER Z +10400; C; 10428; # DESERET CAPITAL LETTER LONG I +10401; C; 10429; # DESERET CAPITAL LETTER LONG E +10402; C; 1042A; # DESERET CAPITAL LETTER LONG A +10403; C; 1042B; # DESERET CAPITAL LETTER LONG AH +10404; C; 1042C; # DESERET CAPITAL LETTER LONG O +10405; C; 1042D; # DESERET CAPITAL LETTER LONG OO +10406; C; 1042E; # DESERET CAPITAL LETTER SHORT I +10407; C; 1042F; # DESERET CAPITAL LETTER SHORT E +10408; C; 10430; # DESERET CAPITAL LETTER SHORT A +10409; C; 10431; # DESERET CAPITAL LETTER SHORT AH +1040A; C; 10432; # DESERET CAPITAL LETTER SHORT O +1040B; C; 10433; # DESERET CAPITAL LETTER SHORT OO +1040C; C; 10434; # DESERET CAPITAL LETTER AY +1040D; C; 10435; # DESERET CAPITAL LETTER OW +1040E; C; 10436; # DESERET CAPITAL LETTER WU +1040F; C; 10437; # DESERET CAPITAL LETTER YEE +10410; C; 10438; # DESERET CAPITAL LETTER H +10411; C; 10439; # DESERET CAPITAL LETTER PEE +10412; C; 1043A; # DESERET CAPITAL LETTER BEE +10413; C; 1043B; # DESERET CAPITAL LETTER TEE +10414; C; 1043C; # DESERET CAPITAL LETTER DEE +10415; C; 1043D; # DESERET CAPITAL LETTER CHEE +10416; C; 1043E; # DESERET CAPITAL LETTER JEE +10417; C; 1043F; # DESERET CAPITAL LETTER KAY +10418; C; 10440; # DESERET CAPITAL LETTER GAY +10419; C; 10441; # DESERET CAPITAL LETTER EF +1041A; C; 10442; # DESERET CAPITAL LETTER VEE +1041B; C; 10443; # DESERET CAPITAL LETTER ETH +1041C; C; 10444; # DESERET CAPITAL LETTER THEE +1041D; C; 10445; # DESERET CAPITAL LETTER ES +1041E; C; 10446; # DESERET CAPITAL LETTER ZEE +1041F; C; 10447; # DESERET CAPITAL LETTER ESH +10420; C; 10448; # DESERET CAPITAL LETTER ZHEE +10421; C; 10449; # DESERET CAPITAL LETTER ER +10422; C; 1044A; # DESERET CAPITAL LETTER EL +10423; C; 1044B; # DESERET CAPITAL LETTER EM +10424; C; 1044C; # DESERET CAPITAL LETTER EN +10425; C; 1044D; # DESERET CAPITAL LETTER ENG +10426; C; 1044E; # DESERET CAPITAL LETTER OI +10427; C; 1044F; # DESERET CAPITAL LETTER EW +104B0; C; 104D8; # OSAGE CAPITAL LETTER A +104B1; C; 104D9; # OSAGE CAPITAL LETTER AI +104B2; C; 104DA; # OSAGE CAPITAL LETTER AIN +104B3; C; 104DB; # OSAGE CAPITAL LETTER AH +104B4; C; 104DC; # OSAGE CAPITAL LETTER BRA +104B5; C; 104DD; # OSAGE CAPITAL LETTER CHA +104B6; C; 104DE; # OSAGE CAPITAL LETTER EHCHA +104B7; C; 104DF; # OSAGE CAPITAL LETTER E +104B8; C; 104E0; # OSAGE CAPITAL LETTER EIN +104B9; C; 104E1; # OSAGE CAPITAL LETTER HA +104BA; C; 104E2; # OSAGE CAPITAL LETTER HYA +104BB; C; 104E3; # OSAGE CAPITAL LETTER I +104BC; C; 104E4; # OSAGE CAPITAL LETTER KA +104BD; C; 104E5; # OSAGE CAPITAL LETTER EHKA +104BE; C; 104E6; # OSAGE CAPITAL LETTER KYA +104BF; C; 104E7; # OSAGE CAPITAL LETTER LA +104C0; C; 104E8; # OSAGE CAPITAL LETTER MA +104C1; C; 104E9; # OSAGE CAPITAL LETTER NA +104C2; C; 104EA; # OSAGE CAPITAL LETTER O +104C3; C; 104EB; # OSAGE CAPITAL LETTER OIN +104C4; C; 104EC; # OSAGE CAPITAL LETTER PA +104C5; C; 104ED; # OSAGE CAPITAL LETTER EHPA +104C6; C; 104EE; # OSAGE CAPITAL LETTER SA +104C7; C; 104EF; # OSAGE CAPITAL LETTER SHA +104C8; C; 104F0; # OSAGE CAPITAL LETTER TA +104C9; C; 104F1; # OSAGE CAPITAL LETTER EHTA +104CA; C; 104F2; # OSAGE CAPITAL LETTER TSA +104CB; C; 104F3; # OSAGE CAPITAL LETTER EHTSA +104CC; C; 104F4; # OSAGE CAPITAL LETTER TSHA +104CD; C; 104F5; # OSAGE CAPITAL LETTER DHA +104CE; C; 104F6; # OSAGE CAPITAL LETTER U +104CF; C; 104F7; # OSAGE CAPITAL LETTER WA +104D0; C; 104F8; # OSAGE CAPITAL LETTER KHA +104D1; C; 104F9; # OSAGE CAPITAL LETTER GHA +104D2; C; 104FA; # OSAGE CAPITAL LETTER ZA +104D3; C; 104FB; # OSAGE CAPITAL LETTER ZHA +10570; C; 10597; # VITHKUQI CAPITAL LETTER A +10571; C; 10598; # VITHKUQI CAPITAL LETTER BBE +10572; C; 10599; # VITHKUQI CAPITAL LETTER BE +10573; C; 1059A; # VITHKUQI CAPITAL LETTER CE +10574; C; 1059B; # VITHKUQI CAPITAL LETTER CHE +10575; C; 1059C; # VITHKUQI CAPITAL LETTER DE +10576; C; 1059D; # VITHKUQI CAPITAL LETTER DHE +10577; C; 1059E; # VITHKUQI CAPITAL LETTER EI +10578; C; 1059F; # VITHKUQI CAPITAL LETTER E +10579; C; 105A0; # VITHKUQI CAPITAL LETTER FE +1057A; C; 105A1; # VITHKUQI CAPITAL LETTER GA +1057C; C; 105A3; # VITHKUQI CAPITAL LETTER HA +1057D; C; 105A4; # VITHKUQI CAPITAL LETTER HHA +1057E; C; 105A5; # VITHKUQI CAPITAL LETTER I +1057F; C; 105A6; # VITHKUQI CAPITAL LETTER IJE +10580; C; 105A7; # VITHKUQI CAPITAL LETTER JE +10581; C; 105A8; # VITHKUQI CAPITAL LETTER KA +10582; C; 105A9; # VITHKUQI CAPITAL LETTER LA +10583; C; 105AA; # VITHKUQI CAPITAL LETTER LLA +10584; C; 105AB; # VITHKUQI CAPITAL LETTER ME +10585; C; 105AC; # VITHKUQI CAPITAL LETTER NE +10586; C; 105AD; # VITHKUQI CAPITAL LETTER NJE +10587; C; 105AE; # VITHKUQI CAPITAL LETTER O +10588; C; 105AF; # VITHKUQI CAPITAL LETTER PE +10589; C; 105B0; # VITHKUQI CAPITAL LETTER QA +1058A; C; 105B1; # VITHKUQI CAPITAL LETTER RE +1058C; C; 105B3; # VITHKUQI CAPITAL LETTER SE +1058D; C; 105B4; # VITHKUQI CAPITAL LETTER SHE +1058E; C; 105B5; # VITHKUQI CAPITAL LETTER TE +1058F; C; 105B6; # VITHKUQI CAPITAL LETTER THE +10590; C; 105B7; # VITHKUQI CAPITAL LETTER U +10591; C; 105B8; # VITHKUQI CAPITAL LETTER VE +10592; C; 105B9; # VITHKUQI CAPITAL LETTER XE +10594; C; 105BB; # VITHKUQI CAPITAL LETTER Y +10595; C; 105BC; # VITHKUQI CAPITAL LETTER ZE +10C80; C; 10CC0; # OLD HUNGARIAN CAPITAL LETTER A +10C81; C; 10CC1; # OLD HUNGARIAN CAPITAL LETTER AA +10C82; C; 10CC2; # OLD HUNGARIAN CAPITAL LETTER EB +10C83; C; 10CC3; # OLD HUNGARIAN CAPITAL LETTER AMB +10C84; C; 10CC4; # OLD HUNGARIAN CAPITAL LETTER EC +10C85; C; 10CC5; # OLD HUNGARIAN CAPITAL LETTER ENC +10C86; C; 10CC6; # OLD HUNGARIAN CAPITAL LETTER ECS +10C87; C; 10CC7; # OLD HUNGARIAN CAPITAL LETTER ED +10C88; C; 10CC8; # OLD HUNGARIAN CAPITAL LETTER AND +10C89; C; 10CC9; # OLD HUNGARIAN CAPITAL LETTER E +10C8A; C; 10CCA; # OLD HUNGARIAN CAPITAL LETTER CLOSE E +10C8B; C; 10CCB; # OLD HUNGARIAN CAPITAL LETTER EE +10C8C; C; 10CCC; # OLD HUNGARIAN CAPITAL LETTER EF +10C8D; C; 10CCD; # OLD HUNGARIAN CAPITAL LETTER EG +10C8E; C; 10CCE; # OLD HUNGARIAN CAPITAL LETTER EGY +10C8F; C; 10CCF; # OLD HUNGARIAN CAPITAL LETTER EH +10C90; C; 10CD0; # OLD HUNGARIAN CAPITAL LETTER I +10C91; C; 10CD1; # OLD HUNGARIAN CAPITAL LETTER II +10C92; C; 10CD2; # OLD HUNGARIAN CAPITAL LETTER EJ +10C93; C; 10CD3; # OLD HUNGARIAN CAPITAL LETTER EK +10C94; C; 10CD4; # OLD HUNGARIAN CAPITAL LETTER AK +10C95; C; 10CD5; # OLD HUNGARIAN CAPITAL LETTER UNK +10C96; C; 10CD6; # OLD HUNGARIAN CAPITAL LETTER EL +10C97; C; 10CD7; # OLD HUNGARIAN CAPITAL LETTER ELY +10C98; C; 10CD8; # OLD HUNGARIAN CAPITAL LETTER EM +10C99; C; 10CD9; # OLD HUNGARIAN CAPITAL LETTER EN +10C9A; C; 10CDA; # OLD HUNGARIAN CAPITAL LETTER ENY +10C9B; C; 10CDB; # OLD HUNGARIAN CAPITAL LETTER O +10C9C; C; 10CDC; # OLD HUNGARIAN CAPITAL LETTER OO +10C9D; C; 10CDD; # OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG OE +10C9E; C; 10CDE; # OLD HUNGARIAN CAPITAL LETTER RUDIMENTA OE +10C9F; C; 10CDF; # OLD HUNGARIAN CAPITAL LETTER OEE +10CA0; C; 10CE0; # OLD HUNGARIAN CAPITAL LETTER EP +10CA1; C; 10CE1; # OLD HUNGARIAN CAPITAL LETTER EMP +10CA2; C; 10CE2; # OLD HUNGARIAN CAPITAL LETTER ER +10CA3; C; 10CE3; # OLD HUNGARIAN CAPITAL LETTER SHORT ER +10CA4; C; 10CE4; # OLD HUNGARIAN CAPITAL LETTER ES +10CA5; C; 10CE5; # OLD HUNGARIAN CAPITAL LETTER ESZ +10CA6; C; 10CE6; # OLD HUNGARIAN CAPITAL LETTER ET +10CA7; C; 10CE7; # OLD HUNGARIAN CAPITAL LETTER ENT +10CA8; C; 10CE8; # OLD HUNGARIAN CAPITAL LETTER ETY +10CA9; C; 10CE9; # OLD HUNGARIAN CAPITAL LETTER ECH +10CAA; C; 10CEA; # OLD HUNGARIAN CAPITAL LETTER U +10CAB; C; 10CEB; # OLD HUNGARIAN CAPITAL LETTER UU +10CAC; C; 10CEC; # OLD HUNGARIAN CAPITAL LETTER NIKOLSBURG UE +10CAD; C; 10CED; # OLD HUNGARIAN CAPITAL LETTER RUDIMENTA UE +10CAE; C; 10CEE; # OLD HUNGARIAN CAPITAL LETTER EV +10CAF; C; 10CEF; # OLD HUNGARIAN CAPITAL LETTER EZ +10CB0; C; 10CF0; # OLD HUNGARIAN CAPITAL LETTER EZS +10CB1; C; 10CF1; # OLD HUNGARIAN CAPITAL LETTER ENT-SHAPED SIGN +10CB2; C; 10CF2; # OLD HUNGARIAN CAPITAL LETTER US +10D50; C; 10D70; # GARAY CAPITAL LETTER A +10D51; C; 10D71; # GARAY CAPITAL LETTER CA +10D52; C; 10D72; # GARAY CAPITAL LETTER MA +10D53; C; 10D73; # GARAY CAPITAL LETTER KA +10D54; C; 10D74; # GARAY CAPITAL LETTER BA +10D55; C; 10D75; # GARAY CAPITAL LETTER JA +10D56; C; 10D76; # GARAY CAPITAL LETTER SA +10D57; C; 10D77; # GARAY CAPITAL LETTER WA +10D58; C; 10D78; # GARAY CAPITAL LETTER LA +10D59; C; 10D79; # GARAY CAPITAL LETTER GA +10D5A; C; 10D7A; # GARAY CAPITAL LETTER DA +10D5B; C; 10D7B; # GARAY CAPITAL LETTER XA +10D5C; C; 10D7C; # GARAY CAPITAL LETTER YA +10D5D; C; 10D7D; # GARAY CAPITAL LETTER TA +10D5E; C; 10D7E; # GARAY CAPITAL LETTER RA +10D5F; C; 10D7F; # GARAY CAPITAL LETTER NYA +10D60; C; 10D80; # GARAY CAPITAL LETTER FA +10D61; C; 10D81; # GARAY CAPITAL LETTER NA +10D62; C; 10D82; # GARAY CAPITAL LETTER PA +10D63; C; 10D83; # GARAY CAPITAL LETTER HA +10D64; C; 10D84; # GARAY CAPITAL LETTER OLD KA +10D65; C; 10D85; # GARAY CAPITAL LETTER OLD NA +118A0; C; 118C0; # WARANG CITI CAPITAL LETTER NGAA +118A1; C; 118C1; # WARANG CITI CAPITAL LETTER A +118A2; C; 118C2; # WARANG CITI CAPITAL LETTER WI +118A3; C; 118C3; # WARANG CITI CAPITAL LETTER YU +118A4; C; 118C4; # WARANG CITI CAPITAL LETTER YA +118A5; C; 118C5; # WARANG CITI CAPITAL LETTER YO +118A6; C; 118C6; # WARANG CITI CAPITAL LETTER II +118A7; C; 118C7; # WARANG CITI CAPITAL LETTER UU +118A8; C; 118C8; # WARANG CITI CAPITAL LETTER E +118A9; C; 118C9; # WARANG CITI CAPITAL LETTER O +118AA; C; 118CA; # WARANG CITI CAPITAL LETTER ANG +118AB; C; 118CB; # WARANG CITI CAPITAL LETTER GA +118AC; C; 118CC; # WARANG CITI CAPITAL LETTER KO +118AD; C; 118CD; # WARANG CITI CAPITAL LETTER ENY +118AE; C; 118CE; # WARANG CITI CAPITAL LETTER YUJ +118AF; C; 118CF; # WARANG CITI CAPITAL LETTER UC +118B0; C; 118D0; # WARANG CITI CAPITAL LETTER ENN +118B1; C; 118D1; # WARANG CITI CAPITAL LETTER ODD +118B2; C; 118D2; # WARANG CITI CAPITAL LETTER TTE +118B3; C; 118D3; # WARANG CITI CAPITAL LETTER NUNG +118B4; C; 118D4; # WARANG CITI CAPITAL LETTER DA +118B5; C; 118D5; # WARANG CITI CAPITAL LETTER AT +118B6; C; 118D6; # WARANG CITI CAPITAL LETTER AM +118B7; C; 118D7; # WARANG CITI CAPITAL LETTER BU +118B8; C; 118D8; # WARANG CITI CAPITAL LETTER PU +118B9; C; 118D9; # WARANG CITI CAPITAL LETTER HIYO +118BA; C; 118DA; # WARANG CITI CAPITAL LETTER HOLO +118BB; C; 118DB; # WARANG CITI CAPITAL LETTER HORR +118BC; C; 118DC; # WARANG CITI CAPITAL LETTER HAR +118BD; C; 118DD; # WARANG CITI CAPITAL LETTER SSUU +118BE; C; 118DE; # WARANG CITI CAPITAL LETTER SII +118BF; C; 118DF; # WARANG CITI CAPITAL LETTER VIYO +16E40; C; 16E60; # MEDEFAIDRIN CAPITAL LETTER M +16E41; C; 16E61; # MEDEFAIDRIN CAPITAL LETTER S +16E42; C; 16E62; # MEDEFAIDRIN CAPITAL LETTER V +16E43; C; 16E63; # MEDEFAIDRIN CAPITAL LETTER W +16E44; C; 16E64; # MEDEFAIDRIN CAPITAL LETTER ATIU +16E45; C; 16E65; # MEDEFAIDRIN CAPITAL LETTER Z +16E46; C; 16E66; # MEDEFAIDRIN CAPITAL LETTER KP +16E47; C; 16E67; # MEDEFAIDRIN CAPITAL LETTER P +16E48; C; 16E68; # MEDEFAIDRIN CAPITAL LETTER T +16E49; C; 16E69; # MEDEFAIDRIN CAPITAL LETTER G +16E4A; C; 16E6A; # MEDEFAIDRIN CAPITAL LETTER F +16E4B; C; 16E6B; # MEDEFAIDRIN CAPITAL LETTER I +16E4C; C; 16E6C; # MEDEFAIDRIN CAPITAL LETTER K +16E4D; C; 16E6D; # MEDEFAIDRIN CAPITAL LETTER A +16E4E; C; 16E6E; # MEDEFAIDRIN CAPITAL LETTER J +16E4F; C; 16E6F; # MEDEFAIDRIN CAPITAL LETTER E +16E50; C; 16E70; # MEDEFAIDRIN CAPITAL LETTER B +16E51; C; 16E71; # MEDEFAIDRIN CAPITAL LETTER C +16E52; C; 16E72; # MEDEFAIDRIN CAPITAL LETTER U +16E53; C; 16E73; # MEDEFAIDRIN CAPITAL LETTER YU +16E54; C; 16E74; # MEDEFAIDRIN CAPITAL LETTER L +16E55; C; 16E75; # MEDEFAIDRIN CAPITAL LETTER Q +16E56; C; 16E76; # MEDEFAIDRIN CAPITAL LETTER HP +16E57; C; 16E77; # MEDEFAIDRIN CAPITAL LETTER NY +16E58; C; 16E78; # MEDEFAIDRIN CAPITAL LETTER X +16E59; C; 16E79; # MEDEFAIDRIN CAPITAL LETTER D +16E5A; C; 16E7A; # MEDEFAIDRIN CAPITAL LETTER OE +16E5B; C; 16E7B; # MEDEFAIDRIN CAPITAL LETTER N +16E5C; C; 16E7C; # MEDEFAIDRIN CAPITAL LETTER R +16E5D; C; 16E7D; # MEDEFAIDRIN CAPITAL LETTER O +16E5E; C; 16E7E; # MEDEFAIDRIN CAPITAL LETTER AI +16E5F; C; 16E7F; # MEDEFAIDRIN CAPITAL LETTER Y +1E900; C; 1E922; # ADLAM CAPITAL LETTER ALIF +1E901; C; 1E923; # ADLAM CAPITAL LETTER DAALI +1E902; C; 1E924; # ADLAM CAPITAL LETTER LAAM +1E903; C; 1E925; # ADLAM CAPITAL LETTER MIIM +1E904; C; 1E926; # ADLAM CAPITAL LETTER BA +1E905; C; 1E927; # ADLAM CAPITAL LETTER SINNYIIYHE +1E906; C; 1E928; # ADLAM CAPITAL LETTER PE +1E907; C; 1E929; # ADLAM CAPITAL LETTER BHE +1E908; C; 1E92A; # ADLAM CAPITAL LETTER RA +1E909; C; 1E92B; # ADLAM CAPITAL LETTER E +1E90A; C; 1E92C; # ADLAM CAPITAL LETTER FA +1E90B; C; 1E92D; # ADLAM CAPITAL LETTER I +1E90C; C; 1E92E; # ADLAM CAPITAL LETTER O +1E90D; C; 1E92F; # ADLAM CAPITAL LETTER DHA +1E90E; C; 1E930; # ADLAM CAPITAL LETTER YHE +1E90F; C; 1E931; # ADLAM CAPITAL LETTER WAW +1E910; C; 1E932; # ADLAM CAPITAL LETTER NUN +1E911; C; 1E933; # ADLAM CAPITAL LETTER KAF +1E912; C; 1E934; # ADLAM CAPITAL LETTER YA +1E913; C; 1E935; # ADLAM CAPITAL LETTER U +1E914; C; 1E936; # ADLAM CAPITAL LETTER JIIM +1E915; C; 1E937; # ADLAM CAPITAL LETTER CHI +1E916; C; 1E938; # ADLAM CAPITAL LETTER HA +1E917; C; 1E939; # ADLAM CAPITAL LETTER QAAF +1E918; C; 1E93A; # ADLAM CAPITAL LETTER GA +1E919; C; 1E93B; # ADLAM CAPITAL LETTER NYA +1E91A; C; 1E93C; # ADLAM CAPITAL LETTER TU +1E91B; C; 1E93D; # ADLAM CAPITAL LETTER NHA +1E91C; C; 1E93E; # ADLAM CAPITAL LETTER VA +1E91D; C; 1E93F; # ADLAM CAPITAL LETTER KHA +1E91E; C; 1E940; # ADLAM CAPITAL LETTER GBE +1E91F; C; 1E941; # ADLAM CAPITAL LETTER ZAL +1E920; C; 1E942; # ADLAM CAPITAL LETTER KPO +1E921; C; 1E943; # ADLAM CAPITAL LETTER SHA +# +# EOF diff --git a/crates/auctioneer-config-data/tests/fixtures/unicode/LICENSE-UNICODE.txt b/crates/auctioneer-config-data/tests/fixtures/unicode/LICENSE-UNICODE.txt new file mode 100644 index 0000000..56da589 --- /dev/null +++ b/crates/auctioneer-config-data/tests/fixtures/unicode/LICENSE-UNICODE.txt @@ -0,0 +1,39 @@ +UNICODE LICENSE V3 + +COPYRIGHT AND PERMISSION NOTICE + +Copyright © 1991-2026 Unicode, Inc. + +NOTICE TO USER: Carefully read the following legal agreement. BY +DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING DATA FILES, AND/OR +SOFTWARE, YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE +TERMS AND CONDITIONS OF THIS AGREEMENT. IF YOU DO NOT AGREE, DO NOT +DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE THE DATA FILES OR SOFTWARE. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of data files and any associated documentation (the "Data Files") or +software and any associated documentation (the "Software") to deal in the +Data Files or Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, and/or sell +copies of the Data Files or Software, and to permit persons to whom the +Data Files or Software are furnished to do so, provided that either (a) +this copyright and permission notice appear with all copies of the Data +Files or Software, or (b) this copyright and permission notice appear in +associated Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF +THIRD PARTY RIGHTS. + +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE +BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, +OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA +FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder shall +not be used in advertising or otherwise to promote the sale, use or other +dealings in these Data Files or Software without prior written +authorization of the copyright holder. diff --git a/crates/auctioneer-config-data/tests/fixtures/unicode/README.md b/crates/auctioneer-config-data/tests/fixtures/unicode/README.md new file mode 100644 index 0000000..9b2052a --- /dev/null +++ b/crates/auctioneer-config-data/tests/fixtures/unicode/README.md @@ -0,0 +1,90 @@ +# Unicode 16 Simple-Fold Qualification Data + +`CaseFolding-16.0.0.txt` is the unmodified official Unicode 16.0.0 data file: +https://www.unicode.org/Public/16.0.0/ucd/CaseFolding.txt + +`ReadMe-16.0.0.txt` is the unmodified release directory's provenance: +https://www.unicode.org/Public/16.0.0/ucd/ReadMe.txt + +The data header points to https://www.unicode.org/terms_of_use.html (redirects +to https://www.unicode.org/copyright.html). Those terms identify files under +`https://www.unicode.org/Public/` as Unicode Data Files and apply Unicode +License v3. `LICENSE-UNICODE.txt` preserves the complete notice downloaded +from https://www.unicode.org/license.txt alongside the original file's +copyright notice. These external files are retained byte-for-byte. + +The independent test oracle uses only common (`C`) and simple (`S`) records. +Full (`F`) and Turkic (`T`) records are validated but grant no equivalence. +Unlisted scalars are singleton classes. No production library supplies expected +classes. The Go 1.23.12 / Unicode 15 JSON capture remains unchanged at its +original privacy-test path; it is historical evidence, not a Unicode 16 oracle. + +## Acquisition And Identity + +Retrieved directly over HTTPS on 2026-11-12. SHA-256 values are literal +checksums of the downloaded bytes, not recomputed expected values in the tests: + +| File | Bytes | SHA-256 | +| --- | ---: | --- | +| `CaseFolding-16.0.0.txt` | 86092 | `6f1f9c588eb4a5c718d9e8f93b782685e5c7fec872cf05e8e6878053599e09bb` | +| `ReadMe-16.0.0.txt` | 693 | `14cafa23788d3a20dd21d6b0cdcb8d6dab520781fcd9ad9392f3b88ea607e633` | +| `LICENSE-UNICODE.txt` | 1995 | `e7a93b009565cfce55919a381437ac4db883e9da2126fa28b91d12732bc53d96` | + +The license URL is unversioned: the retained notice says Unicode License v3, +Copyright 1991-2026 Unicode, Inc. It is the notice served on acquisition, not +a claim that the notice's bytes were published with Unicode 16 in 2024. + +The unchanged `crates/auctioneer-privacy/tests/data/privacy/reference.json` +SHA-256 is `da9414231de7ad7e71abfb3f79e2fa84a5353bb19b40ae391ca1121c20bc9d8f`. +Its embedded versions remain `go1.23.12` and `15.0.0`. + +## Inspected Relation Delta + +These counts were derived by parsing the official file and frozen JSON as +data, without using the Rust case-mapping library or recapturing Go output. +They are fixture observations, not executed Rust-test results. + +The official file contains 1590 records: C=1453, S=31, F=104, T=2. +Its C/S relation has 1454 nontrivial classes containing 2938 scalars. The Go +capture has 1454 noncanonical member/representative records, describing 1424 +nontrivial classes containing 2878 scalars when representatives are included. +All 1424 old nontrivial classes are unchanged. There are no removed nontrivial +classes, no extensions/merges of old nontrivial classes, and no splits. + +There are 30 added two-member classes. Counting singleton classes too, these +are exactly 30 merges of two old singletons, affecting 60 scalars; the other +1112004 scalar class memberships are unchanged. The complete domain has 1112064 +scalars, excluding the 2048 surrogate code points. The total number of classes +including singletons decreases from 1110610 to 1110580. + +The complete added-class inventory (hexadecimal, ascending members) is: + +| First Member | Second Member | +| --- | --- | +| `019B` | `A7DC` | +| `0264` | `A7CB` | +| `0390` | `1FD3` | +| `03B0` | `1FE3` | +| `1C89` | `1C8A` | +| `A7CC` | `A7CD` | +| `A7DA` | `A7DB` | +| `FB05` | `FB06` | +| `10D50` through `10D65` inclusive (22 Garay members) | corresponding first member plus `0020`, `10D70` through `10D85` | + +This is the official-16-versus-Go-15 delta, not a claim that all 30 pairs +originated in Unicode 16. In particular, the Greek and ligature S mappings +are included explicitly rather than silently omitted as unchanged history. + +## Controller Verification + +The named behavioral-red filter is +`tests::unicode16_new_cyrillic_tje_class_is_recognized` with `--exact` in the +existing `simple_fold` integration target. It first proves the pair is absent +from the frozen relation and present in the official relation, then exercises +`simple_fold_eq` in both directions. It intentionally has no Rust-library +version assertion that could substitute for the behavioral failure. + +The author-side helper does not run Cargo, builds or tests. The controller +owns the old-dependency red, subsequent dependency change and serialized +qualification. The existing target retains exhaustive anti-merge/anti-split +checks and asserts exactly 1112064 visited scalars per full-domain comparison. diff --git a/crates/auctioneer-config-data/tests/fixtures/unicode/ReadMe-16.0.0.txt b/crates/auctioneer-config-data/tests/fixtures/unicode/ReadMe-16.0.0.txt new file mode 100644 index 0000000..2dfe542 --- /dev/null +++ b/crates/auctioneer-config-data/tests/fixtures/unicode/ReadMe-16.0.0.txt @@ -0,0 +1,17 @@ +# Unicode Character Database +# Date: 2024-08-25 +# © 2024 Unicode®, Inc. +# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. +# For terms of use and license, see https://www.unicode.org/terms_of_use.html +# +# For documentation, see the following: +# NamesList.html +# UAX #38, "Unicode Han Database (Unihan)" +# UAX #44, "Unicode Character Database" +# UTS #51, "Unicode Emoji" +# UAX #57, "Unicode Egyptian Hieroglyph Database" +# +# The UAXes and UTS #51 can be accessed at https://www.unicode.org/versions/Unicode16.0.0/ + +This directory contains final data files +for the Unicode Character Database, for Version 16.0.0 of the Unicode Standard. diff --git a/crates/auctioneer-config-data/tests/simple_fold.rs b/crates/auctioneer-config-data/tests/simple_fold.rs index 7d8eaae..87c2227 100644 --- a/crates/auctioneer-config-data/tests/simple_fold.rs +++ b/crates/auctioneer-config-data/tests/simple_fold.rs @@ -1,11 +1,23 @@ -//! Exhaustive qualification against the pinned Go 1.23.12 / Unicode 15 fixture. +//! Unicode 16 qualification with an independent official-data oracle and frozen Go evidence. #[cfg(test)] mod tests { use auctioneer_config_data::activity::simple_fold_eq; use serde::Deserialize; - use std::collections::BTreeMap; + use sha2::{Digest as _, Sha256}; + use std::collections::{BTreeMap, BTreeSet}; use std::num::NonZeroU32; + use std::str::from_utf8; + + const OFFICIAL: &[u8] = include_bytes!("fixtures/unicode/CaseFolding-16.0.0.txt"); + const OFFICIAL_SHA256: &str = + "6f1f9c588eb4a5c718d9e8f93b782685e5c7fec872cf05e8e6878053599e09bb"; + const GO_REFERENCE: &[u8] = + include_bytes!("../../auctioneer-privacy/tests/data/privacy/reference.json"); + const GO_SHA256: &str = "da9414231de7ad7e71abfb3f79e2fa84a5353bb19b40ae391ca1121c20bc9d8f"; + + type Canonical = BTreeMap; + type Classes = BTreeMap>; #[derive(Deserialize)] struct Reference { @@ -14,42 +26,205 @@ mod tests { fold_orbits: Vec<(u32, u32)>, } - fn folded(c: char) -> u32 { - unicode_case_mapping::case_folded(c).map_or(u32::from(c), NonZeroU32::get) + #[derive(Debug)] + struct Oracle { + canonical: Canonical, + // C, S, F, T: only the first two grant simple-fold equivalence. + records: [usize; 4], } - #[test] - fn every_unicode_scalar_has_exactly_the_go_simple_fold_equivalence_class() { - let reference: Reference = serde_json::from_str(include_str!( - "../../auctioneer-privacy/tests/data/privacy/reference.json" - )) - .expect("pinned Go reference"); + fn representative(canonical: &Canonical, scalar: u32) -> u32 { + *canonical.get(&scalar).unwrap_or(&scalar) + } + + fn classes(canonical: &Canonical) -> Classes { + let mut result = Classes::new(); + for (&scalar, &root) in canonical { + result.entry(root).or_default().push(scalar); + } + result + } + + fn scalar_token(token: &str) -> Result { + if !(4..=6).contains(&token.len()) + || !token + .bytes() + .all(|b| b.is_ascii_digit() || (b'A'..=b'F').contains(&b)) + { + return Err(format!("invalid code point token: {token}")); + } + let value = u32::from_str_radix(token, 16).map_err(|error| error.to_string())?; + char::from_u32(value).ok_or_else(|| format!("not a Unicode scalar: {token}"))?; + Ok(value) + } + + // This union-find oracle consumes only official C/S edges, never library folds. + fn root(parent: &Canonical, mut scalar: u32) -> u32 { + while let Some(&next) = parent.get(&scalar) { + if next == scalar { + break; + } + scalar = next; + } + scalar + } + + fn parse_case_folding(text: &str) -> Result { + if text.lines().next() != Some("# CaseFolding-16.0.0.txt") + || text.lines().last() != Some("# EOF") + { + return Err("wrong Unicode version/header or missing EOF".into()); + } + let mut parent = Canonical::new(); + let mut statuses = BTreeMap::::new(); + let mut records = [0_usize; 4]; + let mut previous = None; + for (index, line) in text.lines().enumerate() { + if line.is_empty() || line.starts_with('#') { + continue; + } + let line_number = index.saturating_add(1); + let invalid = || format!("invalid CaseFolding record at line {line_number}"); + let (data, name) = line.split_once('#').ok_or_else(invalid)?; + let fields: Vec<_> = data.split(';').map(str::trim).collect(); + if fields.len() != 4 || !fields[3].is_empty() || name.trim().is_empty() { + return Err(invalid()); + } + let source = scalar_token(fields[0])?; + let (slot, bit, status) = match fields[1] { + "C" => (0, 1, b'C'), + "S" => (1, 2, b'S'), + "F" => (2, 4, b'F'), + "T" => (3, 8, b'T'), + _ => return Err(invalid()), + }; + let mapping: Vec<_> = fields[2] + .split_whitespace() + .map(scalar_token) + .collect::>()?; + if (status == b'F' && mapping.len() < 2) || (status != b'F' && mapping.len() != 1) { + return Err(invalid()); + } + let seen = statuses.entry(source).or_default(); + if *seen & bit != 0 { + return Err(format!("duplicate source/status at line {line_number}")); + } + *seen |= bit; + if previous.is_some_and(|p| p >= (source, status)) { + return Err(format!("unordered record at line {line_number}")); + } + previous = Some((source, status)); + records[slot] = records[slot].saturating_add(1); + if status == b'C' || status == b'S' { + if source == mapping[0] { + return Err(format!("identity C/S record at line {line_number}")); + } + let left = root(&parent, source); + let right = root(&parent, mapping[0]); + let minimum = left.min(right); + parent.insert(left, minimum); + parent.insert(right, minimum); + } + } + // C cannot coexist with F/S; S requires F. T supplements C or F only. + if statuses + .values() + .any(|mask| !matches!(*mask, 1 | 4 | 6 | 9 | 12)) + { + return Err("invalid status combination for source".into()); + } + let canonical = parent.keys().map(|&s| (s, root(&parent, s))).collect(); + Ok(Oracle { canonical, records }) + } + + fn pinned_oracle(bytes: &[u8]) -> Result { + if hex::encode(Sha256::digest(bytes)) != OFFICIAL_SHA256 { + return Err("official Unicode 16 SHA-256 mismatch".into()); + } + parse_case_folding(from_utf8(bytes).map_err(|error| error.to_string())?) + } + + fn official_oracle() -> Oracle { + pinned_oracle(OFFICIAL).expect("pinned official Unicode 16 C/S data") + } + + fn frozen_go() -> Canonical { + assert_eq!(hex::encode(Sha256::digest(GO_REFERENCE)), GO_SHA256); + let reference: Reference = + serde_json::from_slice(GO_REFERENCE).expect("unchanged pinned Go reference"); assert_eq!(reference.go, "go1.23.12"); assert_eq!(reference.unicode, "15.0.0"); - assert_eq!(unicode_case_mapping::UNICODE_VERSION, (15, 0, 0)); - let canonical: BTreeMap = reference.fold_orbits.into_iter().collect(); + assert_eq!(reference.fold_orbits.len(), 1_454); + let mut canonical = Canonical::new(); + for (scalar, expected) in reference.fold_orbits { + char::from_u32(scalar).expect("Go member scalar"); + char::from_u32(expected).expect("Go canonical scalar"); + assert!( + expected < scalar, + "Go canonical representative is the minimum" + ); + assert!( + canonical.insert(scalar, expected).is_none(), + "duplicate Go member" + ); + } + let roots: BTreeSet<_> = canonical.values().copied().collect(); + for expected in roots { + assert_eq!(representative(&canonical, expected), expected); + canonical.insert(expected, expected); + } + assert_eq!(canonical.len(), 2_878); + assert_eq!(classes(&canonical).len(), 1_424); + canonical + } + + // Independent literals inspected in the official file, not obtained from the library. + fn expected_added_classes() -> Vec> { + let mut added = vec![ + vec![0x019b, 0xa7dc], + vec![0x0264, 0xa7cb], + vec![0x0390, 0x1fd3], + vec![0x03b0, 0x1fe3], + vec![0x1c89, 0x1c8a], + vec![0xa7cc, 0xa7cd], + vec![0xa7da, 0xa7db], + vec![0xfb05, 0xfb06], + ]; + // The 22 Garay pairs run from 10D50/10D70 through 10D65/10D85. + added.extend( + (0x0001_0d50_u32..=0x0001_0d65) + .map(|upper| vec![upper, upper.checked_add(0x20).expect("Garay lower scalar")]), + ); + added + } + + fn folded(c: char) -> u32 { + unicode_case_mapping::case_folded(c).map_or(u32::from(c), NonZeroU32::get) + } + + fn assert_library_partition(canonical: &Canonical) { let mut actual_classes = BTreeMap::new(); let mut checked = 0_u32; for scalar in 0..=0x0010_ffff { let Some(c) = char::from_u32(scalar) else { continue; }; - let expected = *canonical.get(&scalar).unwrap_or(&scalar); + let expected = representative(canonical, scalar); let actual = folded(c); assert_eq!( - *canonical.get(&actual).unwrap_or(&actual), + representative(canonical, actual), expected, "different orbit for {scalar:x}" ); assert_eq!( - folded(char::from_u32(expected).expect("Go orbit scalar")), + folded(char::from_u32(expected).expect("oracle orbit scalar")), actual, "split orbit for {scalar:x}" ); if let Some(previous) = actual_classes.insert(actual, expected) { assert_eq!( previous, expected, - "distinct Go orbits merged for {scalar:x}" + "distinct oracle orbits merged for {scalar:x}" ); } checked = checked.saturating_add(1); @@ -57,13 +232,258 @@ mod tests { assert_eq!(checked, 1_112_064); } + #[test] + fn official_unicode16_fixture_has_pinned_identity_and_shape() { + let oracle = official_oracle(); + assert_eq!(OFFICIAL.len(), 86_092); + assert_eq!(oracle.records, [1_453, 31, 104, 2]); + assert_eq!(oracle.canonical.len(), 2_938); + assert_eq!(classes(&oracle.canonical).len(), 1_454); + for (bytes, digest) in [ + ( + include_bytes!("fixtures/unicode/ReadMe-16.0.0.txt").as_slice(), + "14cafa23788d3a20dd21d6b0cdcb8d6dab520781fcd9ad9392f3b88ea607e633", + ), + ( + include_bytes!("fixtures/unicode/LICENSE-UNICODE.txt").as_slice(), + "e7a93b009565cfce55919a381437ac4db883e9da2126fa28b91d12732bc53d96", + ), + ] { + assert_eq!(hex::encode(Sha256::digest(bytes)), digest); + } + } + + #[test] + fn every_unicode_scalar_has_exactly_the_official_unicode16_simple_fold_class() { + let oracle = official_oracle(); + assert_eq!(unicode_case_mapping::UNICODE_VERSION, (16, 0, 0)); + assert_library_partition(&oracle.canonical); + } + + #[test] + fn frozen_go_classes_are_unchanged_and_unicode16_delta_is_exact() { + let old = frozen_go(); + let new = official_oracle().canonical; + let old_classes = classes(&old); + let new_classes = classes(&new); + assert_eq!( + 1_112_064_usize + .checked_sub(old.len()) + .expect("old singletons") + .checked_add(old_classes.len()) + .expect("old class count"), + 1_110_610 + ); + assert_eq!( + 1_112_064_usize + .checked_sub(new.len()) + .expect("new singletons") + .checked_add(new_classes.len()) + .expect("new class count"), + 1_110_580 + ); + let old_sets: BTreeSet<_> = old_classes.values().cloned().collect(); + let new_sets: BTreeSet<_> = new_classes.values().cloned().collect(); + let added: Vec<_> = new_sets.difference(&old_sets).cloned().collect(); + let removed: Vec<_> = old_sets.difference(&new_sets).cloned().collect(); + assert_eq!(old_sets.intersection(&new_sets).count(), 1_424); + assert_eq!(added, expected_added_classes()); + assert_eq!(added.len(), 30); + assert!( + removed.is_empty(), + "historical nontrivial classes changed: {removed:x?}" + ); + + // Include implicit singleton classes when detecting both merges and splits. + let members: BTreeSet<_> = old.keys().chain(new.keys()).copied().collect(); + let mut old_to_new = BTreeMap::>::new(); + let mut new_to_old = BTreeMap::>::new(); + let mut changed_members = BTreeSet::new(); + for scalar in members { + let before = representative(&old, scalar); + let after = representative(&new, scalar); + old_to_new.entry(before).or_default().insert(after); + new_to_old.entry(after).or_default().insert(before); + let before_class = old_classes + .get(&before) + .cloned() + .unwrap_or_else(|| vec![scalar]); + let after_class = new_classes + .get(&after) + .cloned() + .unwrap_or_else(|| vec![scalar]); + if before_class != after_class { + changed_members.insert(scalar); + } + } + let splits: Vec<_> = old_to_new.values().filter(|set| set.len() > 1).collect(); + let merges: Vec> = new_to_old + .values() + .filter(|set| set.len() > 1) + .map(|set| set.iter().copied().collect()) + .collect(); + assert!(splits.is_empty(), "old classes split: {splits:x?}"); + assert_eq!(merges, expected_added_classes()); + assert_eq!(merges.len(), 30); + assert_eq!(changed_members.len(), 60); + assert_eq!( + changed_members, + added.iter().flatten().copied().collect::>() + ); + assert_eq!( + 1_112_064_usize.checked_sub(changed_members.len()), + Some(1_112_004) + ); + + // Augment, rather than skip, the frozen relation with the entire pinned delta. + let mut qualified_go = old; + for class in expected_added_classes() { + for &scalar in &class { + assert_eq!(representative(&qualified_go, scalar), scalar); + assert!(qualified_go.insert(scalar, class[0]).is_none()); + } + } + assert_eq!(qualified_go, new); + assert_library_partition(&qualified_go); + } + + #[test] + fn unicode16_new_cyrillic_tje_class_is_recognized() { + let old = frozen_go(); + let new = official_oracle().canonical; + assert_ne!(representative(&old, 0x1c89), representative(&old, 0x1c8a)); + assert_eq!(representative(&new, 0x1c89), 0x1c89); + assert_eq!(representative(&new, 0x1c8a), 0x1c89); + // This is a behavioral red on unicode-case-mapping 0.5, not a version check. + assert!(simple_fold_eq("\u{1c89}", "\u{1c8a}")); + assert!(simple_fold_eq("\u{1c8a}", "\u{1c89}")); + } + + #[test] + fn oracle_rejects_bad_headers_records_statuses_and_scalars() { + let valid = "# CaseFolding-16.0.0.txt\n0041; C; 0061; # A\n# EOF\n"; + let parsed = parse_case_folding(valid).unwrap(); + assert_eq!(parsed.records, [1, 0, 0, 0]); + assert_eq!( + parsed.canonical, + Canonical::from([(0x0041, 0x0041), (0x0061, 0x0041)]) + ); + for malformed in [ + valid.replace("16.0.0", "15.0.0"), + valid.replace("# EOF", ""), + ] { + assert_eq!( + parse_case_folding(&malformed).unwrap_err(), + "wrong Unicode version/header or missing EOF" + ); + } + for records in [ + "0041; C; 0061 # missing final semicolon", + "0041; C; 0061; extra; # extra field", + "0041; C; 0061;", + "0041; C; 0061; #", + "0041; X; 0061; # unknown status", + "0041; CC; 0061; # wide status", + "0041; C; ; # empty mapping", + "0041; C; 0061 0062; # not simple", + "0041; S; 0061 0062; # not simple", + "0041; T; 0061 0062; # not a scalar mapping", + "0041; F; 0061; # not full", + "0041; S; 0061; # S without F", + "0041; T; 0061; # T without default", + "0041; C; 0061; # A\n0041; C; 0061; # duplicate", + "0041; F; 0061 0062; # full\n0041; F; 0061 0062; # duplicate F", + "0041; C; 0061; # common\n0041; F; 0061 0062; # conflict", + "0041; C; 0061; # common\n0041; S; 0062; # conflict", + "0042; C; 0062; # B\n0041; C; 0061; # out of order", + "0041; C; 0041; # identity", + "041; C; 0061; # short token", + "00df; F; 0073 0073; # lowercase hex", + "D800; C; 0061; # surrogate source", + "0041; C; DFFF; # surrogate target", + "110000; C; 0061; # out of range source", + "0041; C; 110000; # out of range target", + "0041; F; 0061 D800; # invalid ignored full target", + "0041; T; 110000; # invalid ignored Turkic target", + ] { + let text = format!("# CaseFolding-16.0.0.txt\n{records}\n# EOF\n"); + assert!(parse_case_folding(&text).is_err(), "accepted {records}"); + } + } + + #[test] + fn mutated_mapping_fails_digest_and_changes_the_independent_relation() { + let text = from_utf8(OFFICIAL).expect("official UTF-8"); + let before = "1C89; C; 1C8A;"; + assert_eq!(text.matches(before).count(), 1); + let mutated = text.replacen(before, "1C89; C; 0061;", 1); + assert!( + pinned_oracle(mutated.as_bytes()) + .expect_err("digest rejection") + .contains("SHA-256") + ); + let original = official_oracle(); + let changed = parse_case_folding(&mutated).expect("structurally valid mutation"); + assert_eq!(original.records, changed.records); + assert_eq!( + representative(&original.canonical, 0x1c89), + representative(&original.canonical, 0x1c8a) + ); + assert_ne!( + representative(&changed.canonical, 0x1c89), + representative(&changed.canonical, 0x1c8a) + ); + assert_eq!( + representative(&changed.canonical, 0x1c89), + representative(&changed.canonical, u32::from('a')) + ); + } + + #[test] + fn oracle_excludes_full_turkic_and_normalization_permissions() { + let oracle = official_oracle(); + for (left, right) in [ + (0x0049, 0x0131), + (0x0130, 0x0069), + (0x00df, 0x0073), + (0xfb05, 0x0073), + (0x00e9, 0x0065), + ] { + assert_ne!( + representative(&oracle.canonical, left), + representative(&oracle.canonical, right) + ); + } + for class in [ + vec![0x004b, 0x006b, 0x212a], + vec![0x0053, 0x0073, 0x017f], + vec![0x03a3, 0x03c2, 0x03c3], + vec![0x00df, 0x1e9e], + ] { + for &scalar in &class { + assert_eq!(representative(&oracle.canonical, scalar), class[0]); + } + } + } + #[test] fn equality_uses_simple_not_ascii_full_locale_or_normalized_folding() { + assert!(simple_fold_eq( + "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "abcdefghijklmnopqrstuvwxyz" + )); for left in ["\u{212a}", "K", "k"] { for right in ["\u{212a}", "K", "k"] { assert!(simple_fold_eq(left, right)); } } + for class in [["S", "s", "\u{17f}"], ["\u{3a3}", "\u{3c2}", "\u{3c3}"]] { + for left in class { + for right in class { + assert!(simple_fold_eq(left, right)); + } + } + } assert!(!simple_fold_eq("\u{df}", "ss")); assert!(simple_fold_eq("\u{1e9e}", "\u{df}")); assert!(!simple_fold_eq("\u{130}", "i")); diff --git a/crates/auctioneer-config/src/activity.rs b/crates/auctioneer-config/src/activity.rs index aa6369c..7fd634a 100644 --- a/crates/auctioneer-config/src/activity.rs +++ b/crates/auctioneer-config/src/activity.rs @@ -59,7 +59,8 @@ impl<'de> Deserialize<'de> for ComponentType { } } -/// Unicode 15 simple folding, qualified against Go 1.23.12 `strings.EqualFold`. +/// Unicode 16 simple folding, qualified against official C/S equivalence classes. +/// The frozen Go 1.23.12 classes are retained with the audited Unicode 16 delta. /// Does not normalize, expand characters, or allocate folded strings. #[must_use] pub fn simple_fold_eq(left: &str, right: &str) -> bool { diff --git a/crates/auctioneer-config/src/bidder_endpoint_codegen.rs b/crates/auctioneer-config/src/bidder_endpoint_codegen.rs index cb59fce..2744976 100644 --- a/crates/auctioneer-config/src/bidder_endpoint_codegen.rs +++ b/crates/auctioneer-config/src/bidder_endpoint_codegen.rs @@ -177,7 +177,7 @@ mod tests { assert!(matches!(method.vis, Visibility::Public(_))); assert!(method.sig.constness.is_some()); assert!(method.sig.asyncness.is_none()); - assert!(method.sig.unsafety.is_none()); + assert!(matches!(method.sig.safety, syn::Safety::Default)); assert!(method.sig.abi.is_none()); assert!(method.sig.variadic.is_none()); assert!(method.sig.generics.params.is_empty()); @@ -190,9 +190,11 @@ mod tests { let syn::FnArg::Receiver(receiver) = &method.sig.inputs[0] else { panic!("expected &self"); }; - assert!(receiver.reference.is_some()); + assert!(matches!( + receiver.kind, + syn::ReceiverKind::Reference(_, None, None) + )); assert!(receiver.mutability.is_none()); - assert!(receiver.colon_token.is_none()); let syn::ReturnType::Type(_, result) = &method.sig.output else { panic!("expected the stack array return type"); diff --git a/crates/auctioneer-config/src/build_catalog.rs b/crates/auctioneer-config/src/build_catalog.rs index 5389ae9..e7fa98c 100644 --- a/crates/auctioneer-config/src/build_catalog.rs +++ b/crates/auctioneer-config/src/build_catalog.rs @@ -422,7 +422,7 @@ fn validate_retained(directory: &Path, key: &str, artifact: &Artifact) -> Result if u64::try_from(bytes.len()).ok() != Some(retained.bytes) { return Err(input(&location, "retained byte length mismatch")); } - if format!("{:x}", Sha256::digest(bytes)) != retained.sha256 { + if hex::encode(Sha256::digest(bytes)) != retained.sha256 { return Err(input(&location, "retained SHA256 mismatch")); } Ok(()) @@ -614,7 +614,7 @@ mod tests { } fn digest(bytes: &[u8]) -> String { - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) } #[test] diff --git a/crates/auctioneer-config/src/schema_staging.rs b/crates/auctioneer-config/src/schema_staging.rs index dfe540a..4ed3ab9 100644 --- a/crates/auctioneer-config/src/schema_staging.rs +++ b/crates/auctioneer-config/src/schema_staging.rs @@ -345,13 +345,13 @@ pub fn identify( } Ok(ArtifactIdentity { qualification: Qualification::Unqualified, - sha256: format!("{:x}", hash.finalize()), + sha256: hex::encode(hash.finalize()), inputs: input_identities, }) } pub(crate) fn digest(bytes: &[u8]) -> String { - format!("{:x}", Sha256::digest(bytes)) + hex::encode(Sha256::digest(bytes)) } fn hash_field(hash: &mut Sha256, field: &str) -> Result<(), String> { @@ -652,7 +652,7 @@ mod tests { #[test] fn fake_identity_is_explicitly_unqualified_and_input_order_independent() { - let hash = format!("{:x}", Sha256::digest(b"fake bytes")); + let hash = hex::encode(Sha256::digest(b"fake bytes")); let mut inputs = inputs(&hash); let expected = identity(&fake_selection(), context(), &inputs); assert_eq!(expected.qualification, Qualification::Unqualified); @@ -664,7 +664,7 @@ mod tests { #[test] fn fake_identity_changes_with_each_build_context_axis_and_membership() { - let hash = format!("{:x}", Sha256::digest(b"fake bytes")); + let hash = hex::encode(Sha256::digest(b"fake bytes")); let inputs = inputs(&hash); let selection = fake_selection(); let baseline = identity(&selection, context(), &inputs); @@ -705,7 +705,7 @@ mod tests { #[test] fn fake_identity_requires_all_planning_code_lock_and_schema_inputs() { - let hash = format!("{:x}", Sha256::digest(b"fake bytes")); + let hash = hex::encode(Sha256::digest(b"fake bytes")); let inputs = inputs(&hash); for index in 0..inputs.len() { let mut missing = inputs.clone(); @@ -748,8 +748,8 @@ mod tests { #[test] fn fake_identity_rebinds_every_changed_input_including_code_helpers_and_lock() { - let old_hash = format!("{:x}", Sha256::digest(b"fake bytes")); - let new_hash = format!("{:x}", Sha256::digest(b"fake changed bytes")); + let old_hash = hex::encode(Sha256::digest(b"fake bytes")); + let new_hash = hex::encode(Sha256::digest(b"fake changed bytes")); let inputs = inputs(&old_hash); let baseline = identity(&fake_selection(), context(), &inputs); for index in 0..inputs.len() { diff --git a/crates/auctioneer-core/Cargo.toml b/crates/auctioneer-core/Cargo.toml index 7adfe2f..51d5d62 100644 --- a/crates/auctioneer-core/Cargo.toml +++ b/crates/auctioneer-core/Cargo.toml @@ -76,6 +76,7 @@ auctioneer-bidder = { workspace = true, features = ["test-support"] } auctioneer-runtime = { workspace = true, features = ["test-support"] } auctioneer-privacy = { workspace = true, features = ["test-support"] } bytes = { workspace = true } +hex = { workspace = true } edgezero-adapter-axum = { workspace = true, features = ["axum"] } futures = { workspace = true } png = { workspace = true } diff --git a/crates/auctioneer-core/src/usersync/signed.rs b/crates/auctioneer-core/src/usersync/signed.rs index 976601e..d5ce18c 100644 --- a/crates/auctioneer-core/src/usersync/signed.rs +++ b/crates/auctioneer-core/src/usersync/signed.rs @@ -5,7 +5,7 @@ use std::{borrow::Cow, collections::BTreeMap, fmt}; use auctioneer_runtime::aux_work::MAX_SYNC_KEYRING_BYTES; use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD}; use edgezero_core::http::HeaderMap; -use hmac::{Hmac, Mac as _}; +use hmac::{Hmac, KeyInit as _, Mac as _}; use serde::Deserialize; use sha2::Sha256; use time::OffsetDateTime; diff --git a/crates/auctioneer-core/tests/boot_strict_parity.rs b/crates/auctioneer-core/tests/boot_strict_parity.rs index ec5d58b..fb0aa7b 100644 --- a/crates/auctioneer-core/tests/boot_strict_parity.rs +++ b/crates/auctioneer-core/tests/boot_strict_parity.rs @@ -417,7 +417,7 @@ mod tests { "catalog_costs": retained::catalog(&gates.catalog_costs), "outbound_meta_bytes": gates.outbound_meta_bytes, "baked_config_bytes": gates.baked_config_bytes, - "baked_config_sha256": format!("{:x}", Sha256::digest(&baked)), + "baked_config_sha256": hex::encode(Sha256::digest(&baked)), "terms": retained::terms(&gates.derived.isolate_terms), "auction_receipts": retained::receipts(&gates.derived.auction_charges), "derived": retained::derived(&gates.derived), diff --git a/crates/auctioneer-core/tests/native_bidder_onboarding/fixtures.rs b/crates/auctioneer-core/tests/native_bidder_onboarding/fixtures.rs index 9f63f37..04976bd 100644 --- a/crates/auctioneer-core/tests/native_bidder_onboarding/fixtures.rs +++ b/crates/auctioneer-core/tests/native_bidder_onboarding/fixtures.rs @@ -200,7 +200,7 @@ fn approved_members(bidder_root: &Path) -> BTreeMap { let bytes = fs::read(path).unwrap(); assert_eq!(u64::try_from(bytes.len()).unwrap(), witness.bytes); assert_eq!( - format!("{:x}", Sha256::digest(&bytes)), + hex::encode(Sha256::digest(&bytes)), witness.sha256, "reviewed requirements changed; do not refresh this digest automatically" ); diff --git a/crates/auctioneer-core/tests/usersync_integrity.rs b/crates/auctioneer-core/tests/usersync_integrity.rs index c3e658d..a98691b 100644 --- a/crates/auctioneer-core/tests/usersync_integrity.rs +++ b/crates/auctioneer-core/tests/usersync_integrity.rs @@ -28,7 +28,7 @@ mod tests { body::Body, http::{Method, StatusCode}, }; - use hmac::{Hmac, Mac as _}; + use hmac::{Hmac, KeyInit as _, Mac as _}; use serde_json::json; use sha2::Sha256; use usersync_app::{TestApp, body}; diff --git a/crates/auctioneer-core/tests/usersync_reference.rs b/crates/auctioneer-core/tests/usersync_reference.rs index 770101b..d32d022 100644 --- a/crates/auctioneer-core/tests/usersync_reference.rs +++ b/crates/auctioneer-core/tests/usersync_reference.rs @@ -163,7 +163,10 @@ mod tests { options.set_skip_ancillary_crc_failures(false); let decoder = png::Decoder::new_with_options(Cursor::new(bytes), options); let mut reader = decoder.read_info()?; - let mut rgba = vec![0; reader.output_buffer_size()]; + let output_bytes = reader + .output_buffer_size() + .ok_or(png::DecodingError::LimitsExceeded)?; + let mut rgba = vec![0; output_bytes]; let info = reader.next_frame(&mut rgba)?; reader.finish()?; Ok((info, rgba)) @@ -174,7 +177,7 @@ mod tests { let bytes = fixture("pixel.png"); assert_eq!(bytes.len(), 86); assert_eq!( - format!("{:x}", Sha256::digest(&bytes)), + hex::encode(Sha256::digest(&bytes)), "c2ecff291918a3caf0b7e470323e89f2a1f05b92e12a10649e598cacebe62acf" ); let (info, rgba) = decode_pixel(&bytes).unwrap(); @@ -776,7 +779,7 @@ mod tests { } } assert_eq!( - format!("{:x}", Sha256::digest(fixture("LICENSE.prebid"))), + hex::encode(Sha256::digest(fixture("LICENSE.prebid"))), hashes["LICENSE"] ); } diff --git a/crates/auctioneer-macros/tests/conformance/fail/malformed_source.stderr b/crates/auctioneer-macros/tests/conformance/fail/malformed_source.stderr index 6db9412..9b1e082 100644 --- a/crates/auctioneer-macros/tests/conformance/fail/malformed_source.stderr +++ b/crates/auctioneer-macros/tests/conformance/fail/malformed_source.stderr @@ -13,7 +13,7 @@ error: expected one of `>`, a const expression, lifetime, or type, found `}` | = note: this error originates in the macro `malformed_model` (in Nightly builds, run with -Z macro-backtrace for more info) -error: unexpected end of input, expected one of: `for`, parentheses, `fn`, `unsafe`, `extern`, identifier, `::`, `<`, `dyn`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime +error: unexpected end of input, expected one of: `for`, parentheses, `unsafe`, `fn`, `extern`, identifier, `::`, `<`, `dyn`, square brackets, `*`, `&`, `!`, `impl`, `_`, lifetime --> tests/conformance/fail/malformed_source.rs:8:9 | 8 | } diff --git a/docs/superpowers/plans/2026-11-11-rust-dependency-upgrade.md b/docs/superpowers/plans/2026-11-11-rust-dependency-upgrade.md new file mode 100644 index 0000000..d9d4dc1 --- /dev/null +++ b/docs/superpowers/plans/2026-11-11-rust-dependency-upgrade.md @@ -0,0 +1,160 @@ +# Complete Rust Dependency Upgrade Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Upgrade the Auctioneer Rust dependency graph within the existing PR #275 SDK constraints, preserving protocol behavior, safety limits and all existing acceptance owners. Report retained upstream constraints rather than claiming an all-latest graph. + +**Architecture:** EdgeZero owns its provider/shared-type/codec tuple; Auctioneer retains its existing immutable PR #275 revision while migrating independently owned dependency families. Workspace requirements, the resolved lockfile and independently replayable vendor patches remain the sources of dependency identity. Unicode 16 is the one explicitly approved matching-policy change; historical captures remain immutable. + +**Tech Stack:** Rust and provider tools from `.tool-versions`, Cargo, the current EdgeZero outbound contract, existing `quote!`/`syn` generators, patched upstream schema/regex libraries and existing native/guest test owners. + +--- + +## Authority And Sequence + +Spec: [Complete Rust Dependency Upgrade](../specs/2026-11-11-rust-dependency-upgrade-design.md). Tracking: [Auctioneer #165](https://github.com/IABTechLab/auctioneer/issues/165). The maintainer approved the written spec, Unicode 16 and the initial separate SDK-first coordination on 2026-11-11. On 2026-11-12 the user directed implementation in existing PR #166 without another PR, required EdgeZero to stay on PR #275, and instructed CREATOR to continue. This supersedes the separate planning-merge/implementation-PR sequence and the SDK-first gate for independent upgrades. Neither repository has merge authorization. [EdgeZero #467](https://github.com/IABTechLab/edgezero/issues/467) still owns future upstream tuple changes, not independent Auctioneer work. + +Use PR #166's existing owned branch/worktree under that explicit user exception; do not open another Auctioneer PR or edit the PR #275 implementer's checkout. Task 1 now freezes the retained SDK and its constraints rather than waiting for another SDK delivery. Refresh `origin/main` and reconcile merged changes before freezing the implementation baseline. An unmerged PR #162 remains separate work, not source to copy or accepted proof. + +A family can require several small commits. Keep the final deliverable one Auctioneer implementation PR, not one PR per package. A compile failure does not justify changing privacy, workload, resource or test contracts. A newly discovered behavioral migration beyond the approved Unicode change returns to review before implementation. + +## File Ownership + +| Owner | Files And Responsibility | +| --- | --- | +| Dependency graph | `Cargo.toml`, `Cargo.lock`, inherited `crates/*/Cargo.toml`; `.tool-versions` only if a justified compatibility decision changes a tool | +| Current upgrade record | `docs/testing/evidence/rust-dependency-upgrade-20261112.md` records the implementation selection, upstream constraints, source/patch identities, actual commands/results and outstanding blockers; not a new backlog | +| SDK adoption | `crates/auctioneer-adapter-{axum,cloudflare,fastly,spin}/src/`, `crates/auctioneer-core/tests/codec_pins.rs`, current acquisition instructions in `docs/testing/development.md` | +| Config and generators | `crates/auctioneer-config/src/`, `crates/auctioneer-config-data/build.rs`, `crates/auctioneer-macros/src/`, existing generated syntax/compiler tests | +| Crypto and utility APIs | `crates/auctioneer-core/src/usersync/signed.rs`, `crates/auctioneer-privacy/src/gvl.rs`, `crates/auctioneer-config/src/url_safety.rs`, `crates/auctioneer-openrtb/src/prepare/implicit_fill.rs`, native CLI maintenance modules | +| Schema compiler | `vendor/jsonschema-macros-core/`, a new versioned original `.crate` archive and portable patches, `vendor/README.md`, existing schema compiler/provenance owners | +| Regex source/layout | `vendor/regex-automata/`, existing or versioned replacement archive/patch, existing `schema_build`/`schema_*` layout and allocator controls | +| Unicode oracle | `crates/auctioneer-config/src/activity.rs`, `crates/auctioneer-config-data/tests/simple_fold.rs`; add official Unicode 16 source and attribution under `crates/auctioneer-config-data/tests/fixtures/unicode/` | +| Artifact inspection | Existing `crates/auctioneer-bidder/tests/schema_build/` modules and `crates/auctioneer-cli/src/qualification/` artifact/provider inspection modules | +| Acceptance | Existing workflows and colocated scripts in `.github/workflows/`; existing test targets, no new workflow snapshots, broad skips or test-target proliferation | + +Use `rg` to derive the complete call-site set for each changed package. The table identifies owners, not permission to skip additional real consumers. Colocate new unit cases; extend existing integration/conformance owners. Use synthetic fake bidders for shared controls and preserve bidder-local protocol/provenance data. + +## Task 1: Freeze The Retained SDK Constraints + +**External owner:** EdgeZero PR #275, with future tuple upgrades tracked in #467. No SDK/provider/codec source changes in this task. + +- [ ] Verify all six SDK requirements and locked packages retain one official-repository revision on PR #275's lineage. Do not adopt unrelated main or a new provider SDK independently. +- [ ] Record the exact provider/shared-type/HTTP/JSON/codec requirements and resolved feature graph. Preserve the Spin fork until its owning SDK permits a coherent replacement. +- [ ] Classify each retained older package instance by its actual upstream owner and constraint. Independent package upgrades may proceed; conflicting shared-version upgrades may not. +- [ ] Preserve the codec single-copy, retained-outbound, deadline/cancellation and provider boundary controls. A resolver failure does not justify removing them or adding incompatible exposed types. +- [ ] Keep future #467 work and missing qualification explicit. This task does not deliver a newer SDK tuple or claim release stability or target fit. + +## Task 2: Freeze The Implementation Inventory And Baseline + +**Files:** `Cargo.toml`, `Cargo.lock`, current upgrade record. Read `.tool-versions`, `vendor/README.md`, [test ownership](../../testing/development.md) and current workflows. + +- [ ] Fetch main into the existing PR #166 cycle and record the exact base and retained SDK commit. Preserve concurrent work, particularly PR #162 if it has merged. Confirm the locked base builds before changing requirements. +- [ ] Capture `cargo metadata --locked --format-version 1` and `cargo tree --locked --duplicates`, then run `cargo upgrade --dry-run --incompatible allow --pinned allow --recursive false` and `cargo update --dry-run --verbose`. These are audit commands, not permission to rewrite the manifest mechanically. +- [ ] Expand every workspace requirement to its owning call sites and every resolved package to its full Cargo package ID/source. Independently inspect Git release tags and relevant upstream repairs. Record selected stable versions and retained upstream constraints; do not depend on `cargo-outdated`'s broken vendor-copy path. +- [ ] Freeze candidates after this selection. The spec's 23 requirements and 147 compatible changes are dated discovery data, not asserted counts for a later resolution. Record new releases discovered afterward without moving a graph already under acceptance. +- [ ] Run the native, standalone compiler/producer, conformance and guest baseline under the current workflow owners, preserving exact commands, features, dispatch counts and result lines. If a baseline fails, report it and obtain a decision before coding; do not call it pre-existing without reproducing the same command on base and carrying head. +- [ ] Commit the inventory/selection record only; no dependency change may be described as tested by this unchanged-graph baseline. + +## Task 3: Adopt The SDK And Shared Tuple + +The original adoption checklist below is conditional on a future explicitly selected PR #275 revision permitting a coherent newer tuple. For this implementation, retain the current SDK/provider/codec pins and record constrained versions; this task does not authorize replacing the SDK, bypassing exact requirements or editing its checkout. Keep the executable SDK locator/provider pins unchanged when no revision is adopted. + +**Files:** root and inherited manifests/lockfile; adapter source; `crates/auctioneer-core/tests/codec_pins.rs`; `.github/workflows/scripts/test/locate-pinned-sdk.sh`; `crates/auctioneer-cli/src/qualification/harness/providers/mod.rs`; current source acquisition instructions and current upgrade record. + +- [ ] First run and retain the existing single-copy codec/source guard and adapter contract controls at the base. Read exposed SDK/provider HTTP/body types and the selected SDK migration notes before touching imports or conversions. +- [ ] Change all workspace EdgeZero requirements together to the accepted immutable official revision. Select matching Fastly, Worker, Spin, HTTP/JSON and codec requirements. Keep ordinary crate declarations workspace-inherited and platform features narrow; do not copy a provider version into an adapter manifest. +- [ ] Resolve online once with `cargo update`, then run `cargo metadata --locked` and inspect `cargo tree --locked --duplicates` plus inverse trees for each shared package instance. Check request/response/header/body interface identity, not only resolution success. +- [ ] Migrate necessary adapter calls using current maintained APIs. Preserve deadlines, eager progress, retained owners, one completion callback, cancellation/drop behavior, decoded-size/window/framing checks and safe diagnostics. Keep native clients native-only. +- [ ] Update `codec_pins` to the independently recorded accepted tuple, preserving its duplicate rejection and source binding. Run `cargo test --locked -p auctioneer-core --test codec_pins --test upstream_primitives --test edgezero_fanout`. A new encoder beside an old decoder must not be accepted by weakening uniqueness. +- [ ] Run native adapter tests and the three guest adapter compile/lint commands from CI before committing this family. Update the CI SDK locator and provider harness's executable source pin along with current acquisition instructions; search for other active uses of the superseded pin. Distinguish these current readers from historical captures, whose evidence pins must not be rewritten. +- [ ] Commit SDK adoption, necessary compatibility repairs and the selected tuple together. Preserve the old record as historical evidence, not a current reproduction recipe. + +## Task 4: Migrate AST, Error And Configuration APIs + +**Files:** workspace manifests; `crates/auctioneer-macros/src/{lib,field_metadata}.rs`; existing `auctioneer-config` generators; `auctioneer-config-data` syntax/build controls; all actual `syn`, `toml` and `thiserror` consumers. + +- [ ] Inspect the selected major release migration documentation/source and run existing config/root-shape/field-metadata/generated-syntax controls before edits. Add literal negative controls first for any changed parser/error branch not already owned: duplicate or unknown config keys, null/absence, override order, malformed input, invalid generated syntax. +- [ ] Upgrade project-owned Syn to 3, thiserror to 2 and TOML to the selected 1.2 release. Preserve upstream Syn 2 if a dependency still owns that major; do not rewrite vendored upstream requirements just to eliminate a duplicate name. +- [ ] Repair AST construction/traversal and error conversions with maintained typed APIs. Continue `quote!` plus parsed `syn` trees, not generated Rust string concatenation. Preserve one runtime-config model and CLI validate/diff/push output/diagnostic boundaries. +- [ ] Run `cargo test --locked -p auctioneer-macros --all-targets`, `cargo test --locked -p auctioneer-config --features build-support --lib --test root_shape`, and `cargo test --locked -p auctioneer-config-data --test codegen --test disclosure_codegen --test product_defaults_snapshot --test usersync_config --test usersync_callback_validation`. Require actual named cases, not an empty filter. +- [ ] Run `bash .github/workflows/scripts/test/verify-schema-compiler-conformance.sh settings` and strict affected-target Clippy. Keep generated output parseable without deleting diagnostics or blessing unrelated snapshots. +- [ ] Commit API changes and their independent regression controls; update the package-ID inventory. + +## Task 5: Upgrade Cookie Crypto Without Changing Its Wire Contract + +**Files:** root requirements/lockfile; `crates/auctioneer-core/src/usersync/signed.rs`; its inline tests and existing `usersync_integrity`, `usersync_cookie`, `usersync_handlers` integration owners. + +- [ ] Run the independent HMAC vector, authenticated unsupported-version, active-key/rotation, key-strength and every-MAC-byte rejection controls before changing HMAC/SHA. Preserve their literal expected signatures. +- [ ] Upgrade HMAC 0.13 and SHA2 0.11 with their matching trait families. Repair imports/construction using maintained APIs; retain constant-time MAC verification, key redaction, existing signed envelope/version and the complete-cookie ceiling. Do not recalculate expected MACs using the new code under test. +- [ ] Run `cargo test --locked -p auctioneer-core --lib usersync::signed::tests` and `cargo test --locked -p auctioneer-core --test usersync_integrity --test usersync_cookie --test usersync_handlers`. Confirm nonzero dispatch and real tamper rejection at both unit and handler boundaries. +- [ ] Run the existing auxiliary/cookie allocation owners to prove stronger alignment or changed dependencies did not exceed funded storage. An overshoot blocks adoption; it does not authorize a larger reservation or smaller workload. +- [ ] Commit crypto API migration and any independently derived new regression case, without changes to capture bytes or envelope semantics. + +## Task 6: Upgrade Utility And Native Maintenance Dependencies + +**Files:** actual users of `getrandom`, `ipnetwork`, `lru`, `mime`, `png`, `zeroize`, native `reqwest`, registry-compatible updates and root lockfile. + +- [ ] Locate users with `rg` and inspect selected release APIs before batching compatible migrations. Use the resolved package-ID inventory to catch broad requirements already current in the manifest but old in the lockfile. +- [ ] Upgrade the project-owned requirements and implement only necessary API repairs. Preserve native HTTP TLS/redirect/timeouts/host restrictions, IP/subnet and implicit-fill behavior, GVL cache eviction, randomness failures, zeroization and diagnostic privacy, exact MIME admission and generated pixel behavior. +- [ ] Add targeted negative/boundary cases before each repair when the existing owner cannot observe that branch. For MIME, keep exact `application/json` acceptance separate from structured suffixes, malformed/double-plus types and parameters; library parsing success must not authorize additional capture. +- [ ] Run `cargo test --locked -p auctioneer-openrtb --all-targets`, `cargo test --locked -p auctioneer-privacy --all-targets`, `cargo test --locked -p auctioneer-core --all-targets`, and `cargo test --locked -p auctioneer-cli --no-default-features --all-targets`. Keep cryptographic/maintenance failure tests free of external credentials and network dependencies. +- [ ] Group commits by actual API/behavior owner, not one enormous incidental formatter diff. Record all remaining old package instances and the upstream owners that constrain them. + +## Task 7: Rebase And Replay The Schema Compiler Patches + +**Files:** `vendor/jsonschema-macros-core/`; new versioned original archive and patch files; `vendor/README.md`; root patch/requirements; `crates/auctioneer-bidder/tests/schema_vendor/`, `schema_replay/`, `schema_compiler_controls.rs` and their existing compiler owners. + +- [ ] Acquire authentic selected published source and inspect its archive members, checksum, VCS and license. Keep old original archives and historical replay assets where existing records need their bytes. Do not use a mutable upstream checkout as the original package. +- [ ] Run the original numeric/type-keyword rejection cases against the unpatched candidate in a disposable workspace. Separately test constructor-once/error caching and explicit-cache ABI/context ownership without each corresponding patch. Record which controls fail before deciding a patch is obsolete. +- [ ] Rebase the type-check, initialization and explicit-cache patches in order, independently replayable against that version's authentic source. Preserve explicit caller-owned context, no implicit clone/default, formats/URI/reference ownership, constructor error behavior and native-only dependency boundaries. +- [ ] Update current archive/member/patch inventories and replay pins only after literal controls pass. Add rejection controls for a wrong version/source, omitted intermediate patch, unexpected added/deleted member and one altered patched member. Expected identities come from independently acquired source and diff assets, not from the expanded tree under test. +- [ ] Run `cargo test --locked -p auctioneer-bidder --test schema_compiler_controls --test schema_cache_controls --test schema_cache_initialization --test schema_cache_bounds`, then the mandatory schema owner: `bash .github/workflows/scripts/test/verify-schema-compiler-conformance.sh schema`. +- [ ] Run existing source-selection/selected semantics and normal/staged core/metadata owners for both feature graphs. Do not enable a serving callback, switch regex engines or claim an outstanding schema proof complete merely because new generated code compiles. +- [ ] Commit the authentic original, portable patch sequence, provenance and code changes as a reviewable family. If upstream removed the ABI needed for existing safety controls and no faithful rebase works, stop for design review rather than shipping a partial upgrade. + +## Task 8: Refresh Artifact Inspection And Implemented Source-Bound Proofs + +**Files:** actual object/gimli/wasmparser/wasm-encoder consumers; `vendor/regex-automata/` and its replay owner if source changes; existing bidder `schema_build`, compiler-layout, regex/source/allocator owners; current upgrade record. + +- [ ] Upgrade root object, gimli, wasmparser and wasm-encoder requirements together with their consuming APIs. Preserve checked section/member bounds, trailing-data and identity rejection, exact generated-validator membership, instrumentation and guest-vs-native distinctions. +- [ ] Reconcile the regex library and all compiler/feature dependencies even if their requirement did not change. Replay the existing resource-layout patch against authentic selected source; if a version changes, use a separately versioned original and rebase, preserving the approved read-only query boundary. +- [ ] Obtain compiler-emitted layouts for the selected native and three guest ABIs from existing probes. Reconcile actual fields/owners against current source inventories; do not infer private layouts from a previous release or a native measurement. +- [ ] Exercise changed bounds using independent literals/source derivations and actual cold/retained/transient allocator owners. Vary unrelated caps independently; preserve fresh processes, exact populations and release assertions. An updated measurement is corroboration, not permission to replace an analytic bound with itself. +- [ ] Run `cargo test --locked -p auctioneer-bidder --test schema_source_conformance -- --test-threads=1`, plus `cargo test --locked -p auctioneer-cli --test bidders_evidence --test bidders_resources --test qualification_migration --test qualification_evidence`. The full source command includes actual application/native/guest probes; a cheap filtered pass cannot replace it. +- [ ] Retain reservation/readiness/limit values. If an implemented bound is invalid under the candidate, stop adoption until an independent same-contract correction is reviewed. Keep already-open complete heap/work/host-fit qualification separate; do not turn this upgrade into an unbounded certification effort. +- [ ] Commit API/proof-identity changes and checkable new observations, not rewritten historical qualification claims. + +## Task 9: Adopt Unicode 16 With An Independent Oracle + +**Files:** `crates/auctioneer-config/src/activity.rs`, `crates/auctioneer-config-data/tests/simple_fold.rs`; new official Unicode 16 source/attribution fixtures under that target's fixture directory; current upgrade record. + +- [ ] Acquire the official [Unicode 16 `CaseFolding.txt`](https://www.unicode.org/Public/16.0.0/ucd/CaseFolding.txt) and its applicable attribution/terms, recording its versioned source and literal digest. The official file defines simple folding as C/S mappings, not full or locale folding. Preserve the original Unicode 15/Go reference capture byte-for-byte. Test the fixture's version, exact record shape, duplicate/status rules, digest and scalar validity in the existing `simple_fold` target. +- [ ] Build an independent test-only equivalence oracle from official C/S records only. Compute each equivalence class's canonical representative without calling `unicode_case_mapping` or `simple_fold_eq`; full (`F`) and Turkic (`T`) mappings must not become simple-fold permissions. No production folding implementation or fixture-generation CLI is added. +- [ ] Before changing the dependency, run the new full-domain Unicode 16 oracle against current Unicode 15 behavior and record the changed classes. Assert the loop covers exactly 1,112,064 Unicode scalar values. Compare old and new class partitions, not only version strings, and report added/merged/split classes explicitly. +- [ ] Upgrade to the selected `unicode-case-mapping` 1.0 release, preserving the single production matching path. Require the full-domain Unicode 16 oracle and ASCII/Kelvin/long-s/sigma/sharp-s/dotted-and-dotless-I/normalization protections. Keep historical unchanged cases; classify changed historical classes explicitly rather than silently filtering failures. +- [ ] Add a negative control proving a known newly recognized equivalence is denied by the old relation and accepted by the new one, plus a one-record mutation proving the independent oracle fails on a changed mapping. Check exact dispatched counts, no skip or empty renamed loop. +- [ ] Run `cargo test --locked -p auctioneer-config-data --test simple_fold --test activity` and affected config/privacy/handler case-insensitive name-resolution controls. Commit the approved semantic migration, oracle source/attribution and delta report together. + +## Task 10: Complete The Locked Graph And Full Acceptance + +**Files:** root requirements/lockfile, current source instructions, current upgrade record. Read current workflows, not a stale copied matrix. + +- [ ] Reconcile every resolved package ID with Task 2's frozen selection. Record upgraded/already-current/removed/upstream-constrained disposition, including coexisting major versions and Git sources. Rerun dry-run audits without adopting later releases; no project-owned requirement or necessary SDK constraint may be silently omitted. +- [ ] Run `cargo fetch --locked` for native and all three guest triples; derive `EDGEZERO_SDK_ROOT` from locked metadata and assert its selected official source/revision. Supply the existing immutable bidder reference objects and tools from `.tool-versions`. No second reference checkout or legacy environment alias is introduced. +- [ ] Run `cargo fmt --all --check` and `cargo clippy --locked --workspace --all-targets -- -D warnings`; execute ordinary secure/default/insecure/CLI feature lanes exactly as owned in `test.yml`. The two existing heavy producer exclusions remain valid only because the mandatory producer owner below executes them separately. +- [ ] Execute all explicit compiler owners with `verify-schema-compiler-conformance.sh all`, `verify-config-build-failures.sh`, `verify-evidence-producers.sh`, the existing full source experiment or its exhaustive CI owners, `resource_boot_parity`, source-selection owners and four normal/staged metadata/core scripts. Preserve `test = false` and required-feature ownership; broad `--all-targets` is not full coverage. +- [ ] Execute the fanout and bidder-handler conformance targets with `conformance-suite`, controlled-native onboarding in secure and insecure feature modes, cold native schema allocation, browser shutdown prerequisites/tests, and real socket cancellation/deadline/privacy owners. Preserve isolated binaries and unchanged workload boundaries. +- [ ] Execute actual WASI catalog/storage controls in both feature modes through `execute-catalog-publication.sh`, all adapter-specific guest checks/lints/conformance builds, the existing Fastly guest runner and the provider workflows' packaging/size gates. Native artifacts cannot stand in for guest/provider evidence. +- [ ] Run the existing raw-JSON, roster, batch-rebase, secure-usersync, libtest-result and feature/dependency-purity gates. Preserve their failure controls. Use the existing scripts rather than adding Rust snapshots of workflow bodies. +- [ ] Record per-command exit status, real libtest result lines, skipped/ignored counts and environmental prerequisites at the exact tested head. Publish CI results separately from local results. Missing provider tooling, unavailable upstream objects, disk failures or jobs that never start remain blocked, not passing. Do not raise timeouts/budgets or remove cases to obtain green. +- [ ] Have the implementation independently reviewed in existing PR #166, with its phase/description updated to the complete version/source delta, compatibility decisions and current proof record. Do not create a second PR. Keep incomplete upgrade/acceptance gates explicit and do not merge without authorization. +- [ ] After approved merge and verified #165 acceptance only, reconcile superseded Dependabot PRs and close the task. Do not close #165 because this planning PR or the upstream prerequisite alone merged. + +## Verification Discipline + +Use @superpowers:test-driven-development for new compatibility repairs, @superpowers:systematic-debugging for failures, and @superpowers:verification-before-completion before claims or publication. Inspect current maintained APIs rather than guessing major-version changes. Record observed reds and greens; planned expected results in this document are not executed output. + +Keep ordinary Cargo caches and serialize heavy local experiments. Compiler/measurement processes retain their existing freshness and independent feature graphs. Do not routinely clean unrelated targets, add result caches, skip slow checks or exceed local disk capacity to run the entire matrix concurrently. Where an existing workflow provides exhaustive isolated owners, preserve that ownership instead of repeating the same expensive child builds in every feature lane. + +The initial planning change contained no upgraded production dependency and did not certify the discovery candidates. Implementation now follows the explicit 2026-11-12 same-PR/retained-SDK amendment above. Preserve the original safety, Unicode-oracle and full acceptance requirements; the later direction changes delivery sequence, not proof or merge gates. diff --git a/docs/superpowers/specs/2026-11-11-rust-dependency-upgrade-design.md b/docs/superpowers/specs/2026-11-11-rust-dependency-upgrade-design.md new file mode 100644 index 0000000..eeb4696 --- /dev/null +++ b/docs/superpowers/specs/2026-11-11-rust-dependency-upgrade-design.md @@ -0,0 +1,102 @@ +# Complete Rust Dependency Upgrade + +## Purpose And Authority + +Deliver [#165](https://github.com/IABTechLab/auctioneer/issues/165), under the existing release-maintenance epic [#12](https://github.com/IABTechLab/auctioneer/issues/12). The user approved upgrading all Rust dependencies, including major releases, Git SDKs, vendored-patch rebases, compatibility fixes and refreshed current proofs on 2026-11-11. Preserve the full adapter acceptance matrix, independent tests and resource limits. + +The requested outcome is one Auctioneer dependency-upgrade implementation PR, with reviewable commits by dependency family. Separate dependency-family PRs would simplify individual reviews but prolong convergence and repeatedly invalidate shared lockfile/proof identities. A compatible-only lockfile refresh is insufficient: it omits the explicitly requested major and exact-pinned upgrades. This document defines the common contract before those changes. + +The user initially authorized a separate, coordinated EdgeZero upgrade first and approved this written spec, including the Unicode 16 proposal, on 2026-11-11. On 2026-11-12 the user directed implementation in existing Auctioneer PR #166 without a new PR, clarified that EdgeZero must stay on PR #275, and instructed CREATOR to continue. This later direction supersedes the separate SDK-first delivery gate for independent Auctioneer upgrades and the separate implementation-PR step. It does not authorize editing PR #275's checkout, forcing incompatible SDK dependencies, weakening acceptance, or merging either repository. + +Retain the existing immutable PR #275 SDK revision and its shared provider/HTTP/JSON/codec constraints while upgrading the remaining graph. [EdgeZero #467](https://github.com/IABTechLab/edgezero/issues/467) remains the owner of future upstream tuple work, not a prerequisite to independent upgrades in #166. Record every version held back by that source explicitly; do not call a constrained package latest. The full all-latest outcome remains unavailable until the corresponding upstream constraints change. + +## Baseline And Inventory + +The planning baseline is `main` at `bc2193096920752cf3b149a1496f9deee1432f8f`, with Rust 1.98.1 and the EdgeZero revision selected by that commit's manifest/lockfile. Use an isolated worktree; preserve the user's modified Fastly configuration, untracked local configuration and unrelated worktrees. + +PR #162 is parallel work, not part of this baseline. If it lands first, rebase on the resulting main, preserve its ownership fixes, refresh the inventory and rerun the affected acceptance. Do not duplicate its code or claim its unmerged proof index is already shipped. + +The following are registry observations from 2026-11-11, not an upgraded build or a promise that upstream releases remain unchanged. `cargo upgrade --dry-run --incompatible allow --pinned allow --recursive false` reported these 23 workspace requirement changes: + +| Dependency | Existing Requirement | Observed Candidate | +| --- | --- | --- | +| hmac | =0.12.1 | =0.13.0 | +| jsonschema | =0.58.6 | =0.61.1 | +| jsonschema-macros-core | =0.58.6 | =0.61.1 | +| fastly | =0.13.1 | =0.13.2 | +| brotli | =8.0.4 | =9.1.1 | +| getrandom | 0.3 | 0.4 | +| gimli | =0.32.3 | =0.34.0 | +| ipnetwork | 0.20 | 0.21 | +| lru | 0.12 | 0.19 | +| mime | 0.3.17 | 0.3.18 | +| object | =0.37.3 | =0.41.0 | +| png | =0.17.16 | =0.18.1 | +| reqwest | 0.12 | 0.13 | +| regex | =1.12.4 | =1.13.1 | +| sha2 | 0.10 | 0.11 | +| zeroize | 1.8 | 1.9 | +| syn | 2 | 3 | +| thiserror | 1 | 2 | +| toml | 0.8 | 1.2 | +| unicode-case-mapping | =0.5.0 | =1.0.0 | +| wasmparser | =0.247.0 | =0.263.0 | +| wasm-encoder | =0.247.0 | =0.263.0 | +| worker | =0.8.5 | =0.9.0 | + +The unchanged-requirement lockfile dry run reported 147 compatible package changes, including updates hidden by broad requirements and dependencies inherited through the SDK. Inventory all resolved package IDs, not only unique crate names: valid different-major instances can coexist. Classify each as upgraded, already current, removed because its owner no longer needs it, or explicitly constrained by an identified upstream requirement. Do not force a transitive major across an upstream API contract or call a retained old instance current merely because another major was upgraded. + +`cargo-outdated 0.19.0` failed because its temporary project omitted the local vendor paths. That failure is not evidence that dependencies are current or that Auctioneer is broken. Use the two successful Cargo dry runs, Cargo metadata and direct upstream registry/source inspection; do not alter production manifests to accommodate that audit tool. + +Refresh the inventory once at implementation selection, then freeze exact registry versions, Git revisions, source archives and patch identities for verification. Report any newer release discovered after that freeze rather than repeatedly changing the tested graph during acceptance. + +Audit versioned Git dependencies separately from the registry dry run. The Spin fork's default branch is not its pinned repair revision. Independent upstream inspection found [v8.0.0](https://github.com/spinframework/spin-rust-sdk/tree/acf428a09f516dd1b9fe6ddfd33038f5b0f3e7e0) at `acf428a09f516dd1b9fe6ddfd33038f5b0f3e7e0` and the required [eager-progress repair #169](https://github.com/spinframework/spin-rust-sdk/pull/169) merged on 2026-11-03. Treat that maintained upstream source as a candidate to replace the version-7 fork, subject to the coordinated interface/progress gates below; the registry-only report did not establish that Spin was current. A missing GitHub Release object does not mean a release tag or registry package is absent. + +## Dependency Ownership + +Keep declarations in `[workspace.dependencies]`, inherited by each crate. `Cargo.lock` binds the complete resolved graph, not just the workspace requirements. Do not add duplicate crate-local versions, legacy dependency aliases, new workspace crates, alternate loaders or unrelated refactors to make a migration easier. + +Keep `.tool-versions` authoritative. Retain the current Rust and provider tools unless a selected dependency or packaging contract requires a reviewed tool change. A new Rust minimum requires checking the actual native and guest toolchain/ABI controls, not just changing the version string. Do not install prerelease dependency versions to satisfy this stable-upgrade request. + +Keep features and platform ownership intentional. Native CLI fetches, artifact inspection and compiler qualification must not become guest serving dependencies. Preserve required worker/Spin/WASI features and the existing release/wasm-release packaging distinction. Resolve duplicate versions only when the actual owners permit unification; do not replace upstream constraints through an unreviewed global patch. + +## SDK And Shared-Type Gate + +The observed EdgeZero PR #275 head is `b97efec185abbaa901e633a980975c98ef2f6c3b`. This is an integration revision, not a published stable SDK release. Adoption must stay on the required retained-outbound/lifetime lineage and use an immutable official-repository revision; changing to an unrelated default branch is not an upgrade strategy. + +A follow-up read during planning found head `14a6ca8bb5a5cbe055a1f725bdab8f42569a3bf0`, two commits ahead, changing Fastly lifecycle/progress-test files but not `Cargo.toml`. Direct inspection confirmed the shared constraints below remain. This is an audit update, not adoption or verification of those new commits. The separate SDK effort must select and review its carrying revision; do not chase a moving tip during downstream acceptance. + +That source still exact-pins older versions in these groups: + +| Group | Concrete Upstream Constraints | Required Decision And Evidence | +| --- | --- | --- | +| Provider interfaces | Fastly 0.13.1; Worker 0.8.5; the reviewed Spin version-7 fork/revision | A compatible SDK revision must own the newer provider ABI before Auctioneer entrypoints use its types. Qualify the upstream Spin version-8 candidate and its retained eager-progress repair before replacing the fork. | +| Shared HTTP/JSON | http 1.4.2; serde_json 1.0.150; bytes 1.12.1 | Bind interface types and raw-value/header storage controls to the selected tuple. Do not introduce incompatible duplicate boundary types. | +| Native HTTP | reqwest 0.13.4 | Verify resolver compatibility and native transport policy. The maintenance fetcher and SDK client have different owners; preserving a crate name does not preserve TLS, redirects, pooling or timeout behavior. | +| Codec stack | async-compression, compression-codecs/core, brotli/decompressor, flate2, CRC/adler helpers | Reconcile the actual decoding tuple and window/framing/cleanup contract. Auctioneer's archive encoder can have a separate owner; do not relabel the SDK decoder as upgraded when only the encoder moved. | + +A newer requirement is not assumed resolvable while an SDK exact pin remains. Obtain concrete resolver/source evidence. Cargo [rejects conflicting exact compatible-version requirements and treats different-version public types as distinct](https://doc.rust-lang.org/cargo/reference/resolver.html). The original SDK-first sequence is superseded narrowly by the 2026-11-12 direction above: retain the existing PR #275 revision for this implementation and upgrade independently owned dependencies around its constraints. Any later SDK adoption must still retain PR #275's required outbound/lifetime contract and publish the shared version tuple, native and guest verification, and unresolved qualification boundaries. Upstream constraints remain blockers to an all-latest outcome; an issue, release tag or successful resolver run is not delivery evidence. + +The current `codec_pins` owner also requires one resolved copy of each asserted codec. Do not weaken that check merely to admit a newer build-time encoder beside an old SDK decoder. Default to a coordinated tuple upgrade; any replacement with a graph-scoped check requires independent build/runtime ownership evidence and at least the same rejection coverage before cutover. + +## Compatibility And Proof Migrations + +1. **General API/tooling:** migrate `syn`/`thiserror`/TOML, randomness/cache and object/DWARF/WASM-inspection call sites using maintained APIs. Continue generating Rust with `quote!` and parsed `syn` trees. Preserve parser rejection cases, config null/absence/override semantics, CLI validate/diff/push behavior and archive safety. Compilation alone does not prove these contracts. +2. **Cryptography and browser state:** upgrade HMAC/SHA together with their trait family, preserving the signed-cookie envelope, MAC bytes, active-key selection, strength/version checks, constant-time verification and complete-cookie ceiling. Use the existing captured/independent expectations and real handler controls. Do not regenerate expected signatures with the implementation under test. +3. **Schema compiler and regex:** acquire authentic new published source, record archive/VCS/license identity, and replay/rebase each required compiler patch independently. Remove a patch only when an upstream implementation passes its original rejection/lifecycle/cache controls without it. Keep the selected engine, schemas, feature boundaries and explicit cache ownership. Recheck already-current patched packages too. Do not write another schema converter or regex engine. +4. **Source-bound resource controls:** update current dependency tuples, portable patch inventories, compiler-emitted layout controls, parse/visitor and allocator regressions against the new source and all relevant ABIs. Do not guess private layouts or change an independent bound to the measured result. If a selected version violates an existing charged bound, stop that adoption pending an independently justified correction or reviewed design decision; do not raise a ceiling or reduce workload. +5. **Unicode and semantic changes:** the existing `simple_fold` owner explicitly asserts Unicode 15. The published `unicode-case-mapping 1.0.0` source uses Unicode 16. The user approved adopting Unicode 16 simple folding as the one current behavior, not adding a compatibility mode. Before cutover, report merged/split equivalence classes against the old contract and validate every scalar against independent official Unicode 16 C/S case-fold data, excluding full/locale folding. Preserve the Go 15 capture bytes, unchanged applicable historical cases, ASCII and special-case protections; do not merely change the expected version literal, filter out changed scalars or derive the new oracle from the upgraded Rust library. Do not add a new production folding engine or CLI just to produce fixtures. Any additional TOML, HTTP, JSON, URL or error semantic change requires its own explicit decision rather than being hidden as API repair. + +Use versioned replacement patch/evidence assets where existing bytes remain referenced. Preserve external/reference captures, original source archives needed by historical records, frozen profiles and historical verification documents. A dependency upgrade changes current source identity; it does not retroactively recertify old measurements. + +OpenRTB recommendations take precedence over reference-server quirks. The proposed Unicode-data migration is an Auctioneer matching-policy decision, not an OpenRTB mandate. Apart from that explicitly reviewed version change, this upgrade does not authorize changing auction messages, no-bid signaling, privacy decision tables, bidder/alias attribution, SSRF/HTTPS policy or one-runtime-config behavior. Surface any unavoidable further semantic change separately before implementing it. + +## Acceptance And Completion + +The workflows and [test ownership guide](../../testing/development.md) remain authoritative for the full matrix. Required validation includes all four ordinary native feature graphs, secure package controls, macro/config and standalone compiler suites, patch replay, both heavy evidence producers, real boot/CLI parity, fanout/onboarding, all guest triples, guest execution where already required, and provider artifact packaging/size gates. Preserve their existing process isolation, environmental prerequisites, feature modes and dispatch-count checks. + +Run focused red/green controls for changed failure/compatibility branches, then the complete matrix at the carrying head. Capture current source/dependency identities, actual result lines, package/version deltas and all unresolved blockers. `--all-targets` does not substitute for explicit `test = false`, required-feature or hosted owners. Missing prerequisites and jobs that never start are not passes. + +Existing source/ABI/container/allocator/provider proofs that were incomplete remain incomplete. This task refreshes implemented proofs and controls; it does not silently absorb the separate full schema or host-fit qualification backlog. Preserve the current accounting, reservations, readiness flags and known limitations unless an independently reviewed correction is part of this change. No upgraded target becomes qualified merely because tests or package-size checks pass. + +Do not mark the implementation ready or close #165 while selected upgrades, required semantic decisions, SDK prerequisites or mandatory acceptance remain unresolved. A draft may report partial progress honestly; it is not the completed all-dependency deliverable. No merge is authorized by approval of this design approach. diff --git a/docs/testing/evidence/rust-dependency-upgrade-20261112.md b/docs/testing/evidence/rust-dependency-upgrade-20261112.md new file mode 100644 index 0000000..b6da8d3 --- /dev/null +++ b/docs/testing/evidence/rust-dependency-upgrade-20261112.md @@ -0,0 +1,110 @@ +# Rust Dependency Upgrade Checkpoints + +This is the current implementation record for [#165](https://github.com/IABTechLab/auctioneer/issues/165) in existing [PR #166](https://github.com/IABTechLab/auctioneer/pull/166). It is not a deployment qualification, a complete all-latest claim, or permission to merge. Full hosted acceptance and independent implementation review remain required. + +## Selection And Retained Sources + +The 2026-11-12 requirement audit found 23 candidate requirement changes; the compatible lockfile audit found 148 updates. Those are selection observations, not test counts. Nineteen candidate requirements are updated below. `Cargo.lock` records the full resolved graph, including remaining transitive versions and sources. Its selected bytes have SHA-256 `9cd3a303b4cebde1619220ef8a3eb67a7d1540ec836d308bf2571f28040746fe`. + +The implementation incorporates main's archive refresh at `7f6773e29d7657819a90dd53522055623b9fd6f2` and preserves the concurrent PR-branch refresh merge `c29c44d608b244994b1bcc05a3391fee85b53aed`; their integrated source trees matched. No separate upgrade PR is created. + +| Workspace Dependency | Selected Requirement | Resolved Version | +| --- | --- | --- | +| hmac | `=0.13.0` | 0.13.0 | +| jsonschema | `=0.61.2` | 0.61.2 | +| jsonschema-macros-core | `=0.61.2` | 0.61.2, patched local source | +| getrandom | `0.4` | 0.4.3 | +| gimli | `=0.34.0` | 0.34.0 | +| ipnetwork | `0.21` | 0.21.1 | +| lru | `0.19` | 0.19.0 | +| mime | `0.3.18` | 0.3.18 | +| object | `=0.41.0` | 0.41.0 | +| png | `=0.18.1` | 0.18.1 | +| regex | `=1.13.1` | 1.13.1 | +| sha2 | `0.11` | 0.11.1 | +| zeroize | `1.9` | 1.9.1 | +| syn | `3` | 3.0.10 | +| thiserror | `2` | 2.0.21 | +| toml | `1.2` | 1.2.1+spec-1.1.0 | +| unicode-case-mapping | `=1.0.0` | 1.0.0 | +| wasmparser | `=0.263.0` | 0.263.0 | +| wasm-encoder | `=0.263.0` | 0.263.0 | + +All six EdgeZero requirements and eight resolved EdgeZero packages retain the official repository and immutable PR #275 revision `598f0a2a490eb83dd31c06c024a0cefa8e049628`. No SDK checkout or exact pin is patched to force a newer shared tuple. Future coordinated tuple work belongs to [EdgeZero #467](https://github.com/IABTechLab/edgezero/issues/467). + +| Retained Owner | Selected Version | Candidate Not Adopted | Constraint | +| --- | --- | --- | --- | +| Fastly | 0.13.1 | 0.13.2 | Retained SDK provider type identity | +| Worker | 0.8.5 | 0.9.0 | Retained SDK provider type identity | +| Brotli | 8.0.4 | 9.1.1 | Retained SDK codec tuple and single-copy contract | +| Maintenance reqwest | 0.12.28 | 0.13.5 | SDK pins 0.13.4; unifying maintenance native-TLS features into that client changes its implicit backend selection | +| Spin Git dependency | 7.0.0 at `6c59ed5b4fcb377072763aee0b27a3abdd8edb72` | Maintained version-8 candidate | Retained SDK's provider/fork identity and eager-progress repair | + +The SDK's reqwest remains 0.13.4. Maintenance retains its existing native TLS, redirect, timeout, gzip and bounded-read behavior. Older transitive major versions remain when their owners require them, including Syn 1/2 alongside workspace Syn 3, the compiler's own Syn 2, and the backtrace/tooling object and WASM parser versions. A duplicate is not removed by silently changing its owner's features or public types. Tool versions, workload limits, reservations, resource ceilings and the additive budget are unchanged. + +## Compatibility Repairs + +SHA-256 output now uses the existing workspace `hex::encode` rather than formatting the newer digest array with an unsupported `LowerHex` implementation. Expected signatures, capture digests and original reference bytes are not regenerated. HMAC's key construction imports its new `KeyInit` trait without changing the envelope or verification algorithm. + +Syn consumers use the maintained trait-implementation, receiver, safety, function-pointer and guarded-pattern AST shapes. Object/DWARF readers use typed flags, checked writer offsets, fallible imports, decoded attributes and absolute tree depth while retaining their refusal predicates and input limits. The PNG decoder handles an absent bounded output size as `LimitsExceeded`. + +Tokio's new descriptor registration API requires one user-approved, narrowly checked unsafe exception in the private stdout writer. The owned descriptor remains private and valid across readiness waits, cancellation and timeout; the existing full-pipe deadline control ran successfully. No workspace unsafe policy is widened. + +The WASM parser now enables async components by default. The existing negative stream control explicitly disables the proposal, rather than relying on the superseded default; positive static component support and malformed-payload refusal remain tested. Local guest controls use the `.tool-versions` Wasmtime 48.0.2, not the unrelated version 45.0.0 found first on the shell's PATH. + +## Compiler And Unicode Provenance + +The authentic 0.61.2 compiler archive, source revision, all 280 published members, retained license and nine patched member identities are checked by the existing source owner. Three versioned patches replay separately and collectively; the original 0.58.6 archive and patches remain unchanged as historical evidence. See [vendor documentation](../../../vendor/README.md). + +The new upstream repetition-count and collapsed-pattern paths bypass original engine construction. The rebase preserves original-pattern construction and its default/supplied limits in every generated mode. A real pre-correction run of `repeated_and_collapsed_patterns_cannot_bypass_engine_construction_limits` failed because an oversized pattern produced no refusal. After correction the same test and all existing initialization/cache controls passed. The source-compatibility failure in the unchanged constructor-observing target was also recorded; its wrapper was not expanded to hide the constructor substitution. + +Unicode 16 uses an independent official C/S oracle, not the upgraded library to generate expected classes. It covers all 1,112,064 scalar values and retains the Go 1.23.12 / Unicode 15 capture unchanged. Exactly 30 pairs merge former singleton classes; all 1,424 old nontrivial classes are unchanged and no class splits. The new Cyrillic pair control failed against the old dependency and passed after upgrade. Source identities, attribution, complete delta and oracle boundaries are in the [fixture record](../../../crates/auctioneer-config-data/tests/fixtures/unicode/README.md). + +## Executed Local Checkpoints + +These are executed working-tree checkpoints, not blanket acceptance of the final commit. Earlier family checks precede the final compiler/source-reader changes. The final whole-tree and hosted results must be read separately. + +| Command/Owner | Actual Result | +| --- | --- | +| Core signed-cookie units | `17 passed; 0 failed; 657 filtered out` | +| Privacy library | `291 passed; 0 failed` | +| Config library and root shape | `419 passed; 0 failed`, then `5 passed; 0 failed` | +| Macro library and conformance owner | `23 passed; 0 failed`, then `3 passed; 0 failed` (26 compiler cases) | +| Unicode/activity owners | `8 passed; 0 failed`, and `2 passed; 0 failed` | +| Pixel/reference owner | `18 passed; 0 failed` | +| Compiler constructor/cache owners | `15 passed; 0 failed`, `1 passed; 0 failed`, `2 passed; 0 failed` | +| Compiler compatibility and cold native allocation | `193 passed; 0 failed`, and `1 passed; 0 failed` | +| Exact vendor inventory/refusal controls | `16 passed; 0 failed; 314 filtered out` | +| Portable patch replay controls | `3 passed; 0 failed; 327 filtered out` | +| Artifact reader group with pinned Wasmtime | `180 passed; 0 failed; 150 filtered out` | +| DWARF layout group | `15 passed; 0 failed; 676 filtered out` | + +An initial complete default-workspace lane exited 101: 6,533 passed, 39 failed, 19 ignored across 245 result summaries. All 39 failures were in three CLI source/evidence targets. The captured artifact bound `inspection.rs` to SHA-256 `04806a2ec28a655b545d586d0216ef4db955562e441cac0156172adcdfaff8ec`, while its subsequently edited file was `107bd610215e29760caf2957d8a8289f6002d671d2776b09cee418ed3d50e0ac`. This is a real nonpassing run, not a waived failure. The source guard remains unchanged; final verification must rebuild against frozen source and rerun the lane. + +## Frozen Native Verification + +The subsequent complete default-workspace lane exited 0, with 245 libtest summaries totaling **6,572 passed, 0 failed, 19 ignored**: + +```sh +cargo test --locked --offline --workspace --all-targets --no-fail-fast -- \ + --skip tests::selected_schema_source_producer_records_exact_real_dispatch_without_qualification \ + --skip tests::controlled_native_acceptance_requires_all_producers_but_never_completes_the_full_catalog +``` + +The only subsequent source change simplified the artifact reader to positively admit ELF/Mach-O and reject other formats, without changing its predicates or adding a lint exception. After that cleanup, all 180 artifact-reader controls passed again. Strict workspace Clippy and explicitly selected `schema_build_controls` / `schema_source_conformance` Clippy both exited 0 under `-D warnings`. The latter targets have explicit CI ownership and are not covered by broad `--all-targets` selection alone. + +The source-bound CLI targets were rebuilt and rerun after that final cleanup, not credited from an earlier artifact: + +```text +test result: ok. 776 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out; finished in 10.97s +test result: ok. 17 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 49.15s +test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 10.05s +``` + +Those are the CLI binary, `bidders_evidence` and `bidders_resources`, respectively. The two producer exclusions are the same ones owned by the existing mandatory producer lane, not new skips. `cargo fmt --all -- --check`, raw-JSON fixture checks and refusal fixtures, batch rebase, roster checks and refusal fixtures, and all 18 libtest-summary controls passed. The raw-JSON gate reported `203 raw JSON fixture(s) across 56 file(s), all budgeted`. + +The scoped read-only author audit found no cryptographic, Unicode or compiler-patch semantic blockers. It did not execute tests and is not formal independent approval. + +## Outstanding Acceptance + +The full hosted matrix remains required: secure/insecure/maintenance/conformance lanes, fresh compiler/producer experiments, normal/staged source controls, actual guest execution and provider packaging. Current-head hosted results and independent implementation review remain pending; local default-workspace success is not a substitute. The two existing workspace producer exclusions retain their separate mandatory CI owner; this record does not create another exclusion. Missing tools, unavailable storage or unexecuted checks are not passes. No hosted acceptance, deployment readiness, issue completion or merge is claimed by this checkpoint. The SDK-constrained candidates above are not upgraded or certified by this work. diff --git a/vendor/README.md b/vendor/README.md index 533e608..f152e6e 100644 --- a/vendor/README.md +++ b/vendor/README.md @@ -2,16 +2,17 @@ ## Schema Compiler -`jsonschema-macros-core/` contains the published 0.58.6 package from +`jsonschema-macros-core/` contains the published 0.61.2 package from [Stranger6667/jsonschema](https://github.com/Stranger6667/jsonschema), with three separate compiler patches. It is excluded from the Auctioneer workspace and patched through -the root manifest. The selected schema engine remains a native test dependency; -this does not enable schema validation in deployed auctions. +the root manifest. It generates the controlled-native validators and the +explicitly staged guest probes. This upgrade does not promote a bidder or +qualify guest serving. The adjacent original `.crate` archive is retained for offline provenance verification. Its SHA-256 is -`bf3ebe067f2c25a981a7d1b2f696fc213e10dbf80ba5fe997f7dc2e4fe261f26`. -Its source revision is `55ac1664384793c5d3b20745d3f9c169dfe2c06f`. +`75afa4b5e6986cc221f5339d7d6149360f0bf8e65bcb23617dc0f92900b576d2`. +Its source revision is `0e82636fde8b2afb5e712ede6c261166ea10fc17`. All 280 published members are preserved. The upstream MIT license, fetched from that source revision, is added because the published package omits it. @@ -44,9 +45,18 @@ shared regex constructors and returns `None` on a cached constructor error. Non-opted-in output keeps the existing ABI. The existing `syn` dependency enables structured mutable AST traversal for this isolated lowering pass. -This patch changes exactly six existing members: `Cargo.toml`, +This patch changes exactly seven existing members: `Cargo.toml`, `Cargo.toml.orig`, `src/codegen.rs`, `src/context.rs`, `src/lib.rs`, and -`src/tests.rs`. It adds one member, `src/codegen/explicit_cache.rs`. +`src/tests.rs`, plus `src/codegen/regex.rs`. It adds one member, +`src/codegen/explicit_cache.rs`. + +Version 0.61.2 introduces repetition-count matchers and collapsed search +patterns before engine construction. The rebased patch retains original-pattern +engine construction in every mode, including the default and supplied size +limits. Otherwise these substitutions bypass the constructor limits and the +initialization failure contract. The unchanged constructor controls and direct +oversized-repetition refusal tests cover this compatibility requirement; it is +not permission to substitute a matcher or relax a resource limit. The direct automata dependency is native test-only. Its resolved engine features and configured NFA/hybrid limits are unchanged. Explicit ownership @@ -69,14 +79,18 @@ the complete schema compatibility set, and target/resource qualification. ## Upgrades The portable changes are -[`patches/jsonschema-macros-core-type-check.patch`](patches/jsonschema-macros-core-type-check.patch), -[`patches/jsonschema-macros-core-regex-initialization.patch`](patches/jsonschema-macros-core-regex-initialization.patch), -and [`patches/jsonschema-macros-core-explicit-cache.patch`](patches/jsonschema-macros-core-explicit-cache.patch). +[`patches/jsonschema-macros-core-0.61.2-type-check.patch`](patches/jsonschema-macros-core-0.61.2-type-check.patch), +[`patches/jsonschema-macros-core-0.61.2-regex-initialization.patch`](patches/jsonschema-macros-core-0.61.2-regex-initialization.patch), +and [`patches/jsonschema-macros-core-0.61.2-explicit-cache-all-modes.patch`](patches/jsonschema-macros-core-0.61.2-explicit-cache-all-modes.patch). Their SHA-256 values match the portable compiler replay test pins: - Type-check: `1d1ed4cdfdd21abbd2c469bbee6f7aa3ea8079c736dd22b9abe5d08e76265358`. -- Regex initialization: `a3a0e791aeedd859835cb97e8a36d9c5c6cdb1db523c6348a21f41d1876a65f2`. -- Explicit cache: `32d16bb697447d2158b0b40da829fc1e93d16527b2b7c1b42345ae5689a18993`. +- Regex initialization: `b21e13915ba100b27a8db5c1b765b5f81c302be806d763359f73e0ca5a5be798`. +- Explicit cache: `846658280e27162d5ea8334ba347eb86e0cf9ff05d22f701e632ce648868befe`. + +The original 0.58.6 archive and unversioned patch files remain historical +artifacts. They are not the active compiler pins. Published 0.61.2 snapshots +come unchanged from its original archive, not from recapturing patched output. Integration tests replay them in order against fresh published source and compare every changed or added member with the checked-in compiler tree. @@ -88,12 +102,12 @@ For a new upstream version, retain the new original package and its checksum, refresh the expanded source, then rebase all three patches in order. From the repository root: ```sh -git apply --check --directory=vendor/jsonschema-macros-core vendor/patches/jsonschema-macros-core-type-check.patch -git apply --directory=vendor/jsonschema-macros-core vendor/patches/jsonschema-macros-core-type-check.patch -git apply --check --directory=vendor/jsonschema-macros-core vendor/patches/jsonschema-macros-core-regex-initialization.patch -git apply --directory=vendor/jsonschema-macros-core vendor/patches/jsonschema-macros-core-regex-initialization.patch -git apply --check --directory=vendor/jsonschema-macros-core vendor/patches/jsonschema-macros-core-explicit-cache.patch -git apply --directory=vendor/jsonschema-macros-core vendor/patches/jsonschema-macros-core-explicit-cache.patch +git apply --check --directory=vendor/jsonschema-macros-core vendor/patches/jsonschema-macros-core-0.61.2-type-check.patch +git apply --directory=vendor/jsonschema-macros-core vendor/patches/jsonschema-macros-core-0.61.2-type-check.patch +git apply --check --directory=vendor/jsonschema-macros-core vendor/patches/jsonschema-macros-core-0.61.2-regex-initialization.patch +git apply --directory=vendor/jsonschema-macros-core vendor/patches/jsonschema-macros-core-0.61.2-regex-initialization.patch +git apply --check --directory=vendor/jsonschema-macros-core vendor/patches/jsonschema-macros-core-0.61.2-explicit-cache-all-modes.patch +git apply --directory=vendor/jsonschema-macros-core vendor/patches/jsonschema-macros-core-0.61.2-explicit-cache-all-modes.patch ``` Update the exact version, archive and patched-file pins only in that reviewed diff --git a/vendor/jsonschema-macros-core-0.61.2.crate b/vendor/jsonschema-macros-core-0.61.2.crate new file mode 100644 index 0000000..7d0ada7 Binary files /dev/null and b/vendor/jsonschema-macros-core-0.61.2.crate differ diff --git a/vendor/jsonschema-macros-core/.cargo_vcs_info.json b/vendor/jsonschema-macros-core/.cargo_vcs_info.json index 5e23258..832081a 100644 --- a/vendor/jsonschema-macros-core/.cargo_vcs_info.json +++ b/vendor/jsonschema-macros-core/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "55ac1664384793c5d3b20745d3f9c169dfe2c06f" + "sha1": "0e82636fde8b2afb5e712ede6c261166ea10fc17" }, "path_in_vcs": "crates/jsonschema-macros-core" } \ No newline at end of file diff --git a/vendor/jsonschema-macros-core/Cargo.lock b/vendor/jsonschema-macros-core/Cargo.lock index fea3482..0eb286e 100644 --- a/vendor/jsonschema-macros-core/Cargo.lock +++ b/vendor/jsonschema-macros-core/Cargo.lock @@ -114,9 +114,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.6.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f74872d07caf508b30a21f6836e7d7016a2eaf7d9ff4f48deaa58cd8a0407630" +checksum = "4ff2a8126fff0f8c839080d619675a585e61720bb12d2baceae45769fd66f155" dependencies = [ "find-msvc-tools", "shlex", @@ -188,9 +188,9 @@ checksum = "1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" [[package]] name = "codspeed" -version = "5.0.2" +version = "5.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0379da47d0de730b2f7900e3f2d9c3b5efc21b46875282305300b4851f03e70" +checksum = "1cade51e6e6e30e7ea2cd9599fa5d5d5f48255a6b221bbd0cab1cf32f3c23c65" dependencies = [ "anyhow", "cc", @@ -206,9 +206,9 @@ dependencies = [ [[package]] name = "codspeed-criterion-compat" -version = "5.0.2" +version = "5.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65f64942456bd4514b06ba4c72623bf197931d05d3d1db61b8a0c6289b30b2c7" +checksum = "b5d1640d31b122c8d754939c6ae4040709a9602f289d11e43075476a21285020" dependencies = [ "clap", "codspeed", @@ -219,9 +219,9 @@ dependencies = [ [[package]] name = "codspeed-criterion-compat-walltime" -version = "5.0.2" +version = "5.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86691354129085562c025293f9e8b35bf9054813bb9981be3a96aa8490c07d1" +checksum = "2a83eed387b8f84aad4cb29607758bec3ab3f53b1734af934ddae7fee626d8ce" dependencies = [ "anes", "cast", @@ -313,9 +313,9 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "either" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" +checksum = "0e9c71c2167ca323c882b99918929403426e2373ea17242ff5653e0d5e1058be" [[package]] name = "encode_unicode" @@ -325,9 +325,9 @@ checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "equivalent" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "00d174d5400e5e8fd687ad1049e2f578285fa914201b1af7e8b112a4546bd826" [[package]] name = "errno" @@ -341,9 +341,9 @@ dependencies = [ [[package]] name = "fancy-regex" -version = "0.19.2" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d301f5bf187b3c295fce6468d3875037a0bccc5f6b151c63cac2f85babf21912" +checksum = "0a2e16b9a584b602f1e0e5e22c30ca0906786088c27500653e432d086def8b53" dependencies = [ "bit-set", "regex-automata", @@ -358,9 +358,9 @@ checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" [[package]] name = "find-msvc-tools" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484" +checksum = "1c66915cc5391097de7a2b0b972e8505aa33c0df401fd3a6811dbdb32881ba48" [[package]] name = "fluent-uri" @@ -491,15 +491,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +checksum = "3bd1574e617a9a6c1f8f8181bd7e841e1f20e4277607ef28945765188d6284d4" [[package]] name = "js-sys" -version = "0.3.106" +version = "0.3.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5" +checksum = "8dc09d2154098bbf4ef54eab6b117a3c24cbbffe94046b16ee6d6d4510584d3a" dependencies = [ "cfg-if", "wasm-bindgen", @@ -507,7 +507,7 @@ dependencies = [ [[package]] name = "jsonschema-macros-core" -version = "0.58.6" +version = "0.61.2" dependencies = [ "codspeed-criterion-compat", "criterion", @@ -529,18 +529,18 @@ dependencies = [ [[package]] name = "jsonschema-regex" -version = "0.58.6" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a968fffd387b2ab005bf00c1851f5d26e90df05b6f7ad609ed0d620033cca5e7" +checksum = "7e41151614b6c927e21982be8bef5a26741ae5a0ae6a781eedee2aa930a980e6" dependencies = [ "regex-syntax", ] [[package]] name = "libc" -version = "0.2.190" +version = "0.2.191" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78" +checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a" [[package]] name = "linux-raw-sys" @@ -716,14 +716,14 @@ checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.10", ] [[package]] name = "referencing" -version = "0.58.6" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558f3855529c0a7e78a48e409fa653456e55f1b167eab4109c16a255b7727e3f" +checksum = "a028057ef852c58a42d75e09da87b5e733f4030f4c7411728955e4f87203a577" dependencies = [ "ahash", "fluent-uri", @@ -767,9 +767,9 @@ checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "rustix" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" +checksum = "e5e76742e5294153d4dde1207dbec5bdd81eef6fabdc0d2118babadabfd858aa" dependencies = [ "bitflags", "errno", @@ -826,14 +826,14 @@ checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.10", ] [[package]] name = "serde_json" -version = "1.0.151" +version = "1.0.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +checksum = "e7e9cc8b1b85264074fbcc02a88680c4096b1e47df8f739dceb03bf482f04bd6" dependencies = [ "itoa", "memchr", @@ -856,9 +856,9 @@ checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" [[package]] name = "smallvec" -version = "1.16.2" +version = "1.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9395f0f0eee849a9b707b2f06bb92a6a422090e2123bb2ef8e87a0e61892a8e" +checksum = "149309498a5f7334b12ddae0cad8aba81ce785fe91755068867e017cf98fee46" [[package]] name = "statrs" @@ -883,9 +883,9 @@ dependencies = [ [[package]] name = "syn" -version = "3.0.6" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" +checksum = "4ae9ccbea3a7b0b09443036490c8f34a8b1b760fd345e5c0dae0aac718faea79" dependencies = [ "proc-macro2", "quote", @@ -907,34 +907,34 @@ dependencies = [ [[package]] name = "test-case" -version = "3.4.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "124953e7f67cb0b2fcfb87e899e4ae5a64fb68e2e160767933cc67b646fb0042" +checksum = "ae6e80608d2037173d7d59a09089d249e43352c182f6dde6b00d138bcb7cfdbe" dependencies = [ "test-case-macros", ] [[package]] name = "test-case-core" -version = "3.4.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd097615b407247e102046ba34426bb594923ab3554cf0f3cdfed050f1a5a3e8" +checksum = "29b8e1f65819001927b8cdcbb5560f2428212f2e5ab5684e3c6815a4d80e72db" dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.10", ] [[package]] name = "test-case-macros" -version = "3.4.0" +version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4ce35ece947bccac166e1ded639133827a953f69a48ba134d17f91108333082" +checksum = "802d6165a14df1598b7290a8c546df402940d3cfbe82d15c0fd35de176771693" dependencies = [ "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.10", "test-case-core", ] @@ -950,18 +950,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "1.1.1+spec-1.1.0" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +checksum = "173f25c883cd2176a2d8212155638c0a60d484a9d84546d270866f40f56b6e49" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.25.15+spec-1.1.0" +version = "0.25.19+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1340ea94a5856333492c9064b02c778b191dd2c853778d9609debdcdfea3a614" +checksum = "dd43688c4858d7264ae1cf9a9f874a67c3feb74a883b1cd7bebd6a4ea8307218" dependencies = [ "indexmap", "toml_datetime", @@ -971,18 +971,18 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.1.3+spec-1.1.0" +version = "1.1.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" +checksum = "baa693a8032d7e1cada7d0041e96126df243179ff061456783ac7f12bda4744c" dependencies = [ "winnow", ] [[package]] name = "unicode-ident" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" +checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563" [[package]] name = "version_check" @@ -1011,12 +1011,11 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.129" +version = "0.2.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409" +checksum = "a0181c14ddd6c7b8b0b0132a5f1ea2f32be0d893cd3ea97b6e3b28886b8a3d1c" dependencies = [ "cfg-if", - "once_cell", "rustversion", "wasm-bindgen-macro", "wasm-bindgen-shared", @@ -1024,9 +1023,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.129" +version = "0.2.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535" +checksum = "6e931a02a39abdbf66966fc35902b5ed58344750a70885bed4ebb3d8eaf28ed9" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1034,22 +1033,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.129" +version = "0.2.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7" +checksum = "2ca4b54280e455bd831e33a6b8e734baf432fe63fbc35c42ac14ce67a043a53a" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 3.0.6", + "syn 3.0.10", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.129" +version = "0.2.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6" +checksum = "3b1f9c3798725016c6ee5f2f57869ec0831e8bbc0ab0310a86e787e97f41389e" dependencies = [ "unicode-ident", ] @@ -1102,9 +1101,9 @@ dependencies = [ [[package]] name = "winnow" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +checksum = "8c3b93199df0ab874cdf0c6a94f0a0dc3423fe41f1cafb62b8bd7b1deb277aef" dependencies = [ "memchr", ] @@ -1117,18 +1116,18 @@ checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "zerocopy" -version = "0.8.60" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6400fc4bb7426f6faac3fb07566122bb18622e3022bd2c36426a92ed489b1dbe" +checksum = "e5fe1f8f1b06191a00962174c61aa5005e0bb391a6d80d07e24d115c01a92ed8" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.60" +version = "0.8.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99c27cc7525bad4df59a45e073c45b2c2aa820efb588234cc23a547ec69a34db" +checksum = "863ad3ac83293fb4d740aedbfdc9240dd8d1a50c1099acd76ce80ce7c7230c7f" dependencies = [ "proc-macro2", "quote", diff --git a/vendor/jsonschema-macros-core/Cargo.toml b/vendor/jsonschema-macros-core/Cargo.toml index 263b62e..6e631e4 100644 --- a/vendor/jsonschema-macros-core/Cargo.toml +++ b/vendor/jsonschema-macros-core/Cargo.toml @@ -13,7 +13,7 @@ edition = "2021" rust-version = "1.85.0" name = "jsonschema-macros-core" -version = "0.58.6" +version = "0.61.2" authors = ["Dmitry Dygalo "] build = false autolib = false @@ -43,13 +43,13 @@ harness = false required-features = ["bench"] [dependencies.fancy-regex] -version = "0.19" +version = "0.20.2" [dependencies.indexmap] version = "2" [dependencies.jsonschema-regex] -version = "0.58.6" +version = "0.61.2" [dependencies.percent-encoding] version = "2.3" @@ -64,7 +64,7 @@ version = "1" version = "1" [dependencies.referencing] -version = "0.58.6" +version = "0.61.2" [dependencies.regex] version = "1" diff --git a/vendor/jsonschema-macros-core/Cargo.toml.orig b/vendor/jsonschema-macros-core/Cargo.toml.orig index 3939629..7deca34 100644 --- a/vendor/jsonschema-macros-core/Cargo.toml.orig +++ b/vendor/jsonschema-macros-core/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "jsonschema-macros-core" -version = "0.58.6" +version = "0.61.2" description = "Code generation implementation for the jsonschema compile-time validator macro" rust-version.workspace = true edition.workspace = true @@ -14,14 +14,14 @@ float-roundtrip = ["serde_json/float_roundtrip"] bench = [] [dependencies] -fancy-regex = "0.19" +fancy-regex = "0.20.2" indexmap = "2" -jsonschema-regex = { version = "0.58.6", path = "../jsonschema-regex" } +jsonschema-regex = { version = "0.61.2", path = "../jsonschema-regex" } percent-encoding = "2.3" proc-macro2 = "1" proc-macro-crate = "3" quote = "1" -referencing = { version = "0.58.6", path = "../jsonschema-referencing" } +referencing = { version = "0.61.2", path = "../jsonschema-referencing" } regex = "1" serde_json = "1" syn = { version = "2", features = ["full", "visit-mut"] } diff --git a/vendor/jsonschema-macros-core/src/codegen.rs b/vendor/jsonschema-macros-core/src/codegen.rs index 350adbf..6f8fb00 100644 --- a/vendor/jsonschema-macros-core/src/codegen.rs +++ b/vendor/jsonschema-macros-core/src/codegen.rs @@ -12,7 +12,7 @@ use self::{ collect_dynamic_anchor_bindings, get_or_create_item_eval_fn, get_or_create_key_eval_fn, }, numeric::value_as_u64, - regex::{compile_regex_match, translate_and_validate_regex}, + regex::{compile_regex_match, translate_and_validate_regex, RegexSite}, }; use crate::context::{CodegenConfig, CompileContext}; use errors::{invalid_schema_minimum_expression, invalid_schema_type_expression}; diff --git a/vendor/jsonschema-macros-core/src/codegen/emit_magnus.rs b/vendor/jsonschema-macros-core/src/codegen/emit_magnus.rs index 954ee42..3eea183 100644 --- a/vendor/jsonschema-macros-core/src/codegen/emit_magnus.rs +++ b/vendor/jsonschema-macros-core/src/codegen/emit_magnus.rs @@ -334,7 +334,7 @@ impl ValueEmitter for MagnusEmitter { if let Some(error) = __json::magnus_take_pending_error() { return Err(error.into()); } - let result = is_valid(node); + let result = run_is_valid(node); if let Some(error) = __json::magnus_take_pending_error() { return Err(error.into()); } @@ -354,7 +354,7 @@ impl ValueEmitter for MagnusEmitter { if let Some(error) = __json::magnus_take_pending_error() { return Err(error.into()); } - let result = match validate(node, &__paths::LazyLocation::new()) { + let result = match run_validate(node) { Some(e) => Err(e), None => Ok(()), }; @@ -377,8 +377,7 @@ impl ValueEmitter for MagnusEmitter { if let Some(error) = __json::magnus_take_pending_error() { return Err(error.into()); } - let mut errors = Vec::new(); - collect_errors(node, &__paths::LazyLocation::new(), &mut errors); + let errors = run_collect_errors(node); if let Some(error) = __json::magnus_take_pending_error() { return Err(error.into()); } diff --git a/vendor/jsonschema-macros-core/src/codegen/emit_pyo3.rs b/vendor/jsonschema-macros-core/src/codegen/emit_pyo3.rs index ee17646..16b21fd 100644 --- a/vendor/jsonschema-macros-core/src/codegen/emit_pyo3.rs +++ b/vendor/jsonschema-macros-core/src/codegen/emit_pyo3.rs @@ -321,7 +321,7 @@ impl ValueEmitter for Pyo3Emitter { quote! { pub(super) fn entry_is_valid(instance: &__Bound<'_>) -> __py3::PyResult { __json::inspect(instance.as_borrowed(), false, || { - is_valid(instance.as_borrowed()) + run_is_valid(instance.as_borrowed()) }) } } @@ -332,7 +332,7 @@ impl ValueEmitter for Pyo3Emitter { instance: &'__i __Bound<'__i>, ) -> __py3::PyResult<::std::result::Result<(), __VE<'__i>>> { __json::inspect(instance.as_borrowed(), false, || { - match validate(instance.as_borrowed(), &__paths::LazyLocation::new()) { + match run_validate(instance.as_borrowed()) { Some(e) => Err(e), None => Ok(()), } @@ -346,13 +346,7 @@ impl ValueEmitter for Pyo3Emitter { instance: &'__i __Bound<'__i>, ) -> __py3::PyResult<__EI<'__i>> { let errors = __json::inspect(instance.as_borrowed(), false, || { - let mut errors = Vec::new(); - collect_errors( - instance.as_borrowed(), - &__paths::LazyLocation::new(), - &mut errors, - ); - errors + run_collect_errors(instance.as_borrowed()) })?; Ok(__err::iterator_from(errors)) } diff --git a/vendor/jsonschema-macros-core/src/codegen/emit_root.rs b/vendor/jsonschema-macros-core/src/codegen/emit_root.rs index c8f870c..04c8241 100644 --- a/vendor/jsonschema-macros-core/src/codegen/emit_root.rs +++ b/vendor/jsonschema-macros-core/src/codegen/emit_root.rs @@ -61,6 +61,27 @@ pub(super) fn emit_root_module( .map(|(name, pattern)| { let helper_ident = format_ident!("{}", name); let storage_ident = format_ident!("{}_REGEX", name.to_uppercase()); + if ctx.repeated_classes.contains(pattern) { + let params = match ctx.config.pattern_options { + PatternEngineConfig::FancyRegex { .. } => quote! { + subject: &str, + _schema_path: &str, + _pattern: Option<&str>, + _instance_path: Option<&__paths::LazyLocation>, + }, + PatternEngineConfig::Regex { .. } => quote! { subject: &str }, + }; + // The engine would unroll the count into as many copies of the class. + return quote! { + static #storage_ident: __Lazy> = + __Lazy::new(|| __re::RepeatedClass::from_translated(#pattern)); + + #[inline] + fn #helper_ident(#params) -> bool { + #storage_ident.as_ref().is_some_and(|class| class.is_match(subject)) + } + }; + } match ctx.config.pattern_options { PatternEngineConfig::FancyRegex { backtrack_limit, @@ -84,10 +105,17 @@ pub(super) fn emit_root_module( }); #[inline] - fn #helper_ident(subject: &str) -> bool { - #storage_ident - .as_ref() - .is_some_and(|re| re.is_match(subject).unwrap_or(false)) + fn #helper_ident( + subject: &str, + schema_path: &str, + pattern: Option<&str>, + instance_path: Option<&__paths::LazyLocation>, + ) -> bool { + #storage_ident.as_ref().is_some_and(|re| { + __unfinished::fancy_is_match( + re, subject, schema_path, pattern, instance_path, + ) + }) } } } @@ -589,6 +617,78 @@ pub(super) fn emit_root_module( } }); + // Entry points resolve regex matches the engine cannot finish; recursive calls must not, so + // they keep calling `is_valid`, `validate` and `collect_errors` directly. + let err_instance = E::err_instance(format_ident!("instance")); + // Only `fancy-regex` can leave a match unfinished. + let regex_used = !ctx.regex_helpers.is_empty() + && matches!( + ctx.config.pattern_options, + PatternEngineConfig::FancyRegex { .. } + ); + let run_is_valid_body = if regex_used { + quote! { + let valid = is_valid(instance); + if !__unfinished::met() { + return valid; + } + __unfinished::is_valid(is_valid, instance) + } + } else { + quote! { is_valid(instance) } + }; + let run_validate_fn = emit_validate.then(|| { + let body = if regex_used { + quote! { + let error = validate(instance, &__paths::LazyLocation::new()); + if !__unfinished::met() { + return error; + } + __unfinished::validate( + || ::core::convert::Into::into(#err_instance), + collect_errors, + instance, + ) + } + } else { + quote! { validate(instance, &__paths::LazyLocation::new()) } + }; + quote! { + pub(super) fn run_validate<'__i>(instance: #borrowed_node) -> Option<__VE<'__i>> { + #function_prelude + #body + } + } + }); + let run_collect_fn = emit_collect.then(|| { + let collect = quote! { + let mut errors = Vec::new(); + collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); + errors + }; + let body = if regex_used { + quote! { + let errors = { #collect }; + if !__unfinished::met() { + return errors; + } + __unfinished::collect_errors( + || ::core::convert::Into::into(#err_instance), + collect_errors, + instance, + ) + } + } else { + collect + }; + quote! { + pub(super) fn run_collect_errors<'__i>(instance: #borrowed_node) -> Vec<__VE<'__i>> { + #function_prelude + #body + } + } + }); + quote! { #[doc(hidden)] #[allow(non_snake_case, dead_code, unused_imports, unused_variables, unreachable_code, clippy::all)] @@ -606,6 +706,7 @@ pub(super) fn emit_root_module( use jsonschema::__private::serde_json as __sj; use jsonschema::__private::types as __types; use jsonschema::__private::unique_items as __uniq; + use jsonschema::__private::unfinished_matches as __unfinished; use jsonschema::paths as __paths; use jsonschema::JsonType as __JT; use jsonschema::JsonTypeSet as __JTS; @@ -636,6 +737,13 @@ pub(super) fn emit_root_module( #validate_fns #collect_fns + + pub(super) fn run_is_valid(instance: #node) -> bool { + #function_prelude + #run_is_valid_body + } + #run_validate_fn + #run_collect_fn #entry_bodies } diff --git a/vendor/jsonschema-macros-core/src/codegen/emit_serde.rs b/vendor/jsonschema-macros-core/src/codegen/emit_serde.rs index 31cec7d..1f0e37f 100644 --- a/vendor/jsonschema-macros-core/src/codegen/emit_serde.rs +++ b/vendor/jsonschema-macros-core/src/codegen/emit_serde.rs @@ -266,7 +266,7 @@ impl ValueEmitter for SerdeEmitter { let is_valid = methods.is_valid.then(|| { quote! { pub(super) fn entry_is_valid(instance: &__Value) -> bool { - is_valid(instance) + run_is_valid(instance) } } }); @@ -275,7 +275,7 @@ impl ValueEmitter for SerdeEmitter { pub(super) fn entry_validate<'__i>( instance: &'__i __Value, ) -> ::std::result::Result<(), __VE<'__i>> { - match validate(instance, &__paths::LazyLocation::new()) { + match run_validate(instance) { Some(e) => Err(e), None => Ok(()), } @@ -285,9 +285,7 @@ impl ValueEmitter for SerdeEmitter { let iter_errors = methods.iter_errors.then(|| { quote! { pub(super) fn entry_iter_errors<'__i>(instance: &'__i __Value) -> __EI<'__i> { - let mut errors = Vec::new(); - collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); - __err::iterator_from(errors) + __err::iterator_from(run_collect_errors(instance)) } } }); diff --git a/vendor/jsonschema-macros-core/src/codegen/helpers.rs b/vendor/jsonschema-macros-core/src/codegen/helpers.rs index c822f79..6bb830b 100644 --- a/vendor/jsonschema-macros-core/src/codegen/helpers.rs +++ b/vendor/jsonschema-macros-core/src/codegen/helpers.rs @@ -148,7 +148,7 @@ pub(crate) fn get_or_create_key_eval_fn( let body = ctx.with_key_eval_scope(location, |ctx| { let schema_value = Value::Object(schema_obj.clone()); ctx.with_schema_env(&schema_value, schema_base_uri, |ctx| { - let compiled = compile_key_evaluated_expr(ctx, schema_obj, true); + let compiled = compile_key_evaluated_expr(ctx, schema_obj, true, false); let is_recursive_anchor = ctx.draft.supports_recursive_ref_keyword() && schema_obj.get("$recursiveAnchor").and_then(Value::as_bool) == Some(true); let dynamic_bindings = if ctx.uses_dynamic_ref { diff --git a/vendor/jsonschema-macros-core/src/codegen/keywords/additional_properties.rs b/vendor/jsonschema-macros-core/src/codegen/keywords/additional_properties.rs index 446414e..c215551 100644 --- a/vendor/jsonschema-macros-core/src/codegen/keywords/additional_properties.rs +++ b/vendor/jsonschema-macros-core/src/codegen/keywords/additional_properties.rs @@ -69,7 +69,7 @@ pub(crate) fn compile( // `patternProperties` combined with a false or schema `additionalProperties` is fused into a // single instance-order pass by `object_pass`, so this path never covers keys by pattern; the // only role of `pattern_properties` here is surfacing an invalid pattern regex. - if let Err(err) = build_pattern_coverage(ctx, pattern_properties) { + if let Err(err) = build_pattern_coverage(ctx, pattern_properties, false) { return Some(err); } diff --git a/vendor/jsonschema-macros-core/src/codegen/keywords/const_.rs b/vendor/jsonschema-macros-core/src/codegen/keywords/const_.rs index d2b20bf..c286332 100644 --- a/vendor/jsonschema-macros-core/src/codegen/keywords/const_.rs +++ b/vendor/jsonschema-macros-core/src/codegen/keywords/const_.rs @@ -61,12 +61,14 @@ pub(in super::super) fn compile( // `serde_json::Value` on the error path. let validate_block = quote! { if !(#is_valid) { - static CONST_EXPECTED: __Lazy<__sj::Value> = + static CONST_EXPECTED: __Lazy<::std::sync::Arc<__sj::Value>> = __Lazy::new(|| { - __sj::from_str(#const_json).expect("Failed to parse const value") + ::std::sync::Arc::new( + __sj::from_str(#const_json).expect("Failed to parse const value"), + ) }); return Some(__err::constant( - #schema_path, __path.into(), #err_instance, CONST_EXPECTED.clone(), + #schema_path, __path.into(), #err_instance, &*CONST_EXPECTED, )); } }; diff --git a/vendor/jsonschema-macros-core/src/codegen/keywords/enum_.rs b/vendor/jsonschema-macros-core/src/codegen/keywords/enum_.rs index b877ea6..c325810 100644 --- a/vendor/jsonschema-macros-core/src/codegen/keywords/enum_.rs +++ b/vendor/jsonschema-macros-core/src/codegen/keywords/enum_.rs @@ -145,9 +145,11 @@ pub(in super::super) fn compile( is_valid.clone(), quote! { if !(#is_valid) { - static ENUM_OPTIONS: __Lazy<__sj::Value> = + static ENUM_OPTIONS: __Lazy<::std::sync::Arc<__sj::Value>> = __Lazy::new(|| { - __sj::from_str(#enum_json).expect("Failed to parse enum options") + ::std::sync::Arc::new( + __sj::from_str(#enum_json).expect("Failed to parse enum options"), + ) }); return Some(__err::enumeration( #schema_path, __path.into(), #err_instance, &*ENUM_OPTIONS, diff --git a/vendor/jsonschema-macros-core/src/codegen/keywords/multiple_of.rs b/vendor/jsonschema-macros-core/src/codegen/keywords/multiple_of.rs index 2d22c80..72b44da 100644 --- a/vendor/jsonschema-macros-core/src/codegen/keywords/multiple_of.rs +++ b/vendor/jsonschema-macros-core/src/codegen/keywords/multiple_of.rs @@ -87,9 +87,7 @@ fn is_strictly_positive_number(value: &Value) -> bool { if let Some(signed) = number.as_i64() { return signed > 0; } - if let Some(float) = number.as_f64() { - return float > 0.0; - } + // The written digits, not `as_f64`: a tiny positive number reads as `0.0` there. let raw = number.to_string(); if raw.starts_with('-') { return false; diff --git a/vendor/jsonschema-macros-core/src/codegen/keywords/not.rs b/vendor/jsonschema-macros-core/src/codegen/keywords/not.rs index bce3a5c..455c79a 100644 --- a/vendor/jsonschema-macros-core/src/codegen/keywords/not.rs +++ b/vendor/jsonschema-macros-core/src/codegen/keywords/not.rs @@ -8,7 +8,7 @@ pub(crate) fn compile( value: &Value, ) -> CompiledExpr { let err_instance = E::err_instance(format_ident!("instance")); - let inner = compile_schema(ctx, value); + let inner = ctx.with_schema_path_segment("not", |ctx| compile_schema(ctx, value)); let schema_path = ctx.schema_path_for_keyword("not"); let not_schema_json = serde_json::to_string(value).expect("Failed to serialize not schema"); diff --git a/vendor/jsonschema-macros-core/src/codegen/keywords/object_pass.rs b/vendor/jsonschema-macros-core/src/codegen/keywords/object_pass.rs index 1e0c3db..c25608b 100644 --- a/vendor/jsonschema-macros-core/src/codegen/keywords/object_pass.rs +++ b/vendor/jsonschema-macros-core/src/codegen/keywords/object_pass.rs @@ -1,6 +1,6 @@ use super::{ super::{compile_schema, expr::ValidateBlock, CompileContext, CompiledExpr}, - pattern_properties::key_match_expr, + pattern_properties::{key_match_expr, KeyMatch}, }; use crate::codegen::emit::ValueEmitter; use proc_macro2::TokenStream; @@ -11,7 +11,7 @@ pub(crate) struct ClusterSubschemas<'a> { pub(crate) properties: Vec<(&'a str, CompiledExpr)>, pub(crate) patterns: Vec<( &'a str, - Result, + Result, Option, )>, pub(crate) additional: Option, @@ -144,6 +144,7 @@ pub(crate) fn compile_validate( let Ok(key_match) = key_match else { return None; }; + let key_match = &key_match.located; let check = check.as_ref().expect("pattern subschema precompiled"); match &check.validate { ValidateBlock::Expr(expr) => pattern_checks.push(quote! { @@ -266,6 +267,7 @@ pub(crate) fn compile_collect( let Ok(key_match) = key_match else { return None; }; + let key_match = &key_match.located; let check = check.as_ref().expect("pattern subschema precompiled"); match &check.validate { ValidateBlock::Expr(_) => { @@ -413,6 +415,7 @@ pub(crate) fn compile_is_valid( let Ok(key_match) = key_match else { return None; }; + let key_match = &key_match.is_valid; let check = check.as_ref().expect("pattern subschema precompiled"); if check.is_trivially_true() { if track_covered { diff --git a/vendor/jsonschema-macros-core/src/codegen/keywords/pattern.rs b/vendor/jsonschema-macros-core/src/codegen/keywords/pattern.rs index ed81902..1e4211d 100644 --- a/vendor/jsonschema-macros-core/src/codegen/keywords/pattern.rs +++ b/vendor/jsonschema-macros-core/src/codegen/keywords/pattern.rs @@ -1,6 +1,6 @@ use super::super::{ compile_regex_match, errors::invalid_schema_type_expression, translate_and_validate_regex, - CompileContext, CompiledExpr, + CompileContext, CompiledExpr, RegexSite, }; use crate::codegen::emit::ValueEmitter; use proc_macro2::TokenStream; @@ -11,10 +11,12 @@ fn pattern_check( schema_path: &str, pattern: &str, check: TokenStream, + located_check: Option<&TokenStream>, ) -> CompiledExpr { let err_instance = E::err_instance(format_ident!("instance")); + let validate_check = located_check.unwrap_or(&check); let validate = quote! { - if !(#check) { + if !(#validate_check) { return Some(__err::pattern( #schema_path, __path.into(), #err_instance, #pattern, )); @@ -34,11 +36,16 @@ pub(crate) fn compile( match jsonschema_regex::analyze_pattern(pattern) { Some(jsonschema_regex::PatternAnalysis::Prefix(prefix)) => { let prefix: &str = prefix.as_ref(); - pattern_check::(&schema_path, pattern, quote! { s.starts_with(#prefix) }) + pattern_check::( + &schema_path, + pattern, + quote! { s.starts_with(#prefix) }, + None, + ) } Some(jsonschema_regex::PatternAnalysis::Exact(exact)) => { let exact: &str = exact.as_ref(); - pattern_check::(&schema_path, pattern, quote! { s == #exact }) + pattern_check::(&schema_path, pattern, quote! { s == #exact }, None) } Some(jsonschema_regex::PatternAnalysis::Alternation(alts)) => { let alts: Vec<&str> = alts.iter().map(String::as_str).collect(); @@ -47,17 +54,26 @@ pub(crate) fn compile( &schema_path, pattern, quote! { matches!(#instance_as_str, #(#alts)|*) }, + None, ) } Some(jsonschema_regex::PatternAnalysis::NoWhitespace) => pattern_check::( &schema_path, pattern, quote! { !__re::contains_ecma_whitespace(s) }, + None, ), None => match translate_and_validate_regex(ctx, "pattern", pattern) { Ok(regex) => { - let check = compile_regex_match(ctx, ®ex, "e! { s }); - pattern_check::(&schema_path, pattern, check) + let mut site = RegexSite { + schema_path: &schema_path, + pattern: Some(pattern), + located: false, + }; + let check = compile_regex_match(ctx, ®ex, "e! { s }, &site); + site.located = true; + let located_check = compile_regex_match(ctx, ®ex, "e! { s }, &site); + pattern_check::(&schema_path, pattern, check, Some(&located_check)) } Err(error) => error, }, diff --git a/vendor/jsonschema-macros-core/src/codegen/keywords/pattern_coverage.rs b/vendor/jsonschema-macros-core/src/codegen/keywords/pattern_coverage.rs index 5c70e0c..8e10565 100644 --- a/vendor/jsonschema-macros-core/src/codegen/keywords/pattern_coverage.rs +++ b/vendor/jsonschema-macros-core/src/codegen/keywords/pattern_coverage.rs @@ -5,7 +5,7 @@ use proc_macro2::TokenStream; use quote::quote; use serde_json::Value; -use super::super::{compile_regex_match, translate_and_validate_regex, CompileContext}; +use super::super::{compile_regex_match, translate_and_validate_regex, CompileContext, RegexSite}; use crate::codegen::CompiledExpr; /// Emitted checks deciding whether a property key is covered by @@ -29,9 +29,11 @@ impl PatternCoverage { /// Build the coverage checks for `patternProperties`, or `Err` with the first /// invalid-regex diagnostic. +/// `located` emits the checks into `validate` code, where `__path` is the object's location. pub(super) fn build_pattern_coverage( ctx: &mut CompileContext<'_, E>, pattern_properties: Option<&Value>, + located: bool, ) -> Result { let Some(obj) = pattern_properties.and_then(Value::as_object) else { return Ok(PatternCoverage { @@ -42,7 +44,7 @@ pub(super) fn build_pattern_coverage( let mut prefixes: Vec> = Vec::new(); let mut literals: Vec = Vec::new(); - let mut regex_patterns: Vec = Vec::new(); + let mut regex_patterns: Vec<(String, &str)> = Vec::new(); let mut predicates: Vec = Vec::new(); for pattern in obj.keys() { match jsonschema_regex::analyze_pattern(pattern) { @@ -56,7 +58,7 @@ pub(super) fn build_pattern_coverage( }), None => { let regex = translate_and_validate_regex(ctx, "patternProperties", pattern)?; - regex_patterns.push(regex); + regex_patterns.push((regex, pattern.as_str())); } } } @@ -92,7 +94,17 @@ pub(super) fn build_pattern_coverage( if !regex_patterns.is_empty() { let regex_checks: Vec = regex_patterns .iter() - .map(|pattern| compile_regex_match(ctx, pattern, "e! { key_str })) + .map(|(regex, pattern)| { + let schema_path = ctx.with_schema_path_segment("patternProperties", |ctx| { + ctx.schema_path_for_keyword(pattern) + }); + let site = RegexSite { + schema_path: &schema_path, + pattern: None, + located, + }; + compile_regex_match(ctx, regex, "e! { key_str }, &site) + }) .collect(); checks.push(super::combine_or(regex_checks)); } diff --git a/vendor/jsonschema-macros-core/src/codegen/keywords/pattern_properties.rs b/vendor/jsonschema-macros-core/src/codegen/keywords/pattern_properties.rs index 8ea041f..0e5034c 100644 --- a/vendor/jsonschema-macros-core/src/codegen/keywords/pattern_properties.rs +++ b/vendor/jsonschema-macros-core/src/codegen/keywords/pattern_properties.rs @@ -1,7 +1,7 @@ use super::{ super::{ compile_regex_match, errors::invalid_schema_type_expression, expr::ValidateBlock, - translate_and_validate_regex, CompileContext, CompiledExpr, + translate_and_validate_regex, CompileContext, CompiledExpr, RegexSite, }, object_pass::ClusterSubschemas, }; @@ -24,8 +24,8 @@ pub(crate) fn compile( let mut pattern_checks = Vec::new(); for (_, key_match, check) in &cluster.patterns { - let key_matches = match key_match { - Ok(condition) => condition.clone(), + let (key_matches_is_valid, key_matches) = match key_match { + Ok(condition) => (condition.is_valid.clone(), condition.located.clone()), Err(error_expr) => { pattern_checks.push(error_expr.clone()); continue; @@ -47,7 +47,7 @@ pub(crate) fn compile( CompiledExpr::with_validate_and_collect_blocks( quote! { #entries - .filter(|(key, _)| #key_matches) + .filter(|(key, _)| #key_matches_is_valid) .all(|(_, instance)| { #schema_is_valid }) }, quote! { @@ -82,33 +82,59 @@ pub(crate) fn compile( } } -/// Boolean condition over `key.as_str()` that a key matches `pattern`. +/// Boolean conditions over `key.as_str()` that a key matches a `patternProperties` pattern. +#[derive(Clone)] +pub(crate) struct KeyMatch { + /// For `is_valid` code. + pub(crate) is_valid: proc_macro2::TokenStream, + /// For `validate` and `collect_errors` code, where `__path` is the object's location. + pub(crate) located: proc_macro2::TokenStream, +} + /// `Err` carries the invalid-schema expression when regex translation fails. pub(crate) fn key_match_expr( ctx: &mut CompileContext<'_, E>, pattern: &str, -) -> Result { +) -> Result { let key_as_str = E::key_as_str(format_ident!("key")); + let literal = |condition: proc_macro2::TokenStream| KeyMatch { + is_valid: condition.clone(), + located: condition, + }; match jsonschema_regex::analyze_pattern(pattern) { Some(jsonschema_regex::PatternAnalysis::Prefix(prefix)) => { let prefix: &str = prefix.as_ref(); - Ok(quote! { #key_as_str.starts_with(#prefix) }) + Ok(literal(quote! { #key_as_str.starts_with(#prefix) })) } Some(jsonschema_regex::PatternAnalysis::Exact(exact)) => { let exact: &str = exact.as_ref(); - Ok(quote! { #key_as_str == #exact }) + Ok(literal(quote! { #key_as_str == #exact })) } Some(jsonschema_regex::PatternAnalysis::Alternation(alts)) => { let alts: Vec<&str> = alts.iter().map(String::as_str).collect(); - Ok(quote! { matches!(#key_as_str, #(#alts)|*) }) - } - Some(jsonschema_regex::PatternAnalysis::NoWhitespace) => { - Ok(quote! { !__re::contains_ecma_whitespace(#key_as_str) }) + Ok(literal(quote! { matches!(#key_as_str, #(#alts)|*) })) } + Some(jsonschema_regex::PatternAnalysis::NoWhitespace) => Ok(literal( + quote! { !__re::contains_ecma_whitespace(#key_as_str) }, + )), None => match translate_and_validate_regex(ctx, "patternProperties", pattern) { Ok(translated) => { - let regex_check = compile_regex_match(ctx, &translated, "e! { #key_as_str }); - Ok(quote! { { #regex_check } }) + let schema_path = ctx.with_schema_path_segment("patternProperties", |ctx| { + ctx.schema_path_for_keyword(pattern) + }); + let mut site = RegexSite { + schema_path: &schema_path, + pattern: None, + located: false, + }; + let is_valid = + compile_regex_match(ctx, &translated, "e! { #key_as_str }, &site); + site.located = true; + let located = compile_regex_match(ctx, &translated, "e! { #key_as_str }, &site); + Ok(KeyMatch { + is_valid: quote! { { #is_valid } }, + located: quote! { { #located } }, + }) } Err(error_expr) => Err(error_expr), }, diff --git a/vendor/jsonschema-macros-core/src/codegen/keywords/unevaluated.rs b/vendor/jsonschema-macros-core/src/codegen/keywords/unevaluated.rs index 008eb5f..ba2e1b8 100644 --- a/vendor/jsonschema-macros-core/src/codegen/keywords/unevaluated.rs +++ b/vendor/jsonschema-macros-core/src/codegen/keywords/unevaluated.rs @@ -293,8 +293,9 @@ fn compile_if_then_else_evaluated( fn compile_pattern_coverage_for_key( ctx: &mut CompileContext<'_, E>, patterns: Option<&Value>, + located: bool, ) -> Option { - let coverage = match super::pattern_coverage::build_pattern_coverage(ctx, patterns) { + let coverage = match super::pattern_coverage::build_pattern_coverage(ctx, patterns, located) { Ok(coverage) => coverage, Err(error_expr) => return Some(error_expr.into_token_stream()), }; @@ -377,7 +378,7 @@ fn recurse_eval( hoist: &mut GuardHoist, ) -> TokenStream { match kind { - EvalKind::Key => compile_key_evaluated_expr(ctx, schema, true), + EvalKind::Key => compile_key_evaluated_expr(ctx, schema, true, false), EvalKind::Item => compile_index_evaluated_expr(ctx, schema, hoist), } } @@ -556,10 +557,12 @@ fn push_ref_dispatch( } } +/// `located` emits the expression into `validate` code, where `__path` is the object's location. pub(crate) fn compile_key_evaluated_expr( ctx: &mut CompileContext<'_, E>, schema: &Map, include_own_unevaluated: bool, + located: bool, ) -> TokenStream { let mut parts = Vec::new(); let applicator_vocab_enabled = ctx.supports_applicator_vocabulary(); @@ -589,7 +592,7 @@ pub(crate) fn compile_key_evaluated_expr( if applicator_vocab_enabled { if let Some(pattern_expr) = - compile_pattern_coverage_for_key(ctx, schema.get("patternProperties")) + compile_pattern_coverage_for_key(ctx, schema.get("patternProperties"), located) { parts.push(pattern_expr); } @@ -599,7 +602,7 @@ pub(crate) fn compile_key_evaluated_expr( if let Some(dependent_schemas) = schema.get("dependentSchemas").and_then(Value::as_object) { for (property, subschema) in dependent_schemas { if let Value::Object(subschema_obj) = subschema { - let sub_eval = compile_key_evaluated_expr(ctx, subschema_obj, true); + let sub_eval = compile_key_evaluated_expr(ctx, subschema_obj, true, located); let contains_key = E::object_contains_key(format_ident!("obj"), property); parts.push(quote! { #contains_key && (#sub_eval) }); } diff --git a/vendor/jsonschema-macros-core/src/codegen/keywords/unevaluated_properties.rs b/vendor/jsonschema-macros-core/src/codegen/keywords/unevaluated_properties.rs index c805baf..f98c212 100644 --- a/vendor/jsonschema-macros-core/src/codegen/keywords/unevaluated_properties.rs +++ b/vendor/jsonschema-macros-core/src/codegen/keywords/unevaluated_properties.rs @@ -33,7 +33,7 @@ pub(crate) fn compile( let uses_recursive_stack = ctx.uses_recursive_ref && ctx.draft.supports_recursive_ref_keyword() && schema.get("$recursiveAnchor").and_then(Value::as_bool) == Some(true); - let evaluated_expr = compile_key_evaluated_expr(ctx, schema, uses_recursive_stack); + let evaluated_expr = compile_key_evaluated_expr(ctx, schema, uses_recursive_stack, false); if !uses_recursive_stack && evaluated_expr.to_string() == "true" { return None; } @@ -98,6 +98,7 @@ pub(crate) fn compile( ); Some(CompiledExpr::with_validate_blocks(is_valid, validate)) } else { + let located_expr = compile_key_evaluated_expr(ctx, schema, false, true); let is_valid = quote! { #entries.all(|(__key, __value)| { let key_str = #key_as_str; @@ -114,7 +115,7 @@ pub(crate) fn compile( let mut __unexpected: Vec = Vec::new(); for (__key, __value) in #entries { let key_str = #key_as_str; - if !(#evaluated_expr) && !(#unevaluated_check) { + if !(#located_expr) && !(#unevaluated_check) { __unexpected.push(#owned_key); } } diff --git a/vendor/jsonschema-macros-core/src/codegen/regex.rs b/vendor/jsonschema-macros-core/src/codegen/regex.rs index e151485..09369b2 100644 --- a/vendor/jsonschema-macros-core/src/codegen/regex.rs +++ b/vendor/jsonschema-macros-core/src/codegen/regex.rs @@ -17,6 +17,8 @@ pub(super) fn translate_and_validate_regex( let Ok(translated) = jsonschema_regex::to_rust_regex(pattern) else { return Err(invalid_regex_expression(keyword, pattern)); }; + // The initialization API preserves engine constructors and their default or supplied + // limits in every mode; search-only substitutions must not bypass them. let translated = translated.into_owned(); let valid = match ctx.config.pattern_options { PatternEngineConfig::FancyRegex { @@ -73,13 +75,35 @@ fn get_or_create_regex_helper( format_ident!("{}", name) } +/// Where a regex match happens, for reporting a match `fancy-regex` cannot finish. +pub(super) struct RegexSite<'a> { + pub(super) schema_path: &'a str, + /// The `pattern` keyword's source pattern. + pub(super) pattern: Option<&'a str>, + /// Emitted into `validate` or `collect_errors` code, where `__path` is the instance location. + pub(super) located: bool, +} + pub(super) fn compile_regex_match( ctx: &mut CompileContext<'_, E>, pattern: &str, subject: &TokenStream, + site: &RegexSite<'_>, ) -> TokenStream { let helper = get_or_create_regex_helper(ctx, pattern); - quote! { - #helper(#subject) + match ctx.config.pattern_options { + PatternEngineConfig::FancyRegex { .. } => { + let schema_path = site.schema_path; + let source = site + .pattern + .map_or_else(|| quote! { None }, |p| quote! { Some(#p) }); + let instance_path = if site.located { + quote! { Some(__path) } + } else { + quote! { None } + }; + quote! { #helper(#subject, #schema_path, #source, #instance_path) } + } + PatternEngineConfig::Regex { .. } => quote! { #helper(#subject) }, } } diff --git a/vendor/jsonschema-macros-core/src/context.rs b/vendor/jsonschema-macros-core/src/context.rs index 9b466e3..ee7bc9c 100644 --- a/vendor/jsonschema-macros-core/src/context.rs +++ b/vendor/jsonschema-macros-core/src/context.rs @@ -255,6 +255,8 @@ pub(crate) struct CompileContext<'cfg, E: ValueEmitter> { /// by their own. Roots live in the registry for the whole expansion. pub(crate) anchor_pointers: HashMap>, pub(crate) translated_regex_cache: HashMap, + /// Translated patterns matched by counting characters, see [`jsonschema_regex::RepeatedClass`]. + pub(crate) repeated_classes: HashSet, pub(crate) regex_helpers: Vec<(String, String)>, pub(crate) regex_counter: usize, pub(crate) custom_keyword_counter: usize, @@ -307,6 +309,7 @@ impl<'cfg, E: ValueEmitter> CompileContext<'cfg, E> { regex_to_helper: HashMap::new(), anchor_pointers: HashMap::new(), translated_regex_cache: HashMap::new(), + repeated_classes: HashSet::new(), regex_helpers: Vec::new(), regex_counter: 0, custom_keyword_counter: 0, diff --git a/vendor/jsonschema-macros-core/src/lib.rs b/vendor/jsonschema-macros-core/src/lib.rs index 1c9120d..9ff5fee 100644 --- a/vendor/jsonschema-macros-core/src/lib.rs +++ b/vendor/jsonschema-macros-core/src/lib.rs @@ -824,8 +824,10 @@ so the generated methods cannot depend on type parameters", } }; - let schema = - schema.map_err(|err| syn::Error::new_spanned(input, format!("Invalid JSON: {err}")))?; + let schema = schema + .map_err(|err| err.to_string()) + .and_then(reject_number_past_f64) + .map_err(|err| syn::Error::new_spanned(input, format!("Invalid JSON: {err}")))?; let name = &input.ident; @@ -846,12 +848,15 @@ so the generated methods cannot depend on type parameters", for entry in &attr.resources { let schema_value: serde_json::Value = match &entry.content { - ResourceContent::Schema(s) => serde_json::from_str(s).map_err(|e| { - syn::Error::new( - proc_macro2::Span::call_site(), - format!("Invalid JSON for resource '{}': {e}", entry.uri), - ) - })?, + ResourceContent::Schema(s) => serde_json::from_str(s) + .map_err(|e| e.to_string()) + .and_then(reject_number_past_f64) + .map_err(|e| { + syn::Error::new( + proc_macro2::Span::call_site(), + format!("Invalid JSON for resource '{}': {e}", entry.uri), + ) + })?, ResourceContent::Path(lit) => { let path = resolve_schema_path(lit)?; let file = File::open(&path).map_err(|e| { @@ -861,12 +866,15 @@ so the generated methods cannot depend on type parameters", recompile_triggers.push(quote! { const _: &str = include_str!(#path_trigger); }); - serde_json::from_reader(BufReader::new(file)).map_err(|e| { - syn::Error::new_spanned( - lit, - format!("Invalid JSON in '{}': {e}", path.display()), - ) - })? + serde_json::from_reader(BufReader::new(file)) + .map_err(|e| e.to_string()) + .and_then(reject_number_past_f64) + .map_err(|e| { + syn::Error::new_spanned( + lit, + format!("Invalid JSON in '{}': {e}", path.display()), + ) + })? } }; resource_pairs.push((entry.uri.clone(), draft.create_resource(schema_value))); @@ -1006,6 +1014,33 @@ so the generated methods cannot depend on type parameters", }) } +// Without `arbitrary-precision`, a number past `f64` parses only when another crate in the build +// enables `serde_json/arbitrary_precision`; it is refused as the parse without that feature does. +fn reject_number_past_f64(document: Value) -> Result { + if cfg!(feature = "arbitrary-precision") { + return Ok(document); + } + match number_past_f64(&document) { + Some(pointer) => Err(format!("number out of range at {pointer}")), + None => Ok(document), + } +} + +fn number_past_f64(value: &Value) -> Option { + match value { + Value::Number(number) if number.as_f64().is_none() => Some(String::new()), + Value::Array(items) => items + .iter() + .enumerate() + .find_map(|(idx, item)| number_past_f64(item).map(|rest| format!("/{idx}{rest}"))), + Value::Object(members) => members.iter().find_map(|(key, item)| { + number_past_f64(item) + .map(|rest| format!("/{}{rest}", key.replace('~', "~0").replace('/', "~1"))) + }), + _ => None, + } +} + fn detect_draft(schema: &Value, draft: Option<&syn::Expr>) -> syn::Result { if let Some(draft_expr) = draft { let syn::Expr::Path(path) = draft_expr else { diff --git a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__collect_if_then.snap b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__collect_if_then.snap index 37e5c39..d1e01c2 100644 --- a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__collect_if_then.snap +++ b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__collect_if_then.snap @@ -9,21 +9,18 @@ if match instance { } { match instance { __Value::Number(n) => { - if !(jsonschema::__private::numeric::ge(n, 10u64)) { + if !(__num::ge(n, 10u64)) { __errors .push( __err::minimum( "/then/minimum", __path.into(), instance, - serde_json::Value::Number(serde_json::Number::from(10u64)), + __sj::Value::Number(__sj::Number::from(10u64)), ), ); } - if !(jsonschema::__private::numeric::is_multiple_of_integer( - n, - 3f64, - )) { + if !(__num::is_multiple_of_integer(n, 3f64)) { __errors .push( __err::multiple_of( diff --git a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__custom_format_direct_call.snap b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__custom_format_direct_call.snap index b056c4a..d028a37 100644 --- a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__custom_format_direct_call.snap +++ b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__custom_format_direct_call.snap @@ -26,6 +26,7 @@ mod __validator_impl { use jsonschema::__private::serde_json as __sj; use jsonschema::__private::types as __types; use jsonschema::__private::unique_items as __uniq; + use jsonschema::__private::unfinished_matches as __unfinished; use jsonschema::paths as __paths; use jsonschema::JsonType as __JT; use jsonschema::JsonTypeSet as __JTS; @@ -97,21 +98,30 @@ mod __validator_impl { } } } - pub(super) fn entry_is_valid(instance: &__Value) -> bool { + pub(super) fn run_is_valid(instance: &__Value) -> bool { is_valid(instance) } + pub(super) fn run_validate<'__i>(instance: &'__i __Value) -> Option<__VE<'__i>> { + validate(instance, &__paths::LazyLocation::new()) + } + pub(super) fn run_collect_errors<'__i>(instance: &'__i __Value) -> Vec<__VE<'__i>> { + let mut errors = Vec::new(); + collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); + errors + } + pub(super) fn entry_is_valid(instance: &__Value) -> bool { + run_is_valid(instance) + } pub(super) fn entry_validate<'__i>( instance: &'__i __Value, ) -> ::std::result::Result<(), __VE<'__i>> { - match validate(instance, &__paths::LazyLocation::new()) { + match run_validate(instance) { Some(e) => Err(e), None => Ok(()), } } pub(super) fn entry_iter_errors<'__i>(instance: &'__i __Value) -> __EI<'__i> { - let mut errors = Vec::new(); - collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); - __err::iterator_from(errors) + __err::iterator_from(run_collect_errors(instance)) } } impl Validator { diff --git a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__duplicate_regex_literals_deduplicated.snap b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__duplicate_regex_literals_deduplicated.snap index 207b475..eab77b4 100644 --- a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__duplicate_regex_literals_deduplicated.snap +++ b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__duplicate_regex_literals_deduplicated.snap @@ -26,6 +26,7 @@ mod __validator_impl { use jsonschema::__private::serde_json as __sj; use jsonschema::__private::types as __types; use jsonschema::__private::unique_items as __uniq; + use jsonschema::__private::unfinished_matches as __unfinished; use jsonschema::paths as __paths; use jsonschema::JsonType as __JT; use jsonschema::JsonTypeSet as __JTS; @@ -35,12 +36,27 @@ mod __validator_impl { use std::sync::LazyLock as __Lazy; type __Map = __sj::Map; #[inline] - fn __jsonschema_regex_0(subject: &str) -> bool { + fn __jsonschema_regex_0( + subject: &str, + schema_path: &str, + pattern: Option<&str>, + instance_path: Option<&__paths::LazyLocation>, + ) -> bool { static REGEX: __Lazy> = __Lazy::new(|| { let mut builder = __fancy::RegexBuilder::new("^[a-z]{2,}$"); builder.build().ok() }); - REGEX.as_ref().is_some_and(|re| re.is_match(subject).unwrap_or(false)) + REGEX + .as_ref() + .is_some_and(|re| { + __unfinished::fancy_is_match( + re, + subject, + schema_path, + pattern, + instance_path, + ) + }) } pub(super) fn is_valid(instance: &__Value) -> bool { match instance { @@ -49,7 +65,14 @@ mod __validator_impl { .iter() .all(|(key, instance)| { let mut covered = false; - if { __jsonschema_regex_0(key.as_str()) } { + if { + __jsonschema_regex_0( + key.as_str(), + "/patternProperties/^[a-z]{2,}$", + None, + None, + ) + } { if !(instance.is_string()) { return false; } @@ -74,7 +97,14 @@ mod __validator_impl { for (key, value) in obj.iter() { let key_str = key.as_str(); let mut covered = false; - if { __jsonschema_regex_0(key.as_str()) } { + if { + __jsonschema_regex_0( + key.as_str(), + "/patternProperties/^[a-z]{2,}$", + None, + Some(__path), + ) + } { let instance = value; let __path = &__path.push(key_str); if !(instance.is_string()) { @@ -120,7 +150,14 @@ mod __validator_impl { for (key, value) in obj.iter() { let key_str = key.as_str(); let mut covered = false; - if { __jsonschema_regex_0(key.as_str()) } { + if { + __jsonschema_regex_0( + key.as_str(), + "/patternProperties/^[a-z]{2,}$", + None, + Some(__path), + ) + } { let instance = value; let __path = &__path.push(key_str); if !(instance.is_string()) { @@ -165,21 +202,52 @@ mod __validator_impl { } } } + pub(super) fn run_is_valid(instance: &__Value) -> bool { + let valid = is_valid(instance); + if !__unfinished::met() { + return valid; + } + __unfinished::is_valid(is_valid, instance) + } + pub(super) fn run_validate<'__i>(instance: &'__i __Value) -> Option<__VE<'__i>> { + let error = validate(instance, &__paths::LazyLocation::new()); + if !__unfinished::met() { + return error; + } + __unfinished::validate( + || ::core::convert::Into::into(instance), + collect_errors, + instance, + ) + } + pub(super) fn run_collect_errors<'__i>(instance: &'__i __Value) -> Vec<__VE<'__i>> { + let errors = { + let mut errors = Vec::new(); + collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); + errors + }; + if !__unfinished::met() { + return errors; + } + __unfinished::collect_errors( + || ::core::convert::Into::into(instance), + collect_errors, + instance, + ) + } pub(super) fn entry_is_valid(instance: &__Value) -> bool { - is_valid(instance) + run_is_valid(instance) } pub(super) fn entry_validate<'__i>( instance: &'__i __Value, ) -> ::std::result::Result<(), __VE<'__i>> { - match validate(instance, &__paths::LazyLocation::new()) { + match run_validate(instance) { Some(e) => Err(e), None => Ok(()), } } pub(super) fn entry_iter_errors<'__i>(instance: &'__i __Value) -> __EI<'__i> { - let mut errors = Vec::new(); - collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); - __err::iterator_from(errors) + __err::iterator_from(run_collect_errors(instance)) } } impl Validator { diff --git a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__dynamic_schema_full_module.snap b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__dynamic_schema_full_module.snap index abcf420..d1d127a 100644 --- a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__dynamic_schema_full_module.snap +++ b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__dynamic_schema_full_module.snap @@ -26,6 +26,7 @@ mod __validator_impl { use jsonschema::__private::serde_json as __sj; use jsonschema::__private::types as __types; use jsonschema::__private::unique_items as __uniq; + use jsonschema::__private::unfinished_matches as __unfinished; use jsonschema::paths as __paths; use jsonschema::JsonType as __JT; use jsonschema::JsonTypeSet as __JTS; @@ -780,21 +781,30 @@ mod __validator_impl { } }); } - pub(super) fn entry_is_valid(instance: &__Value) -> bool { + pub(super) fn run_is_valid(instance: &__Value) -> bool { is_valid(instance) } + pub(super) fn run_validate<'__i>(instance: &'__i __Value) -> Option<__VE<'__i>> { + validate(instance, &__paths::LazyLocation::new()) + } + pub(super) fn run_collect_errors<'__i>(instance: &'__i __Value) -> Vec<__VE<'__i>> { + let mut errors = Vec::new(); + collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); + errors + } + pub(super) fn entry_is_valid(instance: &__Value) -> bool { + run_is_valid(instance) + } pub(super) fn entry_validate<'__i>( instance: &'__i __Value, ) -> ::std::result::Result<(), __VE<'__i>> { - match validate(instance, &__paths::LazyLocation::new()) { + match run_validate(instance) { Some(e) => Err(e), None => Ok(()), } } pub(super) fn entry_iter_errors<'__i>(instance: &'__i __Value) -> __EI<'__i> { - let mut errors = Vec::new(); - collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); - __err::iterator_from(errors) + __err::iterator_from(run_collect_errors(instance)) } } impl Validator { diff --git a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__iri_reference_format_per_call_cache.snap b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__iri_reference_format_per_call_cache.snap index 55094c8..9d06625 100644 --- a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__iri_reference_format_per_call_cache.snap +++ b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__iri_reference_format_per_call_cache.snap @@ -26,6 +26,7 @@ mod __validator_impl { use jsonschema::__private::serde_json as __sj; use jsonschema::__private::types as __types; use jsonschema::__private::unique_items as __uniq; + use jsonschema::__private::unfinished_matches as __unfinished; use jsonschema::paths as __paths; use jsonschema::JsonType as __JT; use jsonschema::JsonTypeSet as __JTS; @@ -121,21 +122,30 @@ mod __validator_impl { } } } - pub(super) fn entry_is_valid(instance: &__Value) -> bool { + pub(super) fn run_is_valid(instance: &__Value) -> bool { is_valid(instance) } + pub(super) fn run_validate<'__i>(instance: &'__i __Value) -> Option<__VE<'__i>> { + validate(instance, &__paths::LazyLocation::new()) + } + pub(super) fn run_collect_errors<'__i>(instance: &'__i __Value) -> Vec<__VE<'__i>> { + let mut errors = Vec::new(); + collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); + errors + } + pub(super) fn entry_is_valid(instance: &__Value) -> bool { + run_is_valid(instance) + } pub(super) fn entry_validate<'__i>( instance: &'__i __Value, ) -> ::std::result::Result<(), __VE<'__i>> { - match validate(instance, &__paths::LazyLocation::new()) { + match run_validate(instance) { Some(e) => Err(e), None => Ok(()), } } pub(super) fn entry_iter_errors<'__i>(instance: &'__i __Value) -> __EI<'__i> { - let mut errors = Vec::new(); - collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); - __err::iterator_from(errors) + __err::iterator_from(run_collect_errors(instance)) } } impl Validator { diff --git a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__magnus_emitter.snap b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__magnus_emitter.snap index 4c692a8..1d29c5f 100644 --- a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__magnus_emitter.snap +++ b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__magnus_emitter.snap @@ -27,6 +27,7 @@ mod __validator_impl { use jsonschema::__private::serde_json as __sj; use jsonschema::__private::types as __types; use jsonschema::__private::unique_items as __uniq; + use jsonschema::__private::unfinished_matches as __unfinished; use jsonschema::paths as __paths; use jsonschema::JsonType as __JT; use jsonschema::JsonTypeSet as __JTS; @@ -143,15 +144,19 @@ mod __validator_impl { _ => false, } }) { - static CONST_EXPECTED: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("1").expect("Failed to parse const value") + static CONST_EXPECTED: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("1").expect("Failed to parse const value"), + ) }); return Some( __err::constant( "/properties/code/oneOf/0/properties/code/const", __path.into(), __NodeExt::lazy_value(&instance), - CONST_EXPECTED.clone(), + &*CONST_EXPECTED, ), ); } @@ -264,15 +269,19 @@ mod __validator_impl { _ => false, } }) { - static CONST_EXPECTED: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("2").expect("Failed to parse const value") + static CONST_EXPECTED: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("2").expect("Failed to parse const value"), + ) }); return Some( __err::constant( "/properties/code/oneOf/1/properties/code/const", __path.into(), __NodeExt::lazy_value(&instance), - CONST_EXPECTED.clone(), + &*CONST_EXPECTED, ), ); } @@ -351,15 +360,19 @@ mod __validator_impl { .extend( (|| -> Option<__VE<'_>> { if !(__NodeExt::as_boolean(&instance) == Some(true)) { - static CONST_EXPECTED: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("true").expect("Failed to parse const value") + static CONST_EXPECTED: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("true").expect("Failed to parse const value"), + ) }); return Some( __err::constant( "/properties/flag/oneOf/0/properties/on/const", __path.into(), __NodeExt::lazy_value(&instance), - CONST_EXPECTED.clone(), + &*CONST_EXPECTED, ), ); } @@ -438,16 +451,20 @@ mod __validator_impl { .extend( (|| -> Option<__VE<'_>> { if !(__NodeExt::as_boolean(&instance) == Some(false)) { - static CONST_EXPECTED: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("false") - .expect("Failed to parse const value") + static CONST_EXPECTED: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("false") + .expect("Failed to parse const value"), + ) }); return Some( __err::constant( "/properties/flag/oneOf/1/properties/on/const", __path.into(), __NodeExt::lazy_value(&instance), - CONST_EXPECTED.clone(), + &*CONST_EXPECTED, ), ); } @@ -533,16 +550,20 @@ mod __validator_impl { if !(__NodeExt::as_string(&instance).as_deref() == Some("circle")) { - static CONST_EXPECTED: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("\"circle\"") - .expect("Failed to parse const value") + static CONST_EXPECTED: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("\"circle\"") + .expect("Failed to parse const value"), + ) }); return Some( __err::constant( "/properties/shape/oneOf/0/properties/kind/const", __path.into(), __NodeExt::lazy_value(&instance), - CONST_EXPECTED.clone(), + &*CONST_EXPECTED, ), ); } @@ -652,16 +673,20 @@ mod __validator_impl { if !(__NodeExt::as_string(&instance).as_deref() == Some("square")) { - static CONST_EXPECTED: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("\"square\"") - .expect("Failed to parse const value") + static CONST_EXPECTED: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("\"square\"") + .expect("Failed to parse const value"), + ) }); return Some( __err::constant( "/properties/shape/oneOf/1/properties/kind/const", __path.into(), __NodeExt::lazy_value(&instance), - CONST_EXPECTED.clone(), + &*CONST_EXPECTED, ), ); } @@ -1177,9 +1202,13 @@ mod __validator_impl { } _ => false, }) { - static ENUM_OPTIONS: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("[1,\"a\",true,null,{\"o\":[1]}]") - .expect("Failed to parse enum options") + static ENUM_OPTIONS: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("[1,\"a\",true,null,{\"o\":[1]}]") + .expect("Failed to parse enum options"), + ) }); return Some( __err::enumeration( @@ -1788,16 +1817,20 @@ mod __validator_impl { }); __NodeExt::equals_value(&instance, &*EXPECTED) }) { - static CONST_EXPECTED: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("{\"o\":true}") - .expect("Failed to parse const value") + static CONST_EXPECTED: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("{\"o\":true}") + .expect("Failed to parse const value"), + ) }); return Some( __err::constant( "/properties/structured/const", __path.into(), __NodeExt::lazy_value(&instance), - CONST_EXPECTED.clone(), + &*CONST_EXPECTED, ), ); } @@ -1985,9 +2018,13 @@ mod __validator_impl { } _ => false, }) { - static ENUM_OPTIONS: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("[1,\"a\",true,null,{\"o\":[1]}]") - .expect("Failed to parse enum options") + static ENUM_OPTIONS: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("[1,\"a\",true,null,{\"o\":[1]}]") + .expect("Failed to parse enum options"), + ) }); return Some( __err::enumeration( @@ -3034,16 +3071,20 @@ mod __validator_impl { }); __NodeExt::equals_value(&instance, &*EXPECTED) }) { - static CONST_EXPECTED: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("{\"o\":true}") - .expect("Failed to parse const value") + static CONST_EXPECTED: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("{\"o\":true}") + .expect("Failed to parse const value"), + ) }); return Some( __err::constant( "/properties/structured/const", __path.into(), __NodeExt::lazy_value(&instance), - CONST_EXPECTED.clone(), + &*CONST_EXPECTED, ), ); } @@ -3182,6 +3223,17 @@ mod __validator_impl { None => {} } } + pub(super) fn run_is_valid(instance: __Value<'_>) -> bool { + is_valid(instance) + } + pub(super) fn run_validate<'__i>(instance: __Value<'__i>) -> Option<__VE<'__i>> { + validate(instance, &__paths::LazyLocation::new()) + } + pub(super) fn run_collect_errors<'__i>(instance: __Value<'__i>) -> Vec<__VE<'__i>> { + let mut errors = Vec::new(); + collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); + errors + } pub(super) fn entry_is_valid( instance: &__rb::Value, ) -> ::std::result::Result { @@ -3192,7 +3244,7 @@ mod __validator_impl { if let Some(error) = __json::magnus_take_pending_error() { return Err(error.into()); } - let result = is_valid(node); + let result = run_is_valid(node); if let Some(error) = __json::magnus_take_pending_error() { return Err(error.into()); } @@ -3208,7 +3260,7 @@ mod __validator_impl { if let Some(error) = __json::magnus_take_pending_error() { return Err(error.into()); } - let result = match validate(node, &__paths::LazyLocation::new()) { + let result = match run_validate(node) { Some(e) => Err(e), None => Ok(()), }; @@ -3227,8 +3279,7 @@ mod __validator_impl { if let Some(error) = __json::magnus_take_pending_error() { return Err(error.into()); } - let mut errors = Vec::new(); - collect_errors(node, &__paths::LazyLocation::new(), &mut errors); + let errors = run_collect_errors(node); if let Some(error) = __json::magnus_take_pending_error() { return Err(error.into()); } diff --git a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__magnus_emitter_draft4.snap b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__magnus_emitter_draft4.snap index 81d61b0..110c0b3 100644 --- a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__magnus_emitter_draft4.snap +++ b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__magnus_emitter_draft4.snap @@ -27,6 +27,7 @@ mod __validator_impl { use jsonschema::__private::serde_json as __sj; use jsonschema::__private::types as __types; use jsonschema::__private::unique_items as __uniq; + use jsonschema::__private::unfinished_matches as __unfinished; use jsonschema::paths as __paths; use jsonschema::JsonType as __JT; use jsonschema::JsonTypeSet as __JTS; @@ -106,6 +107,17 @@ mod __validator_impl { ); } } + pub(super) fn run_is_valid(instance: __Value<'_>) -> bool { + is_valid(instance) + } + pub(super) fn run_validate<'__i>(instance: __Value<'__i>) -> Option<__VE<'__i>> { + validate(instance, &__paths::LazyLocation::new()) + } + pub(super) fn run_collect_errors<'__i>(instance: __Value<'__i>) -> Vec<__VE<'__i>> { + let mut errors = Vec::new(); + collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); + errors + } pub(super) fn entry_is_valid( instance: &__rb::Value, ) -> ::std::result::Result { @@ -116,7 +128,7 @@ mod __validator_impl { if let Some(error) = __json::magnus_take_pending_error() { return Err(error.into()); } - let result = is_valid(node); + let result = run_is_valid(node); if let Some(error) = __json::magnus_take_pending_error() { return Err(error.into()); } @@ -132,7 +144,7 @@ mod __validator_impl { if let Some(error) = __json::magnus_take_pending_error() { return Err(error.into()); } - let result = match validate(node, &__paths::LazyLocation::new()) { + let result = match run_validate(node) { Some(e) => Err(e), None => Ok(()), }; @@ -151,8 +163,7 @@ mod __validator_impl { if let Some(error) = __json::magnus_take_pending_error() { return Err(error.into()); } - let mut errors = Vec::new(); - collect_errors(node, &__paths::LazyLocation::new(), &mut errors); + let errors = run_collect_errors(node); if let Some(error) = __json::magnus_take_pending_error() { return Err(error.into()); } diff --git a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__min_max_equal_float.snap b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__min_max_equal_float.snap index 10be88f..7bc3c28 100644 --- a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__min_max_equal_float.snap +++ b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__min_max_equal_float.snap @@ -4,9 +4,6 @@ description: "{\"maximum\":1.5,\"minimum\":1.5,\"type\":\"number\"}" expression: is_valid_body(schema) --- match instance { - __Value::Number(n) => { - (jsonschema::__private::numeric::ge(n, 1.5f64)) - && (jsonschema::__private::numeric::le(n, 1.5f64)) - } + __Value::Number(n) => (__num::ge(n, 1.5f64)) && (__num::le(n, 1.5f64)), _ => false, } diff --git a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__multiple_of_scientific_zero_error.snap b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__multiple_of_scientific_zero_error.snap index f18e5b8..c89fc1a 100644 --- a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__multiple_of_scientific_zero_error.snap +++ b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__multiple_of_scientific_zero_error.snap @@ -26,6 +26,7 @@ mod __validator_impl { use jsonschema::__private::serde_json as __sj; use jsonschema::__private::types as __types; use jsonschema::__private::unique_items as __uniq; + use jsonschema::__private::unfinished_matches as __unfinished; use jsonschema::paths as __paths; use jsonschema::JsonType as __JT; use jsonschema::JsonTypeSet as __JTS; @@ -70,21 +71,30 @@ mod __validator_impl { _ => {} } } - pub(super) fn entry_is_valid(instance: &__Value) -> bool { + pub(super) fn run_is_valid(instance: &__Value) -> bool { is_valid(instance) } + pub(super) fn run_validate<'__i>(instance: &'__i __Value) -> Option<__VE<'__i>> { + validate(instance, &__paths::LazyLocation::new()) + } + pub(super) fn run_collect_errors<'__i>(instance: &'__i __Value) -> Vec<__VE<'__i>> { + let mut errors = Vec::new(); + collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); + errors + } + pub(super) fn entry_is_valid(instance: &__Value) -> bool { + run_is_valid(instance) + } pub(super) fn entry_validate<'__i>( instance: &'__i __Value, ) -> ::std::result::Result<(), __VE<'__i>> { - match validate(instance, &__paths::LazyLocation::new()) { + match run_validate(instance) { Some(e) => Err(e), None => Ok(()), } } pub(super) fn entry_iter_errors<'__i>(instance: &'__i __Value) -> __EI<'__i> { - let mut errors = Vec::new(); - collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); - __err::iterator_from(errors) + __err::iterator_from(run_collect_errors(instance)) } } impl Validator { diff --git a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__pattern.snap b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__pattern.snap index 79cdea4..ede0bf4 100644 --- a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__pattern.snap +++ b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__pattern.snap @@ -4,6 +4,8 @@ description: "{\"pattern\":\"^[a-z]+$\",\"type\":\"string\"}" expression: is_valid_body(schema) --- match instance { - __Value::String(s) => __jsonschema_regex_0(s), + __Value::String(s) => { + __jsonschema_regex_0(s, "/pattern", Some("^[a-z]+$"), None) + } _ => false, } diff --git a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__pattern_props_prefix_and_regex_uneval.snap b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__pattern_props_prefix_and_regex_uneval.snap index bbe0137..fd4e1a5 100644 --- a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__pattern_props_prefix_and_regex_uneval.snap +++ b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__pattern_props_prefix_and_regex_uneval.snap @@ -13,7 +13,13 @@ match instance { .iter() .all(|(__key, __value)| { let key_str = __key.as_str(); - if key_str.starts_with("a") || __jsonschema_regex_0(key_str) + if key_str.starts_with("a") + || __jsonschema_regex_0( + key_str, + "/patternProperties/^b.c", + None, + None, + ) { true } else { diff --git a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__property_names_multi_pattern_not_subsumed.snap b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__property_names_multi_pattern_not_subsumed.snap index 32f3723..58f8f21 100644 --- a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__property_names_multi_pattern_not_subsumed.snap +++ b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__property_names_multi_pattern_not_subsumed.snap @@ -28,7 +28,17 @@ match instance { true }); __object_pass - }) && (obj.keys().all(|s| { __jsonschema_regex_0(s) })) + }) + && (obj + .keys() + .all(|s| { + __jsonschema_regex_0( + s, + "/propertyNames/pattern", + Some("^[ab]"), + None, + ) + })) } _ => false, } diff --git a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__pyo3_emitter.snap b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__pyo3_emitter.snap index d9d77ec..76718e3 100644 --- a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__pyo3_emitter.snap +++ b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__pyo3_emitter.snap @@ -27,6 +27,7 @@ mod __validator_impl { use jsonschema::__private::serde_json as __sj; use jsonschema::__private::types as __types; use jsonschema::__private::unique_items as __uniq; + use jsonschema::__private::unfinished_matches as __unfinished; use jsonschema::paths as __paths; use jsonschema::JsonType as __JT; use jsonschema::JsonTypeSet as __JTS; @@ -138,15 +139,19 @@ mod __validator_impl { _ => false, } }) { - static CONST_EXPECTED: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("1").expect("Failed to parse const value") + static CONST_EXPECTED: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("1").expect("Failed to parse const value"), + ) }); return Some( __err::constant( "/properties/code/oneOf/0/properties/code/const", __path.into(), __NodeExt::lazy_value(&instance), - CONST_EXPECTED.clone(), + &*CONST_EXPECTED, ), ); } @@ -253,15 +258,19 @@ mod __validator_impl { _ => false, } }) { - static CONST_EXPECTED: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("2").expect("Failed to parse const value") + static CONST_EXPECTED: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("2").expect("Failed to parse const value"), + ) }); return Some( __err::constant( "/properties/code/oneOf/1/properties/code/const", __path.into(), __NodeExt::lazy_value(&instance), - CONST_EXPECTED.clone(), + &*CONST_EXPECTED, ), ); } @@ -334,15 +343,19 @@ mod __validator_impl { .extend( (|| -> Option<__VE<'_>> { if !(__NodeExt::as_boolean(&instance) == Some(true)) { - static CONST_EXPECTED: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("true").expect("Failed to parse const value") + static CONST_EXPECTED: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("true").expect("Failed to parse const value"), + ) }); return Some( __err::constant( "/properties/flag/oneOf/0/properties/on/const", __path.into(), __NodeExt::lazy_value(&instance), - CONST_EXPECTED.clone(), + &*CONST_EXPECTED, ), ); } @@ -415,16 +428,20 @@ mod __validator_impl { .extend( (|| -> Option<__VE<'_>> { if !(__NodeExt::as_boolean(&instance) == Some(false)) { - static CONST_EXPECTED: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("false") - .expect("Failed to parse const value") + static CONST_EXPECTED: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("false") + .expect("Failed to parse const value"), + ) }); return Some( __err::constant( "/properties/flag/oneOf/1/properties/on/const", __path.into(), __NodeExt::lazy_value(&instance), - CONST_EXPECTED.clone(), + &*CONST_EXPECTED, ), ); } @@ -504,16 +521,20 @@ mod __validator_impl { if !(__NodeExt::as_string(&instance).as_deref() == Some("circle")) { - static CONST_EXPECTED: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("\"circle\"") - .expect("Failed to parse const value") + static CONST_EXPECTED: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("\"circle\"") + .expect("Failed to parse const value"), + ) }); return Some( __err::constant( "/properties/shape/oneOf/0/properties/kind/const", __path.into(), __NodeExt::lazy_value(&instance), - CONST_EXPECTED.clone(), + &*CONST_EXPECTED, ), ); } @@ -613,16 +634,20 @@ mod __validator_impl { if !(__NodeExt::as_string(&instance).as_deref() == Some("square")) { - static CONST_EXPECTED: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("\"square\"") - .expect("Failed to parse const value") + static CONST_EXPECTED: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("\"square\"") + .expect("Failed to parse const value"), + ) }); return Some( __err::constant( "/properties/shape/oneOf/1/properties/kind/const", __path.into(), __NodeExt::lazy_value(&instance), - CONST_EXPECTED.clone(), + &*CONST_EXPECTED, ), ); } @@ -1113,9 +1138,13 @@ mod __validator_impl { } _ => false, }) { - static ENUM_OPTIONS: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("[1,\"a\",true,null,{\"o\":[1]}]") - .expect("Failed to parse enum options") + static ENUM_OPTIONS: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("[1,\"a\",true,null,{\"o\":[1]}]") + .expect("Failed to parse enum options"), + ) }); return Some( __err::enumeration( @@ -1689,16 +1718,20 @@ mod __validator_impl { }); __NodeExt::equals_value(&instance, &*EXPECTED) }) { - static CONST_EXPECTED: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("{\"o\":true}") - .expect("Failed to parse const value") + static CONST_EXPECTED: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("{\"o\":true}") + .expect("Failed to parse const value"), + ) }); return Some( __err::constant( "/properties/structured/const", __path.into(), __NodeExt::lazy_value(&instance), - CONST_EXPECTED.clone(), + &*CONST_EXPECTED, ), ); } @@ -1883,9 +1916,13 @@ mod __validator_impl { } _ => false, }) { - static ENUM_OPTIONS: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("[1,\"a\",true,null,{\"o\":[1]}]") - .expect("Failed to parse enum options") + static ENUM_OPTIONS: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("[1,\"a\",true,null,{\"o\":[1]}]") + .expect("Failed to parse enum options"), + ) }); return Some( __err::enumeration( @@ -2815,16 +2852,20 @@ mod __validator_impl { }); __NodeExt::equals_value(&instance, &*EXPECTED) }) { - static CONST_EXPECTED: __Lazy<__sj::Value> = __Lazy::new(|| { - __sj::from_str("{\"o\":true}") - .expect("Failed to parse const value") + static CONST_EXPECTED: __Lazy< + ::std::sync::Arc<__sj::Value>, + > = __Lazy::new(|| { + ::std::sync::Arc::new( + __sj::from_str("{\"o\":true}") + .expect("Failed to parse const value"), + ) }); return Some( __err::constant( "/properties/structured/const", __path.into(), __NodeExt::lazy_value(&instance), - CONST_EXPECTED.clone(), + &*CONST_EXPECTED, ), ); } @@ -2955,11 +2996,25 @@ mod __validator_impl { None => {} } } + pub(super) fn run_is_valid(instance: __Value<'_>) -> bool { + let __py = instance.py(); + is_valid(instance) + } + pub(super) fn run_validate<'__i>(instance: __Value<'__i>) -> Option<__VE<'__i>> { + let __py = instance.py(); + validate(instance, &__paths::LazyLocation::new()) + } + pub(super) fn run_collect_errors<'__i>(instance: __Value<'__i>) -> Vec<__VE<'__i>> { + let __py = instance.py(); + let mut errors = Vec::new(); + collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); + errors + } pub(super) fn entry_is_valid(instance: &__Bound<'_>) -> __py3::PyResult { __json::inspect( instance.as_borrowed(), false, - || { is_valid(instance.as_borrowed()) }, + || { run_is_valid(instance.as_borrowed()) }, ) } pub(super) fn entry_validate<'__i>( @@ -2969,7 +3024,7 @@ mod __validator_impl { instance.as_borrowed(), false, || { - match validate(instance.as_borrowed(), &__paths::LazyLocation::new()) { + match run_validate(instance.as_borrowed()) { Some(e) => Err(e), None => Ok(()), } @@ -2982,15 +3037,7 @@ mod __validator_impl { let errors = __json::inspect( instance.as_borrowed(), false, - || { - let mut errors = Vec::new(); - collect_errors( - instance.as_borrowed(), - &__paths::LazyLocation::new(), - &mut errors, - ); - errors - }, + || { run_collect_errors(instance.as_borrowed()) }, )?; Ok(__err::iterator_from(errors)) } diff --git a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__pyo3_emitter_draft4.snap b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__pyo3_emitter_draft4.snap index ab69eb9..78c2a3c 100644 --- a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__pyo3_emitter_draft4.snap +++ b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__pyo3_emitter_draft4.snap @@ -27,6 +27,7 @@ mod __validator_impl { use jsonschema::__private::serde_json as __sj; use jsonschema::__private::types as __types; use jsonschema::__private::unique_items as __uniq; + use jsonschema::__private::unfinished_matches as __unfinished; use jsonschema::paths as __paths; use jsonschema::JsonType as __JT; use jsonschema::JsonTypeSet as __JTS; @@ -110,11 +111,25 @@ mod __validator_impl { ); } } + pub(super) fn run_is_valid(instance: __Value<'_>) -> bool { + let __py = instance.py(); + is_valid(instance) + } + pub(super) fn run_validate<'__i>(instance: __Value<'__i>) -> Option<__VE<'__i>> { + let __py = instance.py(); + validate(instance, &__paths::LazyLocation::new()) + } + pub(super) fn run_collect_errors<'__i>(instance: __Value<'__i>) -> Vec<__VE<'__i>> { + let __py = instance.py(); + let mut errors = Vec::new(); + collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); + errors + } pub(super) fn entry_is_valid(instance: &__Bound<'_>) -> __py3::PyResult { __json::inspect( instance.as_borrowed(), false, - || { is_valid(instance.as_borrowed()) }, + || { run_is_valid(instance.as_borrowed()) }, ) } pub(super) fn entry_validate<'__i>( @@ -124,7 +139,7 @@ mod __validator_impl { instance.as_borrowed(), false, || { - match validate(instance.as_borrowed(), &__paths::LazyLocation::new()) { + match run_validate(instance.as_borrowed()) { Some(e) => Err(e), None => Ok(()), } @@ -137,15 +152,7 @@ mod __validator_impl { let errors = __json::inspect( instance.as_borrowed(), false, - || { - let mut errors = Vec::new(); - collect_errors( - instance.as_borrowed(), - &__paths::LazyLocation::new(), - &mut errors, - ); - errors - }, + || { run_collect_errors(instance.as_borrowed()) }, )?; Ok(__err::iterator_from(errors)) } diff --git a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__runtime_crate_alias.snap b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__runtime_crate_alias.snap index cdbe49e..d2755d1 100644 --- a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__runtime_crate_alias.snap +++ b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__runtime_crate_alias.snap @@ -27,6 +27,7 @@ mod __validator_impl { use jsonschema::__private::serde_json as __sj; use jsonschema::__private::types as __types; use jsonschema::__private::unique_items as __uniq; + use jsonschema::__private::unfinished_matches as __unfinished; use jsonschema::paths as __paths; use jsonschema::JsonType as __JT; use jsonschema::JsonTypeSet as __JTS; @@ -88,21 +89,30 @@ mod __validator_impl { } } } - pub(super) fn entry_is_valid(instance: &__Value) -> bool { + pub(super) fn run_is_valid(instance: &__Value) -> bool { is_valid(instance) } + pub(super) fn run_validate<'__i>(instance: &'__i __Value) -> Option<__VE<'__i>> { + validate(instance, &__paths::LazyLocation::new()) + } + pub(super) fn run_collect_errors<'__i>(instance: &'__i __Value) -> Vec<__VE<'__i>> { + let mut errors = Vec::new(); + collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); + errors + } + pub(super) fn entry_is_valid(instance: &__Value) -> bool { + run_is_valid(instance) + } pub(super) fn entry_validate<'__i>( instance: &'__i __Value, ) -> ::std::result::Result<(), __VE<'__i>> { - match validate(instance, &__paths::LazyLocation::new()) { + match run_validate(instance) { Some(e) => Err(e), None => Ok(()), } } pub(super) fn entry_iter_errors<'__i>(instance: &'__i __Value) -> __EI<'__i> { - let mut errors = Vec::new(); - collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); - __err::iterator_from(errors) + __err::iterator_from(run_collect_errors(instance)) } } impl Validator { diff --git a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__unknown_format_strict.snap b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__unknown_format_strict.snap index 3edbadf..ea04bdf 100644 --- a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__unknown_format_strict.snap +++ b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__unknown_format_strict.snap @@ -26,6 +26,7 @@ mod __validator_impl { use jsonschema::__private::serde_json as __sj; use jsonschema::__private::types as __types; use jsonschema::__private::unique_items as __uniq; + use jsonschema::__private::unfinished_matches as __unfinished; use jsonschema::paths as __paths; use jsonschema::JsonType as __JT; use jsonschema::JsonTypeSet as __JTS; @@ -91,21 +92,30 @@ mod __validator_impl { _ => {} } } - pub(super) fn entry_is_valid(instance: &__Value) -> bool { + pub(super) fn run_is_valid(instance: &__Value) -> bool { is_valid(instance) } + pub(super) fn run_validate<'__i>(instance: &'__i __Value) -> Option<__VE<'__i>> { + validate(instance, &__paths::LazyLocation::new()) + } + pub(super) fn run_collect_errors<'__i>(instance: &'__i __Value) -> Vec<__VE<'__i>> { + let mut errors = Vec::new(); + collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); + errors + } + pub(super) fn entry_is_valid(instance: &__Value) -> bool { + run_is_valid(instance) + } pub(super) fn entry_validate<'__i>( instance: &'__i __Value, ) -> ::std::result::Result<(), __VE<'__i>> { - match validate(instance, &__paths::LazyLocation::new()) { + match run_validate(instance) { Some(e) => Err(e), None => Ok(()), } } pub(super) fn entry_iter_errors<'__i>(instance: &'__i __Value) -> __EI<'__i> { - let mut errors = Vec::new(); - collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); - __err::iterator_from(errors) + __err::iterator_from(run_collect_errors(instance)) } } impl Validator { diff --git a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__unknown_format_under_assertion_vocabulary.snap b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__unknown_format_under_assertion_vocabulary.snap index 03ec7e5..ef2a6be 100644 --- a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__unknown_format_under_assertion_vocabulary.snap +++ b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__unknown_format_under_assertion_vocabulary.snap @@ -26,6 +26,7 @@ mod __validator_impl { use jsonschema::__private::serde_json as __sj; use jsonschema::__private::types as __types; use jsonschema::__private::unique_items as __uniq; + use jsonschema::__private::unfinished_matches as __unfinished; use jsonschema::paths as __paths; use jsonschema::JsonType as __JT; use jsonschema::JsonTypeSet as __JTS; @@ -91,21 +92,30 @@ mod __validator_impl { _ => {} } } - pub(super) fn entry_is_valid(instance: &__Value) -> bool { + pub(super) fn run_is_valid(instance: &__Value) -> bool { is_valid(instance) } + pub(super) fn run_validate<'__i>(instance: &'__i __Value) -> Option<__VE<'__i>> { + validate(instance, &__paths::LazyLocation::new()) + } + pub(super) fn run_collect_errors<'__i>(instance: &'__i __Value) -> Vec<__VE<'__i>> { + let mut errors = Vec::new(); + collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); + errors + } + pub(super) fn entry_is_valid(instance: &__Value) -> bool { + run_is_valid(instance) + } pub(super) fn entry_validate<'__i>( instance: &'__i __Value, ) -> ::std::result::Result<(), __VE<'__i>> { - match validate(instance, &__paths::LazyLocation::new()) { + match run_validate(instance) { Some(e) => Err(e), None => Ok(()), } } pub(super) fn entry_iter_errors<'__i>(instance: &'__i __Value) -> __EI<'__i> { - let mut errors = Vec::new(); - collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); - __err::iterator_from(errors) + __err::iterator_from(run_collect_errors(instance)) } } impl Validator { diff --git a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__uri_format_per_call_cache.snap b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__uri_format_per_call_cache.snap index 20c8fd2..7549daf 100644 --- a/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__uri_format_per_call_cache.snap +++ b/vendor/jsonschema-macros-core/src/snapshots/jsonschema_macros_core__tests__uri_format_per_call_cache.snap @@ -26,6 +26,7 @@ mod __validator_impl { use jsonschema::__private::serde_json as __sj; use jsonschema::__private::types as __types; use jsonschema::__private::unique_items as __uniq; + use jsonschema::__private::unfinished_matches as __unfinished; use jsonschema::paths as __paths; use jsonschema::JsonType as __JT; use jsonschema::JsonTypeSet as __JTS; @@ -111,21 +112,30 @@ mod __validator_impl { } } } - pub(super) fn entry_is_valid(instance: &__Value) -> bool { + pub(super) fn run_is_valid(instance: &__Value) -> bool { is_valid(instance) } + pub(super) fn run_validate<'__i>(instance: &'__i __Value) -> Option<__VE<'__i>> { + validate(instance, &__paths::LazyLocation::new()) + } + pub(super) fn run_collect_errors<'__i>(instance: &'__i __Value) -> Vec<__VE<'__i>> { + let mut errors = Vec::new(); + collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); + errors + } + pub(super) fn entry_is_valid(instance: &__Value) -> bool { + run_is_valid(instance) + } pub(super) fn entry_validate<'__i>( instance: &'__i __Value, ) -> ::std::result::Result<(), __VE<'__i>> { - match validate(instance, &__paths::LazyLocation::new()) { + match run_validate(instance) { Some(e) => Err(e), None => Ok(()), } } pub(super) fn entry_iter_errors<'__i>(instance: &'__i __Value) -> __EI<'__i> { - let mut errors = Vec::new(); - collect_errors(instance, &__paths::LazyLocation::new(), &mut errors); - __err::iterator_from(errors) + __err::iterator_from(run_collect_errors(instance)) } } impl Validator { diff --git a/vendor/patches/jsonschema-macros-core-0.61.2-explicit-cache-all-modes.patch b/vendor/patches/jsonschema-macros-core-0.61.2-explicit-cache-all-modes.patch new file mode 100644 index 0000000..f6e4ad5 --- /dev/null +++ b/vendor/patches/jsonschema-macros-core-0.61.2-explicit-cache-all-modes.patch @@ -0,0 +1,1035 @@ +diff --git a/Cargo.toml b/Cargo.toml +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -74,7 +74,7 @@ + + [dependencies.syn] + version = "2" +-features = ["full"] ++features = ["full", "visit-mut"] + + [dev-dependencies.codspeed-criterion-compat] + version = "5.0" +diff --git a/Cargo.toml.orig b/Cargo.toml.orig +--- a/Cargo.toml.orig ++++ b/Cargo.toml.orig +@@ -24,7 +24,7 @@ + referencing = { version = "0.61.2", path = "../jsonschema-referencing" } + regex = "1" + serde_json = "1" +-syn = { version = "2", features = ["full"] } ++syn = { version = "2", features = ["full", "visit-mut"] } + + [dev-dependencies] + insta = "1" +diff --git a/src/codegen.rs b/src/codegen.rs +--- a/src/codegen.rs ++++ b/src/codegen.rs +@@ -25,6 +25,7 @@ + mod emit_root; + pub(crate) mod emit_serde; + mod errors; ++mod explicit_cache; + mod expr; + mod helpers; + mod keywords; +@@ -94,7 +95,7 @@ + format!("Unknown vocabulary: '{uri}' is required by the meta-schema. Adjust configuration to declare support for it"), + )); + } +- Ok(emit_root_module( ++ let generated = emit_root_module( + &ctx, + config.runtime_crate_alias.as_ref(), + recompile_trigger, +@@ -107,7 +108,12 @@ + root_key_eval_ident.as_ref(), + root_item_eval_ident.as_ref(), + &root_dynamic_bindings, +- )) ++ ); ++ if let Some(automata) = &config.explicit_cache { ++ explicit_cache::lower(&ctx, generated, name, impl_mod_name, automata) ++ } else { ++ Ok(generated) ++ } + } + + // Draft 4 does not treat integer-valued floats like `-2.0` as integers. +diff --git a/src/codegen/explicit_cache.rs b/src/codegen/explicit_cache.rs +new file mode 100644 +--- /dev/null ++++ b/src/codegen/explicit_cache.rs +@@ -0,0 +1,805 @@ ++//! Closed lowering of the serde boolean helper ABI. Default output never enters this pass. ++ ++use std::collections::HashMap; ++ ++use proc_macro2::{Ident, TokenStream}; ++use quote::{format_ident, quote}; ++use syn::{ ++ parse_quote, ++ visit_mut::{self, VisitMut}, ++ Expr, Item, Pat, ReturnType, Type, ++}; ++ ++use crate::context::{CompileContext, PatternEngineConfig}; ++ ++use super::emit::ValueEmitter; ++ ++#[derive(Clone, Copy)] ++enum Binding { ++ Other, ++ Callable(usize), ++ Dispatch(usize), ++} ++ ++struct State { ++ item: syn::ItemStatic, ++ arity: Option, ++} ++ ++fn failure(node: impl quote::ToTokens, message: &str) -> syn::Error { ++ syn::Error::new_spanned(node, format!("explicit cache lowering: {message}")) ++} ++ ++fn simple_path(expr: &Expr) -> Option<&Ident> { ++ let Expr::Path(path) = expr else { return None }; ++ if path.qself.is_none() && path.path.leading_colon.is_none() { ++ path.path.get_ident() ++ } else { ++ None ++ } ++} ++ ++fn is_bool(output: &ReturnType) -> bool { ++ matches!(output, ReturnType::Type(_, ty) if matches!(ty.as_ref(), Type::Path(path) if path.qself.is_none() && path.path.is_ident("bool"))) ++} ++ ++fn state_arity(name: &str) -> Option> { ++ Some(match name { ++ "__JSONSCHEMA_RECURSIVE_STACK" | "__JSONSCHEMA_DYNAMIC_STACK" => Some(1), ++ "__JSONSCHEMA_RECURSIVE_KEY_EVAL_STACK" | "__JSONSCHEMA_DYNAMIC_KEY_EVAL_STACK" => Some(3), ++ "__JSONSCHEMA_RECURSIVE_ITEM_EVAL_STACK" | "__JSONSCHEMA_DYNAMIC_ITEM_EVAL_STACK" => { ++ Some(4) ++ } ++ "__JSONSCHEMA_VALIDATE_MARK" | "__JSONSCHEMA_EVAL_MARK" => None, ++ _ => return None, ++ }) ++} ++ ++fn unused_error_stack(name: &str) -> bool { ++ matches!( ++ name, ++ "__JSONSCHEMA_RECURSIVE_VALIDATE_STACK" ++ | "__JSONSCHEMA_RECURSIVE_COLLECT_STACK" ++ | "__JSONSCHEMA_DYNAMIC_VALIDATE_STACK" ++ | "__JSONSCHEMA_DYNAMIC_COLLECT_STACK" ++ ) ++} ++ ++struct PointerAbi { ++ arity: usize, ++ found: usize, ++ error: Option, ++} ++ ++impl VisitMut for PointerAbi { ++ fn visit_type_bare_fn_mut(&mut self, ty: &mut syn::TypeBareFn) { ++ if !is_bool(&ty.output) || ty.inputs.len() != self.arity || ty.variadic.is_some() { ++ self.error = Some(failure( ++ &*ty, ++ "unexpected boolean function-pointer signature", ++ )); ++ return; ++ } ++ ty.inputs.push(parse_quote! { &mut __SearchCache }); ++ self.found += 1; ++ } ++} ++ ++fn lower_pointer(ty: &mut Type, arity: usize) -> syn::Result<()> { ++ let mut abi = PointerAbi { ++ arity, ++ found: 0, ++ error: None, ++ }; ++ abi.visit_type_mut(ty); ++ if let Some(error) = abi.error { ++ return Err(error); ++ } ++ if abi.found != 1 { ++ return Err(failure( ++ ty, ++ "expected exactly one boolean function-pointer type", ++ )); ++ } ++ Ok(()) ++} ++ ++fn remove_root_uri_clears(block: &mut syn::Block, uri_names: &[String]) -> syn::Result<()> { ++ let mut removed = 0; ++ let mut statements = Vec::new(); ++ for statement in std::mem::take(&mut block.stmts) { ++ if let syn::Stmt::Expr(Expr::MethodCall(call), _) = &statement { ++ if simple_path(&call.receiver).is_some_and(|name| uri_names.contains(&name.to_string())) ++ { ++ let valid = if let Some(Expr::Closure(closure)) = call.args.first() { ++ matches!(closure.body.as_ref(), Expr::MethodCall(clear) ++ if clear.method == "clear" && clear.args.is_empty() ++ && matches!(closure.inputs.first(), Some(Pat::Ident(pat)) ++ if simple_path(&clear.receiver) == Some(&pat.ident))) ++ && closure.inputs.len() == 1 ++ } else { ++ false ++ }; ++ if call.method != "with_borrow_mut" || call.args.len() != 1 || !valid { ++ return Err(failure(call, "unexpected root URI cache clear")); ++ } ++ removed += 1; ++ continue; ++ } ++ } ++ statements.push(statement); ++ } ++ block.stmts = statements; ++ if removed != uri_names.len() { ++ return Err(failure(block, "missing root URI cache clears")); ++ } ++ Ok(()) ++} ++ ++pub(super) fn lower( ++ ctx: &CompileContext<'_, E>, ++ tokens: TokenStream, ++ name: &Ident, ++ module_name: &Ident, ++ automata: &TokenStream, ++) -> syn::Result { ++ let mut file: syn::File = syn::parse2(tokens)?; ++ let module = file ++ .items ++ .iter_mut() ++ .find_map(|item| match item { ++ Item::Mod(module) if module.ident == *module_name => Some(module), ++ _ => None, ++ }) ++ .ok_or_else(|| failure(module_name, "missing private module"))?; ++ let (_, items) = module ++ .content ++ .as_mut() ++ .ok_or_else(|| failure(module_name, "expected inline private module"))?; ++ let uri_names: Vec<_> = ctx ++ .uri_format_caches ++ .iter() ++ .map(|cache| format!("__JSONSCHEMA_{}_FORMAT_CACHE", cache.base().to_uppercase())) ++ .collect(); ++ let mut states = Vec::new(); ++ let mut retained = Vec::new(); ++ for item in std::mem::take(items) { ++ if let Item::Macro(mac) = &item { ++ if mac ++ .mac ++ .path ++ .segments ++ .last() ++ .is_some_and(|segment| segment.ident == "thread_local") ++ { ++ if mac.mac.path.leading_colon.is_some() ++ || mac.mac.path.segments.len() != 2 ++ || mac.mac.path.segments[0].ident != "std" ++ { ++ return Err(failure(mac, "unexpected thread-local macro")); ++ } ++ let declarations: syn::File = syn::parse2(mac.mac.tokens.clone())?; ++ for declaration in declarations.items { ++ let Item::Static(mut declaration) = declaration else { ++ return Err(failure(declaration, "unexpected thread-local declaration")); ++ }; ++ let state_name = declaration.ident.to_string(); ++ if unused_error_stack(&state_name) { ++ continue; ++ } ++ let arity = if let Some(arity) = state_arity(&state_name) { ++ arity ++ } else if uri_names.contains(&state_name) { ++ None ++ } else { ++ return Err(failure(declaration, "unknown generated thread-local state")); ++ }; ++ if states ++ .iter() ++ .any(|state: &State| state.item.ident == declaration.ident) ++ { ++ return Err(failure(declaration, "duplicate generated state")); ++ } ++ if let Some(arity) = arity { ++ lower_pointer(&mut declaration.ty, arity)?; ++ } ++ states.push(State { ++ item: declaration, ++ arity, ++ }); ++ } ++ continue; ++ } ++ } ++ retained.push(item); ++ } ++ *items = retained; ++ ++ let PatternEngineConfig::Regex { ++ size_limit, ++ dfa_size_limit, ++ } = ctx.config.pattern_options ++ else { ++ return Err(failure(name, "explicit matching requires the regex engine")); ++ }; ++ // These are regex::RegexBuilder's string defaults, not just meta::Regex's defaults. ++ let nfa_limit = size_limit.unwrap_or(10 * (1 << 20)); ++ let hybrid_capacity = dfa_size_limit.unwrap_or(2 * (1 << 20)); ++ let mut regex_fields = Vec::new(); ++ for (helper_name, pattern) in &ctx.regex_helpers { ++ let helper = format_ident!("{helper_name}"); ++ let storage = format_ident!("{}_REGEX", helper_name.to_uppercase()); ++ let field = format_ident!("{helper_name}_cache"); ++ let mut found_static = false; ++ let mut found_helper = false; ++ for item in items.iter_mut() { ++ match item { ++ Item::Static(item) if item.ident == storage => { ++ *item = parse_quote! { ++ static #storage: __Lazy> = __Lazy::new(|| { ++ __ra::meta::Regex::builder() ++ .configure(__ra::meta::Regex::config() ++ .match_kind(__ra::MatchKind::LeftmostFirst) ++ .utf8_empty(true) ++ .nfa_size_limit(Some(#nfa_limit)) ++ .hybrid_cache_capacity(#hybrid_capacity) ++ .pool_capacity(1)) ++ .syntax(__ra::util::syntax::Config::default().utf8(true)) ++ .build(#pattern).ok() ++ }); ++ }; ++ found_static = true; ++ } ++ Item::Fn(item) if item.sig.ident == helper => { ++ item.block = Box::new(parse_quote! { ++ { ++ #storage.as_ref().is_some_and(|regex| { ++ regex.search_half_with( ++ &mut __cache.#field, ++ &__ra::Input::new(subject).earliest(true), ++ ).is_some() ++ }) ++ } ++ }); ++ found_helper = true; ++ } ++ _ => {} ++ } ++ } ++ if !found_static || !found_helper { ++ return Err(failure( ++ helper, ++ "missing regex helper or shared constructor", ++ )); ++ } ++ regex_fields.push((field, storage)); ++ } ++ ++ let helpers: HashMap<_, _> = items ++ .iter() ++ .filter_map(|item| match item { ++ Item::Fn(item) ++ if is_bool(&item.sig.output) && item.sig.ident != "initialize_regexes" => ++ { ++ Some((item.sig.ident.to_string(), item.sig.inputs.len())) ++ } ++ _ => None, ++ }) ++ .collect(); ++ if !helpers.contains_key("is_valid") || !helpers.contains_key("entry_is_valid") { ++ return Err(failure(module_name, "missing boolean entry points")); ++ } ++ let state_names = states ++ .iter() ++ .map(|state| (state.item.ident.to_string(), state.arity)) ++ .collect(); ++ let mut lowering = Lowering { ++ helpers, ++ states: state_names, ++ scopes: Vec::new(), ++ error: None, ++ }; ++ for item in items.iter_mut() { ++ if let Item::Fn(function) = item { ++ if lowering ++ .helpers ++ .contains_key(&function.sig.ident.to_string()) ++ { ++ if function.sig.ident == "is_valid" { ++ remove_root_uri_clears(&mut function.block, &uri_names)?; ++ } ++ function ++ .sig ++ .inputs ++ .push(parse_quote! { __cache: &mut __SearchCache }); ++ lowering.visit_block_mut(&mut function.block); ++ if function.sig.ident == "entry_is_valid" { ++ function ++ .block ++ .stmts ++ .insert(0, parse_quote! { __cache.reset(); }); ++ } ++ } ++ } ++ } ++ if let Some(error) = lowering.error { ++ return Err(error); ++ } ++ ++ let fields = states.iter().map(|state| { ++ let ident = &state.item.ident; ++ let ty = &state.item.ty; ++ quote! { #ident: #ty } ++ }); ++ let initializers = states.iter().map(|state| { ++ let ident = &state.item.ident; ++ let value = &state.item.expr; ++ quote! { #ident: #value } ++ }); ++ let resets = states.iter().map(|state| { ++ let ident = &state.item.ident; ++ quote! { self.#ident.get_mut().clear(); } ++ }); ++ let cache_fields = regex_fields ++ .iter() ++ .map(|(field, _)| quote! { #field: __ra::meta::Cache }); ++ let cache_initializers = regex_fields ++ .iter() ++ .map(|(field, storage)| quote! { #field: #storage.as_ref()?.create_cache() }); ++ let support: syn::File = syn::parse2(quote! { ++ use #automata as __ra; ++ ++ pub(super) struct __SearchCache { ++ #(#cache_fields,)* ++ #(#fields,)* ++ } ++ ++ impl __SearchCache { ++ fn reset(&mut self) { #(#resets)* } ++ } ++ ++ pub(super) fn new_search_cache() -> Option<__SearchCache> { ++ if !initialize_regexes() { return None; } ++ Some(__SearchCache { #(#cache_initializers,)* #(#initializers,)* }) ++ } ++ ++ fn __with_state(state: &std::cell::RefCell, op: impl FnOnce(&std::cell::RefCell) -> R) -> R { ++ op(state) ++ } ++ ++ fn __with_state_mut(state: &std::cell::RefCell, op: impl FnOnce(&mut T) -> R) -> R { ++ op(&mut *state.borrow_mut()) ++ } ++ })?; ++ items.extend(support.items); ++ ++ let cache_name = format_ident!("{}SearchCache", name); ++ let mut found_public = false; ++ for item in &mut file.items { ++ if let Item::Impl(item) = item { ++ if matches!(item.self_ty.as_ref(), Type::Path(path) if path.path.is_ident(name)) { ++ for member in &mut item.items { ++ if let syn::ImplItem::Fn(method) = member { ++ if method.sig.ident == "is_valid" { ++ method ++ .sig ++ .inputs ++ .push(parse_quote! { __cache: &mut #cache_name }); ++ method.block = parse_quote! { ++ { #module_name::entry_is_valid(instance, &mut __cache.__inner) } ++ }; ++ found_public = true; ++ } ++ } ++ } ++ item.items.push(parse_quote! { ++ pub fn new_search_cache() -> Option<#cache_name> { ++ #module_name::new_search_cache().map(|__inner| #cache_name { __inner }) ++ } ++ }); ++ } ++ } ++ } ++ if !found_public { ++ return Err(failure(name, "missing public boolean wrapper")); ++ } ++ Ok(quote! { #file }) ++} ++ ++struct Lowering { ++ helpers: HashMap, ++ states: HashMap>, ++ scopes: Vec>, ++ error: Option, ++} ++ ++impl Lowering { ++ fn reject(&mut self, node: impl quote::ToTokens, message: &str) { ++ if self.error.is_none() { ++ self.error = Some(failure(node, message)); ++ } ++ } ++ ++ fn binding(&self, ident: &Ident) -> Option { ++ self.scopes ++ .iter() ++ .rev() ++ .find_map(|scope| scope.get(&ident.to_string()).copied()) ++ } ++ ++ fn bind(&mut self, ident: &Ident, binding: Binding) { ++ if let Some(scope) = self.scopes.last_mut() { ++ scope.insert(ident.to_string(), binding); ++ } ++ } ++ ++ fn bind_pattern(&mut self, pat: &Pat) { ++ match pat { ++ Pat::Ident(pat) => { ++ self.bind(&pat.ident, Binding::Other); ++ if let Some((_, pat)) = &pat.subpat { ++ self.bind_pattern(pat); ++ } ++ } ++ Pat::Type(pat) => self.bind_pattern(&pat.pat), ++ Pat::Reference(pat) => self.bind_pattern(&pat.pat), ++ Pat::Paren(pat) => self.bind_pattern(&pat.pat), ++ Pat::Tuple(pat) => { ++ for pat in &pat.elems { ++ self.bind_pattern(pat); ++ } ++ } ++ Pat::TupleStruct(pat) => { ++ for pat in &pat.elems { ++ self.bind_pattern(pat); ++ } ++ } ++ Pat::Struct(pat) => { ++ for field in &pat.fields { ++ self.bind_pattern(&field.pat); ++ } ++ } ++ Pat::Slice(pat) => { ++ for pat in &pat.elems { ++ self.bind_pattern(pat); ++ } ++ } ++ Pat::Or(pat) => { ++ for pat in &pat.cases { ++ self.bind_pattern(pat); ++ } ++ } ++ _ => {} ++ } ++ } ++ ++ fn callable_arity(&self, ident: &Ident) -> Option { ++ match self.binding(ident) { ++ Some(Binding::Callable(arity)) => Some(arity), ++ Some(_) => None, ++ None => self.helpers.get(&ident.to_string()).copied(), ++ } ++ } ++ ++ fn dispatch_arity(&self, expr: &Expr) -> Option { ++ let Expr::MethodCall(call) = expr else { ++ return None; ++ }; ++ if call.method != "with" { ++ return None; ++ } ++ let ident = simple_path(&call.receiver)?; ++ self.states.get(&ident.to_string()).copied().flatten() ++ } ++} ++ ++impl VisitMut for Lowering { ++ fn visit_block_mut(&mut self, block: &mut syn::Block) { ++ self.scopes.push(HashMap::new()); ++ visit_mut::visit_block_mut(self, block); ++ self.scopes.pop(); ++ } ++ ++ fn visit_expr_call_mut(&mut self, call: &mut syn::ExprCall) { ++ visit_mut::visit_expr_call_mut(self, call); ++ if let Some(arity) = simple_path(&call.func).and_then(|ident| self.callable_arity(ident)) { ++ if call.args.len() != arity { ++ self.reject(&*call, "unexpected helper call arity"); ++ } else { ++ call.args.push(parse_quote! { __cache }); ++ } ++ } ++ } ++ ++ fn visit_local_mut(&mut self, local: &mut syn::Local) { ++ let dispatch = local ++ .init ++ .as_ref() ++ .and_then(|init| self.dispatch_arity(&init.expr)); ++ let local_fn = if let Pat::Type(pat) = &mut local.pat { ++ if let Pat::Ident(ident) = pat.pat.as_ref() { ++ match ident.ident.to_string().as_str() { ++ "__root_key_eval" => Some((ident.ident.clone(), 3)), ++ "__root_item_eval" => Some((ident.ident.clone(), 4)), ++ _ => None, ++ } ++ } else { ++ None ++ } ++ } else { ++ None ++ }; ++ if let Some((_, arity)) = &local_fn { ++ let Pat::Type(pat) = &mut local.pat else { ++ unreachable!() ++ }; ++ if let Err(error) = lower_pointer(&mut pat.ty, *arity) { ++ self.error = Some(error); ++ } ++ if let Some(init) = &mut local.init { ++ if let Expr::Closure(closure) = init.expr.as_mut() { ++ if closure.inputs.len() != *arity || closure.capture.is_some() { ++ self.reject(&*closure, "unexpected local evaluator closure"); ++ } else { ++ closure.inputs.push(Pat::Type(syn::PatType { ++ attrs: Vec::new(), ++ pat: Box::new(parse_quote! { __cache }), ++ colon_token: Default::default(), ++ ty: Box::new(parse_quote! { &mut __SearchCache }), ++ })); ++ } ++ } else { ++ self.reject(&init.expr, "expected a noncapturing local evaluator"); ++ } ++ } else { ++ self.reject(&local.pat, "local evaluator has no initializer"); ++ } ++ } ++ if let Some(init) = &mut local.init { ++ self.visit_expr_mut(&mut init.expr); ++ if let Some((_, diverge)) = &mut init.diverge { ++ self.visit_expr_mut(diverge); ++ } ++ } ++ self.bind_pattern(&local.pat); ++ if let Some((ident, arity)) = local_fn { ++ self.bind(&ident, Binding::Callable(arity)); ++ } else if let Some(arity) = dispatch { ++ if let Pat::Ident(pat) = &local.pat { ++ self.bind(&pat.ident, Binding::Dispatch(arity)); ++ } ++ } ++ } ++ ++ fn visit_expr_closure_mut(&mut self, closure: &mut syn::ExprClosure) { ++ self.scopes.push(HashMap::new()); ++ for input in &closure.inputs { ++ self.bind_pattern(input); ++ } ++ self.visit_expr_mut(&mut closure.body); ++ self.scopes.pop(); ++ } ++ ++ fn visit_expr_if_mut(&mut self, expr: &mut syn::ExprIf) { ++ let dispatch = if let Expr::Let(condition) = expr.cond.as_ref() { ++ if let (Pat::TupleStruct(pat), Some(source)) = ++ (condition.pat.as_ref(), simple_path(&condition.expr)) ++ { ++ if pat.path.is_ident("Some") && pat.elems.len() == 1 { ++ if let (Some(Binding::Dispatch(arity)), Some(Pat::Ident(target))) = ++ (self.binding(source), pat.elems.first()) ++ { ++ Some((target.ident.clone(), arity)) ++ } else { ++ None ++ } ++ } else { ++ None ++ } ++ } else { ++ None ++ } ++ } else { ++ None ++ }; ++ self.visit_expr_mut(&mut expr.cond); ++ self.scopes.push(HashMap::new()); ++ if let Expr::Let(condition) = expr.cond.as_ref() { ++ self.bind_pattern(&condition.pat); ++ } ++ if let Some((target, arity)) = dispatch { ++ self.bind(&target, Binding::Callable(arity)); ++ } ++ self.visit_block_mut(&mut expr.then_branch); ++ self.scopes.pop(); ++ if let Some((_, branch)) = &mut expr.else_branch { ++ self.visit_expr_mut(branch); ++ } ++ } ++ ++ fn visit_arm_mut(&mut self, arm: &mut syn::Arm) { ++ self.scopes.push(HashMap::new()); ++ self.bind_pattern(&arm.pat); ++ if let Some((_, guard)) = &mut arm.guard { ++ self.visit_expr_mut(guard); ++ } ++ self.visit_expr_mut(&mut arm.body); ++ self.scopes.pop(); ++ } ++ ++ fn visit_expr_for_loop_mut(&mut self, expr: &mut syn::ExprForLoop) { ++ self.visit_expr_mut(&mut expr.expr); ++ self.scopes.push(HashMap::new()); ++ self.bind_pattern(&expr.pat); ++ self.visit_block_mut(&mut expr.body); ++ self.scopes.pop(); ++ } ++ ++ fn visit_expr_cast_mut(&mut self, expr: &mut syn::ExprCast) { ++ visit_mut::visit_expr_cast_mut(self, expr); ++ if matches!(expr.ty.as_ref(), Type::BareFn(ty) if is_bool(&ty.output)) { ++ if let Some(arity) = ++ simple_path(&expr.expr).and_then(|ident| self.callable_arity(ident)) ++ { ++ if let Err(error) = lower_pointer(&mut expr.ty, arity) { ++ self.error = Some(error); ++ } ++ } else { ++ self.reject(&*expr, "unknown boolean function-pointer cast"); ++ } ++ } ++ } ++ ++ fn visit_expr_mut(&mut self, expr: &mut Expr) { ++ if let Expr::MethodCall(call) = expr { ++ let state = simple_path(&call.receiver) ++ .filter(|ident| self.states.contains_key(&ident.to_string())) ++ .cloned(); ++ if let Some(state) = state { ++ let helper = match call.method.to_string().as_str() { ++ "with" => format_ident!("__with_state"), ++ "with_borrow_mut" => format_ident!("__with_state_mut"), ++ _ => { ++ self.reject(&*call, "unknown local-key operation"); ++ return; ++ } ++ }; ++ if call.args.len() != 1 { ++ self.reject(&*call, "expected one local-key closure"); ++ return; ++ } ++ let Some(Expr::Closure(closure)) = call.args.first_mut() else { ++ self.reject(&*call, "expected one local-key closure"); ++ return; ++ }; ++ self.visit_expr_closure_mut(closure); ++ *expr = parse_quote! { #helper(&__cache.#state, #closure) }; ++ return; ++ } ++ } ++ if let Some(ident) = simple_path(expr) { ++ if self.states.contains_key(&ident.to_string()) ++ || unused_error_stack(&ident.to_string()) ++ { ++ self.reject(&*expr, "unlowered local-key reference"); ++ return; ++ } ++ } ++ visit_mut::visit_expr_mut(self, expr); ++ } ++} ++ ++#[cfg(test)] ++mod tests { ++ use super::*; ++ ++ fn lowering() -> Lowering { ++ Lowering { ++ helpers: HashMap::from([("is_valid".into(), 1)]), ++ states: HashMap::from([("__JSONSCHEMA_DYNAMIC_STACK".into(), Some(1))]), ++ scopes: Vec::new(), ++ error: None, ++ } ++ } ++ ++ fn call_arity(stmt: &syn::Stmt) -> usize { ++ let syn::Stmt::Expr(Expr::Call(call), _) = stmt else { ++ panic!("expected direct call"); ++ }; ++ call.args.len() ++ } ++ ++ #[test] ++ fn indirect_dispatch_does_not_rewrite_external_target_names() { ++ let mut body = parse_quote! { ++ { ++ target(subject); ++ let selected = __JSONSCHEMA_DYNAMIC_STACK.with(|stack| { ++ stack.borrow().first().map(|(_, function)| *function) ++ }); ++ if let Some(target) = selected { ++ target(instance); ++ } else { ++ target(subject); ++ } ++ target(subject); ++ } ++ }; ++ let mut pass = lowering(); ++ pass.visit_block_mut(&mut body); ++ assert!(pass.error.is_none()); ++ assert_eq!(call_arity(&body.stmts[0]), 1); ++ let syn::Stmt::Expr(Expr::If(branch), _) = &body.stmts[2] else { ++ panic!("expected dispatch branch"); ++ }; ++ assert_eq!(call_arity(&branch.then_branch.stmts[0]), 2); ++ let Expr::Block(otherwise) = branch.else_branch.as_ref().unwrap().1.as_ref() else { ++ panic!("expected fallback block"); ++ }; ++ assert_eq!(call_arity(&otherwise.block.stmts[0]), 1); ++ assert_eq!(call_arity(&body.stmts[3]), 1); ++ } ++ ++ #[test] ++ fn typed_local_evaluators_remain_noncapturing_function_pointers() { ++ let mut body = parse_quote! { ++ { ++ let __root_key_eval: fn(&__Value, &__Map, &str) -> bool = ++ |instance, obj, key_str| is_valid(instance); ++ __root_key_eval(instance, obj, key_str) ++ } ++ }; ++ let mut pass = lowering(); ++ pass.visit_block_mut(&mut body); ++ assert!(pass.error.is_none()); ++ let syn::Stmt::Local(local) = &body.stmts[0] else { ++ panic!("expected local") ++ }; ++ let Pat::Type(pat) = &local.pat else { ++ panic!("expected typed local") ++ }; ++ let Type::BareFn(ty) = pat.ty.as_ref() else { ++ panic!("expected function pointer") ++ }; ++ assert_eq!(ty.inputs.len(), 4); ++ let Expr::Closure(closure) = local.init.as_ref().unwrap().expr.as_ref() else { ++ panic!("expected evaluator closure"); ++ }; ++ assert_eq!(closure.inputs.len(), 4); ++ assert!(closure.capture.is_none()); ++ let Expr::Call(child) = closure.body.as_ref() else { ++ panic!("expected child call") ++ }; ++ assert_eq!(child.args.len(), 2); ++ assert_eq!(call_arity(&body.stmts[1]), 4); ++ } ++ ++ #[test] ++ fn unexpected_local_key_operations_refuse_lowering() { ++ let mut body = parse_quote! { ++ { __JSONSCHEMA_DYNAMIC_STACK.with_borrow(|stack| stack.len()); } ++ }; ++ let mut pass = lowering(); ++ pass.visit_block_mut(&mut body); ++ assert!(pass ++ .error ++ .unwrap() ++ .to_string() ++ .contains("unknown local-key operation")); ++ } ++ ++ #[test] ++ fn plain_reference_cycle_cast_receives_the_same_boolean_abi() { ++ let mut expr: Expr = parse_quote! { is_valid as fn(&__Value) -> bool }; ++ let mut pass = lowering(); ++ pass.visit_expr_mut(&mut expr); ++ assert!(pass.error.is_none()); ++ let Expr::Cast(cast) = expr else { ++ panic!("expected cast") ++ }; ++ let Type::BareFn(ty) = cast.ty.as_ref() else { ++ panic!("expected function pointer") ++ }; ++ assert_eq!(ty.inputs.len(), 2); ++ } ++} +diff --git a/src/codegen/regex.rs b/src/codegen/regex.rs +--- a/src/codegen/regex.rs ++++ b/src/codegen/regex.rs +@@ -17,17 +17,9 @@ + let Ok(translated) = jsonschema_regex::to_rust_regex(pattern) else { + return Err(invalid_regex_expression(keyword, pattern)); + }; +- let translated = match jsonschema_regex::search_form(pattern, &translated) { +- Some(jsonschema_regex::Search::RepeatedClass(_)) => { +- let translated = translated.into_owned(); +- ctx.repeated_classes.insert(translated.clone()); +- ctx.translated_regex_cache +- .insert(pattern.to_string(), translated.clone()); +- return Ok(translated); +- } +- Some(jsonschema_regex::Search::Collapsed(collapsed)) => collapsed, +- None => translated.into_owned(), +- }; ++ // The initialization API preserves engine constructors and their default or supplied ++ // limits in every mode; search-only substitutions must not bypass them. ++ let translated = translated.into_owned(); + let valid = match ctx.config.pattern_options { + PatternEngineConfig::FancyRegex { + backtrack_limit, +diff --git a/src/context.rs b/src/context.rs +--- a/src/context.rs ++++ b/src/context.rs +@@ -224,6 +224,8 @@ + pub(crate) ignore_unknown_formats: bool, + pub(crate) email_options: Option, + pub(crate) pattern_options: PatternEngineConfig, ++ /// Runtime automata crate path; present only for explicit search-cache generation. ++ pub(crate) explicit_cache: Option, + pub(crate) methods: MethodGates, + } + +diff --git a/src/lib.rs b/src/lib.rs +--- a/src/lib.rs ++++ b/src/lib.rs +@@ -77,6 +77,7 @@ + ignore_unknown_formats: true, + email_options: None, + pattern_options: PatternEngineConfig::default(), ++ explicit_cache: None, + methods: MethodGates::default(), + }) + } +@@ -149,6 +150,7 @@ + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct PatternOptionsConfig { + engine: PatternEngine, ++ explicit_cache: bool, + backtrack_limit: Option, + size_limit: Option, + dfa_size_limit: Option, +@@ -158,6 +160,7 @@ + fn default() -> Self { + Self { + engine: PatternEngine::FancyRegex, ++ explicit_cache: false, + backtrack_limit: None, + size_limit: None, + dfa_size_limit: None, +@@ -381,6 +384,16 @@ + let value: LitInt = content.parse()?; + options.backtrack_limit = Some(parse_pattern_limit(value, "backtrack_limit")?); + backtrack_limit_span = Some(key.span()); ++ } ++ "cache" => { ++ let value: Ident = content.parse()?; ++ if value != "explicit" { ++ return Err(syn::Error::new_spanned( ++ value, ++ "Unknown cache policy. Expected `explicit`", ++ )); ++ } ++ options.explicit_cache = true; + } + "size_limit" => { + let value: LitInt = content.parse()?; +@@ -393,7 +406,7 @@ + _ => { + return Err(syn::Error::new_spanned( + key, +- "Unknown pattern_options key. Expected `engine`, `backtrack_limit`, `size_limit`, or `dfa_size_limit`", ++ "Unknown pattern_options key. Expected `engine`, `cache`, `backtrack_limit`, `size_limit`, or `dfa_size_limit`", + )); + } + } +@@ -738,6 +751,24 @@ + ) + })?; + ++ if pattern_options.explicit_cache { ++ if pattern_options.engine != PatternEngine::Regex { ++ return Err(syn::Error::new( ++ input.span(), ++ "`cache = explicit` requires `engine = regex`", ++ )); ++ } ++ if backend != Backend::SerdeJson { ++ return Err(syn::Error::new( ++ input.span(), ++ "`cache = explicit` requires `backend = SerdeJson`", ++ )); ++ } ++ if !methods.is_valid || methods.validate || methods.iter_errors { ++ return Err(syn::Error::new(input.span(), "`cache = explicit` requires boolean-only methods: `is_valid = true, validate = false, iter_errors = false`")); ++ } ++ } ++ + Ok(Config { + source: schema_source, + draft, +@@ -925,6 +956,20 @@ + size_limit: attr.pattern_options.size_limit, + dfa_size_limit: attr.pattern_options.dfa_size_limit, + }, ++ }, ++ explicit_cache: if attr.pattern_options.explicit_cache { ++ let found = crate_name("regex-automata").map_err(|_| syn::Error::new_spanned( ++ &input.ident, "`cache = explicit` requires a direct `regex-automata` dependency with the existing meta engine features", ++ ))?; ++ Some(match found { ++ FoundCrate::Itself => quote! { crate }, ++ FoundCrate::Name(found) => { ++ let ident = format_ident!("{found}"); ++ quote! { ::#ident } ++ } ++ }) ++ } else { ++ None + }, + methods: attr.methods, + }; +@@ -952,10 +997,20 @@ + } + }; + ++ let cache_type = attr.pattern_options.explicit_cache.then(|| { ++ let visibility = &input.vis; ++ let cache_name = format_ident!("{}SearchCache", name); ++ quote! { ++ #visibility struct #cache_name { ++ __inner: #impl_mod_name::__SearchCache, ++ } ++ } ++ }); + Ok(quote! { + #input + + #tokens ++ #cache_type + }) + } + +diff --git a/src/tests.rs b/src/tests.rs +--- a/src/tests.rs ++++ b/src/tests.rs +@@ -100,6 +100,7 @@ + ignore_unknown_formats: true, + email_options: None, + pattern_options: crate::context::PatternEngineConfig::default(), ++ explicit_cache: None, + methods: crate::context::MethodGates::default(), + } + } diff --git a/vendor/patches/jsonschema-macros-core-0.61.2-regex-initialization.patch b/vendor/patches/jsonschema-macros-core-0.61.2-regex-initialization.patch new file mode 100644 index 0000000..430759c --- /dev/null +++ b/vendor/patches/jsonschema-macros-core-0.61.2-regex-initialization.patch @@ -0,0 +1,124 @@ +diff --git a/src/codegen/emit_root.rs b/src/codegen/emit_root.rs +--- a/src/codegen/emit_root.rs ++++ b/src/codegen/emit_root.rs +@@ -60,6 +60,7 @@ + .iter() + .map(|(name, pattern)| { + let helper_ident = format_ident!("{}", name); ++ let storage_ident = format_ident!("{}_REGEX", name.to_uppercase()); + if ctx.repeated_classes.contains(pattern) { + let params = match ctx.config.pattern_options { + PatternEngineConfig::FancyRegex { .. } => quote! { +@@ -72,11 +73,12 @@ + }; + // The engine would unroll the count into as many copies of the class. + return quote! { ++ static #storage_ident: __Lazy> = ++ __Lazy::new(|| __re::RepeatedClass::from_translated(#pattern)); ++ + #[inline] + fn #helper_ident(#params) -> bool { +- static CLASS: __Lazy> = +- __Lazy::new(|| __re::RepeatedClass::from_translated(#pattern)); +- CLASS.as_ref().is_some_and(|class| class.is_match(subject)) ++ #storage_ident.as_ref().is_some_and(|class| class.is_match(subject)) + } + }; + } +@@ -93,6 +95,15 @@ + let set_dfa_size_limit = dfa_size_limit + .map(|limit| quote! { builder.delegate_dfa_size_limit(#limit); }); + quote! { ++ static #storage_ident: __Lazy> = ++ __Lazy::new(|| { ++ let mut builder = __fancy::RegexBuilder::new(#pattern); ++ #set_backtrack_limit ++ #set_size_limit ++ #set_dfa_size_limit ++ builder.build().ok() ++ }); ++ + #[inline] + fn #helper_ident( + subject: &str, +@@ -100,15 +111,7 @@ + pattern: Option<&str>, + instance_path: Option<&__paths::LazyLocation>, + ) -> bool { +- static REGEX: __Lazy> = +- __Lazy::new(|| { +- let mut builder = __fancy::RegexBuilder::new(#pattern); +- #set_backtrack_limit +- #set_size_limit +- #set_dfa_size_limit +- builder.build().ok() +- }); +- REGEX.as_ref().is_some_and(|re| { ++ #storage_ident.as_ref().is_some_and(|re| { + __unfinished::fancy_is_match( + re, subject, schema_path, pattern, instance_path, + ) +@@ -125,22 +128,27 @@ + let set_dfa_size_limit = + dfa_size_limit.map(|limit| quote! { builder.dfa_size_limit(#limit); }); + quote! { ++ static #storage_ident: __Lazy> = ++ __Lazy::new(|| { ++ let mut builder = __re::RegexBuilder::new(#pattern); ++ #set_size_limit ++ #set_dfa_size_limit ++ builder.build().ok() ++ }); ++ + #[inline] + fn #helper_ident(subject: &str) -> bool { +- static REGEX: __Lazy> = +- __Lazy::new(|| { +- let mut builder = __re::RegexBuilder::new(#pattern); +- #set_size_limit +- #set_dfa_size_limit +- builder.build().ok() +- }); +- REGEX.as_ref().is_some_and(|re| re.is_match(subject)) ++ #storage_ident.as_ref().is_some_and(|re| re.is_match(subject)) + } + } + } + } + }) + .collect(); ++ let regex_initializers = ctx.regex_helpers.iter().map(|(name, _)| { ++ let storage_ident = format_ident!("{}_REGEX", name.to_uppercase()); ++ quote! { ready &= #storage_ident.as_ref().is_some(); } ++ }); + + let mut uri_cache_statics: Vec = Vec::new(); + let mut uri_cache_wrappers: Vec = Vec::new(); +@@ -709,6 +717,12 @@ + #recursive_stack + #uri_cache_defs + #(#regex_helpers)* ++ pub(super) fn initialize_regexes() -> bool { ++ let mut ready = true; ++ #(#regex_initializers)* ++ ready ++ } ++ + #(#branch_helpers)* + #(#is_valid_fns)* + #(#key_eval_fns)* +@@ -734,6 +748,14 @@ + } + + impl #name { ++ /// Initializes every generated pattern regex, including after a ++ /// failed constructor. Returns false if any cached construction ++ /// failed. Repeated calls do not reconstruct or retry regexes. ++ /// This does not initialize custom formats or bound search caches. ++ pub fn initialize_regexes() -> bool { ++ #impl_mod_name::initialize_regexes() ++ } ++ + #entry_points + } + } diff --git a/vendor/patches/jsonschema-macros-core-0.61.2-type-check.patch b/vendor/patches/jsonschema-macros-core-0.61.2-type-check.patch new file mode 100644 index 0000000..81cb89c --- /dev/null +++ b/vendor/patches/jsonschema-macros-core-0.61.2-type-check.patch @@ -0,0 +1,19 @@ +--- a/src/codegen/object_schema.rs ++++ b/src/codegen/object_schema.rs +@@ -125,13 +125,13 @@ + + let has_type_constraint = schema.contains_key("type") && validation_vocab_enabled; + +- let typed = compile_typed(ctx, schema, has_type_constraint); +- let has_typed_checks = typed.is_some(); ++ // Enforce `type` independently of type-specific keyword dispatch. ++ let typed = compile_typed(ctx, schema, false); + + let mut untyped: Vec = Vec::new(); + let type_is_redundant = type_check_is_redundant(schema, ctx.draft); + +- if has_type_constraint && !has_typed_checks && !type_is_redundant { ++ if has_type_constraint && !type_is_redundant { + if let Some(value) = schema.get("type") { + untyped.push(keywords::type_::compile(ctx, value)); + }