[READ-ONLY] Mirror of https://github.com/probablykasper/cpc. Text calculator with support for units and conversion cpc.kasper.space
calculator cli conversion converter library math package units units-converter wasm website
0

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #48 from probablykasper/currency

Add currency units

authored by

Kasper and committed by
GitHub
(Jun 29, 2026, 12:33 PM +0200) ae0915ae de5f1cfc

+2286 -152
+3
CHANGELOG.md
··· 1 1 # Changelog 2 2 3 + ## Next 4 + - Add currency units 5 + 3 6 ## 4.0.0 - 2026 Jun 27 4 7 - Rewrite units to be exponent-based, making things like `km^5` and `sqkm^-1` possible 5 8 - Add generic unit multiplication and division, such as `1kg/1m` and `1m*1kg`
+1607 -12
Cargo.lock
··· 12 12 ] 13 13 14 14 [[package]] 15 + name = "atomic-waker" 16 + version = "1.1.2" 17 + source = "registry+https://github.com/rust-lang/crates.io-index" 18 + checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 19 + 20 + [[package]] 15 21 name = "autocfg" 16 22 version = "1.5.1" 17 23 source = "registry+https://github.com/rust-lang/crates.io-index" 18 24 checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" 19 25 20 26 [[package]] 27 + name = "aws-lc-rs" 28 + version = "1.17.0" 29 + source = "registry+https://github.com/rust-lang/crates.io-index" 30 + checksum = "5ec2f1fc3ec205783a5da9a7e6c1509cc69dedf09a1949e412c1e18469326d00" 31 + dependencies = [ 32 + "aws-lc-sys", 33 + "zeroize", 34 + ] 35 + 36 + [[package]] 37 + name = "aws-lc-sys" 38 + version = "0.41.0" 39 + source = "registry+https://github.com/rust-lang/crates.io-index" 40 + checksum = "1a2f9779ce85b93ab6170dd940ad0169b5766ff848247aff13bb788b832fe3f4" 41 + dependencies = [ 42 + "cc", 43 + "cmake", 44 + "dunce", 45 + "fs_extra", 46 + ] 47 + 48 + [[package]] 49 + name = "base64" 50 + version = "0.22.1" 51 + source = "registry+https://github.com/rust-lang/crates.io-index" 52 + checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 53 + 54 + [[package]] 55 + name = "bitflags" 56 + version = "2.13.0" 57 + source = "registry+https://github.com/rust-lang/crates.io-index" 58 + checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" 59 + 60 + [[package]] 21 61 name = "bnum" 22 62 version = "0.12.1" 23 63 source = "registry+https://github.com/rust-lang/crates.io-index" 24 64 checksum = "f781dba93de3a5ef6dc5b17c9958b208f6f3f021623b360fb605ea51ce443f10" 65 + dependencies = [ 66 + "serde", 67 + "serde-big-array", 68 + ] 25 69 26 70 [[package]] 27 71 name = "bumpalo" ··· 30 74 checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" 31 75 32 76 [[package]] 77 + name = "bytes" 78 + version = "1.12.0" 79 + source = "registry+https://github.com/rust-lang/crates.io-index" 80 + checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" 81 + 82 + [[package]] 83 + name = "cc" 84 + version = "1.2.65" 85 + source = "registry+https://github.com/rust-lang/crates.io-index" 86 + checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" 87 + dependencies = [ 88 + "find-msvc-tools", 89 + "jobserver", 90 + "libc", 91 + "shlex", 92 + ] 93 + 94 + [[package]] 33 95 name = "cfg-if" 34 96 version = "1.0.4" 35 97 source = "registry+https://github.com/rust-lang/crates.io-index" 36 98 checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" 37 99 38 100 [[package]] 101 + name = "cfg_aliases" 102 + version = "0.2.1" 103 + source = "registry+https://github.com/rust-lang/crates.io-index" 104 + checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 105 + 106 + [[package]] 107 + name = "cmake" 108 + version = "0.1.58" 109 + source = "registry+https://github.com/rust-lang/crates.io-index" 110 + checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" 111 + dependencies = [ 112 + "cc", 113 + ] 114 + 115 + [[package]] 116 + name = "combine" 117 + version = "4.6.7" 118 + source = "registry+https://github.com/rust-lang/crates.io-index" 119 + checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" 120 + dependencies = [ 121 + "bytes", 122 + "memchr", 123 + ] 124 + 125 + [[package]] 39 126 name = "console_error_panic_hook" 40 127 version = "0.1.7" 41 128 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 46 133 ] 47 134 48 135 [[package]] 136 + name = "core-foundation" 137 + version = "0.9.4" 138 + source = "registry+https://github.com/rust-lang/crates.io-index" 139 + checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 140 + dependencies = [ 141 + "core-foundation-sys", 142 + "libc", 143 + ] 144 + 145 + [[package]] 146 + name = "core-foundation" 147 + version = "0.10.1" 148 + source = "registry+https://github.com/rust-lang/crates.io-index" 149 + checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" 150 + dependencies = [ 151 + "core-foundation-sys", 152 + "libc", 153 + ] 154 + 155 + [[package]] 156 + name = "core-foundation-sys" 157 + version = "0.8.7" 158 + source = "registry+https://github.com/rust-lang/crates.io-index" 159 + checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 160 + 161 + [[package]] 49 162 name = "cpc" 50 163 version = "4.0.0" 51 164 dependencies = [ ··· 53 166 "fastnum", 54 167 "js-sys", 55 168 "regex", 169 + "reqwest", 170 + "serde", 171 + "serde_json", 56 172 "unicode-segmentation", 57 173 "wasm-bindgen", 58 174 "web-time", 59 175 ] 60 176 61 177 [[package]] 178 + name = "displaydoc" 179 + version = "0.2.6" 180 + source = "registry+https://github.com/rust-lang/crates.io-index" 181 + checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" 182 + dependencies = [ 183 + "proc-macro2", 184 + "quote", 185 + "syn", 186 + ] 187 + 188 + [[package]] 189 + name = "dunce" 190 + version = "1.0.5" 191 + source = "registry+https://github.com/rust-lang/crates.io-index" 192 + checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" 193 + 194 + [[package]] 195 + name = "encoding_rs" 196 + version = "0.8.35" 197 + source = "registry+https://github.com/rust-lang/crates.io-index" 198 + checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" 199 + dependencies = [ 200 + "cfg-if", 201 + ] 202 + 203 + [[package]] 204 + name = "equivalent" 205 + version = "1.0.2" 206 + source = "registry+https://github.com/rust-lang/crates.io-index" 207 + checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 208 + 209 + [[package]] 62 210 name = "fastnum" 63 211 version = "0.7.5" 64 212 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 67 215 "bnum", 68 216 "num-integer", 69 217 "num-traits", 218 + "serde", 219 + ] 220 + 221 + [[package]] 222 + name = "find-msvc-tools" 223 + version = "0.1.9" 224 + source = "registry+https://github.com/rust-lang/crates.io-index" 225 + checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" 226 + 227 + [[package]] 228 + name = "fnv" 229 + version = "1.0.7" 230 + source = "registry+https://github.com/rust-lang/crates.io-index" 231 + checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 232 + 233 + [[package]] 234 + name = "form_urlencoded" 235 + version = "1.2.2" 236 + source = "registry+https://github.com/rust-lang/crates.io-index" 237 + checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" 238 + dependencies = [ 239 + "percent-encoding", 240 + ] 241 + 242 + [[package]] 243 + name = "fs_extra" 244 + version = "1.3.0" 245 + source = "registry+https://github.com/rust-lang/crates.io-index" 246 + checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" 247 + 248 + [[package]] 249 + name = "futures-channel" 250 + version = "0.3.32" 251 + source = "registry+https://github.com/rust-lang/crates.io-index" 252 + checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" 253 + dependencies = [ 254 + "futures-core", 255 + "futures-sink", 70 256 ] 71 257 72 258 [[package]] ··· 76 262 checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" 77 263 78 264 [[package]] 265 + name = "futures-io" 266 + version = "0.3.32" 267 + source = "registry+https://github.com/rust-lang/crates.io-index" 268 + checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" 269 + 270 + [[package]] 271 + name = "futures-sink" 272 + version = "0.3.32" 273 + source = "registry+https://github.com/rust-lang/crates.io-index" 274 + checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" 275 + 276 + [[package]] 79 277 name = "futures-task" 80 278 version = "0.3.32" 81 279 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 88 286 checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" 89 287 dependencies = [ 90 288 "futures-core", 289 + "futures-io", 290 + "futures-sink", 91 291 "futures-task", 292 + "memchr", 92 293 "pin-project-lite", 93 294 "slab", 94 295 ] 95 296 96 297 [[package]] 298 + name = "getrandom" 299 + version = "0.2.17" 300 + source = "registry+https://github.com/rust-lang/crates.io-index" 301 + checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" 302 + dependencies = [ 303 + "cfg-if", 304 + "js-sys", 305 + "libc", 306 + "wasi", 307 + "wasm-bindgen", 308 + ] 309 + 310 + [[package]] 311 + name = "getrandom" 312 + version = "0.3.4" 313 + source = "registry+https://github.com/rust-lang/crates.io-index" 314 + checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" 315 + dependencies = [ 316 + "cfg-if", 317 + "js-sys", 318 + "libc", 319 + "r-efi", 320 + "wasip2", 321 + "wasm-bindgen", 322 + ] 323 + 324 + [[package]] 325 + name = "h2" 326 + version = "0.4.15" 327 + source = "registry+https://github.com/rust-lang/crates.io-index" 328 + checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155" 329 + dependencies = [ 330 + "atomic-waker", 331 + "bytes", 332 + "fnv", 333 + "futures-core", 334 + "futures-sink", 335 + "http", 336 + "indexmap", 337 + "slab", 338 + "tokio", 339 + "tokio-util", 340 + "tracing", 341 + ] 342 + 343 + [[package]] 344 + name = "hashbrown" 345 + version = "0.17.1" 346 + source = "registry+https://github.com/rust-lang/crates.io-index" 347 + checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" 348 + 349 + [[package]] 350 + name = "http" 351 + version = "1.4.2" 352 + source = "registry+https://github.com/rust-lang/crates.io-index" 353 + checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" 354 + dependencies = [ 355 + "bytes", 356 + "itoa", 357 + ] 358 + 359 + [[package]] 360 + name = "http-body" 361 + version = "1.0.1" 362 + source = "registry+https://github.com/rust-lang/crates.io-index" 363 + checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 364 + dependencies = [ 365 + "bytes", 366 + "http", 367 + ] 368 + 369 + [[package]] 370 + name = "http-body-util" 371 + version = "0.1.3" 372 + source = "registry+https://github.com/rust-lang/crates.io-index" 373 + checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" 374 + dependencies = [ 375 + "bytes", 376 + "futures-core", 377 + "http", 378 + "http-body", 379 + "pin-project-lite", 380 + ] 381 + 382 + [[package]] 383 + name = "httparse" 384 + version = "1.10.1" 385 + source = "registry+https://github.com/rust-lang/crates.io-index" 386 + checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" 387 + 388 + [[package]] 389 + name = "hyper" 390 + version = "1.10.1" 391 + source = "registry+https://github.com/rust-lang/crates.io-index" 392 + checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" 393 + dependencies = [ 394 + "atomic-waker", 395 + "bytes", 396 + "futures-channel", 397 + "futures-core", 398 + "h2", 399 + "http", 400 + "http-body", 401 + "httparse", 402 + "itoa", 403 + "pin-project-lite", 404 + "smallvec", 405 + "tokio", 406 + "want", 407 + ] 408 + 409 + [[package]] 410 + name = "hyper-rustls" 411 + version = "0.27.9" 412 + source = "registry+https://github.com/rust-lang/crates.io-index" 413 + checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" 414 + dependencies = [ 415 + "http", 416 + "hyper", 417 + "hyper-util", 418 + "rustls", 419 + "tokio", 420 + "tokio-rustls", 421 + "tower-service", 422 + ] 423 + 424 + [[package]] 425 + name = "hyper-util" 426 + version = "0.1.20" 427 + source = "registry+https://github.com/rust-lang/crates.io-index" 428 + checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" 429 + dependencies = [ 430 + "base64", 431 + "bytes", 432 + "futures-channel", 433 + "futures-util", 434 + "http", 435 + "http-body", 436 + "hyper", 437 + "ipnet", 438 + "libc", 439 + "percent-encoding", 440 + "pin-project-lite", 441 + "socket2", 442 + "system-configuration", 443 + "tokio", 444 + "tower-service", 445 + "tracing", 446 + "windows-registry", 447 + ] 448 + 449 + [[package]] 450 + name = "icu_collections" 451 + version = "2.2.0" 452 + source = "registry+https://github.com/rust-lang/crates.io-index" 453 + checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" 454 + dependencies = [ 455 + "displaydoc", 456 + "potential_utf", 457 + "utf8_iter", 458 + "yoke", 459 + "zerofrom", 460 + "zerovec", 461 + ] 462 + 463 + [[package]] 464 + name = "icu_locale_core" 465 + version = "2.2.0" 466 + source = "registry+https://github.com/rust-lang/crates.io-index" 467 + checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" 468 + dependencies = [ 469 + "displaydoc", 470 + "litemap", 471 + "tinystr", 472 + "writeable", 473 + "zerovec", 474 + ] 475 + 476 + [[package]] 477 + name = "icu_normalizer" 478 + version = "2.2.0" 479 + source = "registry+https://github.com/rust-lang/crates.io-index" 480 + checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" 481 + dependencies = [ 482 + "icu_collections", 483 + "icu_normalizer_data", 484 + "icu_properties", 485 + "icu_provider", 486 + "smallvec", 487 + "zerovec", 488 + ] 489 + 490 + [[package]] 491 + name = "icu_normalizer_data" 492 + version = "2.2.0" 493 + source = "registry+https://github.com/rust-lang/crates.io-index" 494 + checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" 495 + 496 + [[package]] 497 + name = "icu_properties" 498 + version = "2.2.0" 499 + source = "registry+https://github.com/rust-lang/crates.io-index" 500 + checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" 501 + dependencies = [ 502 + "icu_collections", 503 + "icu_locale_core", 504 + "icu_properties_data", 505 + "icu_provider", 506 + "zerotrie", 507 + "zerovec", 508 + ] 509 + 510 + [[package]] 511 + name = "icu_properties_data" 512 + version = "2.2.0" 513 + source = "registry+https://github.com/rust-lang/crates.io-index" 514 + checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" 515 + 516 + [[package]] 517 + name = "icu_provider" 518 + version = "2.2.0" 519 + source = "registry+https://github.com/rust-lang/crates.io-index" 520 + checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" 521 + dependencies = [ 522 + "displaydoc", 523 + "icu_locale_core", 524 + "writeable", 525 + "yoke", 526 + "zerofrom", 527 + "zerotrie", 528 + "zerovec", 529 + ] 530 + 531 + [[package]] 532 + name = "idna" 533 + version = "1.1.0" 534 + source = "registry+https://github.com/rust-lang/crates.io-index" 535 + checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" 536 + dependencies = [ 537 + "idna_adapter", 538 + "smallvec", 539 + "utf8_iter", 540 + ] 541 + 542 + [[package]] 543 + name = "idna_adapter" 544 + version = "1.2.2" 545 + source = "registry+https://github.com/rust-lang/crates.io-index" 546 + checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" 547 + dependencies = [ 548 + "icu_normalizer", 549 + "icu_properties", 550 + ] 551 + 552 + [[package]] 553 + name = "indexmap" 554 + version = "2.14.0" 555 + source = "registry+https://github.com/rust-lang/crates.io-index" 556 + checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" 557 + dependencies = [ 558 + "equivalent", 559 + "hashbrown", 560 + ] 561 + 562 + [[package]] 563 + name = "ipnet" 564 + version = "2.12.0" 565 + source = "registry+https://github.com/rust-lang/crates.io-index" 566 + checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" 567 + 568 + [[package]] 569 + name = "itoa" 570 + version = "1.0.18" 571 + source = "registry+https://github.com/rust-lang/crates.io-index" 572 + checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" 573 + 574 + [[package]] 575 + name = "jni" 576 + version = "0.22.4" 577 + source = "registry+https://github.com/rust-lang/crates.io-index" 578 + checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" 579 + dependencies = [ 580 + "cfg-if", 581 + "combine", 582 + "jni-macros", 583 + "jni-sys", 584 + "log", 585 + "simd_cesu8", 586 + "thiserror", 587 + "walkdir", 588 + "windows-link", 589 + ] 590 + 591 + [[package]] 592 + name = "jni-macros" 593 + version = "0.22.4" 594 + source = "registry+https://github.com/rust-lang/crates.io-index" 595 + checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" 596 + dependencies = [ 597 + "proc-macro2", 598 + "quote", 599 + "rustc_version", 600 + "simd_cesu8", 601 + "syn", 602 + ] 603 + 604 + [[package]] 605 + name = "jni-sys" 606 + version = "0.4.1" 607 + source = "registry+https://github.com/rust-lang/crates.io-index" 608 + checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" 609 + dependencies = [ 610 + "jni-sys-macros", 611 + ] 612 + 613 + [[package]] 614 + name = "jni-sys-macros" 615 + version = "0.4.1" 616 + source = "registry+https://github.com/rust-lang/crates.io-index" 617 + checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" 618 + dependencies = [ 619 + "quote", 620 + "syn", 621 + ] 622 + 623 + [[package]] 624 + name = "jobserver" 625 + version = "0.1.34" 626 + source = "registry+https://github.com/rust-lang/crates.io-index" 627 + checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" 628 + dependencies = [ 629 + "getrandom 0.3.4", 630 + "libc", 631 + ] 632 + 633 + [[package]] 97 634 name = "js-sys" 98 - version = "0.3.102" 635 + version = "0.3.103" 99 636 source = "registry+https://github.com/rust-lang/crates.io-index" 100 - checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31" 637 + checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" 101 638 dependencies = [ 102 639 "cfg-if", 103 640 "futures-util", ··· 105 642 ] 106 643 107 644 [[package]] 645 + name = "libc" 646 + version = "0.2.186" 647 + source = "registry+https://github.com/rust-lang/crates.io-index" 648 + checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" 649 + 650 + [[package]] 651 + name = "litemap" 652 + version = "0.8.2" 653 + source = "registry+https://github.com/rust-lang/crates.io-index" 654 + checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" 655 + 656 + [[package]] 657 + name = "log" 658 + version = "0.4.33" 659 + source = "registry+https://github.com/rust-lang/crates.io-index" 660 + checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" 661 + 662 + [[package]] 663 + name = "lru-slab" 664 + version = "0.1.2" 665 + source = "registry+https://github.com/rust-lang/crates.io-index" 666 + checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" 667 + 668 + [[package]] 108 669 name = "memchr" 109 670 version = "2.8.2" 110 671 source = "registry+https://github.com/rust-lang/crates.io-index" 111 672 checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" 112 673 113 674 [[package]] 675 + name = "mime" 676 + version = "0.3.17" 677 + source = "registry+https://github.com/rust-lang/crates.io-index" 678 + checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 679 + 680 + [[package]] 681 + name = "mio" 682 + version = "1.2.1" 683 + source = "registry+https://github.com/rust-lang/crates.io-index" 684 + checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" 685 + dependencies = [ 686 + "libc", 687 + "wasi", 688 + "windows-sys 0.61.2", 689 + ] 690 + 691 + [[package]] 114 692 name = "num-integer" 115 693 version = "0.1.46" 116 694 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 135 713 checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" 136 714 137 715 [[package]] 716 + name = "openssl-probe" 717 + version = "0.2.1" 718 + source = "registry+https://github.com/rust-lang/crates.io-index" 719 + checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" 720 + 721 + [[package]] 722 + name = "percent-encoding" 723 + version = "2.3.2" 724 + source = "registry+https://github.com/rust-lang/crates.io-index" 725 + checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" 726 + 727 + [[package]] 138 728 name = "pin-project-lite" 139 729 version = "0.2.17" 140 730 source = "registry+https://github.com/rust-lang/crates.io-index" 141 731 checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" 142 732 143 733 [[package]] 734 + name = "potential_utf" 735 + version = "0.1.5" 736 + source = "registry+https://github.com/rust-lang/crates.io-index" 737 + checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" 738 + dependencies = [ 739 + "zerovec", 740 + ] 741 + 742 + [[package]] 743 + name = "ppv-lite86" 744 + version = "0.2.21" 745 + source = "registry+https://github.com/rust-lang/crates.io-index" 746 + checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" 747 + dependencies = [ 748 + "zerocopy", 749 + ] 750 + 751 + [[package]] 144 752 name = "proc-macro2" 145 753 version = "1.0.106" 146 754 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 150 758 ] 151 759 152 760 [[package]] 761 + name = "quinn" 762 + version = "0.11.11" 763 + source = "registry+https://github.com/rust-lang/crates.io-index" 764 + checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" 765 + dependencies = [ 766 + "bytes", 767 + "cfg_aliases", 768 + "pin-project-lite", 769 + "quinn-proto", 770 + "quinn-udp", 771 + "rustc-hash", 772 + "rustls", 773 + "socket2", 774 + "thiserror", 775 + "tokio", 776 + "tracing", 777 + "web-time", 778 + ] 779 + 780 + [[package]] 781 + name = "quinn-proto" 782 + version = "0.11.15" 783 + source = "registry+https://github.com/rust-lang/crates.io-index" 784 + checksum = "4fcb935c5bec503c2f0e306bdd3e58bb9029dcb14fa8d9ac76e3a5256ac0763e" 785 + dependencies = [ 786 + "aws-lc-rs", 787 + "bytes", 788 + "getrandom 0.3.4", 789 + "lru-slab", 790 + "rand", 791 + "ring", 792 + "rustc-hash", 793 + "rustls", 794 + "rustls-pki-types", 795 + "slab", 796 + "thiserror", 797 + "tinyvec", 798 + "tracing", 799 + "web-time", 800 + ] 801 + 802 + [[package]] 803 + name = "quinn-udp" 804 + version = "0.5.14" 805 + source = "registry+https://github.com/rust-lang/crates.io-index" 806 + checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" 807 + dependencies = [ 808 + "cfg_aliases", 809 + "libc", 810 + "once_cell", 811 + "socket2", 812 + "tracing", 813 + "windows-sys 0.60.2", 814 + ] 815 + 816 + [[package]] 153 817 name = "quote" 154 - version = "1.0.45" 818 + version = "1.0.46" 155 819 source = "registry+https://github.com/rust-lang/crates.io-index" 156 - checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" 820 + checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" 157 821 dependencies = [ 158 822 "proc-macro2", 159 823 ] 160 824 161 825 [[package]] 826 + name = "r-efi" 827 + version = "5.3.0" 828 + source = "registry+https://github.com/rust-lang/crates.io-index" 829 + checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" 830 + 831 + [[package]] 832 + name = "rand" 833 + version = "0.9.4" 834 + source = "registry+https://github.com/rust-lang/crates.io-index" 835 + checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" 836 + dependencies = [ 837 + "rand_chacha", 838 + "rand_core", 839 + ] 840 + 841 + [[package]] 842 + name = "rand_chacha" 843 + version = "0.9.0" 844 + source = "registry+https://github.com/rust-lang/crates.io-index" 845 + checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 846 + dependencies = [ 847 + "ppv-lite86", 848 + "rand_core", 849 + ] 850 + 851 + [[package]] 852 + name = "rand_core" 853 + version = "0.9.5" 854 + source = "registry+https://github.com/rust-lang/crates.io-index" 855 + checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" 856 + dependencies = [ 857 + "getrandom 0.3.4", 858 + ] 859 + 860 + [[package]] 162 861 name = "regex" 163 862 version = "1.12.4" 164 863 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 188 887 checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" 189 888 190 889 [[package]] 890 + name = "reqwest" 891 + version = "0.13.4" 892 + source = "registry+https://github.com/rust-lang/crates.io-index" 893 + checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" 894 + dependencies = [ 895 + "base64", 896 + "bytes", 897 + "encoding_rs", 898 + "futures-channel", 899 + "futures-core", 900 + "futures-util", 901 + "h2", 902 + "http", 903 + "http-body", 904 + "http-body-util", 905 + "hyper", 906 + "hyper-rustls", 907 + "hyper-util", 908 + "js-sys", 909 + "log", 910 + "mime", 911 + "percent-encoding", 912 + "pin-project-lite", 913 + "quinn", 914 + "rustls", 915 + "rustls-pki-types", 916 + "rustls-platform-verifier", 917 + "serde", 918 + "serde_json", 919 + "sync_wrapper", 920 + "tokio", 921 + "tokio-rustls", 922 + "tower", 923 + "tower-http", 924 + "tower-service", 925 + "url", 926 + "wasm-bindgen", 927 + "wasm-bindgen-futures", 928 + "web-sys", 929 + ] 930 + 931 + [[package]] 932 + name = "ring" 933 + version = "0.17.14" 934 + source = "registry+https://github.com/rust-lang/crates.io-index" 935 + checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" 936 + dependencies = [ 937 + "cc", 938 + "cfg-if", 939 + "getrandom 0.2.17", 940 + "libc", 941 + "untrusted", 942 + "windows-sys 0.52.0", 943 + ] 944 + 945 + [[package]] 946 + name = "rustc-hash" 947 + version = "2.1.2" 948 + source = "registry+https://github.com/rust-lang/crates.io-index" 949 + checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" 950 + 951 + [[package]] 952 + name = "rustc_version" 953 + version = "0.4.1" 954 + source = "registry+https://github.com/rust-lang/crates.io-index" 955 + checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" 956 + dependencies = [ 957 + "semver", 958 + ] 959 + 960 + [[package]] 961 + name = "rustls" 962 + version = "0.23.41" 963 + source = "registry+https://github.com/rust-lang/crates.io-index" 964 + checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" 965 + dependencies = [ 966 + "aws-lc-rs", 967 + "once_cell", 968 + "rustls-pki-types", 969 + "rustls-webpki", 970 + "subtle", 971 + "zeroize", 972 + ] 973 + 974 + [[package]] 975 + name = "rustls-native-certs" 976 + version = "0.8.4" 977 + source = "registry+https://github.com/rust-lang/crates.io-index" 978 + checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" 979 + dependencies = [ 980 + "openssl-probe", 981 + "rustls-pki-types", 982 + "schannel", 983 + "security-framework", 984 + ] 985 + 986 + [[package]] 987 + name = "rustls-pki-types" 988 + version = "1.14.1" 989 + source = "registry+https://github.com/rust-lang/crates.io-index" 990 + checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" 991 + dependencies = [ 992 + "web-time", 993 + "zeroize", 994 + ] 995 + 996 + [[package]] 997 + name = "rustls-platform-verifier" 998 + version = "0.7.0" 999 + source = "registry+https://github.com/rust-lang/crates.io-index" 1000 + checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" 1001 + dependencies = [ 1002 + "core-foundation 0.10.1", 1003 + "core-foundation-sys", 1004 + "jni", 1005 + "log", 1006 + "once_cell", 1007 + "rustls", 1008 + "rustls-native-certs", 1009 + "rustls-platform-verifier-android", 1010 + "rustls-webpki", 1011 + "security-framework", 1012 + "security-framework-sys", 1013 + "webpki-root-certs", 1014 + "windows-sys 0.61.2", 1015 + ] 1016 + 1017 + [[package]] 1018 + name = "rustls-platform-verifier-android" 1019 + version = "0.1.1" 1020 + source = "registry+https://github.com/rust-lang/crates.io-index" 1021 + checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" 1022 + 1023 + [[package]] 1024 + name = "rustls-webpki" 1025 + version = "0.103.13" 1026 + source = "registry+https://github.com/rust-lang/crates.io-index" 1027 + checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" 1028 + dependencies = [ 1029 + "aws-lc-rs", 1030 + "ring", 1031 + "rustls-pki-types", 1032 + "untrusted", 1033 + ] 1034 + 1035 + [[package]] 191 1036 name = "rustversion" 192 1037 version = "1.0.22" 193 1038 source = "registry+https://github.com/rust-lang/crates.io-index" 194 1039 checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" 195 1040 196 1041 [[package]] 1042 + name = "same-file" 1043 + version = "1.0.6" 1044 + source = "registry+https://github.com/rust-lang/crates.io-index" 1045 + checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" 1046 + dependencies = [ 1047 + "winapi-util", 1048 + ] 1049 + 1050 + [[package]] 1051 + name = "schannel" 1052 + version = "0.1.29" 1053 + source = "registry+https://github.com/rust-lang/crates.io-index" 1054 + checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" 1055 + dependencies = [ 1056 + "windows-sys 0.61.2", 1057 + ] 1058 + 1059 + [[package]] 1060 + name = "security-framework" 1061 + version = "3.7.0" 1062 + source = "registry+https://github.com/rust-lang/crates.io-index" 1063 + checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" 1064 + dependencies = [ 1065 + "bitflags", 1066 + "core-foundation 0.10.1", 1067 + "core-foundation-sys", 1068 + "libc", 1069 + "security-framework-sys", 1070 + ] 1071 + 1072 + [[package]] 1073 + name = "security-framework-sys" 1074 + version = "2.17.0" 1075 + source = "registry+https://github.com/rust-lang/crates.io-index" 1076 + checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" 1077 + dependencies = [ 1078 + "core-foundation-sys", 1079 + "libc", 1080 + ] 1081 + 1082 + [[package]] 1083 + name = "semver" 1084 + version = "1.0.28" 1085 + source = "registry+https://github.com/rust-lang/crates.io-index" 1086 + checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" 1087 + 1088 + [[package]] 1089 + name = "serde" 1090 + version = "1.0.228" 1091 + source = "registry+https://github.com/rust-lang/crates.io-index" 1092 + checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" 1093 + dependencies = [ 1094 + "serde_core", 1095 + "serde_derive", 1096 + ] 1097 + 1098 + [[package]] 1099 + name = "serde-big-array" 1100 + version = "0.5.1" 1101 + source = "registry+https://github.com/rust-lang/crates.io-index" 1102 + checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" 1103 + dependencies = [ 1104 + "serde", 1105 + ] 1106 + 1107 + [[package]] 1108 + name = "serde_core" 1109 + version = "1.0.228" 1110 + source = "registry+https://github.com/rust-lang/crates.io-index" 1111 + checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" 1112 + dependencies = [ 1113 + "serde_derive", 1114 + ] 1115 + 1116 + [[package]] 1117 + name = "serde_derive" 1118 + version = "1.0.228" 1119 + source = "registry+https://github.com/rust-lang/crates.io-index" 1120 + checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" 1121 + dependencies = [ 1122 + "proc-macro2", 1123 + "quote", 1124 + "syn", 1125 + ] 1126 + 1127 + [[package]] 1128 + name = "serde_json" 1129 + version = "1.0.150" 1130 + source = "registry+https://github.com/rust-lang/crates.io-index" 1131 + checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" 1132 + dependencies = [ 1133 + "itoa", 1134 + "memchr", 1135 + "serde", 1136 + "serde_core", 1137 + "zmij", 1138 + ] 1139 + 1140 + [[package]] 1141 + name = "shlex" 1142 + version = "2.0.1" 1143 + source = "registry+https://github.com/rust-lang/crates.io-index" 1144 + checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" 1145 + 1146 + [[package]] 1147 + name = "simd_cesu8" 1148 + version = "1.1.1" 1149 + source = "registry+https://github.com/rust-lang/crates.io-index" 1150 + checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" 1151 + dependencies = [ 1152 + "rustc_version", 1153 + "simdutf8", 1154 + ] 1155 + 1156 + [[package]] 1157 + name = "simdutf8" 1158 + version = "0.1.5" 1159 + source = "registry+https://github.com/rust-lang/crates.io-index" 1160 + checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" 1161 + 1162 + [[package]] 197 1163 name = "slab" 198 1164 version = "0.4.12" 199 1165 source = "registry+https://github.com/rust-lang/crates.io-index" 200 1166 checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" 201 1167 202 1168 [[package]] 1169 + name = "smallvec" 1170 + version = "1.15.2" 1171 + source = "registry+https://github.com/rust-lang/crates.io-index" 1172 + checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" 1173 + 1174 + [[package]] 1175 + name = "socket2" 1176 + version = "0.6.4" 1177 + source = "registry+https://github.com/rust-lang/crates.io-index" 1178 + checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" 1179 + dependencies = [ 1180 + "libc", 1181 + "windows-sys 0.61.2", 1182 + ] 1183 + 1184 + [[package]] 1185 + name = "stable_deref_trait" 1186 + version = "1.2.1" 1187 + source = "registry+https://github.com/rust-lang/crates.io-index" 1188 + checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" 1189 + 1190 + [[package]] 1191 + name = "subtle" 1192 + version = "2.6.1" 1193 + source = "registry+https://github.com/rust-lang/crates.io-index" 1194 + checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1195 + 1196 + [[package]] 203 1197 name = "syn" 204 1198 version = "2.0.118" 205 1199 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 211 1205 ] 212 1206 213 1207 [[package]] 1208 + name = "sync_wrapper" 1209 + version = "1.0.2" 1210 + source = "registry+https://github.com/rust-lang/crates.io-index" 1211 + checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 1212 + dependencies = [ 1213 + "futures-core", 1214 + ] 1215 + 1216 + [[package]] 1217 + name = "synstructure" 1218 + version = "0.13.2" 1219 + source = "registry+https://github.com/rust-lang/crates.io-index" 1220 + checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" 1221 + dependencies = [ 1222 + "proc-macro2", 1223 + "quote", 1224 + "syn", 1225 + ] 1226 + 1227 + [[package]] 1228 + name = "system-configuration" 1229 + version = "0.7.0" 1230 + source = "registry+https://github.com/rust-lang/crates.io-index" 1231 + checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" 1232 + dependencies = [ 1233 + "bitflags", 1234 + "core-foundation 0.9.4", 1235 + "system-configuration-sys", 1236 + ] 1237 + 1238 + [[package]] 1239 + name = "system-configuration-sys" 1240 + version = "0.6.0" 1241 + source = "registry+https://github.com/rust-lang/crates.io-index" 1242 + checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" 1243 + dependencies = [ 1244 + "core-foundation-sys", 1245 + "libc", 1246 + ] 1247 + 1248 + [[package]] 1249 + name = "thiserror" 1250 + version = "2.0.18" 1251 + source = "registry+https://github.com/rust-lang/crates.io-index" 1252 + checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" 1253 + dependencies = [ 1254 + "thiserror-impl", 1255 + ] 1256 + 1257 + [[package]] 1258 + name = "thiserror-impl" 1259 + version = "2.0.18" 1260 + source = "registry+https://github.com/rust-lang/crates.io-index" 1261 + checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" 1262 + dependencies = [ 1263 + "proc-macro2", 1264 + "quote", 1265 + "syn", 1266 + ] 1267 + 1268 + [[package]] 1269 + name = "tinystr" 1270 + version = "0.8.3" 1271 + source = "registry+https://github.com/rust-lang/crates.io-index" 1272 + checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" 1273 + dependencies = [ 1274 + "displaydoc", 1275 + "zerovec", 1276 + ] 1277 + 1278 + [[package]] 1279 + name = "tinyvec" 1280 + version = "1.11.0" 1281 + source = "registry+https://github.com/rust-lang/crates.io-index" 1282 + checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" 1283 + dependencies = [ 1284 + "tinyvec_macros", 1285 + ] 1286 + 1287 + [[package]] 1288 + name = "tinyvec_macros" 1289 + version = "0.1.1" 1290 + source = "registry+https://github.com/rust-lang/crates.io-index" 1291 + checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 1292 + 1293 + [[package]] 1294 + name = "tokio" 1295 + version = "1.52.3" 1296 + source = "registry+https://github.com/rust-lang/crates.io-index" 1297 + checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" 1298 + dependencies = [ 1299 + "bytes", 1300 + "libc", 1301 + "mio", 1302 + "pin-project-lite", 1303 + "socket2", 1304 + "windows-sys 0.61.2", 1305 + ] 1306 + 1307 + [[package]] 1308 + name = "tokio-rustls" 1309 + version = "0.26.4" 1310 + source = "registry+https://github.com/rust-lang/crates.io-index" 1311 + checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" 1312 + dependencies = [ 1313 + "rustls", 1314 + "tokio", 1315 + ] 1316 + 1317 + [[package]] 1318 + name = "tokio-util" 1319 + version = "0.7.18" 1320 + source = "registry+https://github.com/rust-lang/crates.io-index" 1321 + checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" 1322 + dependencies = [ 1323 + "bytes", 1324 + "futures-core", 1325 + "futures-sink", 1326 + "pin-project-lite", 1327 + "tokio", 1328 + ] 1329 + 1330 + [[package]] 1331 + name = "tower" 1332 + version = "0.5.3" 1333 + source = "registry+https://github.com/rust-lang/crates.io-index" 1334 + checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" 1335 + dependencies = [ 1336 + "futures-core", 1337 + "futures-util", 1338 + "pin-project-lite", 1339 + "sync_wrapper", 1340 + "tokio", 1341 + "tower-layer", 1342 + "tower-service", 1343 + ] 1344 + 1345 + [[package]] 1346 + name = "tower-http" 1347 + version = "0.6.11" 1348 + source = "registry+https://github.com/rust-lang/crates.io-index" 1349 + checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" 1350 + dependencies = [ 1351 + "bitflags", 1352 + "bytes", 1353 + "futures-util", 1354 + "http", 1355 + "http-body", 1356 + "pin-project-lite", 1357 + "tower", 1358 + "tower-layer", 1359 + "tower-service", 1360 + "url", 1361 + ] 1362 + 1363 + [[package]] 1364 + name = "tower-layer" 1365 + version = "0.3.3" 1366 + source = "registry+https://github.com/rust-lang/crates.io-index" 1367 + checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" 1368 + 1369 + [[package]] 1370 + name = "tower-service" 1371 + version = "0.3.3" 1372 + source = "registry+https://github.com/rust-lang/crates.io-index" 1373 + checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 1374 + 1375 + [[package]] 1376 + name = "tracing" 1377 + version = "0.1.44" 1378 + source = "registry+https://github.com/rust-lang/crates.io-index" 1379 + checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" 1380 + dependencies = [ 1381 + "pin-project-lite", 1382 + "tracing-core", 1383 + ] 1384 + 1385 + [[package]] 1386 + name = "tracing-core" 1387 + version = "0.1.36" 1388 + source = "registry+https://github.com/rust-lang/crates.io-index" 1389 + checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" 1390 + dependencies = [ 1391 + "once_cell", 1392 + ] 1393 + 1394 + [[package]] 1395 + name = "try-lock" 1396 + version = "0.2.5" 1397 + source = "registry+https://github.com/rust-lang/crates.io-index" 1398 + checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 1399 + 1400 + [[package]] 214 1401 name = "unicode-ident" 215 1402 version = "1.0.24" 216 1403 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 223 1410 checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" 224 1411 225 1412 [[package]] 1413 + name = "untrusted" 1414 + version = "0.9.0" 1415 + source = "registry+https://github.com/rust-lang/crates.io-index" 1416 + checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 1417 + 1418 + [[package]] 1419 + name = "url" 1420 + version = "2.5.8" 1421 + source = "registry+https://github.com/rust-lang/crates.io-index" 1422 + checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" 1423 + dependencies = [ 1424 + "form_urlencoded", 1425 + "idna", 1426 + "percent-encoding", 1427 + "serde", 1428 + ] 1429 + 1430 + [[package]] 1431 + name = "utf8_iter" 1432 + version = "1.0.4" 1433 + source = "registry+https://github.com/rust-lang/crates.io-index" 1434 + checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 1435 + 1436 + [[package]] 1437 + name = "walkdir" 1438 + version = "2.5.0" 1439 + source = "registry+https://github.com/rust-lang/crates.io-index" 1440 + checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" 1441 + dependencies = [ 1442 + "same-file", 1443 + "winapi-util", 1444 + ] 1445 + 1446 + [[package]] 1447 + name = "want" 1448 + version = "0.3.1" 1449 + source = "registry+https://github.com/rust-lang/crates.io-index" 1450 + checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1451 + dependencies = [ 1452 + "try-lock", 1453 + ] 1454 + 1455 + [[package]] 1456 + name = "wasi" 1457 + version = "0.11.1+wasi-snapshot-preview1" 1458 + source = "registry+https://github.com/rust-lang/crates.io-index" 1459 + checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" 1460 + 1461 + [[package]] 1462 + name = "wasip2" 1463 + version = "1.0.4+wasi-0.2.12" 1464 + source = "registry+https://github.com/rust-lang/crates.io-index" 1465 + checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" 1466 + dependencies = [ 1467 + "wit-bindgen", 1468 + ] 1469 + 1470 + [[package]] 226 1471 name = "wasm-bindgen" 227 - version = "0.2.125" 1472 + version = "0.2.126" 228 1473 source = "registry+https://github.com/rust-lang/crates.io-index" 229 - checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a" 1474 + checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" 230 1475 dependencies = [ 231 1476 "cfg-if", 232 1477 "once_cell", ··· 236 1481 ] 237 1482 238 1483 [[package]] 1484 + name = "wasm-bindgen-futures" 1485 + version = "0.4.76" 1486 + source = "registry+https://github.com/rust-lang/crates.io-index" 1487 + checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" 1488 + dependencies = [ 1489 + "js-sys", 1490 + "wasm-bindgen", 1491 + ] 1492 + 1493 + [[package]] 239 1494 name = "wasm-bindgen-macro" 240 - version = "0.2.125" 1495 + version = "0.2.126" 241 1496 source = "registry+https://github.com/rust-lang/crates.io-index" 242 - checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d" 1497 + checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" 243 1498 dependencies = [ 244 1499 "quote", 245 1500 "wasm-bindgen-macro-support", ··· 247 1502 248 1503 [[package]] 249 1504 name = "wasm-bindgen-macro-support" 250 - version = "0.2.125" 1505 + version = "0.2.126" 251 1506 source = "registry+https://github.com/rust-lang/crates.io-index" 252 - checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd" 1507 + checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" 253 1508 dependencies = [ 254 1509 "bumpalo", 255 1510 "proc-macro2", ··· 260 1515 261 1516 [[package]] 262 1517 name = "wasm-bindgen-shared" 263 - version = "0.2.125" 1518 + version = "0.2.126" 264 1519 source = "registry+https://github.com/rust-lang/crates.io-index" 265 - checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f" 1520 + checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" 266 1521 dependencies = [ 267 1522 "unicode-ident", 268 1523 ] 269 1524 270 1525 [[package]] 1526 + name = "web-sys" 1527 + version = "0.3.103" 1528 + source = "registry+https://github.com/rust-lang/crates.io-index" 1529 + checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" 1530 + dependencies = [ 1531 + "js-sys", 1532 + "wasm-bindgen", 1533 + ] 1534 + 1535 + [[package]] 271 1536 name = "web-time" 272 1537 version = "1.1.0" 273 1538 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 276 1541 "js-sys", 277 1542 "wasm-bindgen", 278 1543 ] 1544 + 1545 + [[package]] 1546 + name = "webpki-root-certs" 1547 + version = "1.0.8" 1548 + source = "registry+https://github.com/rust-lang/crates.io-index" 1549 + checksum = "0d46a5a140e6f7afeccd8eae97eff335163939eac8b929834875168b29b3d267" 1550 + dependencies = [ 1551 + "rustls-pki-types", 1552 + ] 1553 + 1554 + [[package]] 1555 + name = "winapi-util" 1556 + version = "0.1.11" 1557 + source = "registry+https://github.com/rust-lang/crates.io-index" 1558 + checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" 1559 + dependencies = [ 1560 + "windows-sys 0.61.2", 1561 + ] 1562 + 1563 + [[package]] 1564 + name = "windows-link" 1565 + version = "0.2.1" 1566 + source = "registry+https://github.com/rust-lang/crates.io-index" 1567 + checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 1568 + 1569 + [[package]] 1570 + name = "windows-registry" 1571 + version = "0.6.1" 1572 + source = "registry+https://github.com/rust-lang/crates.io-index" 1573 + checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" 1574 + dependencies = [ 1575 + "windows-link", 1576 + "windows-result", 1577 + "windows-strings", 1578 + ] 1579 + 1580 + [[package]] 1581 + name = "windows-result" 1582 + version = "0.4.1" 1583 + source = "registry+https://github.com/rust-lang/crates.io-index" 1584 + checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" 1585 + dependencies = [ 1586 + "windows-link", 1587 + ] 1588 + 1589 + [[package]] 1590 + name = "windows-strings" 1591 + version = "0.5.1" 1592 + source = "registry+https://github.com/rust-lang/crates.io-index" 1593 + checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" 1594 + dependencies = [ 1595 + "windows-link", 1596 + ] 1597 + 1598 + [[package]] 1599 + name = "windows-sys" 1600 + version = "0.52.0" 1601 + source = "registry+https://github.com/rust-lang/crates.io-index" 1602 + checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 1603 + dependencies = [ 1604 + "windows-targets 0.52.6", 1605 + ] 1606 + 1607 + [[package]] 1608 + name = "windows-sys" 1609 + version = "0.60.2" 1610 + source = "registry+https://github.com/rust-lang/crates.io-index" 1611 + checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" 1612 + dependencies = [ 1613 + "windows-targets 0.53.5", 1614 + ] 1615 + 1616 + [[package]] 1617 + name = "windows-sys" 1618 + version = "0.61.2" 1619 + source = "registry+https://github.com/rust-lang/crates.io-index" 1620 + checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" 1621 + dependencies = [ 1622 + "windows-link", 1623 + ] 1624 + 1625 + [[package]] 1626 + name = "windows-targets" 1627 + version = "0.52.6" 1628 + source = "registry+https://github.com/rust-lang/crates.io-index" 1629 + checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1630 + dependencies = [ 1631 + "windows_aarch64_gnullvm 0.52.6", 1632 + "windows_aarch64_msvc 0.52.6", 1633 + "windows_i686_gnu 0.52.6", 1634 + "windows_i686_gnullvm 0.52.6", 1635 + "windows_i686_msvc 0.52.6", 1636 + "windows_x86_64_gnu 0.52.6", 1637 + "windows_x86_64_gnullvm 0.52.6", 1638 + "windows_x86_64_msvc 0.52.6", 1639 + ] 1640 + 1641 + [[package]] 1642 + name = "windows-targets" 1643 + version = "0.53.5" 1644 + source = "registry+https://github.com/rust-lang/crates.io-index" 1645 + checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" 1646 + dependencies = [ 1647 + "windows-link", 1648 + "windows_aarch64_gnullvm 0.53.1", 1649 + "windows_aarch64_msvc 0.53.1", 1650 + "windows_i686_gnu 0.53.1", 1651 + "windows_i686_gnullvm 0.53.1", 1652 + "windows_i686_msvc 0.53.1", 1653 + "windows_x86_64_gnu 0.53.1", 1654 + "windows_x86_64_gnullvm 0.53.1", 1655 + "windows_x86_64_msvc 0.53.1", 1656 + ] 1657 + 1658 + [[package]] 1659 + name = "windows_aarch64_gnullvm" 1660 + version = "0.52.6" 1661 + source = "registry+https://github.com/rust-lang/crates.io-index" 1662 + checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1663 + 1664 + [[package]] 1665 + name = "windows_aarch64_gnullvm" 1666 + version = "0.53.1" 1667 + source = "registry+https://github.com/rust-lang/crates.io-index" 1668 + checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" 1669 + 1670 + [[package]] 1671 + name = "windows_aarch64_msvc" 1672 + version = "0.52.6" 1673 + source = "registry+https://github.com/rust-lang/crates.io-index" 1674 + checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1675 + 1676 + [[package]] 1677 + name = "windows_aarch64_msvc" 1678 + version = "0.53.1" 1679 + source = "registry+https://github.com/rust-lang/crates.io-index" 1680 + checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" 1681 + 1682 + [[package]] 1683 + name = "windows_i686_gnu" 1684 + version = "0.52.6" 1685 + source = "registry+https://github.com/rust-lang/crates.io-index" 1686 + checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1687 + 1688 + [[package]] 1689 + name = "windows_i686_gnu" 1690 + version = "0.53.1" 1691 + source = "registry+https://github.com/rust-lang/crates.io-index" 1692 + checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" 1693 + 1694 + [[package]] 1695 + name = "windows_i686_gnullvm" 1696 + version = "0.52.6" 1697 + source = "registry+https://github.com/rust-lang/crates.io-index" 1698 + checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1699 + 1700 + [[package]] 1701 + name = "windows_i686_gnullvm" 1702 + version = "0.53.1" 1703 + source = "registry+https://github.com/rust-lang/crates.io-index" 1704 + checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" 1705 + 1706 + [[package]] 1707 + name = "windows_i686_msvc" 1708 + version = "0.52.6" 1709 + source = "registry+https://github.com/rust-lang/crates.io-index" 1710 + checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1711 + 1712 + [[package]] 1713 + name = "windows_i686_msvc" 1714 + version = "0.53.1" 1715 + source = "registry+https://github.com/rust-lang/crates.io-index" 1716 + checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" 1717 + 1718 + [[package]] 1719 + name = "windows_x86_64_gnu" 1720 + version = "0.52.6" 1721 + source = "registry+https://github.com/rust-lang/crates.io-index" 1722 + checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1723 + 1724 + [[package]] 1725 + name = "windows_x86_64_gnu" 1726 + version = "0.53.1" 1727 + source = "registry+https://github.com/rust-lang/crates.io-index" 1728 + checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" 1729 + 1730 + [[package]] 1731 + name = "windows_x86_64_gnullvm" 1732 + version = "0.52.6" 1733 + source = "registry+https://github.com/rust-lang/crates.io-index" 1734 + checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1735 + 1736 + [[package]] 1737 + name = "windows_x86_64_gnullvm" 1738 + version = "0.53.1" 1739 + source = "registry+https://github.com/rust-lang/crates.io-index" 1740 + checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" 1741 + 1742 + [[package]] 1743 + name = "windows_x86_64_msvc" 1744 + version = "0.52.6" 1745 + source = "registry+https://github.com/rust-lang/crates.io-index" 1746 + checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1747 + 1748 + [[package]] 1749 + name = "windows_x86_64_msvc" 1750 + version = "0.53.1" 1751 + source = "registry+https://github.com/rust-lang/crates.io-index" 1752 + checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" 1753 + 1754 + [[package]] 1755 + name = "wit-bindgen" 1756 + version = "0.57.1" 1757 + source = "registry+https://github.com/rust-lang/crates.io-index" 1758 + checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" 1759 + 1760 + [[package]] 1761 + name = "writeable" 1762 + version = "0.6.3" 1763 + source = "registry+https://github.com/rust-lang/crates.io-index" 1764 + checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" 1765 + 1766 + [[package]] 1767 + name = "yoke" 1768 + version = "0.8.3" 1769 + source = "registry+https://github.com/rust-lang/crates.io-index" 1770 + checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" 1771 + dependencies = [ 1772 + "stable_deref_trait", 1773 + "yoke-derive", 1774 + "zerofrom", 1775 + ] 1776 + 1777 + [[package]] 1778 + name = "yoke-derive" 1779 + version = "0.8.2" 1780 + source = "registry+https://github.com/rust-lang/crates.io-index" 1781 + checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" 1782 + dependencies = [ 1783 + "proc-macro2", 1784 + "quote", 1785 + "syn", 1786 + "synstructure", 1787 + ] 1788 + 1789 + [[package]] 1790 + name = "zerocopy" 1791 + version = "0.8.52" 1792 + source = "registry+https://github.com/rust-lang/crates.io-index" 1793 + checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" 1794 + dependencies = [ 1795 + "zerocopy-derive", 1796 + ] 1797 + 1798 + [[package]] 1799 + name = "zerocopy-derive" 1800 + version = "0.8.52" 1801 + source = "registry+https://github.com/rust-lang/crates.io-index" 1802 + checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" 1803 + dependencies = [ 1804 + "proc-macro2", 1805 + "quote", 1806 + "syn", 1807 + ] 1808 + 1809 + [[package]] 1810 + name = "zerofrom" 1811 + version = "0.1.8" 1812 + source = "registry+https://github.com/rust-lang/crates.io-index" 1813 + checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" 1814 + dependencies = [ 1815 + "zerofrom-derive", 1816 + ] 1817 + 1818 + [[package]] 1819 + name = "zerofrom-derive" 1820 + version = "0.1.7" 1821 + source = "registry+https://github.com/rust-lang/crates.io-index" 1822 + checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" 1823 + dependencies = [ 1824 + "proc-macro2", 1825 + "quote", 1826 + "syn", 1827 + "synstructure", 1828 + ] 1829 + 1830 + [[package]] 1831 + name = "zeroize" 1832 + version = "1.9.0" 1833 + source = "registry+https://github.com/rust-lang/crates.io-index" 1834 + checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" 1835 + 1836 + [[package]] 1837 + name = "zerotrie" 1838 + version = "0.2.4" 1839 + source = "registry+https://github.com/rust-lang/crates.io-index" 1840 + checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" 1841 + dependencies = [ 1842 + "displaydoc", 1843 + "yoke", 1844 + "zerofrom", 1845 + ] 1846 + 1847 + [[package]] 1848 + name = "zerovec" 1849 + version = "0.11.6" 1850 + source = "registry+https://github.com/rust-lang/crates.io-index" 1851 + checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" 1852 + dependencies = [ 1853 + "yoke", 1854 + "zerofrom", 1855 + "zerovec-derive", 1856 + ] 1857 + 1858 + [[package]] 1859 + name = "zerovec-derive" 1860 + version = "0.11.3" 1861 + source = "registry+https://github.com/rust-lang/crates.io-index" 1862 + checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" 1863 + dependencies = [ 1864 + "proc-macro2", 1865 + "quote", 1866 + "syn", 1867 + ] 1868 + 1869 + [[package]] 1870 + name = "zmij" 1871 + version = "1.0.21" 1872 + source = "registry+https://github.com/rust-lang/crates.io-index" 1873 + checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
+4 -1
Cargo.toml
··· 22 22 crate-type = ["cdylib", "rlib"] 23 23 24 24 [dependencies] 25 - fastnum = "0.7" 25 + fastnum = { version = "0.7", features = ["serde"] } 26 26 unicode-segmentation = "1.13" 27 27 web-time = "1.1.0" 28 + reqwest = { version = "0.13", features = ["blocking", "json"] } 29 + serde = { version = "1.0", features = ["derive"] } 30 + serde_json = "1.0" 28 31 29 32 [target.'cfg(target_arch = "wasm32")'.dependencies] 30 33 console_error_panic_hook = "0.1.7"
+1 -4
README.md
··· 52 52 ## Supported unit types 53 53 - Normal numbers 54 54 - Area 55 + - Currency 55 56 - Digital storage (bytes etc) 56 57 - Electric current 57 58 - Energy ··· 166 167 - Fractional numbers (to make 1/3*2*3 accurate) 167 168 - E notation, like 2E+10 168 169 - Unit types 169 - - Currency: How to go about dynamically updating the weights? 170 - - https://api.exchangerate-api.com/v4/latest/USD 171 - - https://www.coingecko.com/en/api 172 - - https://developers.coinbase.com/api/v2 173 170 - Timezones 174 171 - Binary/octal/decimal/hexadecimal/base32/base64 175 172 - Fuel consumption
+299
src/currency.rs
··· 1 + //! Currency exchange rate fetching and management 2 + 3 + use crate::units::Unit; 4 + use fastnum::D128; 5 + use fastnum::decimal::Context; 6 + use serde::Deserialize; 7 + use std::collections::HashMap; 8 + use std::sync::RwLock; 9 + 10 + #[cfg(target_arch = "wasm32")] 11 + use wasm_bindgen::prelude::*; 12 + 13 + /// Global cache for currency exchange rates relative to EUR 14 + /// Maps currency Unit to its rate relative to EUR 15 + static CURRENCY_CACHE: RwLock<Option<HashMap<Unit, D128>>> = RwLock::new(None); 16 + 17 + /// The base currency for all exchange rates (EUR) 18 + pub const BASE_CURRENCY: Unit = Unit::EUR; 19 + 20 + #[derive(Deserialize, Debug)] 21 + pub struct CurrencyRate { 22 + #[allow(dead_code)] 23 + pub date: String, 24 + pub base: String, 25 + pub quote: String, 26 + pub rate: serde_json::Number, 27 + } 28 + 29 + pub fn set_currency_cache(rates: Vec<CurrencyRate>) -> Result<(), String> { 30 + let mut cache = HashMap::with_capacity(rates.len() + 1); 31 + 32 + // Add EUR as base 33 + cache.insert(BASE_CURRENCY, D128::from(1)); 34 + 35 + for entry in rates { 36 + if entry.base != "EUR" { 37 + return Err("Exchange rate base currency must be EUR".to_string()); 38 + } 39 + if let Ok(quote_unit) = currency_code_to_unit(&entry.quote.to_ascii_lowercase()) { 40 + let rate_str = entry.rate.to_string(); 41 + let rate = D128::parse_str(&rate_str, Context::default()); 42 + cache.insert(quote_unit, rate); 43 + } 44 + } 45 + 46 + *CURRENCY_CACHE.write().unwrap() = Some(cache); 47 + Ok(()) 48 + } 49 + 50 + #[cfg(not(target_arch = "wasm32"))] 51 + pub fn initialize_currency_cache() -> Result<(), String> { 52 + if CURRENCY_CACHE.read().unwrap().is_some() { 53 + return Ok(()); // Already initialized 54 + } 55 + 56 + let rates = fetch_currency_rates()?; 57 + set_currency_cache(rates)?; 58 + Ok(()) 59 + } 60 + 61 + /// Limit the sig figs (precision) of the number 62 + fn round_to_sig_figs(x: D128, sig_figs: i32) -> D128 { 63 + if x.is_zero() { 64 + return x; 65 + } 66 + let mag: i32 = x.log10().floor().try_into().unwrap(); 67 + let shift = sig_figs - 1 - mag; 68 + let factor = D128::TEN.powi(shift); 69 + (x * factor).round(0) / factor 70 + } 71 + 72 + /// Get the exchange rate from one currency to another 73 + /// Both currencies must be currency units 74 + pub fn get_exchange_rate(from: Unit, to: Unit) -> Result<D128, String> { 75 + if from == to { 76 + return Ok(D128::from(1)); 77 + } 78 + 79 + // Ensure cache is initialized 80 + #[cfg(not(target_arch = "wasm32"))] 81 + initialize_currency_cache()?; 82 + 83 + let cache = CURRENCY_CACHE.read().unwrap(); 84 + let cache = cache.as_ref().unwrap(); 85 + 86 + // Get rates relative to EUR 87 + let from_rate = cache 88 + .get(&from) 89 + .ok_or_else(|| format!("No exchange rate found for {:?}", from))?; 90 + let to_rate = cache 91 + .get(&to) 92 + .ok_or_else(|| format!("No exchange rate found for {:?}", to))?; 93 + 94 + let rate = *to_rate / *from_rate; 95 + let rounded_rate = round_to_sig_figs(rate, 6); 96 + Ok(rounded_rate) 97 + } 98 + 99 + /// Fetch currency rates from the Frankfurter API (native version) 100 + #[cfg(not(target_arch = "wasm32"))] 101 + fn fetch_currency_rates() -> Result<Vec<CurrencyRate>, String> { 102 + use reqwest::blocking::get; 103 + 104 + let url = "https://api.frankfurter.dev/v2/rates?base=EUR"; 105 + let response = get(url).map_err(|e| format!("Failed to fetch currency rates: {}", e))?; 106 + 107 + let rates: Vec<CurrencyRate> = response 108 + .json() 109 + .map_err(|e| format!("Failed to parse currency rates: {:?}", e))?; 110 + 111 + Ok(rates) 112 + } 113 + 114 + /// Convert currency code to Unit enum 115 + pub fn currency_code_to_unit(code: &str) -> Result<Unit, String> { 116 + let unit = match code { 117 + "afn" => Unit::AFN, 118 + "all" => Unit::ALL, 119 + "amd" => Unit::AMD, 120 + "ang" => Unit::ANG, 121 + "aoa" => Unit::AOA, 122 + "ars" => Unit::ARS, 123 + "aud" => Unit::AUD, 124 + "awg" => Unit::AWG, 125 + "azn" => Unit::AZN, 126 + "bam" => Unit::BAM, 127 + "bbd" => Unit::BBD, 128 + "bdt" => Unit::BDT, 129 + "bhd" => Unit::BHD, 130 + "bif" => Unit::BIF, 131 + "bmd" => Unit::BMD, 132 + "bnd" => Unit::BND, 133 + "bob" => Unit::BOB, 134 + "brl" => Unit::BRL, 135 + "bsd" => Unit::BSD, 136 + "btn" => Unit::BTN, 137 + "bwp" => Unit::BWP, 138 + "byn" => Unit::BYN, 139 + "bzd" => Unit::BZD, 140 + "cad" => Unit::CAD, 141 + "cdf" => Unit::CDF, 142 + "chf" => Unit::CHF, 143 + "clp" => Unit::CLP, 144 + "cnh" => Unit::CNH, 145 + "cny" => Unit::CNY, 146 + "cop" => Unit::COP, 147 + "crc" => Unit::CRC, 148 + "cup" => Unit::CUP, 149 + "cve" => Unit::CVE, 150 + "czk" => Unit::CZK, 151 + "djf" => Unit::DJF, 152 + "dkk" => Unit::DKK, 153 + "dop" => Unit::DOP, 154 + "dzd" => Unit::DZD, 155 + "egp" => Unit::EGP, 156 + "ern" => Unit::ERN, 157 + "etb" => Unit::ETB, 158 + "eur" => Unit::EUR, 159 + "fjd" => Unit::FJD, 160 + "fkp" => Unit::FKP, 161 + "gbp" => Unit::GBP, 162 + "gel" => Unit::GEL, 163 + "ggp" => Unit::GGP, 164 + "ghs" => Unit::GHS, 165 + "gip" => Unit::GIP, 166 + "gmd" => Unit::GMD, 167 + "gnf" => Unit::GNF, 168 + "gtq" => Unit::GTQ, 169 + "gyd" => Unit::GYD, 170 + "hkd" => Unit::HKD, 171 + "hnl" => Unit::HNL, 172 + "htg" => Unit::HTG, 173 + "huf" => Unit::HUF, 174 + "idr" => Unit::IDR, 175 + "ils" => Unit::ILS, 176 + "imp" => Unit::IMP, 177 + "inr" => Unit::INR, 178 + "iqd" => Unit::IQD, 179 + "irr" => Unit::IRR, 180 + "isk" => Unit::ISK, 181 + "jep" => Unit::JEP, 182 + "jmd" => Unit::JMD, 183 + "jod" => Unit::JOD, 184 + "jpy" => Unit::JPY, 185 + "kes" => Unit::KES, 186 + "kgs" => Unit::KGS, 187 + "khr" => Unit::KHR, 188 + "kmf" => Unit::KMF, 189 + "kpw" => Unit::KPW, 190 + "krw" => Unit::KRW, 191 + "kwd" => Unit::KWD, 192 + "kyd" => Unit::KYD, 193 + "kzt" => Unit::KZT, 194 + "lak" => Unit::LAK, 195 + "lbp" => Unit::LBP, 196 + "lkr" => Unit::LKR, 197 + "lrd" => Unit::LRD, 198 + "lsl" => Unit::LSL, 199 + "lyd" => Unit::LYD, 200 + "mad" => Unit::MAD, 201 + "mdl" => Unit::MDL, 202 + "mga" => Unit::MGA, 203 + "mkd" => Unit::MKD, 204 + "mmk" => Unit::MMK, 205 + "mnt" => Unit::MNT, 206 + "mop" => Unit::MOP, 207 + "mro" => Unit::MRO, 208 + "mru" => Unit::MRU, 209 + "mur" => Unit::MUR, 210 + "mvr" => Unit::MVR, 211 + "mwk" => Unit::MWK, 212 + "mxn" => Unit::MXN, 213 + "myr" => Unit::MYR, 214 + "mzn" => Unit::MZN, 215 + "nad" => Unit::NAD, 216 + "ngn" => Unit::NGN, 217 + "nio" => Unit::NIO, 218 + "nok" => Unit::NOK, 219 + "npr" => Unit::NPR, 220 + "nzd" => Unit::NZD, 221 + "omr" => Unit::OMR, 222 + "pab" => Unit::PAB, 223 + "pen" => Unit::PEN, 224 + "pgk" => Unit::PGK, 225 + "php" => Unit::PHP, 226 + "pkr" => Unit::PKR, 227 + "pln" => Unit::PLN, 228 + "pyg" => Unit::PYG, 229 + "qar" => Unit::QAR, 230 + "ron" => Unit::RON, 231 + "rsd" => Unit::RSD, 232 + "rub" => Unit::RUB, 233 + "rwf" => Unit::RWF, 234 + "sar" => Unit::SAR, 235 + "sbd" => Unit::SBD, 236 + "scr" => Unit::SCR, 237 + "sdg" => Unit::SDG, 238 + "sek" => Unit::SEK, 239 + "sgd" => Unit::SGD, 240 + "shp" => Unit::SHP, 241 + "sle" => Unit::SLE, 242 + "sos" => Unit::SOS, 243 + "srd" => Unit::SRD, 244 + "ssp" => Unit::SSP, 245 + "stn" => Unit::STN, 246 + "svc" => Unit::SVC, 247 + "syp" => Unit::SYP, 248 + "szl" => Unit::SZL, 249 + "thb" => Unit::THB, 250 + "tjs" => Unit::TJS, 251 + "tmt" => Unit::TMT, 252 + "tnd" => Unit::TND, 253 + "top" => Unit::TOP, 254 + "try" => Unit::TRY, 255 + "ttd" => Unit::TTD, 256 + "twd" => Unit::TWD, 257 + "tzs" => Unit::TZS, 258 + "uah" => Unit::UAH, 259 + "ugx" => Unit::UGX, 260 + "usd" => Unit::USD, 261 + "uyu" => Unit::UYU, 262 + "uzs" => Unit::UZS, 263 + "ves" => Unit::VES, 264 + "vnd" => Unit::VND, 265 + "vuv" => Unit::VUV, 266 + "wst" => Unit::WST, 267 + "xaf" => Unit::XAF, 268 + "xag" => Unit::XAG, 269 + "xau" => Unit::XAU, 270 + "xcd" => Unit::XCD, 271 + "xcg" => Unit::XCG, 272 + "xdr" => Unit::XDR, 273 + "xof" => Unit::XOF, 274 + "xpd" => Unit::XPD, 275 + "xpf" => Unit::XPF, 276 + "xpt" => Unit::XPT, 277 + "yer" => Unit::YER, 278 + "zar" => Unit::ZAR, 279 + "zmw" => Unit::ZMW, 280 + "zwg" => Unit::ZWG, 281 + _ => return Err(format!("Unsupported currency code: {}", code)), 282 + }; 283 + Ok(unit) 284 + } 285 + 286 + /// Initialize the currency cache with JSON from the API (for WASM use) 287 + /// The web app should fetch from https://api.frankfurter.dev/v2/rates?base=EUR 288 + /// and pass the JSON response (an array of {base, quote, rate} objects) to this function 289 + #[cfg(target_arch = "wasm32")] 290 + #[wasm_bindgen] 291 + pub fn init_currency_cache_with_json(rates_json: &str) -> Result<(), JsValue> { 292 + let rates: Vec<CurrencyRate> = serde_json::from_str(rates_json) 293 + .map_err(|e| JsValue::from_str(&format!("Failed to parse JSON: {}", e)))?; 294 + 295 + set_currency_cache(rates) 296 + .map_err(|e| JsValue::from_str(&format!("Failed to parse JSON: {}", e)))?; 297 + 298 + Ok(()) 299 + }
+103 -76
src/evaluator.rs
··· 315 315 316 316 #[cfg(test)] 317 317 mod tests { 318 - use super::*; 319 - use crate::{eval, units::Unit::*}; 318 + use std::str::FromStr; 320 319 321 - fn eval_default<'a>(input: &'a str) -> Number { 320 + use crate::eval; 321 + 322 + #[track_caller] 323 + fn eval_test(input: &str, expected: &str) { 322 324 let result = eval(input, true, false).unwrap(); 323 - result 325 + assert_eq!(result.to_string(), expected); 324 326 } 325 - fn eval_num<'a>(input: &'a str) -> String { 326 - let result = eval(input, true, false).unwrap(); 327 - assert!(result.is_unitless()); 328 327 329 - result.to_string() 328 + #[track_caller] 329 + fn results_eq(a: &str, b: &str) { 330 + let result_a = crate::eval(a, true, false).unwrap(); 331 + let result_b = crate::eval(b, true, false).unwrap(); 332 + assert_eq!(result_a, result_b, "{a} != {b}"); 333 + assert_eq!( 334 + result_a.value.op_signals(), 335 + result_b.value.op_signals(), 336 + "{a} != {b}", 337 + ); 330 338 } 331 339 332 340 #[test] 333 341 fn test_evaluations() { 334 - assert_eq!(eval_num("-2(-3)"), "6"); 335 - assert_eq!(eval_num("-2(3)"), "-6"); 336 - assert_eq!(eval_num("(3)-2"), "1"); 337 - assert_eq!( 338 - eval_default("-1km to m"), 339 - Number::with_basic_unit(d!(-1000), Meter) 340 - ); 341 - assert_eq!(eval_num("2*-3*0.5"), "-3"); 342 - assert_eq!(eval_num("-3^2"), "-9"); 343 - assert_eq!(eval_num("e^2"), "≈ 7.3890560989306502272304274605750078132"); 344 - assert_eq!( 345 - eval_num("e^2.5"), 346 - "≈ 12.1824939607034734380701759511679661832" 347 - ); 348 - assert_eq!(eval_num("-1+2"), "1"); 342 + eval_test("-2(-3)", "6"); 343 + eval_test("-2(3)", "-6"); 344 + eval_test("(3)-2", "1"); 345 + eval_test("-1km to m", "-1000 meters"); 346 + eval_test("2*-3*0.5", "-3"); 347 + eval_test("-3^2", "-9"); 348 + eval_test("e^2", "≈ 7.3890560989306502272304274605750078132"); 349 + eval_test("e^2.5", "≈ 12.1824939607034734380701759511679661832"); 350 + eval_test("-1+2", "1"); 349 351 } 350 352 351 353 #[test] 352 354 fn test_functions() { 353 - assert_eq!(eval_num("cbrt(125)"), "5"); 354 - assert_eq!( 355 - eval_num("cbrt(2)"), 356 - "≈ 1.25992104989487316476721060727822835057" 357 - ); 355 + eval_test("cbrt(125)", "5"); 356 + eval_test("cbrt(2)", "≈ 1.25992104989487316476721060727822835057"); 357 + 358 + eval_test("sqrt(25)", "5"); 359 + eval_test("sqrt(2)", "≈ 1.41421356237309504880168872420969807857"); 360 + 361 + eval_test("log(100)", "2"); 362 + eval_test("log(2)", "≈ 0.301029995663981195213738894724493026768"); 363 + 364 + eval_test("ln(1)", "0"); 365 + eval_test("ln(2)", "≈ 0.69314718055994530941723212145817656808"); 366 + eval_test("ln(e)", "≈ 1"); 367 + eval_test("ln(e^2)", "≈ 2"); 368 + 369 + eval_test("exp(1)", "≈ 2.71828182845904523536028747135266249776"); 358 370 359 - assert_eq!(eval_num("sqrt(25)"), "5"); 360 - assert_eq!( 361 - eval_num("sqrt(2)"), 362 - "≈ 1.41421356237309504880168872420969807857" 363 - ); 371 + eval_test("round(1.4)", "1"); 372 + eval_test("round(1.6)", "2"); 373 + eval_test("round(1.5)", "2"); 374 + eval_test("round(2.5)", "3"); 364 375 365 - assert_eq!(eval_num("log(100)"), "2"); 366 - assert_eq!( 367 - eval_num("log(2)"), 368 - "≈ 0.301029995663981195213738894724493026768" 369 - ); 376 + eval_test("ceil(1.5)", "2"); 377 + eval_test("ceil(-1.5)", "-1"); 370 378 371 - assert_eq!(eval_num("ln(1)"), "0"); 372 - assert_eq!( 373 - eval_num("ln(2)"), 374 - "≈ 0.69314718055994530941723212145817656808" 375 - ); 376 - assert_eq!(eval_num("ln(e)"), "≈ 1"); 377 - assert_eq!(eval_num("ln(e^2)"), "≈ 2"); 379 + eval_test("floor(1.5)", "1"); 380 + eval_test("floor(-1.5)", "-2"); 378 381 379 - assert_eq!( 380 - eval_num("exp(1)"), 381 - "≈ 2.71828182845904523536028747135266249776" 382 - ); 382 + eval_test("abs(-3)", "3"); 383 383 384 - assert_eq!(eval_num("round(1.4)"), "1"); 385 - assert_eq!(eval_num("round(1.6)"), "2"); 386 - assert_eq!(eval_num("round(1.5)"), "2"); 387 - assert_eq!(eval_num("round(2.5)"), "3"); 384 + eval_test("sin(2)", "≈ 0.9092974268256816953960198659117448427"); 385 + eval_test("sin(-2)", "≈ -0.9092974268256816953960198659117448427"); 388 386 389 - assert_eq!(eval_num("ceil(1.5)"), "2"); 390 - assert_eq!(eval_num("ceil(-1.5)"), "-1"); 387 + eval_test("cos(2)", "≈ -0.41614683654714238699756822950076218977"); 388 + eval_test("cos(-2)", "≈ -0.41614683654714238699756822950076218977"); 389 + eval_test("tan(2)", "≈ -2.18503986326151899164330610231368254343"); 390 + } 391 391 392 - assert_eq!(eval_num("floor(1.5)"), "1"); 393 - assert_eq!(eval_num("floor(-1.5)"), "-2"); 392 + #[test] 393 + fn test_currency() { 394 + use crate::currency::{CurrencyRate, set_currency_cache}; 395 + use serde_json::Number; 394 396 395 - assert_eq!(eval_num("abs(-3)"), "3"); 397 + set_currency_cache(vec![CurrencyRate { 398 + date: "2000-01-01".to_string(), 399 + base: "EUR".to_string(), 400 + quote: "NOK".to_string(), 401 + rate: Number::from_str("11.2839").unwrap(), 402 + }]) 403 + .unwrap(); 396 404 397 - assert_eq!( 398 - eval_num("sin(2)"), 399 - "≈ 0.9092974268256816953960198659117448427" 405 + eval_test("1 EUR to NOK", "11.2839 NOK"); 406 + eval_test("11.2839 NOK to EUR", "≈ 0.99999952902 EUR"); 407 + eval_test("1 NOK to EUR", "≈ 0.0886218 EUR"); 408 + eval_test("1 EUR/liter to NOK/liter", "11.2839 NOK / liter"); 409 + eval_test( 410 + "1 EUR/gallon to NOK/liter", 411 + "≈ 2.98089102160411090430525272544562882356 NOK / liter", 400 412 ); 401 - assert_eq!( 402 - eval_num("sin(-2)"), 403 - "≈ -0.9092974268256816953960198659117448427" 404 - ); 413 + } 405 414 406 - assert_eq!( 407 - eval_num("cos(2)"), 408 - "≈ -0.41614683654714238699756822950076218977" 409 - ); 410 - assert_eq!( 411 - eval_num("cos(-2)"), 412 - "≈ -0.41614683654714238699756822950076218977" 413 - ); 414 - assert_eq!( 415 - eval_num("tan(2)"), 416 - "≈ -2.18503986326151899164330610231368254343" 415 + #[test] 416 + fn test_unit_evals() { 417 + results_eq("100kg*sqm / 2s^2", "50j"); 418 + results_eq("3.6km/1h", "3.6 kph"); 419 + results_eq("0.3048 m/s to ft/s", "1 ft/s"); 420 + eval_test("1.609344 km/1h to mph", "≈ 1 mile per hour"); 421 + eval_test("1.852 kph to knots", "≈ 1 knot"); 422 + results_eq("120 seconds to minutes", "2 minutes"); 423 + results_eq("100 cm to m", "1 m"); 424 + results_eq("1 km2 to m2", "1000000 m2"); 425 + results_eq("1 liter to ml", "1000 ml"); 426 + results_eq("1 kg to g", "1000 g"); 427 + results_eq("1 KB to bytes", "1000 bytes"); 428 + results_eq("1 MBps to KBps", "1000 KBps"); 429 + results_eq("1 KFLOP to FLOP", "1000 FLOP"); 430 + results_eq("1 KFLOPs to FLOPs", "1000 FLOPs"); 431 + results_eq("1 kWh to Wh", "1000 Wh"); 432 + results_eq("1 kW to W", "1000 W"); 433 + results_eq("1000 mA to A", "1 A"); 434 + results_eq("1000 mΩ to Ω", "1 Ω"); 435 + results_eq("1000 mV to V", "1 V"); 436 + results_eq("1 bar to Pa", "100000 Pa"); 437 + results_eq("1 kHz to Hz", "1000 Hz"); 438 + eval_test( 439 + "1 km/h to m/s", 440 + "≈ 0.277777777777777777777777777777777777778 meters / second", 417 441 ); 442 + results_eq("0 C to K", "273.15 K"); 443 + results_eq("8 megabytes per second * 1 minute", "480mb"); 444 + results_eq("8 megaFLOP per second * 1 minute", "480megaFLOP"); 418 445 } 419 446 }
+23
src/lexer.rs
··· 6 6 use crate::TextOperator::*; 7 7 use crate::Token; 8 8 use crate::UnaryOperator::*; 9 + use crate::currency::currency_code_to_unit; 9 10 use crate::units::Unit::*; 10 11 use fastnum::D128; 11 12 use fastnum::decimal::Context; ··· 636 637 "c" | "celsius" => Token::unit(Celsius), 637 638 "f" | "fahrenheit" | "fahrenheits" => Token::unit(Fahrenheit), 638 639 640 + "AU$" => Token::unit(AUD), 641 + "R$" => Token::unit(BRL), 642 + "CA$" | "C$" => Token::unit(CAD), 643 + "€" | "euro" | "euros" => Token::unit(EUR), 644 + "£" => Token::unit(GBP), 645 + "HK$" => Token::unit(HKD), 646 + "₹" | "Rs" => Token::unit(INR), 647 + "₪" => Token::unit(ILS), 648 + "¥" => Token::unit(JPY), 649 + "₩" => Token::unit(KRW), 650 + "MX$" => Token::unit(MXN), 651 + "NZ$" => Token::unit(NZD), 652 + "₱" => Token::unit(PHP), 653 + "zl" | "zł" => Token::unit(PLN), 654 + "S$" => Token::unit(SGD), 655 + "฿" => Token::unit(THB), 656 + "tl" | "₺" => Token::unit(TRY), 657 + "₴" => Token::unit(UAH), 658 + "$" | "US$" => Token::unit(USD), 659 + "₫" => Token::unit(VND), 660 + 661 + string if let Ok(unit) = currency_code_to_unit(string) => Token::unit(unit), 639 662 string => { 640 663 return Err(format!("Invalid string: {}", string)); 641 664 }
+4 -2
src/lib.rs
··· 27 27 use std::fmt::{self, Debug, Display}; 28 28 use web_time::Instant; 29 29 30 + /// Currency exchange rates 31 + pub mod currency; 30 32 /// Turns an [`AstNode`](parser::AstNode) into a [`Number`] 31 33 pub mod evaluator; 32 34 /// Turns a string into [`Token`]s ··· 82 84 pub fn primitive_unit(&self) -> Vec<(Unit, isize)> { 83 85 primitive_unit(&self.unit) 84 86 } 85 - pub fn contains_primitive(&self, unit: UnitType) -> bool { 86 - self.unit.iter().any(|(u, _)| u.category() == unit) 87 + pub fn contains_category(&self, category: UnitType) -> bool { 88 + self.unit.iter().any(|(u, _)| u.category() == category) 87 89 } 88 90 fn get_unit_string(&self, plural: bool) -> String { 89 91 let mut s = String::new();
+223 -53
src/units.rs
··· 1 1 use crate::Number; 2 + use crate::currency; 2 3 use fastnum::{D128, dec128 as d}; 3 4 use std::cmp::Reverse; 4 5 ··· 41 42 Speed, 42 43 /// A unit of temperature, for example [`Kelvin`] 43 44 Temperature, 45 + /// A unit of currency, for example [`EUR`] 46 + Currency, 44 47 } 45 48 impl UnitType { 46 49 fn primitive(&self) -> Vec<(Unit, isize)> { ··· 63 66 Frequency => vec![(Second, -1)], 64 67 Speed => vec![(Meter, 1), (Second, -1)], 65 68 Temperature => vec![(Kelvin, 1)], 69 + Currency => vec![(EUR, 1)], 66 70 }; 67 71 #[cfg(debug_assertions)] 68 72 { ··· 108 112 // and evaluator 109 113 macro_rules! create_units { 110 114 ( $( $variant:ident : $properties:expr ),*, ) => { 111 - #[derive(Clone, Copy, PartialEq, Debug, Eq, PartialOrd, Ord)] 115 + #[derive(Clone, Copy, PartialEq, Debug, Eq, PartialOrd, Ord, Hash)] 112 116 /// A Unit enum. Note that it can also be [`NoUnit`]. 113 117 pub enum Unit { 114 118 $($variant),* ··· 395 399 Kelvin: (Temperature, d!(0), "kelvin", "kelvin"), 396 400 Celsius: (Temperature, d!(0), "celsius", "celsius"), 397 401 Fahrenheit: (Temperature, d!(0), "fahrenheit", "fahrenheit"), 402 + 403 + // Currency weights are fetched on-demand 404 + AFN: (Currency, d!(0), "AFN", "AFN"), 405 + ALL: (Currency, d!(0), "ALL", "ALL"), 406 + AMD: (Currency, d!(0), "AMD", "AMD"), 407 + ANG: (Currency, d!(0), "ANG", "ANG"), 408 + AOA: (Currency, d!(0), "AOA", "AOA"), 409 + ARS: (Currency, d!(0), "ARS", "ARS"), 410 + AUD: (Currency, d!(0), "AUD", "AUD"), 411 + AWG: (Currency, d!(0), "AWG", "AWG"), 412 + AZN: (Currency, d!(0), "AZN", "AZN"), 413 + BAM: (Currency, d!(0), "BAM", "BAM"), 414 + BBD: (Currency, d!(0), "BBD", "BBD"), 415 + BDT: (Currency, d!(0), "BDT", "BDT"), 416 + BHD: (Currency, d!(0), "BHD", "BHD"), 417 + BIF: (Currency, d!(0), "BIF", "BIF"), 418 + BMD: (Currency, d!(0), "BMD", "BMD"), 419 + BND: (Currency, d!(0), "BND", "BND"), 420 + BOB: (Currency, d!(0), "BOB", "BOB"), 421 + BRL: (Currency, d!(0), "BRL", "BRL"), 422 + BSD: (Currency, d!(0), "BSD", "BSD"), 423 + BTN: (Currency, d!(0), "BTN", "BTN"), 424 + BWP: (Currency, d!(0), "BWP", "BWP"), 425 + BYN: (Currency, d!(0), "BYN", "BYN"), 426 + BZD: (Currency, d!(0), "BZD", "BZD"), 427 + CAD: (Currency, d!(0), "CAD", "CAD"), 428 + CDF: (Currency, d!(0), "CDF", "CDF"), 429 + CHF: (Currency, d!(0), "CHF", "CHF"), 430 + CLP: (Currency, d!(0), "CLP", "CLP"), 431 + CNH: (Currency, d!(0), "CNH", "CNH"), 432 + CNY: (Currency, d!(0), "CNY", "CNY"), 433 + COP: (Currency, d!(0), "COP", "COP"), 434 + CRC: (Currency, d!(0), "CRC", "CRC"), 435 + CUP: (Currency, d!(0), "CUP", "CUP"), 436 + CVE: (Currency, d!(0), "CVE", "CVE"), 437 + CZK: (Currency, d!(0), "CZK", "CZK"), 438 + DJF: (Currency, d!(0), "DJF", "DJF"), 439 + DKK: (Currency, d!(0), "DKK", "DKK"), 440 + DOP: (Currency, d!(0), "DOP", "DOP"), 441 + DZD: (Currency, d!(0), "DZD", "DZD"), 442 + EGP: (Currency, d!(0), "EGP", "EGP"), 443 + ERN: (Currency, d!(0), "ERN", "ERN"), 444 + ETB: (Currency, d!(0), "ETB", "ETB"), 445 + EUR: (Currency, d!(0), "EUR", "EUR"), 446 + FJD: (Currency, d!(0), "FJD", "FJD"), 447 + FKP: (Currency, d!(0), "FKP", "FKP"), 448 + GBP: (Currency, d!(0), "GBP", "GBP"), 449 + GEL: (Currency, d!(0), "GEL", "GEL"), 450 + GGP: (Currency, d!(0), "GGP", "GGP"), 451 + GHS: (Currency, d!(0), "GHS", "GHS"), 452 + GIP: (Currency, d!(0), "GIP", "GIP"), 453 + GMD: (Currency, d!(0), "GMD", "GMD"), 454 + GNF: (Currency, d!(0), "GNF", "GNF"), 455 + GTQ: (Currency, d!(0), "GTQ", "GTQ"), 456 + GYD: (Currency, d!(0), "GYD", "GYD"), 457 + HKD: (Currency, d!(0), "HKD", "HKD"), 458 + HNL: (Currency, d!(0), "HNL", "HNL"), 459 + HTG: (Currency, d!(0), "HTG", "HTG"), 460 + HUF: (Currency, d!(0), "HUF", "HUF"), 461 + IDR: (Currency, d!(0), "IDR", "IDR"), 462 + ILS: (Currency, d!(0), "ILS", "ILS"), 463 + IMP: (Currency, d!(0), "IMP", "IMP"), 464 + INR: (Currency, d!(0), "INR", "INR"), 465 + IQD: (Currency, d!(0), "IQD", "IQD"), 466 + IRR: (Currency, d!(0), "IRR", "IRR"), 467 + ISK: (Currency, d!(0), "ISK", "ISK"), 468 + JEP: (Currency, d!(0), "JEP", "JEP"), 469 + JMD: (Currency, d!(0), "JMD", "JMD"), 470 + JOD: (Currency, d!(0), "JOD", "JOD"), 471 + JPY: (Currency, d!(0), "JPY", "JPY"), 472 + KES: (Currency, d!(0), "KES", "KES"), 473 + KGS: (Currency, d!(0), "KGS", "KGS"), 474 + KHR: (Currency, d!(0), "KHR", "KHR"), 475 + KMF: (Currency, d!(0), "KMF", "KMF"), 476 + KPW: (Currency, d!(0), "KPW", "KPW"), 477 + KRW: (Currency, d!(0), "KRW", "KRW"), 478 + KWD: (Currency, d!(0), "KWD", "KWD"), 479 + KYD: (Currency, d!(0), "KYD", "KYD"), 480 + KZT: (Currency, d!(0), "KZT", "KZT"), 481 + LAK: (Currency, d!(0), "LAK", "LAK"), 482 + LBP: (Currency, d!(0), "LBP", "LBP"), 483 + LKR: (Currency, d!(0), "LKR", "LKR"), 484 + LRD: (Currency, d!(0), "LRD", "LRD"), 485 + LSL: (Currency, d!(0), "LSL", "LSL"), 486 + LYD: (Currency, d!(0), "LYD", "LYD"), 487 + MAD: (Currency, d!(0), "MAD", "MAD"), 488 + MDL: (Currency, d!(0), "MDL", "MDL"), 489 + MGA: (Currency, d!(0), "MGA", "MGA"), 490 + MKD: (Currency, d!(0), "MKD", "MKD"), 491 + MMK: (Currency, d!(0), "MMK", "MMK"), 492 + MNT: (Currency, d!(0), "MNT", "MNT"), 493 + MOP: (Currency, d!(0), "MOP", "MOP"), 494 + MRO: (Currency, d!(0), "MRO", "MRO"), 495 + MRU: (Currency, d!(0), "MRU", "MRU"), 496 + MUR: (Currency, d!(0), "MUR", "MUR"), 497 + MVR: (Currency, d!(0), "MVR", "MVR"), 498 + MWK: (Currency, d!(0), "MWK", "MWK"), 499 + MXN: (Currency, d!(0), "MXN", "MXN"), 500 + MYR: (Currency, d!(0), "MYR", "MYR"), 501 + MZN: (Currency, d!(0), "MZN", "MZN"), 502 + NAD: (Currency, d!(0), "NAD", "NAD"), 503 + NGN: (Currency, d!(0), "NGN", "NGN"), 504 + NIO: (Currency, d!(0), "NIO", "NIO"), 505 + NOK: (Currency, d!(0), "NOK", "NOK"), 506 + NPR: (Currency, d!(0), "NPR", "NPR"), 507 + NZD: (Currency, d!(0), "NZD", "NZD"), 508 + OMR: (Currency, d!(0), "OMR", "OMR"), 509 + PAB: (Currency, d!(0), "PAB", "PAB"), 510 + PEN: (Currency, d!(0), "PEN", "PEN"), 511 + PGK: (Currency, d!(0), "PGK", "PGK"), 512 + PHP: (Currency, d!(0), "PHP", "PHP"), 513 + PKR: (Currency, d!(0), "PKR", "PKR"), 514 + PLN: (Currency, d!(0), "PLN", "PLN"), 515 + PYG: (Currency, d!(0), "PYG", "PYG"), 516 + QAR: (Currency, d!(0), "QAR", "QAR"), 517 + RON: (Currency, d!(0), "RON", "RON"), 518 + RSD: (Currency, d!(0), "RSD", "RSD"), 519 + RUB: (Currency, d!(0), "RUB", "RUB"), 520 + RWF: (Currency, d!(0), "RWF", "RWF"), 521 + SAR: (Currency, d!(0), "SAR", "SAR"), 522 + SBD: (Currency, d!(0), "SBD", "SBD"), 523 + SCR: (Currency, d!(0), "SCR", "SCR"), 524 + SDG: (Currency, d!(0), "SDG", "SDG"), 525 + SEK: (Currency, d!(0), "SEK", "SEK"), 526 + SGD: (Currency, d!(0), "SGD", "SGD"), 527 + SHP: (Currency, d!(0), "SHP", "SHP"), 528 + SLE: (Currency, d!(0), "SLE", "SLE"), 529 + SOS: (Currency, d!(0), "SOS", "SOS"), 530 + SRD: (Currency, d!(0), "SRD", "SRD"), 531 + SSP: (Currency, d!(0), "SSP", "SSP"), 532 + STN: (Currency, d!(0), "STN", "STN"), 533 + SVC: (Currency, d!(0), "SVC", "SVC"), 534 + SYP: (Currency, d!(0), "SYP", "SYP"), 535 + SZL: (Currency, d!(0), "SZL", "SZL"), 536 + THB: (Currency, d!(0), "THB", "THB"), 537 + TJS: (Currency, d!(0), "TJS", "TJS"), 538 + TMT: (Currency, d!(0), "TMT", "TMT"), 539 + TND: (Currency, d!(0), "TND", "TND"), 540 + TOP: (Currency, d!(0), "TOP", "TOP"), 541 + TRY: (Currency, d!(0), "TRY", "TRY"), 542 + TTD: (Currency, d!(0), "TTD", "TTD"), 543 + TWD: (Currency, d!(0), "TWD", "TWD"), 544 + TZS: (Currency, d!(0), "TZS", "TZS"), 545 + UAH: (Currency, d!(0), "UAH", "UAH"), 546 + UGX: (Currency, d!(0), "UGX", "UGX"), 547 + USD: (Currency, d!(0), "USD", "USD"), 548 + UYU: (Currency, d!(0), "UYU", "UYU"), 549 + UZS: (Currency, d!(0), "UZS", "UZS"), 550 + VES: (Currency, d!(0), "VES", "VES"), 551 + VND: (Currency, d!(0), "VND", "VND"), 552 + VUV: (Currency, d!(0), "VUV", "VUV"), 553 + WST: (Currency, d!(0), "WST", "WST"), 554 + XAF: (Currency, d!(0), "XAF", "XAF"), 555 + XAG: (Currency, d!(0), "XAG", "XAG"), 556 + XAU: (Currency, d!(0), "XAU", "XAU"), 557 + XCD: (Currency, d!(0), "XCD", "XCD"), 558 + XCG: (Currency, d!(0), "XCG", "XCG"), 559 + XDR: (Currency, d!(0), "XDR", "XDR"), 560 + XOF: (Currency, d!(0), "XOF", "XOF"), 561 + XPD: (Currency, d!(0), "XPD", "XPD"), 562 + XPF: (Currency, d!(0), "XPF", "XPF"), 563 + XPT: (Currency, d!(0), "XPT", "XPT"), 564 + YER: (Currency, d!(0), "YER", "YER"), 565 + ZAR: (Currency, d!(0), "ZAR", "ZAR"), 566 + ZMW: (Currency, d!(0), "ZMW", "ZMW"), 567 + ZWG: (Currency, d!(0), "ZWG", "ZWG"), 398 568 ); 399 569 400 570 fn combined_weight(unit: &[(Unit, isize)]) -> D128 { ··· 412 582 } 413 583 } 414 584 585 + fn contains_category(unit: &[(Unit, isize)], category: UnitType) -> bool { 586 + unit.iter().any(|(u, _)| u.category() == category) 587 + } 588 + 589 + /// Get the non-currency weight of a unit vector 590 + fn non_currency_weight(unit: &[(Unit, isize)]) -> D128 { 591 + use UnitType::*; 592 + unit.iter().fold(D128::from(1), |acc, (u, exp)| { 593 + if u.category() == Currency { 594 + acc 595 + } else { 596 + acc * integer_power(u.weight(), *exp) 597 + } 598 + }) 599 + } 600 + 415 601 /// Convert a [`Number`] to a specified [`Unit`]. 416 602 pub fn convert(number: Number, to_unit: Vec<(Unit, isize)>) -> Result<Number, String> { 417 603 if number.primitive_unit() != primitive_unit(&to_unit) { ··· 451 637 Number::with_unit(d!(0), to_unit).plural() 452 638 )), 453 639 } 640 + } else if number.contains_category(Currency) && contains_category(&to_unit, Currency) { 641 + // Handle compound units with currency, like "EUR/liter" 642 + // Find the currency in both units 643 + let from_currency = number 644 + .unit 645 + .iter() 646 + .find(|(u, _)| u.category() == Currency) 647 + .map(|(u, _)| *u); 648 + let to_currency = to_unit 649 + .iter() 650 + .find(|(u, _)| u.category() == Currency) 651 + .map(|(u, _)| *u); 652 + 653 + if let (Some(from_curr), Some(to_curr)) = (from_currency, to_currency) { 654 + let rate = currency::get_exchange_rate(from_curr, to_curr)?; 655 + 656 + // Calculate the ratio of non-currency parts 657 + let source_non_currency = non_currency_weight(&number.unit); 658 + let target_non_currency = non_currency_weight(&to_unit); 659 + 660 + let value = number.value * rate * source_non_currency / target_non_currency; 661 + 662 + Ok(Number { 663 + value, 664 + unit: to_unit.to_vec(), 665 + }) 666 + } else { 667 + Err("Currency conversion requires both units to have currency".to_string()) 668 + } 454 669 } else { 455 670 let source_weight = combined_weight(&number.unit); 456 671 let target_weight = combined_weight(&to_unit); ··· 482 697 if left.unit == right.unit { 483 698 Ok(Number::with_unit(left.value + right.value, left.unit)) 484 699 } else if left.primitive_unit() == right.primitive_unit() 485 - && !left.contains_primitive(Temperature) 700 + && !left.contains_category(Temperature) 486 701 { 487 702 let (left, right) = convert_to_lowest(left, right)?; 488 703 Ok(Number::with_unit(left.value + right.value, left.unit)) ··· 496 711 if left.unit == right.unit { 497 712 Ok(Number::with_unit(left.value - right.value, left.unit)) 498 713 } else if left.primitive_unit() == right.primitive_unit() 499 - && !left.contains_primitive(Temperature) 714 + && !left.contains_category(Temperature) 500 715 { 501 716 let (left, right) = convert_to_lowest(left, right)?; 502 717 Ok(Number::with_unit(left.value - right.value, left.unit)) ··· 700 915 /// 701 916 /// Temperatures don't work 702 917 pub fn multiply(left: Number, right: Number) -> Result<Number, String> { 703 - if left.contains_primitive(Temperature) || right.contains_primitive(Temperature) { 918 + if left.contains_category(Temperature) || right.contains_category(Temperature) { 704 919 Err(format!("Cannot multiply {} and {}", left, right)) 705 920 } else { 706 921 multiply_any(left, right) ··· 726 941 /// 727 942 /// Temperatures don't work. 728 943 pub fn divide(left: Number, right: Number) -> Result<Number, String> { 729 - if left.contains_primitive(Temperature) || right.contains_primitive(Temperature) { 944 + if left.contains_category(Temperature) || right.contains_category(Temperature) { 730 945 Err(format!("Cannot divide {} by {}", left, right)) 731 946 } else { 732 947 divide_any(left, right) ··· 752 967 /// 753 968 /// Temperatures don't work. 754 969 pub fn modulo(left: Number, right: Number) -> Result<Number, String> { 755 - if left.contains_primitive(Temperature) || right.contains_primitive(Temperature) { 970 + if left.contains_category(Temperature) || right.contains_category(Temperature) { 756 971 Err(format!("Cannot modulo {} by {}", left, right)) 757 972 } else if left.primitive_unit() == right.primitive_unit() { 758 973 // 5 km % 3 m ··· 771 986 /// - etc. 772 987 pub fn pow(left: Number, right: Number) -> Result<Number, String> { 773 988 // I tried converting `right` to use powi, but somehow that was slower 774 - if left.contains_primitive(Temperature) || right.has_unit() { 989 + if left.contains_category(Temperature) || right.has_unit() { 775 990 Err(format!("Cannot raise {} to the power of {}", left, right)) 776 991 } else if left.is_unitless() { 777 992 let result = left.value.pow(right.value); ··· 799 1014 800 1015 #[cfg(test)] 801 1016 mod tests { 1017 + use super::*; 802 1018 use fastnum::decimal::Context; 803 - 804 - use super::*; 805 1019 806 1020 macro_rules! assert_float_eq { 807 1021 ( $actual:expr, $expected:literal ) => { ··· 1186 1400 assert_float_eq!(convert_test(-15.0, Celsius, Fahrenheit), 5.0); 1187 1401 assert_float_eq!(convert_test(80.33, Fahrenheit, Kelvin), 300.0); 1188 1402 assert_float_eq!(convert_test(5.0, Fahrenheit, Celsius), -15.0); 1189 - } 1190 - 1191 - #[track_caller] 1192 - fn eval_test(a: &str, b: &str) { 1193 - let result_a = crate::eval(a, true, false).unwrap(); 1194 - let result_b = crate::eval(b, true, false).unwrap(); 1195 - assert_eq!(result_a, result_b, "{a} != {b}"); 1196 - } 1197 - #[track_caller] 1198 - fn eval_approx_test(a: &str, b: &str) { 1199 - let result_a = crate::eval(a, true, false).unwrap(); 1200 - let result_b = crate::eval(b, true, false).unwrap(); 1201 - let diff_pct: D128 = result_a.value / result_b.value - 1; 1202 - let diff_pct = diff_pct.abs(); 1203 - assert!(diff_pct <= d!(0.00000001), "{a} !≈ {b}") 1204 - } 1205 - 1206 - #[test] 1207 - fn test_unit_evals() { 1208 - eval_test("100kg*sqm / 2s^2", "50j"); 1209 - eval_test("3.6km/1h", "3.6 kph"); 1210 - eval_test("0.3048 m/s to ft/s", "1 ft/s"); 1211 - eval_test("1.609344 km/1h to mph", "1 mph"); 1212 - eval_approx_test("1.852 kph to knots", "1 knots"); 1213 - eval_test("120 seconds to minutes", "2 minutes"); 1214 - eval_test("100 cm to m", "1 m"); 1215 - eval_test("1 km2 to m2", "1000000 m2"); 1216 - eval_test("1 liter to ml", "1000 ml"); 1217 - eval_test("1 kg to g", "1000 g"); 1218 - eval_test("1 KB to bytes", "1000 bytes"); 1219 - eval_test("1 MBps to KBps", "1000 KBps"); 1220 - eval_test("1 KFLOP to FLOP", "1000 FLOP"); 1221 - eval_test("1 KFLOPs to FLOPs", "1000 FLOPs"); 1222 - eval_test("1 kWh to Wh", "1000 Wh"); 1223 - eval_test("1 kW to W", "1000 W"); 1224 - eval_test("1000 mA to A", "1 A"); 1225 - eval_test("1000 mΩ to Ω", "1 Ω"); 1226 - eval_test("1000 mV to V", "1 V"); 1227 - eval_test("1 bar to Pa", "100000 Pa"); 1228 - eval_test("1 kHz to Hz", "1000 Hz"); 1229 - eval_approx_test("1 km/h to m/s", "0.27777777777777777777 m/s"); 1230 - eval_test("0 C to K", "273.15 K"); 1231 - eval_test("8 megabytes per second * 1 minute", "480mb"); 1232 - eval_test("8 megaFLOP per second * 1 minute", "480megaFLOP"); 1233 1403 } 1234 1404 }
+19 -4
web/src/routes/+page.svelte
··· 8 8 // https://github.com/sveltejs/svelte/issues/13155 9 9 const cpc_promise = import("cpc"); 10 10 let cpc: typeof import("cpc") | undefined; 11 - cpc_promise.then((mod) => { 11 + 12 + // Initialize currency cache when cpc module is loaded 13 + cpc_promise.then(async (mod) => { 12 14 cpc = mod; 15 + 16 + // Fetch exchange rates and initialize currency cache 17 + try { 18 + const response = await fetch("https://api.frankfurter.dev/v2/rates?base=EUR"); 19 + const ratesJson = await response.text(); 20 + if (typeof mod.init_currency_cache_with_json !== 'function') { 21 + output = 'Error: Missing currency init function' 22 + } 23 + mod.init_currency_cache_with_json(ratesJson); 24 + } catch (e) { 25 + console.error("Failed to fetch currency rates:", e); 26 + output = "Error: Failed to fetch currency rates:", e 27 + } 13 28 }); 14 29 15 - function wasm_eval(input: string) { 16 - if (!cpc || input.trim().length === 0) { 30 + function wasm_eval() { 31 + if (input === '' || !cpc || input.trim().length === 0) { 17 32 return ""; 18 33 } 19 34 try { ··· 24 39 } 25 40 26 41 let input = $state(""); 27 - let output = $derived(wasm_eval(input)); 42 + let output = $derived(wasm_eval()); 28 43 let calc_history = new PersistedState< 29 44 { id: number; in: string; out: string }[] 30 45 >("calc_history", []);