Rust wrapper for the ATProto tap utility

v0.2.0 - make things work well with jacquard schemas and validation

+5445 -622
+1669 -93
Cargo.lock
··· 3 3 version = 4 4 4 5 5 [[package]] 6 + name = "abnf" 7 + version = "0.13.0" 8 + source = "registry+https://github.com/rust-lang/crates.io-index" 9 + checksum = "087113bd50d9adce24850eed5d0476c7d199d532fce8fab5173650331e09033a" 10 + dependencies = [ 11 + "abnf-core", 12 + "nom", 13 + ] 14 + 15 + [[package]] 16 + name = "abnf-core" 17 + version = "0.5.0" 18 + source = "registry+https://github.com/rust-lang/crates.io-index" 19 + checksum = "c44e09c43ae1c368fb91a03a566472d0087c26cf7e1b9e8e289c14ede681dd7d" 20 + dependencies = [ 21 + "nom", 22 + ] 23 + 24 + [[package]] 25 + name = "adler2" 26 + version = "2.0.1" 27 + source = "registry+https://github.com/rust-lang/crates.io-index" 28 + checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" 29 + 30 + [[package]] 6 31 name = "aho-corasick" 7 32 version = "1.1.4" 8 33 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 12 37 ] 13 38 14 39 [[package]] 40 + name = "aliasable" 41 + version = "0.1.3" 42 + source = "registry+https://github.com/rust-lang/crates.io-index" 43 + checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" 44 + 45 + [[package]] 46 + name = "android_system_properties" 47 + version = "0.1.5" 48 + source = "registry+https://github.com/rust-lang/crates.io-index" 49 + checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 50 + dependencies = [ 51 + "libc", 52 + ] 53 + 54 + [[package]] 15 55 name = "anstream" 16 56 version = "0.6.21" 17 57 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 62 102 ] 63 103 64 104 [[package]] 105 + name = "async-compression" 106 + version = "0.4.37" 107 + source = "registry+https://github.com/rust-lang/crates.io-index" 108 + checksum = "d10e4f991a553474232bc0a31799f6d24b034a84c0971d80d2e2f78b2e576e40" 109 + dependencies = [ 110 + "compression-codecs", 111 + "compression-core", 112 + "pin-project-lite", 113 + "tokio", 114 + ] 115 + 116 + [[package]] 117 + name = "atomic-polyfill" 118 + version = "1.0.3" 119 + source = "registry+https://github.com/rust-lang/crates.io-index" 120 + checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" 121 + dependencies = [ 122 + "critical-section", 123 + ] 124 + 125 + [[package]] 65 126 name = "atomic-waker" 66 127 version = "1.1.2" 67 128 source = "registry+https://github.com/rust-lang/crates.io-index" 68 129 checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 69 130 70 131 [[package]] 132 + name = "autocfg" 133 + version = "1.5.0" 134 + source = "registry+https://github.com/rust-lang/crates.io-index" 135 + checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" 136 + 137 + [[package]] 138 + name = "base-x" 139 + version = "0.2.11" 140 + source = "registry+https://github.com/rust-lang/crates.io-index" 141 + checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" 142 + 143 + [[package]] 144 + name = "base16ct" 145 + version = "0.2.0" 146 + source = "registry+https://github.com/rust-lang/crates.io-index" 147 + checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" 148 + 149 + [[package]] 150 + name = "base256emoji" 151 + version = "1.0.2" 152 + source = "registry+https://github.com/rust-lang/crates.io-index" 153 + checksum = "b5e9430d9a245a77c92176e649af6e275f20839a48389859d1661e9a128d077c" 154 + dependencies = [ 155 + "const-str", 156 + "match-lookup", 157 + ] 158 + 159 + [[package]] 71 160 name = "base64" 72 161 version = "0.22.1" 73 162 source = "registry+https://github.com/rust-lang/crates.io-index" 74 163 checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 75 164 76 165 [[package]] 166 + name = "base64ct" 167 + version = "1.8.3" 168 + source = "registry+https://github.com/rust-lang/crates.io-index" 169 + checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" 170 + 171 + [[package]] 77 172 name = "bitflags" 78 173 version = "2.10.0" 79 174 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 89 184 ] 90 185 91 186 [[package]] 187 + name = "bon" 188 + version = "3.8.2" 189 + source = "registry+https://github.com/rust-lang/crates.io-index" 190 + checksum = "234655ec178edd82b891e262ea7cf71f6584bcd09eff94db786be23f1821825c" 191 + dependencies = [ 192 + "bon-macros", 193 + "rustversion", 194 + ] 195 + 196 + [[package]] 197 + name = "bon-macros" 198 + version = "3.8.2" 199 + source = "registry+https://github.com/rust-lang/crates.io-index" 200 + checksum = "89ec27229c38ed0eb3c0feee3d2c1d6a4379ae44f418a29a658890e062d8f365" 201 + dependencies = [ 202 + "darling 0.23.0", 203 + "ident_case", 204 + "prettyplease", 205 + "proc-macro2", 206 + "quote", 207 + "rustversion", 208 + "syn 2.0.114", 209 + ] 210 + 211 + [[package]] 212 + name = "borsh" 213 + version = "1.6.0" 214 + source = "registry+https://github.com/rust-lang/crates.io-index" 215 + checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" 216 + dependencies = [ 217 + "cfg_aliases", 218 + ] 219 + 220 + [[package]] 221 + name = "btree-range-map" 222 + version = "0.7.2" 223 + source = "registry+https://github.com/rust-lang/crates.io-index" 224 + checksum = "1be5c9672446d3800bcbcaabaeba121fe22f1fb25700c4562b22faf76d377c33" 225 + dependencies = [ 226 + "btree-slab", 227 + "cc-traits", 228 + "range-traits", 229 + "serde", 230 + "slab", 231 + ] 232 + 233 + [[package]] 234 + name = "btree-slab" 235 + version = "0.6.1" 236 + source = "registry+https://github.com/rust-lang/crates.io-index" 237 + checksum = "7a2b56d3029f075c4fa892428a098425b86cef5c89ae54073137ece416aef13c" 238 + dependencies = [ 239 + "cc-traits", 240 + "slab", 241 + "smallvec", 242 + ] 243 + 244 + [[package]] 92 245 name = "bumpalo" 93 246 version = "3.19.1" 94 247 source = "registry+https://github.com/rust-lang/crates.io-index" 95 248 checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" 96 249 97 250 [[package]] 251 + name = "byteorder" 252 + version = "1.5.0" 253 + source = "registry+https://github.com/rust-lang/crates.io-index" 254 + checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 255 + 256 + [[package]] 98 257 name = "bytes" 99 258 version = "1.11.0" 100 259 source = "registry+https://github.com/rust-lang/crates.io-index" 101 260 checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" 102 261 103 262 [[package]] 263 + name = "cbor4ii" 264 + version = "0.2.14" 265 + source = "registry+https://github.com/rust-lang/crates.io-index" 266 + checksum = "b544cf8c89359205f4f990d0e6f3828db42df85b5dac95d09157a250eb0749c4" 267 + dependencies = [ 268 + "serde", 269 + ] 270 + 271 + [[package]] 104 272 name = "cc" 105 - version = "1.2.52" 273 + version = "1.2.53" 106 274 source = "registry+https://github.com/rust-lang/crates.io-index" 107 - checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3" 275 + checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932" 108 276 dependencies = [ 109 277 "find-msvc-tools", 110 278 "shlex", 111 279 ] 112 280 113 281 [[package]] 282 + name = "cc-traits" 283 + version = "2.0.0" 284 + source = "registry+https://github.com/rust-lang/crates.io-index" 285 + checksum = "060303ef31ef4a522737e1b1ab68c67916f2a787bb2f4f54f383279adba962b5" 286 + dependencies = [ 287 + "slab", 288 + ] 289 + 290 + [[package]] 114 291 name = "cfg-if" 115 292 version = "1.0.4" 116 293 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 123 300 checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 124 301 125 302 [[package]] 303 + name = "chrono" 304 + version = "0.4.43" 305 + source = "registry+https://github.com/rust-lang/crates.io-index" 306 + checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" 307 + dependencies = [ 308 + "iana-time-zone", 309 + "js-sys", 310 + "num-traits", 311 + "serde", 312 + "wasm-bindgen", 313 + "windows-link", 314 + ] 315 + 316 + [[package]] 317 + name = "ciborium" 318 + version = "0.2.2" 319 + source = "registry+https://github.com/rust-lang/crates.io-index" 320 + checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" 321 + dependencies = [ 322 + "ciborium-io", 323 + "ciborium-ll", 324 + "serde", 325 + ] 326 + 327 + [[package]] 328 + name = "ciborium-io" 329 + version = "0.2.2" 330 + source = "registry+https://github.com/rust-lang/crates.io-index" 331 + checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" 332 + 333 + [[package]] 334 + name = "ciborium-ll" 335 + version = "0.2.2" 336 + source = "registry+https://github.com/rust-lang/crates.io-index" 337 + checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" 338 + dependencies = [ 339 + "ciborium-io", 340 + "half", 341 + ] 342 + 343 + [[package]] 344 + name = "cid" 345 + version = "0.11.1" 346 + source = "registry+https://github.com/rust-lang/crates.io-index" 347 + checksum = "3147d8272e8fa0ccd29ce51194dd98f79ddfb8191ba9e3409884e751798acf3a" 348 + dependencies = [ 349 + "core2", 350 + "multibase", 351 + "multihash", 352 + "serde", 353 + "serde_bytes", 354 + "unsigned-varint", 355 + ] 356 + 357 + [[package]] 358 + name = "cobs" 359 + version = "0.3.0" 360 + source = "registry+https://github.com/rust-lang/crates.io-index" 361 + checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" 362 + dependencies = [ 363 + "thiserror 2.0.18", 364 + ] 365 + 366 + [[package]] 126 367 name = "colorchoice" 127 368 version = "1.0.4" 128 369 source = "registry+https://github.com/rust-lang/crates.io-index" 129 370 checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" 130 371 131 372 [[package]] 373 + name = "compression-codecs" 374 + version = "0.4.36" 375 + source = "registry+https://github.com/rust-lang/crates.io-index" 376 + checksum = "00828ba6fd27b45a448e57dbfe84f1029d4c9f26b368157e9a448a5f49a2ec2a" 377 + dependencies = [ 378 + "compression-core", 379 + "flate2", 380 + "memchr", 381 + ] 382 + 383 + [[package]] 384 + name = "compression-core" 385 + version = "0.4.31" 386 + source = "registry+https://github.com/rust-lang/crates.io-index" 387 + checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" 388 + 389 + [[package]] 390 + name = "const-oid" 391 + version = "0.9.6" 392 + source = "registry+https://github.com/rust-lang/crates.io-index" 393 + checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" 394 + 395 + [[package]] 396 + name = "const-str" 397 + version = "0.4.3" 398 + source = "registry+https://github.com/rust-lang/crates.io-index" 399 + checksum = "2f421161cb492475f1661ddc9815a745a1c894592070661180fdec3d4872e9c3" 400 + 401 + [[package]] 402 + name = "core-foundation" 403 + version = "0.9.4" 404 + source = "registry+https://github.com/rust-lang/crates.io-index" 405 + checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" 406 + dependencies = [ 407 + "core-foundation-sys", 408 + "libc", 409 + ] 410 + 411 + [[package]] 132 412 name = "core-foundation" 133 413 version = "0.10.1" 134 414 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 145 425 checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 146 426 147 427 [[package]] 428 + name = "core2" 429 + version = "0.4.0" 430 + source = "registry+https://github.com/rust-lang/crates.io-index" 431 + checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" 432 + dependencies = [ 433 + "memchr", 434 + ] 435 + 436 + [[package]] 148 437 name = "cpufeatures" 149 438 version = "0.2.17" 150 439 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 154 443 ] 155 444 156 445 [[package]] 446 + name = "crc32fast" 447 + version = "1.5.0" 448 + source = "registry+https://github.com/rust-lang/crates.io-index" 449 + checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" 450 + dependencies = [ 451 + "cfg-if", 452 + ] 453 + 454 + [[package]] 455 + name = "critical-section" 456 + version = "1.2.0" 457 + source = "registry+https://github.com/rust-lang/crates.io-index" 458 + checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" 459 + 460 + [[package]] 461 + name = "crossbeam-utils" 462 + version = "0.8.21" 463 + source = "registry+https://github.com/rust-lang/crates.io-index" 464 + checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" 465 + 466 + [[package]] 467 + name = "crunchy" 468 + version = "0.2.4" 469 + source = "registry+https://github.com/rust-lang/crates.io-index" 470 + checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" 471 + 472 + [[package]] 473 + name = "crypto-bigint" 474 + version = "0.5.5" 475 + source = "registry+https://github.com/rust-lang/crates.io-index" 476 + checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" 477 + dependencies = [ 478 + "generic-array", 479 + "rand_core 0.6.4", 480 + "subtle", 481 + "zeroize", 482 + ] 483 + 484 + [[package]] 157 485 name = "crypto-common" 158 - version = "0.1.7" 486 + version = "0.1.6" 159 487 source = "registry+https://github.com/rust-lang/crates.io-index" 160 - checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" 488 + checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 161 489 dependencies = [ 162 490 "generic-array", 163 491 "typenum", 164 492 ] 165 493 166 494 [[package]] 495 + name = "darling" 496 + version = "0.21.3" 497 + source = "registry+https://github.com/rust-lang/crates.io-index" 498 + checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" 499 + dependencies = [ 500 + "darling_core 0.21.3", 501 + "darling_macro 0.21.3", 502 + ] 503 + 504 + [[package]] 505 + name = "darling" 506 + version = "0.23.0" 507 + source = "registry+https://github.com/rust-lang/crates.io-index" 508 + checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" 509 + dependencies = [ 510 + "darling_core 0.23.0", 511 + "darling_macro 0.23.0", 512 + ] 513 + 514 + [[package]] 515 + name = "darling_core" 516 + version = "0.21.3" 517 + source = "registry+https://github.com/rust-lang/crates.io-index" 518 + checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" 519 + dependencies = [ 520 + "fnv", 521 + "ident_case", 522 + "proc-macro2", 523 + "quote", 524 + "strsim", 525 + "syn 2.0.114", 526 + ] 527 + 528 + [[package]] 529 + name = "darling_core" 530 + version = "0.23.0" 531 + source = "registry+https://github.com/rust-lang/crates.io-index" 532 + checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" 533 + dependencies = [ 534 + "ident_case", 535 + "proc-macro2", 536 + "quote", 537 + "strsim", 538 + "syn 2.0.114", 539 + ] 540 + 541 + [[package]] 542 + name = "darling_macro" 543 + version = "0.21.3" 544 + source = "registry+https://github.com/rust-lang/crates.io-index" 545 + checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" 546 + dependencies = [ 547 + "darling_core 0.21.3", 548 + "quote", 549 + "syn 2.0.114", 550 + ] 551 + 552 + [[package]] 553 + name = "darling_macro" 554 + version = "0.23.0" 555 + source = "registry+https://github.com/rust-lang/crates.io-index" 556 + checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" 557 + dependencies = [ 558 + "darling_core 0.23.0", 559 + "quote", 560 + "syn 2.0.114", 561 + ] 562 + 563 + [[package]] 564 + name = "dashmap" 565 + version = "6.1.0" 566 + source = "registry+https://github.com/rust-lang/crates.io-index" 567 + checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" 568 + dependencies = [ 569 + "cfg-if", 570 + "crossbeam-utils", 571 + "hashbrown 0.14.5", 572 + "lock_api", 573 + "once_cell", 574 + "parking_lot_core", 575 + ] 576 + 577 + [[package]] 167 578 name = "data-encoding" 168 579 version = "2.10.0" 169 580 source = "registry+https://github.com/rust-lang/crates.io-index" 170 581 checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" 171 582 172 583 [[package]] 584 + name = "data-encoding-macro" 585 + version = "0.1.19" 586 + source = "registry+https://github.com/rust-lang/crates.io-index" 587 + checksum = "8142a83c17aa9461d637e649271eae18bf2edd00e91f2e105df36c3c16355bdb" 588 + dependencies = [ 589 + "data-encoding", 590 + "data-encoding-macro-internal", 591 + ] 592 + 593 + [[package]] 594 + name = "data-encoding-macro-internal" 595 + version = "0.1.17" 596 + source = "registry+https://github.com/rust-lang/crates.io-index" 597 + checksum = "7ab67060fc6b8ef687992d439ca0fa36e7ed17e9a0b16b25b601e8757df720de" 598 + dependencies = [ 599 + "data-encoding", 600 + "syn 2.0.114", 601 + ] 602 + 603 + [[package]] 604 + name = "der" 605 + version = "0.7.10" 606 + source = "registry+https://github.com/rust-lang/crates.io-index" 607 + checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" 608 + dependencies = [ 609 + "const-oid", 610 + "pem-rfc7468", 611 + "zeroize", 612 + ] 613 + 614 + [[package]] 615 + name = "deranged" 616 + version = "0.5.5" 617 + source = "registry+https://github.com/rust-lang/crates.io-index" 618 + checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" 619 + dependencies = [ 620 + "powerfmt", 621 + "serde_core", 622 + ] 623 + 624 + [[package]] 173 625 name = "digest" 174 626 version = "0.10.7" 175 627 source = "registry+https://github.com/rust-lang/crates.io-index" 176 628 checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 177 629 dependencies = [ 178 630 "block-buffer", 631 + "const-oid", 179 632 "crypto-common", 633 + "subtle", 180 634 ] 181 635 182 636 [[package]] ··· 187 641 dependencies = [ 188 642 "proc-macro2", 189 643 "quote", 190 - "syn", 644 + "syn 2.0.114", 191 645 ] 192 646 193 647 [[package]] 194 - name = "either" 195 - version = "1.15.0" 648 + name = "dyn-clone" 649 + version = "1.0.20" 650 + source = "registry+https://github.com/rust-lang/crates.io-index" 651 + checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" 652 + 653 + [[package]] 654 + name = "ecdsa" 655 + version = "0.16.9" 196 656 source = "registry+https://github.com/rust-lang/crates.io-index" 197 - checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 657 + checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" 658 + dependencies = [ 659 + "der", 660 + "digest", 661 + "elliptic-curve", 662 + "rfc6979", 663 + "signature", 664 + "spki", 665 + ] 666 + 667 + [[package]] 668 + name = "elliptic-curve" 669 + version = "0.13.8" 670 + source = "registry+https://github.com/rust-lang/crates.io-index" 671 + checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" 672 + dependencies = [ 673 + "base16ct", 674 + "crypto-bigint", 675 + "digest", 676 + "ff", 677 + "generic-array", 678 + "group", 679 + "pem-rfc7468", 680 + "pkcs8", 681 + "rand_core 0.6.4", 682 + "sec1", 683 + "subtle", 684 + "zeroize", 685 + ] 686 + 687 + [[package]] 688 + name = "embedded-io" 689 + version = "0.4.0" 690 + source = "registry+https://github.com/rust-lang/crates.io-index" 691 + checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" 692 + 693 + [[package]] 694 + name = "embedded-io" 695 + version = "0.6.1" 696 + source = "registry+https://github.com/rust-lang/crates.io-index" 697 + checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" 698 + 699 + [[package]] 700 + name = "encoding_rs" 701 + version = "0.8.35" 702 + source = "registry+https://github.com/rust-lang/crates.io-index" 703 + checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" 704 + dependencies = [ 705 + "cfg-if", 706 + ] 198 707 199 708 [[package]] 200 709 name = "env_filter" ··· 205 714 "log", 206 715 "regex", 207 716 ] 208 - 209 - [[package]] 210 - name = "env_home" 211 - version = "0.1.0" 212 - source = "registry+https://github.com/rust-lang/crates.io-index" 213 - checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" 214 717 215 718 [[package]] 216 719 name = "env_logger" ··· 226 729 ] 227 730 228 731 [[package]] 732 + name = "equivalent" 733 + version = "1.0.2" 734 + source = "registry+https://github.com/rust-lang/crates.io-index" 735 + checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 736 + 737 + [[package]] 229 738 name = "errno" 230 739 version = "0.3.14" 231 740 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 236 745 ] 237 746 238 747 [[package]] 748 + name = "ff" 749 + version = "0.13.1" 750 + source = "registry+https://github.com/rust-lang/crates.io-index" 751 + checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" 752 + dependencies = [ 753 + "rand_core 0.6.4", 754 + "subtle", 755 + ] 756 + 757 + [[package]] 239 758 name = "find-msvc-tools" 240 - version = "0.1.7" 759 + version = "0.1.8" 241 760 source = "registry+https://github.com/rust-lang/crates.io-index" 242 - checksum = "f449e6c6c08c865631d4890cfacf252b3d396c9bcc83adb6623cdb02a8336c41" 761 + checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" 762 + 763 + [[package]] 764 + name = "flate2" 765 + version = "1.1.8" 766 + source = "registry+https://github.com/rust-lang/crates.io-index" 767 + checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369" 768 + dependencies = [ 769 + "crc32fast", 770 + "miniz_oxide", 771 + ] 772 + 773 + [[package]] 774 + name = "fnv" 775 + version = "1.0.7" 776 + source = "registry+https://github.com/rust-lang/crates.io-index" 777 + checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 243 778 244 779 [[package]] 245 780 name = "form_urlencoded" ··· 273 808 dependencies = [ 274 809 "proc-macro2", 275 810 "quote", 276 - "syn", 811 + "syn 2.0.114", 277 812 ] 278 813 279 814 [[package]] ··· 305 840 306 841 [[package]] 307 842 name = "generic-array" 308 - version = "0.14.7" 843 + version = "0.14.9" 309 844 source = "registry+https://github.com/rust-lang/crates.io-index" 310 - checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 845 + checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" 311 846 dependencies = [ 312 847 "typenum", 313 848 "version_check", 849 + "zeroize", 314 850 ] 315 851 316 852 [[package]] ··· 341 877 ] 342 878 343 879 [[package]] 880 + name = "group" 881 + version = "0.13.0" 882 + source = "registry+https://github.com/rust-lang/crates.io-index" 883 + checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" 884 + dependencies = [ 885 + "ff", 886 + "rand_core 0.6.4", 887 + "subtle", 888 + ] 889 + 890 + [[package]] 891 + name = "h2" 892 + version = "0.4.13" 893 + source = "registry+https://github.com/rust-lang/crates.io-index" 894 + checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" 895 + dependencies = [ 896 + "atomic-waker", 897 + "bytes", 898 + "fnv", 899 + "futures-core", 900 + "futures-sink", 901 + "http", 902 + "indexmap 2.13.0", 903 + "slab", 904 + "tokio", 905 + "tokio-util", 906 + "tracing", 907 + ] 908 + 909 + [[package]] 910 + name = "half" 911 + version = "2.7.1" 912 + source = "registry+https://github.com/rust-lang/crates.io-index" 913 + checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" 914 + dependencies = [ 915 + "cfg-if", 916 + "crunchy", 917 + "zerocopy", 918 + ] 919 + 920 + [[package]] 921 + name = "hash32" 922 + version = "0.2.1" 923 + source = "registry+https://github.com/rust-lang/crates.io-index" 924 + checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" 925 + dependencies = [ 926 + "byteorder", 927 + ] 928 + 929 + [[package]] 930 + name = "hashbrown" 931 + version = "0.12.3" 932 + source = "registry+https://github.com/rust-lang/crates.io-index" 933 + checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 934 + 935 + [[package]] 936 + name = "hashbrown" 937 + version = "0.14.5" 938 + source = "registry+https://github.com/rust-lang/crates.io-index" 939 + checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 940 + 941 + [[package]] 942 + name = "hashbrown" 943 + version = "0.16.1" 944 + source = "registry+https://github.com/rust-lang/crates.io-index" 945 + checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" 946 + 947 + [[package]] 948 + name = "heapless" 949 + version = "0.7.17" 950 + source = "registry+https://github.com/rust-lang/crates.io-index" 951 + checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" 952 + dependencies = [ 953 + "atomic-polyfill", 954 + "hash32", 955 + "rustc_version", 956 + "serde", 957 + "spin", 958 + "stable_deref_trait", 959 + ] 960 + 961 + [[package]] 962 + name = "heck" 963 + version = "0.4.1" 964 + source = "registry+https://github.com/rust-lang/crates.io-index" 965 + checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 966 + 967 + [[package]] 968 + name = "heck" 969 + version = "0.5.0" 970 + source = "registry+https://github.com/rust-lang/crates.io-index" 971 + checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 972 + 973 + [[package]] 974 + name = "hex" 975 + version = "0.4.3" 976 + source = "registry+https://github.com/rust-lang/crates.io-index" 977 + checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 978 + 979 + [[package]] 980 + name = "hex_fmt" 981 + version = "0.3.0" 982 + source = "registry+https://github.com/rust-lang/crates.io-index" 983 + checksum = "b07f60793ff0a4d9cef0f18e63b5357e06209987153a64648c972c1e5aff336f" 984 + 985 + [[package]] 986 + name = "hmac" 987 + version = "0.12.1" 988 + source = "registry+https://github.com/rust-lang/crates.io-index" 989 + checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 990 + dependencies = [ 991 + "digest", 992 + ] 993 + 994 + [[package]] 344 995 name = "http" 345 996 version = "1.4.0" 346 997 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 389 1040 "bytes", 390 1041 "futures-channel", 391 1042 "futures-core", 1043 + "h2", 392 1044 "http", 393 1045 "http-body", 394 1046 "httparse", ··· 436 1088 "percent-encoding", 437 1089 "pin-project-lite", 438 1090 "socket2", 1091 + "system-configuration", 439 1092 "tokio", 440 1093 "tower-service", 441 1094 "tracing", 1095 + "windows-registry", 1096 + ] 1097 + 1098 + [[package]] 1099 + name = "iana-time-zone" 1100 + version = "0.1.64" 1101 + source = "registry+https://github.com/rust-lang/crates.io-index" 1102 + checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" 1103 + dependencies = [ 1104 + "android_system_properties", 1105 + "core-foundation-sys", 1106 + "iana-time-zone-haiku", 1107 + "js-sys", 1108 + "log", 1109 + "wasm-bindgen", 1110 + "windows-core", 1111 + ] 1112 + 1113 + [[package]] 1114 + name = "iana-time-zone-haiku" 1115 + version = "0.1.2" 1116 + source = "registry+https://github.com/rust-lang/crates.io-index" 1117 + checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 1118 + dependencies = [ 1119 + "cc", 442 1120 ] 443 1121 444 1122 [[package]] ··· 523 1201 ] 524 1202 525 1203 [[package]] 1204 + name = "ident_case" 1205 + version = "1.0.1" 1206 + source = "registry+https://github.com/rust-lang/crates.io-index" 1207 + checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 1208 + 1209 + [[package]] 526 1210 name = "idna" 527 1211 version = "1.1.0" 528 1212 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 544 1228 ] 545 1229 546 1230 [[package]] 1231 + name = "indexmap" 1232 + version = "1.9.3" 1233 + source = "registry+https://github.com/rust-lang/crates.io-index" 1234 + checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 1235 + dependencies = [ 1236 + "autocfg", 1237 + "hashbrown 0.12.3", 1238 + "serde", 1239 + ] 1240 + 1241 + [[package]] 1242 + name = "indexmap" 1243 + version = "2.13.0" 1244 + source = "registry+https://github.com/rust-lang/crates.io-index" 1245 + checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" 1246 + dependencies = [ 1247 + "equivalent", 1248 + "hashbrown 0.16.1", 1249 + "serde", 1250 + "serde_core", 1251 + ] 1252 + 1253 + [[package]] 1254 + name = "indoc" 1255 + version = "2.0.7" 1256 + source = "registry+https://github.com/rust-lang/crates.io-index" 1257 + checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" 1258 + dependencies = [ 1259 + "rustversion", 1260 + ] 1261 + 1262 + [[package]] 1263 + name = "inventory" 1264 + version = "0.3.21" 1265 + source = "registry+https://github.com/rust-lang/crates.io-index" 1266 + checksum = "bc61209c082fbeb19919bee74b176221b27223e27b65d781eb91af24eb1fb46e" 1267 + dependencies = [ 1268 + "rustversion", 1269 + ] 1270 + 1271 + [[package]] 1272 + name = "ipld-core" 1273 + version = "0.4.2" 1274 + source = "registry+https://github.com/rust-lang/crates.io-index" 1275 + checksum = "104718b1cc124d92a6d01ca9c9258a7df311405debb3408c445a36452f9bf8db" 1276 + dependencies = [ 1277 + "cid", 1278 + "serde", 1279 + "serde_bytes", 1280 + ] 1281 + 1282 + [[package]] 547 1283 name = "ipnet" 548 1284 version = "2.11.0" 549 1285 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 572 1308 checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" 573 1309 574 1310 [[package]] 1311 + name = "jacquard-common" 1312 + version = "0.9.5" 1313 + source = "registry+https://github.com/rust-lang/crates.io-index" 1314 + checksum = "1751921e0bdae5e0077afade6161545e9ef7698306c868f800916e99ecbcaae9" 1315 + dependencies = [ 1316 + "base64", 1317 + "bon", 1318 + "bytes", 1319 + "chrono", 1320 + "cid", 1321 + "getrandom 0.2.17", 1322 + "getrandom 0.3.4", 1323 + "http", 1324 + "ipld-core", 1325 + "k256", 1326 + "langtag", 1327 + "miette", 1328 + "multibase", 1329 + "multihash", 1330 + "ouroboros", 1331 + "p256", 1332 + "postcard", 1333 + "rand", 1334 + "regex", 1335 + "regex-lite", 1336 + "reqwest", 1337 + "serde", 1338 + "serde_bytes", 1339 + "serde_html_form", 1340 + "serde_ipld_dagcbor", 1341 + "serde_json", 1342 + "signature", 1343 + "smol_str", 1344 + "thiserror 2.0.18", 1345 + "tokio", 1346 + "tokio-util", 1347 + "trait-variant", 1348 + "url", 1349 + ] 1350 + 1351 + [[package]] 1352 + name = "jacquard-derive" 1353 + version = "0.9.5" 1354 + source = "registry+https://github.com/rust-lang/crates.io-index" 1355 + checksum = "9c8d73dfee07943fdab93569ed1c28b06c6921ed891c08b415c4a323ff67e593" 1356 + dependencies = [ 1357 + "heck 0.5.0", 1358 + "jacquard-lexicon", 1359 + "proc-macro2", 1360 + "quote", 1361 + "syn 2.0.114", 1362 + ] 1363 + 1364 + [[package]] 1365 + name = "jacquard-lexicon" 1366 + version = "0.9.5" 1367 + source = "registry+https://github.com/rust-lang/crates.io-index" 1368 + checksum = "8411aff546569b0a1e0ef669bed2380cec1c00d48f02f3fcd57a71545321b3d8" 1369 + dependencies = [ 1370 + "cid", 1371 + "dashmap", 1372 + "heck 0.5.0", 1373 + "inventory", 1374 + "jacquard-common", 1375 + "miette", 1376 + "multihash", 1377 + "prettyplease", 1378 + "proc-macro2", 1379 + "quote", 1380 + "serde", 1381 + "serde_ipld_dagcbor", 1382 + "serde_json", 1383 + "serde_repr", 1384 + "serde_with", 1385 + "sha2", 1386 + "syn 2.0.114", 1387 + "thiserror 2.0.18", 1388 + "unicode-segmentation", 1389 + ] 1390 + 1391 + [[package]] 575 1392 name = "jiff" 576 1393 version = "0.2.18" 577 1394 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 592 1409 dependencies = [ 593 1410 "proc-macro2", 594 1411 "quote", 595 - "syn", 1412 + "syn 2.0.114", 596 1413 ] 597 1414 598 1415 [[package]] ··· 606 1423 ] 607 1424 608 1425 [[package]] 609 - name = "libc" 610 - version = "0.2.180" 1426 + name = "k256" 1427 + version = "0.13.4" 611 1428 source = "registry+https://github.com/rust-lang/crates.io-index" 612 - checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" 1429 + checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" 1430 + dependencies = [ 1431 + "cfg-if", 1432 + "ecdsa", 1433 + "elliptic-curve", 1434 + "sha2", 1435 + ] 613 1436 614 1437 [[package]] 615 - name = "linux-raw-sys" 616 - version = "0.11.0" 1438 + name = "langtag" 1439 + version = "0.4.0" 617 1440 source = "registry+https://github.com/rust-lang/crates.io-index" 618 - checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" 1441 + checksum = "9ecb4c689a30e48ebeaa14237f34037e300dd072e6ad21a9ec72e810ff3c6600" 1442 + dependencies = [ 1443 + "serde", 1444 + "static-regular-grammar", 1445 + "thiserror 1.0.69", 1446 + ] 1447 + 1448 + [[package]] 1449 + name = "lexicons-example" 1450 + version = "0.1.0" 1451 + dependencies = [ 1452 + "jacquard-common", 1453 + "jacquard-derive", 1454 + "jacquard-lexicon", 1455 + "rustversion", 1456 + "serde", 1457 + "unicode-segmentation", 1458 + ] 1459 + 1460 + [[package]] 1461 + name = "libc" 1462 + version = "0.2.180" 1463 + source = "registry+https://github.com/rust-lang/crates.io-index" 1464 + checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" 619 1465 620 1466 [[package]] 621 1467 name = "litemap" ··· 624 1470 checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" 625 1471 626 1472 [[package]] 1473 + name = "lock_api" 1474 + version = "0.4.14" 1475 + source = "registry+https://github.com/rust-lang/crates.io-index" 1476 + checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" 1477 + dependencies = [ 1478 + "scopeguard", 1479 + ] 1480 + 1481 + [[package]] 627 1482 name = "log" 628 1483 version = "0.4.29" 629 1484 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 636 1491 checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" 637 1492 638 1493 [[package]] 1494 + name = "match-lookup" 1495 + version = "0.1.2" 1496 + source = "registry+https://github.com/rust-lang/crates.io-index" 1497 + checksum = "757aee279b8bdbb9f9e676796fd459e4207a1f986e87886700abf589f5abf771" 1498 + dependencies = [ 1499 + "proc-macro2", 1500 + "quote", 1501 + "syn 2.0.114", 1502 + ] 1503 + 1504 + [[package]] 639 1505 name = "memchr" 640 1506 version = "2.7.6" 641 1507 source = "registry+https://github.com/rust-lang/crates.io-index" 642 1508 checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" 643 1509 644 1510 [[package]] 1511 + name = "miette" 1512 + version = "7.6.0" 1513 + source = "registry+https://github.com/rust-lang/crates.io-index" 1514 + checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" 1515 + dependencies = [ 1516 + "cfg-if", 1517 + "miette-derive", 1518 + "unicode-width", 1519 + ] 1520 + 1521 + [[package]] 1522 + name = "miette-derive" 1523 + version = "7.6.0" 1524 + source = "registry+https://github.com/rust-lang/crates.io-index" 1525 + checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" 1526 + dependencies = [ 1527 + "proc-macro2", 1528 + "quote", 1529 + "syn 2.0.114", 1530 + ] 1531 + 1532 + [[package]] 1533 + name = "mime" 1534 + version = "0.3.17" 1535 + source = "registry+https://github.com/rust-lang/crates.io-index" 1536 + checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 1537 + 1538 + [[package]] 1539 + name = "minimal-lexical" 1540 + version = "0.2.1" 1541 + source = "registry+https://github.com/rust-lang/crates.io-index" 1542 + checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 1543 + 1544 + [[package]] 1545 + name = "miniz_oxide" 1546 + version = "0.8.9" 1547 + source = "registry+https://github.com/rust-lang/crates.io-index" 1548 + checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" 1549 + dependencies = [ 1550 + "adler2", 1551 + "simd-adler32", 1552 + ] 1553 + 1554 + [[package]] 645 1555 name = "mio" 646 1556 version = "1.1.1" 647 1557 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 653 1563 ] 654 1564 655 1565 [[package]] 1566 + name = "multibase" 1567 + version = "0.9.2" 1568 + source = "registry+https://github.com/rust-lang/crates.io-index" 1569 + checksum = "8694bb4835f452b0e3bb06dbebb1d6fc5385b6ca1caf2e55fd165c042390ec77" 1570 + dependencies = [ 1571 + "base-x", 1572 + "base256emoji", 1573 + "data-encoding", 1574 + "data-encoding-macro", 1575 + ] 1576 + 1577 + [[package]] 1578 + name = "multihash" 1579 + version = "0.19.3" 1580 + source = "registry+https://github.com/rust-lang/crates.io-index" 1581 + checksum = "6b430e7953c29dd6a09afc29ff0bb69c6e306329ee6794700aee27b76a1aea8d" 1582 + dependencies = [ 1583 + "core2", 1584 + "serde", 1585 + "unsigned-varint", 1586 + ] 1587 + 1588 + [[package]] 1589 + name = "nom" 1590 + version = "7.1.3" 1591 + source = "registry+https://github.com/rust-lang/crates.io-index" 1592 + checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 1593 + dependencies = [ 1594 + "memchr", 1595 + "minimal-lexical", 1596 + ] 1597 + 1598 + [[package]] 1599 + name = "num-conv" 1600 + version = "0.1.0" 1601 + source = "registry+https://github.com/rust-lang/crates.io-index" 1602 + checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 1603 + 1604 + [[package]] 1605 + name = "num-traits" 1606 + version = "0.2.19" 1607 + source = "registry+https://github.com/rust-lang/crates.io-index" 1608 + checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 1609 + dependencies = [ 1610 + "autocfg", 1611 + ] 1612 + 1613 + [[package]] 656 1614 name = "once_cell" 657 1615 version = "1.21.3" 658 1616 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 666 1624 667 1625 [[package]] 668 1626 name = "openssl-probe" 669 - version = "0.2.0" 1627 + version = "0.2.1" 1628 + source = "registry+https://github.com/rust-lang/crates.io-index" 1629 + checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" 1630 + 1631 + [[package]] 1632 + name = "ouroboros" 1633 + version = "0.18.5" 1634 + source = "registry+https://github.com/rust-lang/crates.io-index" 1635 + checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59" 1636 + dependencies = [ 1637 + "aliasable", 1638 + "ouroboros_macro", 1639 + "static_assertions", 1640 + ] 1641 + 1642 + [[package]] 1643 + name = "ouroboros_macro" 1644 + version = "0.18.5" 670 1645 source = "registry+https://github.com/rust-lang/crates.io-index" 671 - checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" 1646 + checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0" 1647 + dependencies = [ 1648 + "heck 0.4.1", 1649 + "proc-macro2", 1650 + "proc-macro2-diagnostics", 1651 + "quote", 1652 + "syn 2.0.114", 1653 + ] 1654 + 1655 + [[package]] 1656 + name = "p256" 1657 + version = "0.13.2" 1658 + source = "registry+https://github.com/rust-lang/crates.io-index" 1659 + checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" 1660 + dependencies = [ 1661 + "ecdsa", 1662 + "elliptic-curve", 1663 + "primeorder", 1664 + "sha2", 1665 + ] 1666 + 1667 + [[package]] 1668 + name = "parking_lot_core" 1669 + version = "0.9.12" 1670 + source = "registry+https://github.com/rust-lang/crates.io-index" 1671 + checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" 1672 + dependencies = [ 1673 + "cfg-if", 1674 + "libc", 1675 + "redox_syscall", 1676 + "smallvec", 1677 + "windows-link", 1678 + ] 1679 + 1680 + [[package]] 1681 + name = "pem-rfc7468" 1682 + version = "0.7.0" 1683 + source = "registry+https://github.com/rust-lang/crates.io-index" 1684 + checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" 1685 + dependencies = [ 1686 + "base64ct", 1687 + ] 672 1688 673 1689 [[package]] 674 1690 name = "percent-encoding" ··· 689 1705 checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 690 1706 691 1707 [[package]] 1708 + name = "pkcs8" 1709 + version = "0.10.2" 1710 + source = "registry+https://github.com/rust-lang/crates.io-index" 1711 + checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" 1712 + dependencies = [ 1713 + "der", 1714 + "spki", 1715 + ] 1716 + 1717 + [[package]] 692 1718 name = "portable-atomic" 693 1719 version = "1.13.0" 694 1720 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 704 1730 ] 705 1731 706 1732 [[package]] 1733 + name = "postcard" 1734 + version = "1.1.3" 1735 + source = "registry+https://github.com/rust-lang/crates.io-index" 1736 + checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" 1737 + dependencies = [ 1738 + "cobs", 1739 + "embedded-io 0.4.0", 1740 + "embedded-io 0.6.1", 1741 + "heapless", 1742 + "serde", 1743 + ] 1744 + 1745 + [[package]] 707 1746 name = "potential_utf" 708 1747 version = "0.1.4" 709 1748 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 713 1752 ] 714 1753 715 1754 [[package]] 1755 + name = "powerfmt" 1756 + version = "0.2.0" 1757 + source = "registry+https://github.com/rust-lang/crates.io-index" 1758 + checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 1759 + 1760 + [[package]] 716 1761 name = "ppv-lite86" 717 1762 version = "0.2.21" 718 1763 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 722 1767 ] 723 1768 724 1769 [[package]] 1770 + name = "prettyplease" 1771 + version = "0.2.37" 1772 + source = "registry+https://github.com/rust-lang/crates.io-index" 1773 + checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" 1774 + dependencies = [ 1775 + "proc-macro2", 1776 + "syn 2.0.114", 1777 + ] 1778 + 1779 + [[package]] 1780 + name = "primeorder" 1781 + version = "0.13.6" 1782 + source = "registry+https://github.com/rust-lang/crates.io-index" 1783 + checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" 1784 + dependencies = [ 1785 + "elliptic-curve", 1786 + ] 1787 + 1788 + [[package]] 1789 + name = "proc-macro-error" 1790 + version = "1.0.4" 1791 + source = "registry+https://github.com/rust-lang/crates.io-index" 1792 + checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 1793 + dependencies = [ 1794 + "proc-macro-error-attr", 1795 + "proc-macro2", 1796 + "quote", 1797 + "syn 1.0.109", 1798 + "version_check", 1799 + ] 1800 + 1801 + [[package]] 1802 + name = "proc-macro-error-attr" 1803 + version = "1.0.4" 1804 + source = "registry+https://github.com/rust-lang/crates.io-index" 1805 + checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 1806 + dependencies = [ 1807 + "proc-macro2", 1808 + "quote", 1809 + "version_check", 1810 + ] 1811 + 1812 + [[package]] 725 1813 name = "proc-macro2" 726 - version = "1.0.105" 1814 + version = "1.0.106" 727 1815 source = "registry+https://github.com/rust-lang/crates.io-index" 728 - checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" 1816 + checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" 729 1817 dependencies = [ 730 1818 "unicode-ident", 731 1819 ] 732 1820 733 1821 [[package]] 1822 + name = "proc-macro2-diagnostics" 1823 + version = "0.10.1" 1824 + source = "registry+https://github.com/rust-lang/crates.io-index" 1825 + checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" 1826 + dependencies = [ 1827 + "proc-macro2", 1828 + "quote", 1829 + "syn 2.0.114", 1830 + "version_check", 1831 + "yansi", 1832 + ] 1833 + 1834 + [[package]] 734 1835 name = "quinn" 735 1836 version = "0.11.9" 736 1837 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 744 1845 "rustc-hash", 745 1846 "rustls", 746 1847 "socket2", 747 - "thiserror", 1848 + "thiserror 2.0.18", 748 1849 "tokio", 749 1850 "tracing", 750 1851 "web-time", ··· 765 1866 "rustls", 766 1867 "rustls-pki-types", 767 1868 "slab", 768 - "thiserror", 1869 + "thiserror 2.0.18", 769 1870 "tinyvec", 770 1871 "tracing", 771 1872 "web-time", ··· 787 1888 788 1889 [[package]] 789 1890 name = "quote" 790 - version = "1.0.43" 1891 + version = "1.0.44" 791 1892 source = "registry+https://github.com/rust-lang/crates.io-index" 792 - checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" 1893 + checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" 793 1894 dependencies = [ 794 1895 "proc-macro2", 795 1896 ] ··· 807 1908 checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" 808 1909 dependencies = [ 809 1910 "rand_chacha", 810 - "rand_core", 1911 + "rand_core 0.9.5", 811 1912 ] 812 1913 813 1914 [[package]] ··· 817 1918 checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 818 1919 dependencies = [ 819 1920 "ppv-lite86", 820 - "rand_core", 1921 + "rand_core 0.9.5", 1922 + ] 1923 + 1924 + [[package]] 1925 + name = "rand_core" 1926 + version = "0.6.4" 1927 + source = "registry+https://github.com/rust-lang/crates.io-index" 1928 + checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1929 + dependencies = [ 1930 + "getrandom 0.2.17", 821 1931 ] 822 1932 823 1933 [[package]] ··· 830 1940 ] 831 1941 832 1942 [[package]] 1943 + name = "range-traits" 1944 + version = "0.3.2" 1945 + source = "registry+https://github.com/rust-lang/crates.io-index" 1946 + checksum = "d20581732dd76fa913c7dff1a2412b714afe3573e94d41c34719de73337cc8ab" 1947 + 1948 + [[package]] 1949 + name = "redox_syscall" 1950 + version = "0.5.18" 1951 + source = "registry+https://github.com/rust-lang/crates.io-index" 1952 + checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" 1953 + dependencies = [ 1954 + "bitflags", 1955 + ] 1956 + 1957 + [[package]] 1958 + name = "ref-cast" 1959 + version = "1.0.25" 1960 + source = "registry+https://github.com/rust-lang/crates.io-index" 1961 + checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" 1962 + dependencies = [ 1963 + "ref-cast-impl", 1964 + ] 1965 + 1966 + [[package]] 1967 + name = "ref-cast-impl" 1968 + version = "1.0.25" 1969 + source = "registry+https://github.com/rust-lang/crates.io-index" 1970 + checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" 1971 + dependencies = [ 1972 + "proc-macro2", 1973 + "quote", 1974 + "syn 2.0.114", 1975 + ] 1976 + 1977 + [[package]] 833 1978 name = "regex" 834 1979 version = "1.12.2" 835 1980 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 853 1998 ] 854 1999 855 2000 [[package]] 2001 + name = "regex-lite" 2002 + version = "0.1.8" 2003 + source = "registry+https://github.com/rust-lang/crates.io-index" 2004 + checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" 2005 + 2006 + [[package]] 856 2007 name = "regex-syntax" 857 2008 version = "0.8.8" 858 2009 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 866 2017 dependencies = [ 867 2018 "base64", 868 2019 "bytes", 2020 + "encoding_rs", 869 2021 "futures-core", 2022 + "h2", 870 2023 "http", 871 2024 "http-body", 872 2025 "http-body-util", ··· 875 2028 "hyper-util", 876 2029 "js-sys", 877 2030 "log", 2031 + "mime", 878 2032 "percent-encoding", 879 2033 "pin-project-lite", 880 2034 "quinn", ··· 897 2051 ] 898 2052 899 2053 [[package]] 2054 + name = "rfc6979" 2055 + version = "0.4.0" 2056 + source = "registry+https://github.com/rust-lang/crates.io-index" 2057 + checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" 2058 + dependencies = [ 2059 + "hmac", 2060 + "subtle", 2061 + ] 2062 + 2063 + [[package]] 900 2064 name = "ring" 901 2065 version = "0.17.14" 902 2066 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 917 2081 checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" 918 2082 919 2083 [[package]] 920 - name = "rustix" 921 - version = "1.1.3" 2084 + name = "rustc_version" 2085 + version = "0.4.1" 922 2086 source = "registry+https://github.com/rust-lang/crates.io-index" 923 - checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" 2087 + checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" 924 2088 dependencies = [ 925 - "bitflags", 926 - "errno", 927 - "libc", 928 - "linux-raw-sys", 929 - "windows-sys 0.61.2", 2089 + "semver", 930 2090 ] 931 2091 932 2092 [[package]] ··· 957 2117 958 2118 [[package]] 959 2119 name = "rustls-pki-types" 960 - version = "1.13.2" 2120 + version = "1.14.0" 961 2121 source = "registry+https://github.com/rust-lang/crates.io-index" 962 - checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" 2122 + checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" 963 2123 dependencies = [ 964 2124 "web-time", 965 2125 "zeroize", ··· 967 2127 968 2128 [[package]] 969 2129 name = "rustls-webpki" 970 - version = "0.103.8" 2130 + version = "0.103.9" 971 2131 source = "registry+https://github.com/rust-lang/crates.io-index" 972 - checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" 2132 + checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" 973 2133 dependencies = [ 974 2134 "ring", 975 2135 "rustls-pki-types", ··· 998 2158 ] 999 2159 1000 2160 [[package]] 2161 + name = "schemars" 2162 + version = "0.9.0" 2163 + source = "registry+https://github.com/rust-lang/crates.io-index" 2164 + checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" 2165 + dependencies = [ 2166 + "dyn-clone", 2167 + "ref-cast", 2168 + "serde", 2169 + "serde_json", 2170 + ] 2171 + 2172 + [[package]] 2173 + name = "schemars" 2174 + version = "1.2.0" 2175 + source = "registry+https://github.com/rust-lang/crates.io-index" 2176 + checksum = "54e910108742c57a770f492731f99be216a52fadd361b06c8fb59d74ccc267d2" 2177 + dependencies = [ 2178 + "dyn-clone", 2179 + "ref-cast", 2180 + "serde", 2181 + "serde_json", 2182 + ] 2183 + 2184 + [[package]] 2185 + name = "scopeguard" 2186 + version = "1.2.0" 2187 + source = "registry+https://github.com/rust-lang/crates.io-index" 2188 + checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 2189 + 2190 + [[package]] 2191 + name = "sec1" 2192 + version = "0.7.3" 2193 + source = "registry+https://github.com/rust-lang/crates.io-index" 2194 + checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" 2195 + dependencies = [ 2196 + "base16ct", 2197 + "der", 2198 + "generic-array", 2199 + "pkcs8", 2200 + "subtle", 2201 + "zeroize", 2202 + ] 2203 + 2204 + [[package]] 1001 2205 name = "security-framework" 1002 2206 version = "3.5.1" 1003 2207 source = "registry+https://github.com/rust-lang/crates.io-index" 1004 2208 checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" 1005 2209 dependencies = [ 1006 2210 "bitflags", 1007 - "core-foundation", 2211 + "core-foundation 0.10.1", 1008 2212 "core-foundation-sys", 1009 2213 "libc", 1010 2214 "security-framework-sys", ··· 1021 2225 ] 1022 2226 1023 2227 [[package]] 2228 + name = "self_cell" 2229 + version = "1.2.2" 2230 + source = "registry+https://github.com/rust-lang/crates.io-index" 2231 + checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89" 2232 + 2233 + [[package]] 2234 + name = "semver" 2235 + version = "1.0.27" 2236 + source = "registry+https://github.com/rust-lang/crates.io-index" 2237 + checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" 2238 + 2239 + [[package]] 1024 2240 name = "serde" 1025 2241 version = "1.0.228" 1026 2242 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1031 2247 ] 1032 2248 1033 2249 [[package]] 2250 + name = "serde_bytes" 2251 + version = "0.11.19" 2252 + source = "registry+https://github.com/rust-lang/crates.io-index" 2253 + checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" 2254 + dependencies = [ 2255 + "serde", 2256 + "serde_core", 2257 + ] 2258 + 2259 + [[package]] 1034 2260 name = "serde_core" 1035 2261 version = "1.0.228" 1036 2262 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1047 2273 dependencies = [ 1048 2274 "proc-macro2", 1049 2275 "quote", 1050 - "syn", 2276 + "syn 2.0.114", 2277 + ] 2278 + 2279 + [[package]] 2280 + name = "serde_html_form" 2281 + version = "0.2.8" 2282 + source = "registry+https://github.com/rust-lang/crates.io-index" 2283 + checksum = "b2f2d7ff8a2140333718bb329f5c40fc5f0865b84c426183ce14c97d2ab8154f" 2284 + dependencies = [ 2285 + "form_urlencoded", 2286 + "indexmap 2.13.0", 2287 + "itoa", 2288 + "ryu", 2289 + "serde_core", 2290 + ] 2291 + 2292 + [[package]] 2293 + name = "serde_ipld_dagcbor" 2294 + version = "0.6.4" 2295 + source = "registry+https://github.com/rust-lang/crates.io-index" 2296 + checksum = "46182f4f08349a02b45c998ba3215d3f9de826246ba02bb9dddfe9a2a2100778" 2297 + dependencies = [ 2298 + "cbor4ii", 2299 + "ipld-core", 2300 + "scopeguard", 2301 + "serde", 1051 2302 ] 1052 2303 1053 2304 [[package]] ··· 1064 2315 ] 1065 2316 1066 2317 [[package]] 2318 + name = "serde_repr" 2319 + version = "0.1.20" 2320 + source = "registry+https://github.com/rust-lang/crates.io-index" 2321 + checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" 2322 + dependencies = [ 2323 + "proc-macro2", 2324 + "quote", 2325 + "syn 2.0.114", 2326 + ] 2327 + 2328 + [[package]] 1067 2329 name = "serde_urlencoded" 1068 2330 version = "0.7.1" 1069 2331 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1076 2338 ] 1077 2339 1078 2340 [[package]] 2341 + name = "serde_with" 2342 + version = "3.16.1" 2343 + source = "registry+https://github.com/rust-lang/crates.io-index" 2344 + checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" 2345 + dependencies = [ 2346 + "base64", 2347 + "chrono", 2348 + "hex", 2349 + "indexmap 1.9.3", 2350 + "indexmap 2.13.0", 2351 + "schemars 0.9.0", 2352 + "schemars 1.2.0", 2353 + "serde_core", 2354 + "serde_json", 2355 + "serde_with_macros", 2356 + "time", 2357 + ] 2358 + 2359 + [[package]] 2360 + name = "serde_with_macros" 2361 + version = "3.16.1" 2362 + source = "registry+https://github.com/rust-lang/crates.io-index" 2363 + checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" 2364 + dependencies = [ 2365 + "darling 0.21.3", 2366 + "proc-macro2", 2367 + "quote", 2368 + "syn 2.0.114", 2369 + ] 2370 + 2371 + [[package]] 1079 2372 name = "sha1" 1080 2373 version = "0.10.6" 1081 2374 source = "registry+https://github.com/rust-lang/crates.io-index" 1082 2375 checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 2376 + dependencies = [ 2377 + "cfg-if", 2378 + "cpufeatures", 2379 + "digest", 2380 + ] 2381 + 2382 + [[package]] 2383 + name = "sha2" 2384 + version = "0.10.9" 2385 + source = "registry+https://github.com/rust-lang/crates.io-index" 2386 + checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" 1083 2387 dependencies = [ 1084 2388 "cfg-if", 1085 2389 "cpufeatures", ··· 1103 2407 ] 1104 2408 1105 2409 [[package]] 2410 + name = "signature" 2411 + version = "2.2.0" 2412 + source = "registry+https://github.com/rust-lang/crates.io-index" 2413 + checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" 2414 + dependencies = [ 2415 + "digest", 2416 + "rand_core 0.6.4", 2417 + ] 2418 + 2419 + [[package]] 2420 + name = "simd-adler32" 2421 + version = "0.3.8" 2422 + source = "registry+https://github.com/rust-lang/crates.io-index" 2423 + checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" 2424 + 2425 + [[package]] 1106 2426 name = "slab" 1107 2427 version = "0.4.11" 1108 2428 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1115 2435 checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 1116 2436 1117 2437 [[package]] 2438 + name = "smol_str" 2439 + version = "0.3.5" 2440 + source = "registry+https://github.com/rust-lang/crates.io-index" 2441 + checksum = "0f7a918bd2a9951d18ee6e48f076843e8e73a9a5d22cf05bcd4b7a81bdd04e17" 2442 + dependencies = [ 2443 + "borsh", 2444 + "serde_core", 2445 + ] 2446 + 2447 + [[package]] 1118 2448 name = "socket2" 1119 2449 version = "0.6.1" 1120 2450 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1125 2455 ] 1126 2456 1127 2457 [[package]] 2458 + name = "spin" 2459 + version = "0.9.8" 2460 + source = "registry+https://github.com/rust-lang/crates.io-index" 2461 + checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 2462 + dependencies = [ 2463 + "lock_api", 2464 + ] 2465 + 2466 + [[package]] 2467 + name = "spki" 2468 + version = "0.7.3" 2469 + source = "registry+https://github.com/rust-lang/crates.io-index" 2470 + checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" 2471 + dependencies = [ 2472 + "base64ct", 2473 + "der", 2474 + ] 2475 + 2476 + [[package]] 1128 2477 name = "stable_deref_trait" 1129 2478 version = "1.2.1" 1130 2479 source = "registry+https://github.com/rust-lang/crates.io-index" 1131 2480 checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" 1132 2481 1133 2482 [[package]] 2483 + name = "standard-site-sync" 2484 + version = "0.1.0" 2485 + dependencies = [ 2486 + "env_logger", 2487 + "jacquard-common", 2488 + "jacquard-lexicon", 2489 + "lexicons-example", 2490 + "log", 2491 + "serde", 2492 + "serde_json", 2493 + "tapped", 2494 + "tokio", 2495 + ] 2496 + 2497 + [[package]] 2498 + name = "static-regular-grammar" 2499 + version = "2.0.2" 2500 + source = "registry+https://github.com/rust-lang/crates.io-index" 2501 + checksum = "4f4a6c40247579acfbb138c3cd7de3dab113ab4ac6227f1b7de7d626ee667957" 2502 + dependencies = [ 2503 + "abnf", 2504 + "btree-range-map", 2505 + "ciborium", 2506 + "hex_fmt", 2507 + "indoc", 2508 + "proc-macro-error", 2509 + "proc-macro2", 2510 + "quote", 2511 + "serde", 2512 + "sha2", 2513 + "syn 2.0.114", 2514 + "thiserror 1.0.69", 2515 + ] 2516 + 2517 + [[package]] 2518 + name = "static_assertions" 2519 + version = "1.1.0" 2520 + source = "registry+https://github.com/rust-lang/crates.io-index" 2521 + checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 2522 + 2523 + [[package]] 2524 + name = "strsim" 2525 + version = "0.11.1" 2526 + source = "registry+https://github.com/rust-lang/crates.io-index" 2527 + checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 2528 + 2529 + [[package]] 1134 2530 name = "subtle" 1135 2531 version = "2.6.1" 1136 2532 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1138 2534 1139 2535 [[package]] 1140 2536 name = "syn" 2537 + version = "1.0.109" 2538 + source = "registry+https://github.com/rust-lang/crates.io-index" 2539 + checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 2540 + dependencies = [ 2541 + "proc-macro2", 2542 + "unicode-ident", 2543 + ] 2544 + 2545 + [[package]] 2546 + name = "syn" 1141 2547 version = "2.0.114" 1142 2548 source = "registry+https://github.com/rust-lang/crates.io-index" 1143 2549 checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" ··· 1164 2570 dependencies = [ 1165 2571 "proc-macro2", 1166 2572 "quote", 1167 - "syn", 2573 + "syn 2.0.114", 2574 + ] 2575 + 2576 + [[package]] 2577 + name = "system-configuration" 2578 + version = "0.6.1" 2579 + source = "registry+https://github.com/rust-lang/crates.io-index" 2580 + checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" 2581 + dependencies = [ 2582 + "bitflags", 2583 + "core-foundation 0.9.4", 2584 + "system-configuration-sys", 2585 + ] 2586 + 2587 + [[package]] 2588 + name = "system-configuration-sys" 2589 + version = "0.6.0" 2590 + source = "registry+https://github.com/rust-lang/crates.io-index" 2591 + checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" 2592 + dependencies = [ 2593 + "core-foundation-sys", 2594 + "libc", 1168 2595 ] 1169 2596 1170 2597 [[package]] 1171 2598 name = "tapped" 1172 - version = "0.1.0" 2599 + version = "0.2.0" 1173 2600 dependencies = [ 1174 2601 "base64", 1175 - "env_logger", 1176 2602 "futures-util", 1177 2603 "libc", 1178 - "log", 1179 2604 "reqwest", 2605 + "self_cell", 1180 2606 "serde", 1181 2607 "serde_json", 1182 - "thiserror", 2608 + "thiserror 2.0.18", 1183 2609 "tokio", 1184 2610 "tokio-tungstenite", 1185 2611 "tracing", 2612 + "tungstenite", 1186 2613 "url", 1187 - "which", 1188 2614 ] 1189 2615 1190 2616 [[package]] 1191 2617 name = "thiserror" 1192 - version = "2.0.17" 2618 + version = "1.0.69" 1193 2619 source = "registry+https://github.com/rust-lang/crates.io-index" 1194 - checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" 2620 + checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 1195 2621 dependencies = [ 1196 - "thiserror-impl", 2622 + "thiserror-impl 1.0.69", 2623 + ] 2624 + 2625 + [[package]] 2626 + name = "thiserror" 2627 + version = "2.0.18" 2628 + source = "registry+https://github.com/rust-lang/crates.io-index" 2629 + checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" 2630 + dependencies = [ 2631 + "thiserror-impl 2.0.18", 1197 2632 ] 1198 2633 1199 2634 [[package]] 1200 2635 name = "thiserror-impl" 1201 - version = "2.0.17" 2636 + version = "1.0.69" 1202 2637 source = "registry+https://github.com/rust-lang/crates.io-index" 1203 - checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" 2638 + checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 1204 2639 dependencies = [ 1205 2640 "proc-macro2", 1206 2641 "quote", 1207 - "syn", 2642 + "syn 2.0.114", 2643 + ] 2644 + 2645 + [[package]] 2646 + name = "thiserror-impl" 2647 + version = "2.0.18" 2648 + source = "registry+https://github.com/rust-lang/crates.io-index" 2649 + checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" 2650 + dependencies = [ 2651 + "proc-macro2", 2652 + "quote", 2653 + "syn 2.0.114", 2654 + ] 2655 + 2656 + [[package]] 2657 + name = "time" 2658 + version = "0.3.45" 2659 + source = "registry+https://github.com/rust-lang/crates.io-index" 2660 + checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" 2661 + dependencies = [ 2662 + "deranged", 2663 + "itoa", 2664 + "num-conv", 2665 + "powerfmt", 2666 + "serde_core", 2667 + "time-core", 2668 + "time-macros", 2669 + ] 2670 + 2671 + [[package]] 2672 + name = "time-core" 2673 + version = "0.1.7" 2674 + source = "registry+https://github.com/rust-lang/crates.io-index" 2675 + checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" 2676 + 2677 + [[package]] 2678 + name = "time-macros" 2679 + version = "0.2.25" 2680 + source = "registry+https://github.com/rust-lang/crates.io-index" 2681 + checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" 2682 + dependencies = [ 2683 + "num-conv", 2684 + "time-core", 1208 2685 ] 1209 2686 1210 2687 [[package]] ··· 1256 2733 dependencies = [ 1257 2734 "proc-macro2", 1258 2735 "quote", 1259 - "syn", 2736 + "syn 2.0.114", 1260 2737 ] 1261 2738 1262 2739 [[package]] ··· 1271 2748 1272 2749 [[package]] 1273 2750 name = "tokio-tungstenite" 1274 - version = "0.26.2" 2751 + version = "0.28.0" 1275 2752 source = "registry+https://github.com/rust-lang/crates.io-index" 1276 - checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" 2753 + checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" 1277 2754 dependencies = [ 1278 2755 "futures-util", 1279 2756 "log", ··· 1286 2763 ] 1287 2764 1288 2765 [[package]] 2766 + name = "tokio-util" 2767 + version = "0.7.18" 2768 + source = "registry+https://github.com/rust-lang/crates.io-index" 2769 + checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" 2770 + dependencies = [ 2771 + "bytes", 2772 + "futures-core", 2773 + "futures-sink", 2774 + "pin-project-lite", 2775 + "tokio", 2776 + ] 2777 + 2778 + [[package]] 1289 2779 name = "tower" 1290 2780 version = "0.5.3" 1291 2781 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1306 2796 source = "registry+https://github.com/rust-lang/crates.io-index" 1307 2797 checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" 1308 2798 dependencies = [ 2799 + "async-compression", 1309 2800 "bitflags", 1310 2801 "bytes", 2802 + "futures-core", 1311 2803 "futures-util", 1312 2804 "http", 1313 2805 "http-body", 2806 + "http-body-util", 1314 2807 "iri-string", 1315 2808 "pin-project-lite", 2809 + "tokio", 2810 + "tokio-util", 1316 2811 "tower", 1317 2812 "tower-layer", 1318 2813 "tower-service", ··· 1349 2844 dependencies = [ 1350 2845 "proc-macro2", 1351 2846 "quote", 1352 - "syn", 2847 + "syn 2.0.114", 1353 2848 ] 1354 2849 1355 2850 [[package]] ··· 1362 2857 ] 1363 2858 1364 2859 [[package]] 2860 + name = "trait-variant" 2861 + version = "0.1.2" 2862 + source = "registry+https://github.com/rust-lang/crates.io-index" 2863 + checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" 2864 + dependencies = [ 2865 + "proc-macro2", 2866 + "quote", 2867 + "syn 2.0.114", 2868 + ] 2869 + 2870 + [[package]] 1365 2871 name = "try-lock" 1366 2872 version = "0.2.5" 1367 2873 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1369 2875 1370 2876 [[package]] 1371 2877 name = "tungstenite" 1372 - version = "0.26.2" 2878 + version = "0.28.0" 1373 2879 source = "registry+https://github.com/rust-lang/crates.io-index" 1374 - checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" 2880 + checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" 1375 2881 dependencies = [ 1376 2882 "bytes", 1377 2883 "data-encoding", ··· 1382 2888 "rustls", 1383 2889 "rustls-pki-types", 1384 2890 "sha1", 1385 - "thiserror", 2891 + "thiserror 2.0.18", 1386 2892 "utf-8", 1387 2893 ] 1388 2894 ··· 1399 2905 checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" 1400 2906 1401 2907 [[package]] 2908 + name = "unicode-segmentation" 2909 + version = "1.12.0" 2910 + source = "registry+https://github.com/rust-lang/crates.io-index" 2911 + checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" 2912 + 2913 + [[package]] 2914 + name = "unicode-width" 2915 + version = "0.1.14" 2916 + source = "registry+https://github.com/rust-lang/crates.io-index" 2917 + checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" 2918 + 2919 + [[package]] 2920 + name = "unsigned-varint" 2921 + version = "0.8.0" 2922 + source = "registry+https://github.com/rust-lang/crates.io-index" 2923 + checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" 2924 + 2925 + [[package]] 1402 2926 name = "untrusted" 1403 2927 version = "0.9.0" 1404 2928 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1458 2982 1459 2983 [[package]] 1460 2984 name = "wasip2" 1461 - version = "1.0.1+wasi-0.2.4" 2985 + version = "1.0.2+wasi-0.2.9" 1462 2986 source = "registry+https://github.com/rust-lang/crates.io-index" 1463 - checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" 2987 + checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" 1464 2988 dependencies = [ 1465 2989 "wit-bindgen", 1466 2990 ] ··· 1511 3035 "bumpalo", 1512 3036 "proc-macro2", 1513 3037 "quote", 1514 - "syn", 3038 + "syn 2.0.114", 1515 3039 "wasm-bindgen-shared", 1516 3040 ] 1517 3041 ··· 1554 3078 ] 1555 3079 1556 3080 [[package]] 1557 - name = "which" 1558 - version = "7.0.3" 3081 + name = "windows-core" 3082 + version = "0.62.2" 3083 + source = "registry+https://github.com/rust-lang/crates.io-index" 3084 + checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" 3085 + dependencies = [ 3086 + "windows-implement", 3087 + "windows-interface", 3088 + "windows-link", 3089 + "windows-result", 3090 + "windows-strings", 3091 + ] 3092 + 3093 + [[package]] 3094 + name = "windows-implement" 3095 + version = "0.60.2" 3096 + source = "registry+https://github.com/rust-lang/crates.io-index" 3097 + checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" 3098 + dependencies = [ 3099 + "proc-macro2", 3100 + "quote", 3101 + "syn 2.0.114", 3102 + ] 3103 + 3104 + [[package]] 3105 + name = "windows-interface" 3106 + version = "0.59.3" 1559 3107 source = "registry+https://github.com/rust-lang/crates.io-index" 1560 - checksum = "24d643ce3fd3e5b54854602a080f34fb10ab75e0b813ee32d00ca2b44fa74762" 3108 + checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" 1561 3109 dependencies = [ 1562 - "either", 1563 - "env_home", 1564 - "rustix", 1565 - "winsafe", 3110 + "proc-macro2", 3111 + "quote", 3112 + "syn 2.0.114", 1566 3113 ] 1567 3114 1568 3115 [[package]] ··· 1572 3119 checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 1573 3120 1574 3121 [[package]] 3122 + name = "windows-registry" 3123 + version = "0.6.1" 3124 + source = "registry+https://github.com/rust-lang/crates.io-index" 3125 + checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" 3126 + dependencies = [ 3127 + "windows-link", 3128 + "windows-result", 3129 + "windows-strings", 3130 + ] 3131 + 3132 + [[package]] 3133 + name = "windows-result" 3134 + version = "0.4.1" 3135 + source = "registry+https://github.com/rust-lang/crates.io-index" 3136 + checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" 3137 + dependencies = [ 3138 + "windows-link", 3139 + ] 3140 + 3141 + [[package]] 3142 + name = "windows-strings" 3143 + version = "0.5.1" 3144 + source = "registry+https://github.com/rust-lang/crates.io-index" 3145 + checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" 3146 + dependencies = [ 3147 + "windows-link", 3148 + ] 3149 + 3150 + [[package]] 1575 3151 name = "windows-sys" 1576 3152 version = "0.52.0" 1577 3153 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1728 3304 checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" 1729 3305 1730 3306 [[package]] 1731 - name = "winsafe" 1732 - version = "0.0.19" 1733 - source = "registry+https://github.com/rust-lang/crates.io-index" 1734 - checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" 1735 - 1736 - [[package]] 1737 3307 name = "wit-bindgen" 1738 - version = "0.46.0" 3308 + version = "0.51.0" 1739 3309 source = "registry+https://github.com/rust-lang/crates.io-index" 1740 - checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" 3310 + checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" 1741 3311 1742 3312 [[package]] 1743 3313 name = "writeable" ··· 1746 3316 checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" 1747 3317 1748 3318 [[package]] 3319 + name = "yansi" 3320 + version = "1.0.1" 3321 + source = "registry+https://github.com/rust-lang/crates.io-index" 3322 + checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" 3323 + 3324 + [[package]] 1749 3325 name = "yoke" 1750 3326 version = "0.8.1" 1751 3327 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1764 3340 dependencies = [ 1765 3341 "proc-macro2", 1766 3342 "quote", 1767 - "syn", 3343 + "syn 2.0.114", 1768 3344 "synstructure", 1769 3345 ] 1770 3346 ··· 1785 3361 dependencies = [ 1786 3362 "proc-macro2", 1787 3363 "quote", 1788 - "syn", 3364 + "syn 2.0.114", 1789 3365 ] 1790 3366 1791 3367 [[package]] ··· 1805 3381 dependencies = [ 1806 3382 "proc-macro2", 1807 3383 "quote", 1808 - "syn", 3384 + "syn 2.0.114", 1809 3385 "synstructure", 1810 3386 ] 1811 3387 ··· 1845 3421 dependencies = [ 1846 3422 "proc-macro2", 1847 3423 "quote", 1848 - "syn", 3424 + "syn 2.0.114", 1849 3425 ] 1850 3426 1851 3427 [[package]] 1852 3428 name = "zmij" 1853 - version = "1.0.14" 3429 + version = "1.0.16" 1854 3430 source = "registry+https://github.com/rust-lang/crates.io-index" 1855 - checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea" 3431 + checksum = "dfcd145825aace48cff44a8844de64bf75feec3080e0aa5cdbde72961ae51a65"
+7 -29
Cargo.toml
··· 1 - [package] 2 - name = "tapped" 3 - version = "0.1.0" 4 - edition = "2021" 5 - description = "Rust wrapper for the tap ATProto utility" 6 - license = "MIT" 7 - readme = "README.md" 8 - authors = ["Thomas Karpiniec <tom.karpiniec@outlook.com>"] 9 - keywords = ["atproto", "tap"] 10 - repository = "https://github.com/thombles/tapped" 11 - 12 - [dependencies] 13 - tokio = { version = "1", features = ["net", "process", "rt", "sync", "time"] } 14 - reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json"] } 15 - tokio-tungstenite = { version = "0.26", features = ["rustls-tls-native-roots"] } 16 - serde = { version = "1", features = ["derive"] } 17 - serde_json = "1" 18 - thiserror = "2" 19 - url = { version = "2", features = ["serde"] } 20 - futures-util = "0.3" 21 - tracing = "0.1" 22 - base64 = "0.22" 23 - libc = "0.2" 24 - 25 - [dev-dependencies] 26 - tokio = { version = "1", features = ["macros", "rt-multi-thread"] } 27 - which = "7" 28 - env_logger = "0.11" 29 - log = "0.4" 1 + [workspace] 2 + members = [ 3 + "tapped", 4 + "lexicons-example", 5 + "standard-site-sync", 6 + ] 7 + resolver = "2"
+50 -28
README.md
··· 20 20 21 21 ```toml 22 22 [dependencies] 23 - tapped = "0.1" 23 + tapped = "0.2" 24 24 ``` 25 25 26 26 You'll also need the `tap` binary. Build it from the [indigo repository](https://github.com/bluesky-social/indigo): ··· 32 32 `tapped` has been most recently tested against: 33 33 34 34 ``` 35 - tap version v0.0.0-20260114211028-207c9d49d0de-rev-207c9d4 35 + tap version v0.0.0-20260120225912-12d69fa4d209-rev-12d69fa 36 36 ``` 37 37 38 38 ## Quick Start ··· 56 56 while let Ok(received) = channel.recv().await { 57 57 match &received.event { 58 58 Event::Record(record) => { 59 - println!("[{}] {}/{}", 60 - record.action, 61 - record.collection, 59 + println!("[{:?}] {}/{}", 60 + record.action, 61 + record.collection, 62 62 record.rkey 63 63 ); 64 64 } ··· 96 96 .build(); 97 97 98 98 let mut process = TapProcess::spawn("/path/to/tap", config).await?; 99 - let client = process.client(); 99 + let client = process.client()?; 100 100 101 101 // Use the client... 102 102 ··· 136 136 137 137 // Network 138 138 .bind("127.0.0.1:2480") 139 - .relay_url("wss://bsky.network") 140 - .plc_url("https://plc.directory") 139 + .relay_url("wss://bsky.network".parse().unwrap()) 140 + .plc_url("https://plc.directory".parse().unwrap()) 141 141 142 142 // Filtering 143 143 .signal_collection("app.bsky.feed.post") ··· 176 176 Event::Record(record) => { 177 177 match record.action { 178 178 RecordAction::Create => { 179 - if let Some(ref rec) = record.record { 180 - // Access the raw JSON 181 - println!("Type: {:?}", rec.record_type()); 182 - 183 - // Or deserialize to a specific type 184 - // let post: MyPostType = rec.deserialize_as()?; 179 + // Access the raw JSON as a string 180 + if let Some(json) = record.record_as_str() { 181 + println!("Raw JSON: {}", json); 185 182 } 183 + 184 + // Or deserialize to a specific type 185 + // let post: MyPostType = record.deserialize_as()?; 186 186 } 187 187 RecordAction::Update => { /* ... */ } 188 188 RecordAction::Delete => { /* ... */ } ··· 229 229 println!("Firehose cursor: {:?}", cursors.firehose); 230 230 ``` 231 231 232 - ## Error Handling 232 + ## Example: Syncing standard.site Records with Schema Generation and Validation 233 233 234 - All operations return `tapped::Result<T>`, which uses the `tapped::Error` enum: 234 + The repository includes a complete example demonstrating how to sync and validate ATProto records using `tapped` together with the [jacquard](https://crates.io/crates/jacquard) crates. 235 235 236 - ```rust 237 - use tapped::Error; 236 + The jacquard ecosystem provides runtime validation of records against their lexicon constraints, and the ability to generate Rust structs from lexicon JSON files. 238 237 239 - match client.health().await { 240 - Ok(()) => println!("Healthy!"), 241 - Err(Error::Http(e)) => println!("HTTP error: {}", e), 242 - Err(Error::Timeout) => println!("Request timed out"), 243 - Err(e) => println!("Other error: {}", e), 244 - } 238 + ``` 239 + tapped/ 240 + ├── tapped/ # The main tapped library 241 + ├── lexicons-example/ # Generated types from lexicon schemas 242 + │ ├── lexicons/ # Source lexicon JSON files 243 + │ │ ├── site.standard.publication.json 244 + │ │ ├── site.standard.document.json 245 + │ │ └── ... 246 + │ └── src/ # Generated Rust code 247 + └── standard-site-sync/ # Example binary using both packages 248 + ``` 249 + 250 + These files were generated like so: 251 + 252 + ```bash 253 + # Install the code generator 254 + cargo install jacquard-lexgen 255 + 256 + jacquard-codegen -i lexicons-example/lexicons -o lexicons-example/src 245 257 ``` 246 258 247 - ## Example: Syncing Standard Site Records 259 + This produces strongly-typed structs with built-in validation. For example, the `site.standard.publication` lexicon becomes: 248 260 249 - See [examples/standard_site_sync.rs](examples/standard_site_sync.rs) for a complete example that syncs `site.standard.publication` and `site.standard.document` records to local files. 261 + ```rust 262 + use lexicons_example::site_standard::publication::Publication; 263 + 264 + // Deserialize from JSON 265 + let publication: Publication = serde_json::from_str(json)?; 266 + 267 + // Validate against lexicon constraints (max length, grapheme limits, etc.) 268 + publication.validate()?; 250 269 251 - ```bash 252 - cargo run --example standard_site_sync 270 + // Access typed fields 271 + println!("Name: {}", publication.name.as_str()); 272 + println!("URL: {}", publication.url.as_str()); 253 273 ``` 274 + 275 + For more details see `process_record_event` [in `main.rs`](https://tangled.org/octet-stream.net/tapped/blob/main/standard-site-sync/src/main.rs). 254 276 255 277 ## License 256 278
-295
examples/standard_site_sync.rs
··· 1 - //! Example: Sync site.standard.publication and site.standard.document records. 2 - //! 3 - //! This example demonstrates using tapped to track publication and document 4 - //! records from the ATProto network. It maintains an on-disk cache and 5 - //! writes URL lists to disk on each change for inspection. 6 - //! 7 - //! Run with: `RUST_LOG=info cargo run --example standard_site_sync` 8 - 9 - use std::collections::HashMap; 10 - use std::fs; 11 - 12 - use log::info; 13 - use serde::{Deserialize, Serialize}; 14 - use tapped::{Event, RecordAction, RecordEvent, TapConfig, TapProcess}; 15 - 16 - /// A site.standard.publication record (subset of fields). 17 - #[derive(Debug, Deserialize)] 18 - struct Publication { 19 - url: String, 20 - name: String, 21 - } 22 - 23 - /// A site.standard.document record (subset of fields). 24 - #[derive(Debug, Deserialize)] 25 - struct Document { 26 - site: String, 27 - title: String, 28 - #[serde(default)] 29 - path: Option<String>, 30 - } 31 - 32 - /// Key for storing records in cache. 33 - #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] 34 - struct RecordKey { 35 - did: String, 36 - collection: String, 37 - rkey: String, 38 - } 39 - 40 - impl RecordKey { 41 - fn new(event: &RecordEvent) -> Self { 42 - Self { 43 - did: event.did.clone(), 44 - collection: event.collection.clone(), 45 - rkey: event.rkey.clone(), 46 - } 47 - } 48 - } 49 - 50 - /// Cached record data. 51 - #[derive(Debug, Clone, Serialize, Deserialize)] 52 - #[serde(tag = "type")] 53 - enum CachedRecord { 54 - Publication { url: String }, 55 - Document { site: String, path: Option<String> }, 56 - } 57 - 58 - fn main() -> Result<(), Box<dyn std::error::Error>> { 59 - tokio::runtime::Builder::new_multi_thread() 60 - .enable_all() 61 - .build()? 62 - .block_on(async_main()) 63 - } 64 - 65 - async fn async_main() -> Result<(), Box<dyn std::error::Error>> { 66 - env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")) 67 - .format_timestamp_secs() 68 - .init(); 69 - 70 - info!("Starting standard.site sync example"); 71 - 72 - let config = TapConfig::builder() 73 - .database_url("sqlite://./tap-example.db") 74 - .bind(":2480") 75 - .signal_collection("site.standard.publication") 76 - .collection_filters(vec![ 77 - "site.standard.publication".to_string(), 78 - "site.standard.document".to_string(), 79 - ]) 80 - .disable_acks(false) 81 - .inherit_stdio(true) 82 - .build(); 83 - 84 - info!("Spawning tap process..."); 85 - 86 - // Spawn tap (looks for ./tap first, then tap on PATH) 87 - let process = TapProcess::spawn_default(config).await?; 88 - info!("Tap running at {}", process.url()); 89 - 90 - let client = process.client()?; 91 - client.health().await?; 92 - info!("Tap is healthy!"); 93 - 94 - let mut receiver = client.channel().await?; 95 - info!("Connected! Waiting for events..."); 96 - 97 - // In-memory cache - load from disk if available 98 - let mut cache: HashMap<RecordKey, CachedRecord> = load_cache_from_disk(); 99 - let (pub_count, doc_count) = count_cached(&cache); 100 - info!( 101 - "Loaded cache from disk: {} publications, {} documents", 102 - pub_count, doc_count 103 - ); 104 - 105 - let mut live_count = 0u64; 106 - let mut backfill_count = 0u64; 107 - 108 - loop { 109 - match receiver.recv().await { 110 - Ok(received) => { 111 - if let Event::Record(ref record_event) = *received { 112 - // Track live vs backfill 113 - if record_event.live { 114 - live_count += 1; 115 - } else { 116 - backfill_count += 1; 117 - } 118 - 119 - process_record_event(record_event, &mut cache); 120 - write_output_files(&cache)?; 121 - 122 - // Periodically show event source breakdown 123 - if (live_count + backfill_count).is_multiple_of(100) { 124 - info!( 125 - "[Stats] Live events: {}, Backfill events: {}", 126 - live_count, backfill_count 127 - ); 128 - } 129 - } else if let Event::Identity(ref identity_event) = *received { 130 - info!( 131 - "[IDENTITY] {} -> {} (active: {})", 132 - identity_event.did, identity_event.handle, identity_event.is_active 133 - ); 134 - } 135 - // Event is automatically acked when `received` is dropped here 136 - } 137 - Err(e) => { 138 - eprintln!("Error receiving event: {}", e); 139 - break; 140 - } 141 - } 142 - } 143 - 144 - Ok(()) 145 - } 146 - 147 - fn process_record_event(event: &RecordEvent, cache: &mut HashMap<RecordKey, CachedRecord>) { 148 - let key = RecordKey::new(event); 149 - let action_str = match event.action { 150 - RecordAction::Create => "CREATE", 151 - RecordAction::Update => "UPDATE", 152 - RecordAction::Delete => "DELETE", 153 - _ => "UNKNOWN", 154 - }; 155 - 156 - // Show whether this is a live or backfill event 157 - let source = if event.live { "LIVE" } else { "BACKFILL" }; 158 - 159 - info!( 160 - "[{} {}] {} {}/{}", 161 - action_str, source, event.did, event.collection, event.rkey 162 - ); 163 - 164 - match event.action { 165 - RecordAction::Create | RecordAction::Update => { 166 - if let Some(ref record) = event.record { 167 - match event.collection.as_str() { 168 - "site.standard.publication" => match record.deserialize_as::<Publication>() { 169 - Ok(pub_record) => { 170 - info!("Publication: {} ({})", pub_record.name, pub_record.url); 171 - cache.insert( 172 - key, 173 - CachedRecord::Publication { 174 - url: pub_record.url, 175 - }, 176 - ); 177 - } 178 - Err(e) => { 179 - log::error!("Failed to parse publication: {}", e); 180 - } 181 - }, 182 - "site.standard.document" => match record.deserialize_as::<Document>() { 183 - Ok(doc_record) => { 184 - let full_url = match &doc_record.path { 185 - Some(path) if !path.is_empty() => { 186 - format!( 187 - "{}/{}", 188 - doc_record.site.trim_end_matches('/'), 189 - path.trim_start_matches('/') 190 - ) 191 - } 192 - _ => doc_record.site.clone(), 193 - }; 194 - info!("Document: {} ({})", doc_record.title, full_url); 195 - cache.insert( 196 - key, 197 - CachedRecord::Document { 198 - site: doc_record.site, 199 - path: doc_record.path, 200 - }, 201 - ); 202 - } 203 - Err(e) => { 204 - log::error!("Failed to parse document: {}", e); 205 - } 206 - }, 207 - _ => {} 208 - } 209 - } 210 - } 211 - RecordAction::Delete => { 212 - cache.remove(&key); 213 - } 214 - _ => {} 215 - } 216 - 217 - // Log cache stats 218 - let (pub_count, doc_count) = count_cached(cache); 219 - info!( 220 - "Cached: {} publications, {} documents", 221 - pub_count, doc_count 222 - ); 223 - } 224 - 225 - fn count_cached(cache: &HashMap<RecordKey, CachedRecord>) -> (usize, usize) { 226 - let mut publications = 0; 227 - let mut documents = 0; 228 - 229 - for record in cache.values() { 230 - match record { 231 - CachedRecord::Publication { .. } => publications += 1, 232 - CachedRecord::Document { .. } => documents += 1, 233 - } 234 - } 235 - 236 - (publications, documents) 237 - } 238 - 239 - fn write_output_files(cache: &HashMap<RecordKey, CachedRecord>) -> Result<(), std::io::Error> { 240 - let mut publication_urls: Vec<&str> = Vec::new(); 241 - let mut document_urls: Vec<String> = Vec::new(); 242 - 243 - for record in cache.values() { 244 - match record { 245 - CachedRecord::Publication { url } => { 246 - publication_urls.push(url); 247 - } 248 - CachedRecord::Document { site, path } => { 249 - let full_url = match path { 250 - Some(p) if !p.is_empty() => { 251 - format!( 252 - "{}/{}", 253 - site.trim_end_matches('/'), 254 - p.trim_start_matches('/') 255 - ) 256 - } 257 - _ => site.clone(), 258 - }; 259 - document_urls.push(full_url); 260 - } 261 - } 262 - } 263 - 264 - publication_urls.sort(); 265 - document_urls.sort(); 266 - 267 - fs::write("publications.txt", publication_urls.join("\n"))?; 268 - 269 - // Write documents.txt (publication + document URLs combined) 270 - let mut all_urls: Vec<String> = publication_urls.iter().map(|s| s.to_string()).collect(); 271 - all_urls.extend(document_urls); 272 - all_urls.sort(); 273 - all_urls.dedup(); 274 - fs::write("documents.txt", all_urls.join("\n"))?; 275 - 276 - // Write cache.json for persistence 277 - let cache_entries: Vec<(&RecordKey, &CachedRecord)> = cache.iter().collect(); 278 - let cache_json = serde_json::to_string_pretty(&cache_entries).map_err(std::io::Error::other)?; 279 - fs::write("cache.json", cache_json)?; 280 - 281 - Ok(()) 282 - } 283 - 284 - fn load_cache_from_disk() -> HashMap<RecordKey, CachedRecord> { 285 - match fs::read_to_string("cache.json") { 286 - Ok(content) => match serde_json::from_str::<Vec<(RecordKey, CachedRecord)>>(&content) { 287 - Ok(entries) => entries.into_iter().collect(), 288 - Err(e) => { 289 - log::warn!("Failed to parse cache.json: {}", e); 290 - HashMap::new() 291 - } 292 - }, 293 - Err(_) => HashMap::new(), 294 - } 295 - }
+29
lexicons-example/Cargo.toml
··· 1 + [package] 2 + name = "lexicons-example" 3 + version = "0.1.0" 4 + edition = "2021" 5 + license = "MIT" 6 + description = "Generated lexicon types for standard.site" 7 + authors = ["Thomas Karpiniec <tom.karpiniec@fastmail.com.au>"] 8 + publish = false 9 + 10 + [dependencies] 11 + jacquard-common = "0.9.5" 12 + jacquard-lexicon = "0.9.5" 13 + jacquard-derive = "0.9.5" 14 + serde = { version = "1", features = ["derive"] } 15 + rustversion = "1.0" 16 + unicode-segmentation = "1.12" 17 + 18 + [features] 19 + default = ["com_atproto", "site_standard"] 20 + com_atproto = [] 21 + site_standard = [] 22 + 23 + [lints.rust] 24 + non_snake_case = "allow" 25 + 26 + [lints.clippy] 27 + new_ret_no_self = "allow" 28 + new_without_default = "allow" 29 + type_complexity = "allow"
+15
lexicons-example/lexicons/com.atproto.repo.strongRef.json
··· 1 + { 2 + "lexicon": 1, 3 + "id": "com.atproto.repo.strongRef", 4 + "description": "A URI with a content-hash fingerprint.", 5 + "defs": { 6 + "main": { 7 + "type": "object", 8 + "required": ["uri", "cid"], 9 + "properties": { 10 + "uri": { "type": "string", "format": "at-uri" }, 11 + "cid": { "type": "string", "format": "cid" } 12 + } 13 + } 14 + } 15 + }
+74
lexicons-example/lexicons/site.standard.document.json
··· 1 + { 2 + "defs": { 3 + "main": { 4 + "key": "tid", 5 + "record": { 6 + "properties": { 7 + "bskyPostRef": { 8 + "ref": "com.atproto.repo.strongRef", 9 + "type": "ref" 10 + }, 11 + "content": { 12 + "closed": false, 13 + "refs": [], 14 + "type": "union" 15 + }, 16 + "coverImage": { 17 + "accept": [ 18 + "image/*" 19 + ], 20 + "maxSize": 1000000, 21 + "type": "blob" 22 + }, 23 + "description": { 24 + "maxGraphemes": 300, 25 + "maxLength": 3000, 26 + "type": "string" 27 + }, 28 + "path": { 29 + "description": "combine with the publication url or the document site to construct a full url to the document", 30 + "type": "string" 31 + }, 32 + "publishedAt": { 33 + "format": "datetime", 34 + "type": "string" 35 + }, 36 + "site": { 37 + "description": "URI to the site or publication this document belongs to (https or at-uri)", 38 + "format": "uri", 39 + "type": "string" 40 + }, 41 + "tags": { 42 + "items": { 43 + "maxGraphemes": 50, 44 + "maxLength": 100, 45 + "type": "string" 46 + }, 47 + "type": "array" 48 + }, 49 + "textContent": { 50 + "type": "string" 51 + }, 52 + "title": { 53 + "maxGraphemes": 128, 54 + "maxLength": 1280, 55 + "type": "string" 56 + }, 57 + "updatedAt": { 58 + "format": "datetime", 59 + "type": "string" 60 + } 61 + }, 62 + "required": [ 63 + "site", 64 + "title", 65 + "publishedAt" 66 + ], 67 + "type": "object" 68 + }, 69 + "type": "record" 70 + } 71 + }, 72 + "id": "site.standard.document", 73 + "lexicon": 1 74 + }
+24
lexicons-example/lexicons/site.standard.graph.subscription.json
··· 1 + { 2 + "id": "site.standard.graph.subscription", 3 + "defs": { 4 + "main": { 5 + "key": "tid", 6 + "type": "record", 7 + "record": { 8 + "type": "object", 9 + "required": [ 10 + "publication" 11 + ], 12 + "properties": { 13 + "publication": { 14 + "type": "string", 15 + "format": "at-uri", 16 + "description": "AT-URI reference to the publication record being subscribed to (ex: at://did:plc:abc123/site.standard.publication/xyz789)." 17 + } 18 + } 19 + }, 20 + "description": "Record declaring a subscription to a publication" 21 + } 22 + }, 23 + "lexicon": 1 24 + }
+57
lexicons-example/lexicons/site.standard.publication.json
··· 1 + { 2 + "defs": { 3 + "main": { 4 + "key": "tid", 5 + "record": { 6 + "properties": { 7 + "basicTheme": { 8 + "ref": "site.standard.theme.basic", 9 + "type": "ref" 10 + }, 11 + "description": { 12 + "maxGraphemes": 300, 13 + "maxLength": 3000, 14 + "type": "string" 15 + }, 16 + "icon": { 17 + "accept": [ 18 + "image/*" 19 + ], 20 + "maxSize": 1000000, 21 + "type": "blob" 22 + }, 23 + "name": { 24 + "maxGraphemes": 128, 25 + "maxLength": 1280, 26 + "type": "string" 27 + }, 28 + "preferences": { 29 + "ref": "#preferences", 30 + "type": "ref" 31 + }, 32 + "url": { 33 + "format": "uri", 34 + "type": "string" 35 + } 36 + }, 37 + "required": [ 38 + "url", 39 + "name" 40 + ], 41 + "type": "object" 42 + }, 43 + "type": "record" 44 + }, 45 + "preferences": { 46 + "properties": { 47 + "showInDiscover": { 48 + "default": true, 49 + "type": "boolean" 50 + } 51 + }, 52 + "type": "object" 53 + } 54 + }, 55 + "id": "site.standard.publication", 56 + "lexicon": 1 57 + }
+46
lexicons-example/lexicons/site.standard.theme.basic.json
··· 1 + { 2 + "id": "site.standard.theme.basic", 3 + "defs": { 4 + "main": { 5 + "type": "object", 6 + "required": [ 7 + "background", 8 + "foreground", 9 + "accent", 10 + "accentForeground" 11 + ], 12 + "properties": { 13 + "accent": { 14 + "refs": [ 15 + "site.standard.theme.color#rgb" 16 + ], 17 + "type": "union", 18 + "description": "Color used for links and button backgrounds." 19 + }, 20 + "background": { 21 + "refs": [ 22 + "site.standard.theme.color#rgb" 23 + ], 24 + "type": "union", 25 + "description": "Color used for content background." 26 + }, 27 + "foreground": { 28 + "refs": [ 29 + "site.standard.theme.color#rgb" 30 + ], 31 + "type": "union", 32 + "description": "Color used for content text." 33 + }, 34 + "accentForeground": { 35 + "refs": [ 36 + "site.standard.theme.color#rgb" 37 + ], 38 + "type": "union", 39 + "description": "Color used for button text." 40 + } 41 + }, 42 + "description": "A simplified theme definition for publications, providing basic color customization for content display across different platforms and applications." 43 + } 44 + }, 45 + "lexicon": 1 46 + }
+62
lexicons-example/lexicons/site.standard.theme.color.json
··· 1 + { 2 + "id": "site.standard.theme.color", 3 + "defs": { 4 + "rgb": { 5 + "type": "object", 6 + "required": [ 7 + "r", 8 + "g", 9 + "b" 10 + ], 11 + "properties": { 12 + "b": { 13 + "type": "integer", 14 + "maximum": 255, 15 + "minimum": 0 16 + }, 17 + "g": { 18 + "type": "integer", 19 + "maximum": 255, 20 + "minimum": 0 21 + }, 22 + "r": { 23 + "type": "integer", 24 + "maximum": 255, 25 + "minimum": 0 26 + } 27 + } 28 + }, 29 + "rgba": { 30 + "type": "object", 31 + "required": [ 32 + "r", 33 + "g", 34 + "b", 35 + "a" 36 + ], 37 + "properties": { 38 + "a": { 39 + "type": "integer", 40 + "maximum": 100, 41 + "minimum": 0 42 + }, 43 + "b": { 44 + "type": "integer", 45 + "maximum": 255, 46 + "minimum": 0 47 + }, 48 + "g": { 49 + "type": "integer", 50 + "maximum": 255, 51 + "minimum": 0 52 + }, 53 + "r": { 54 + "type": "integer", 55 + "maximum": 255, 56 + "minimum": 0 57 + } 58 + } 59 + } 60 + }, 61 + "lexicon": 1 62 + }
+43
lexicons-example/src/builder_types.rs
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // This file was automatically generated from Lexicon schemas. 4 + // Any manual changes will be overwritten on the next regeneration. 5 + 6 + /// Marker type indicating a builder field has been set 7 + pub struct Set<T>(pub T); 8 + impl<T> Set<T> { 9 + /// Extract the inner value 10 + #[inline] 11 + pub fn into_inner(self) -> T { 12 + self.0 13 + } 14 + } 15 + 16 + /// Marker type indicating a builder field has not been set 17 + pub struct Unset; 18 + /// Trait indicating a builder field is set (has a value) 19 + #[rustversion::attr( 20 + since(1.78.0), 21 + diagnostic::on_unimplemented( 22 + message = "the field `{Self}` was not set, but this method requires it to be set", 23 + label = "the field `{Self}` was not set" 24 + ) 25 + )] 26 + pub trait IsSet: private::Sealed {} 27 + /// Trait indicating a builder field is unset (no value yet) 28 + #[rustversion::attr( 29 + since(1.78.0), 30 + diagnostic::on_unimplemented( 31 + message = "the field `{Self}` was already set, but this method requires it to be unset", 32 + label = "the field `{Self}` was already set" 33 + ) 34 + )] 35 + pub trait IsUnset: private::Sealed {} 36 + impl<T> IsSet for Set<T> {} 37 + impl IsUnset for Unset {} 38 + mod private { 39 + /// Sealed trait to prevent external implementations 40 + pub trait Sealed {} 41 + impl<T> Sealed for super::Set<T> {} 42 + impl Sealed for super::Unset {} 43 + }
+6
lexicons-example/src/com_atproto.rs
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // This file was automatically generated from Lexicon schemas. 4 + // Any manual changes will be overwritten on the next regeneration. 5 + 6 + pub mod repo;
+6
lexicons-example/src/com_atproto/repo.rs
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // This file was automatically generated from Lexicon schemas. 4 + // Any manual changes will be overwritten on the next regeneration. 5 + 6 + pub mod strong_ref;
+244
lexicons-example/src/com_atproto/repo/strong_ref.rs
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // Lexicon: com.atproto.repo.strongRef 4 + // 5 + // This file was automatically generated from Lexicon schemas. 6 + // Any manual changes will be overwritten on the next regeneration. 7 + 8 + #[jacquard_derive::lexicon] 9 + #[derive( 10 + serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq, jacquard_derive::IntoStatic, 11 + )] 12 + #[serde(rename_all = "camelCase")] 13 + pub struct StrongRef<'a> { 14 + #[serde(borrow)] 15 + pub cid: jacquard_common::types::string::Cid<'a>, 16 + #[serde(borrow)] 17 + pub uri: jacquard_common::types::string::AtUri<'a>, 18 + } 19 + 20 + pub mod strong_ref_state { 21 + 22 + pub use crate::builder_types::{IsSet, IsUnset, Set, Unset}; 23 + #[allow(unused)] 24 + use ::core::marker::PhantomData; 25 + mod sealed { 26 + pub trait Sealed {} 27 + } 28 + /// State trait tracking which required fields have been set 29 + pub trait State: sealed::Sealed { 30 + type Uri; 31 + type Cid; 32 + } 33 + /// Empty state - all required fields are unset 34 + pub struct Empty(()); 35 + impl sealed::Sealed for Empty {} 36 + impl State for Empty { 37 + type Uri = Unset; 38 + type Cid = Unset; 39 + } 40 + ///State transition - sets the `uri` field to Set 41 + pub struct SetUri<S: State = Empty>(PhantomData<fn() -> S>); 42 + impl<S: State> sealed::Sealed for SetUri<S> {} 43 + impl<S: State> State for SetUri<S> { 44 + type Uri = Set<members::uri>; 45 + type Cid = S::Cid; 46 + } 47 + ///State transition - sets the `cid` field to Set 48 + pub struct SetCid<S: State = Empty>(PhantomData<fn() -> S>); 49 + impl<S: State> sealed::Sealed for SetCid<S> {} 50 + impl<S: State> State for SetCid<S> { 51 + type Uri = S::Uri; 52 + type Cid = Set<members::cid>; 53 + } 54 + /// Marker types for field names 55 + #[allow(non_camel_case_types)] 56 + pub mod members { 57 + ///Marker type for the `uri` field 58 + pub struct uri(()); 59 + ///Marker type for the `cid` field 60 + pub struct cid(()); 61 + } 62 + } 63 + 64 + /// Builder for constructing an instance of this type 65 + pub struct StrongRefBuilder<'a, S: strong_ref_state::State> { 66 + _phantom_state: ::core::marker::PhantomData<fn() -> S>, 67 + __unsafe_private_named: ( 68 + ::core::option::Option<jacquard_common::types::string::Cid<'a>>, 69 + ::core::option::Option<jacquard_common::types::string::AtUri<'a>>, 70 + ), 71 + _phantom: ::core::marker::PhantomData<&'a ()>, 72 + } 73 + 74 + impl<'a> StrongRef<'a> { 75 + /// Create a new builder for this type 76 + pub fn new() -> StrongRefBuilder<'a, strong_ref_state::Empty> { 77 + StrongRefBuilder::new() 78 + } 79 + } 80 + 81 + impl<'a> StrongRefBuilder<'a, strong_ref_state::Empty> { 82 + /// Create a new builder with all fields unset 83 + pub fn new() -> Self { 84 + StrongRefBuilder { 85 + _phantom_state: ::core::marker::PhantomData, 86 + __unsafe_private_named: (None, None), 87 + _phantom: ::core::marker::PhantomData, 88 + } 89 + } 90 + } 91 + 92 + impl<'a, S> StrongRefBuilder<'a, S> 93 + where 94 + S: strong_ref_state::State, 95 + S::Cid: strong_ref_state::IsUnset, 96 + { 97 + /// Set the `cid` field (required) 98 + pub fn cid( 99 + mut self, 100 + value: impl Into<jacquard_common::types::string::Cid<'a>>, 101 + ) -> StrongRefBuilder<'a, strong_ref_state::SetCid<S>> { 102 + self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into()); 103 + StrongRefBuilder { 104 + _phantom_state: ::core::marker::PhantomData, 105 + __unsafe_private_named: self.__unsafe_private_named, 106 + _phantom: ::core::marker::PhantomData, 107 + } 108 + } 109 + } 110 + 111 + impl<'a, S> StrongRefBuilder<'a, S> 112 + where 113 + S: strong_ref_state::State, 114 + S::Uri: strong_ref_state::IsUnset, 115 + { 116 + /// Set the `uri` field (required) 117 + pub fn uri( 118 + mut self, 119 + value: impl Into<jacquard_common::types::string::AtUri<'a>>, 120 + ) -> StrongRefBuilder<'a, strong_ref_state::SetUri<S>> { 121 + self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into()); 122 + StrongRefBuilder { 123 + _phantom_state: ::core::marker::PhantomData, 124 + __unsafe_private_named: self.__unsafe_private_named, 125 + _phantom: ::core::marker::PhantomData, 126 + } 127 + } 128 + } 129 + 130 + impl<'a, S> StrongRefBuilder<'a, S> 131 + where 132 + S: strong_ref_state::State, 133 + S::Uri: strong_ref_state::IsSet, 134 + S::Cid: strong_ref_state::IsSet, 135 + { 136 + /// Build the final struct 137 + pub fn build(self) -> StrongRef<'a> { 138 + StrongRef { 139 + cid: self.__unsafe_private_named.0.unwrap(), 140 + uri: self.__unsafe_private_named.1.unwrap(), 141 + extra_data: Default::default(), 142 + } 143 + } 144 + /// Build the final struct with custom extra_data 145 + pub fn build_with_data( 146 + self, 147 + extra_data: std::collections::BTreeMap< 148 + jacquard_common::smol_str::SmolStr, 149 + jacquard_common::types::value::Data<'a>, 150 + >, 151 + ) -> StrongRef<'a> { 152 + StrongRef { 153 + cid: self.__unsafe_private_named.0.unwrap(), 154 + uri: self.__unsafe_private_named.1.unwrap(), 155 + extra_data: Some(extra_data), 156 + } 157 + } 158 + } 159 + 160 + fn lexicon_doc_com_atproto_repo_strongRef() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> { 161 + ::jacquard_lexicon::lexicon::LexiconDoc { 162 + lexicon: ::jacquard_lexicon::lexicon::Lexicon::Lexicon1, 163 + id: ::jacquard_common::CowStr::new_static("com.atproto.repo.strongRef"), 164 + revision: None, 165 + description: None, 166 + defs: { 167 + let mut map = ::std::collections::BTreeMap::new(); 168 + map.insert( 169 + ::jacquard_common::smol_str::SmolStr::new_static("main"), 170 + ::jacquard_lexicon::lexicon::LexUserType::Object( 171 + ::jacquard_lexicon::lexicon::LexObject { 172 + description: None, 173 + required: Some(vec![ 174 + ::jacquard_common::smol_str::SmolStr::new_static("uri"), 175 + ::jacquard_common::smol_str::SmolStr::new_static("cid"), 176 + ]), 177 + nullable: None, 178 + properties: { 179 + #[allow(unused_mut)] 180 + let mut map = ::std::collections::BTreeMap::new(); 181 + map.insert( 182 + ::jacquard_common::smol_str::SmolStr::new_static("cid"), 183 + ::jacquard_lexicon::lexicon::LexObjectProperty::String( 184 + ::jacquard_lexicon::lexicon::LexString { 185 + description: None, 186 + format: Some( 187 + ::jacquard_lexicon::lexicon::LexStringFormat::Cid, 188 + ), 189 + default: None, 190 + min_length: None, 191 + max_length: None, 192 + min_graphemes: None, 193 + max_graphemes: None, 194 + r#enum: None, 195 + r#const: None, 196 + known_values: None, 197 + }, 198 + ), 199 + ); 200 + map.insert( 201 + ::jacquard_common::smol_str::SmolStr::new_static("uri"), 202 + ::jacquard_lexicon::lexicon::LexObjectProperty::String( 203 + ::jacquard_lexicon::lexicon::LexString { 204 + description: None, 205 + format: Some( 206 + ::jacquard_lexicon::lexicon::LexStringFormat::AtUri, 207 + ), 208 + default: None, 209 + min_length: None, 210 + max_length: None, 211 + min_graphemes: None, 212 + max_graphemes: None, 213 + r#enum: None, 214 + r#const: None, 215 + known_values: None, 216 + }, 217 + ), 218 + ); 219 + map 220 + }, 221 + }, 222 + ), 223 + ); 224 + map 225 + }, 226 + } 227 + } 228 + 229 + impl<'a> ::jacquard_lexicon::schema::LexiconSchema for StrongRef<'a> { 230 + fn nsid() -> &'static str { 231 + "com.atproto.repo.strongRef" 232 + } 233 + fn def_name() -> &'static str { 234 + "main" 235 + } 236 + fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> { 237 + lexicon_doc_com_atproto_repo_strongRef() 238 + } 239 + fn validate( 240 + &self, 241 + ) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> { 242 + Ok(()) 243 + } 244 + }
+12
lexicons-example/src/lib.rs
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // This file was automatically generated from Lexicon schemas. 4 + // Any manual changes will be overwritten on the next regeneration. 5 + 6 + pub mod builder_types; 7 + 8 + #[cfg(feature = "com_atproto")] 9 + pub mod com_atproto; 10 + 11 + #[cfg(feature = "site_standard")] 12 + pub mod site_standard;
+9
lexicons-example/src/site_standard.rs
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // This file was automatically generated from Lexicon schemas. 4 + // Any manual changes will be overwritten on the next regeneration. 5 + 6 + pub mod document; 7 + pub mod graph; 8 + pub mod publication; 9 + pub mod theme;
+714
lexicons-example/src/site_standard/document.rs
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // Lexicon: site.standard.document 4 + // 5 + // This file was automatically generated from Lexicon schemas. 6 + // Any manual changes will be overwritten on the next regeneration. 7 + 8 + #[jacquard_derive::lexicon] 9 + #[derive( 10 + serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq, jacquard_derive::IntoStatic, 11 + )] 12 + #[serde(rename_all = "camelCase")] 13 + pub struct Document<'a> { 14 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 15 + #[serde(borrow)] 16 + pub bsky_post_ref: std::option::Option<crate::com_atproto::repo::strong_ref::StrongRef<'a>>, 17 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 18 + #[serde(borrow)] 19 + pub content: std::option::Option<jacquard_common::types::value::Data<'a>>, 20 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 21 + #[serde(borrow)] 22 + pub cover_image: std::option::Option<jacquard_common::types::blob::BlobRef<'a>>, 23 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 24 + #[serde(borrow)] 25 + pub description: std::option::Option<jacquard_common::CowStr<'a>>, 26 + /// combine with the publication url or the document site to construct a full url to the document 27 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 28 + #[serde(borrow)] 29 + pub path: std::option::Option<jacquard_common::CowStr<'a>>, 30 + pub published_at: jacquard_common::types::string::Datetime, 31 + /// URI to the site or publication this document belongs to (https or at-uri) 32 + #[serde(borrow)] 33 + pub site: jacquard_common::types::string::Uri<'a>, 34 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 35 + #[serde(borrow)] 36 + pub tags: std::option::Option<Vec<jacquard_common::CowStr<'a>>>, 37 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 38 + #[serde(borrow)] 39 + pub text_content: std::option::Option<jacquard_common::CowStr<'a>>, 40 + #[serde(borrow)] 41 + pub title: jacquard_common::CowStr<'a>, 42 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 43 + pub updated_at: std::option::Option<jacquard_common::types::string::Datetime>, 44 + } 45 + 46 + pub mod document_state { 47 + 48 + pub use crate::builder_types::{IsSet, IsUnset, Set, Unset}; 49 + #[allow(unused)] 50 + use ::core::marker::PhantomData; 51 + mod sealed { 52 + pub trait Sealed {} 53 + } 54 + /// State trait tracking which required fields have been set 55 + pub trait State: sealed::Sealed { 56 + type Title; 57 + type Site; 58 + type PublishedAt; 59 + } 60 + /// Empty state - all required fields are unset 61 + pub struct Empty(()); 62 + impl sealed::Sealed for Empty {} 63 + impl State for Empty { 64 + type Title = Unset; 65 + type Site = Unset; 66 + type PublishedAt = Unset; 67 + } 68 + ///State transition - sets the `title` field to Set 69 + pub struct SetTitle<S: State = Empty>(PhantomData<fn() -> S>); 70 + impl<S: State> sealed::Sealed for SetTitle<S> {} 71 + impl<S: State> State for SetTitle<S> { 72 + type Title = Set<members::title>; 73 + type Site = S::Site; 74 + type PublishedAt = S::PublishedAt; 75 + } 76 + ///State transition - sets the `site` field to Set 77 + pub struct SetSite<S: State = Empty>(PhantomData<fn() -> S>); 78 + impl<S: State> sealed::Sealed for SetSite<S> {} 79 + impl<S: State> State for SetSite<S> { 80 + type Title = S::Title; 81 + type Site = Set<members::site>; 82 + type PublishedAt = S::PublishedAt; 83 + } 84 + ///State transition - sets the `published_at` field to Set 85 + pub struct SetPublishedAt<S: State = Empty>(PhantomData<fn() -> S>); 86 + impl<S: State> sealed::Sealed for SetPublishedAt<S> {} 87 + impl<S: State> State for SetPublishedAt<S> { 88 + type Title = S::Title; 89 + type Site = S::Site; 90 + type PublishedAt = Set<members::published_at>; 91 + } 92 + /// Marker types for field names 93 + #[allow(non_camel_case_types)] 94 + pub mod members { 95 + ///Marker type for the `title` field 96 + pub struct title(()); 97 + ///Marker type for the `site` field 98 + pub struct site(()); 99 + ///Marker type for the `published_at` field 100 + pub struct published_at(()); 101 + } 102 + } 103 + 104 + /// Builder for constructing an instance of this type 105 + pub struct DocumentBuilder<'a, S: document_state::State> { 106 + _phantom_state: ::core::marker::PhantomData<fn() -> S>, 107 + __unsafe_private_named: ( 108 + ::core::option::Option<crate::com_atproto::repo::strong_ref::StrongRef<'a>>, 109 + ::core::option::Option<jacquard_common::types::value::Data<'a>>, 110 + ::core::option::Option<jacquard_common::types::blob::BlobRef<'a>>, 111 + ::core::option::Option<jacquard_common::CowStr<'a>>, 112 + ::core::option::Option<jacquard_common::CowStr<'a>>, 113 + ::core::option::Option<jacquard_common::types::string::Datetime>, 114 + ::core::option::Option<jacquard_common::types::string::Uri<'a>>, 115 + ::core::option::Option<Vec<jacquard_common::CowStr<'a>>>, 116 + ::core::option::Option<jacquard_common::CowStr<'a>>, 117 + ::core::option::Option<jacquard_common::CowStr<'a>>, 118 + ::core::option::Option<jacquard_common::types::string::Datetime>, 119 + ), 120 + _phantom: ::core::marker::PhantomData<&'a ()>, 121 + } 122 + 123 + impl<'a> Document<'a> { 124 + /// Create a new builder for this type 125 + pub fn new() -> DocumentBuilder<'a, document_state::Empty> { 126 + DocumentBuilder::new() 127 + } 128 + } 129 + 130 + impl<'a> DocumentBuilder<'a, document_state::Empty> { 131 + /// Create a new builder with all fields unset 132 + pub fn new() -> Self { 133 + DocumentBuilder { 134 + _phantom_state: ::core::marker::PhantomData, 135 + __unsafe_private_named: ( 136 + None, None, None, None, None, None, None, None, None, None, None, 137 + ), 138 + _phantom: ::core::marker::PhantomData, 139 + } 140 + } 141 + } 142 + 143 + impl<'a, S: document_state::State> DocumentBuilder<'a, S> { 144 + /// Set the `bskyPostRef` field (optional) 145 + pub fn bsky_post_ref( 146 + mut self, 147 + value: impl Into<Option<crate::com_atproto::repo::strong_ref::StrongRef<'a>>>, 148 + ) -> Self { 149 + self.__unsafe_private_named.0 = value.into(); 150 + self 151 + } 152 + /// Set the `bskyPostRef` field to an Option value (optional) 153 + pub fn maybe_bsky_post_ref( 154 + mut self, 155 + value: Option<crate::com_atproto::repo::strong_ref::StrongRef<'a>>, 156 + ) -> Self { 157 + self.__unsafe_private_named.0 = value; 158 + self 159 + } 160 + } 161 + 162 + impl<'a, S: document_state::State> DocumentBuilder<'a, S> { 163 + /// Set the `content` field (optional) 164 + pub fn content( 165 + mut self, 166 + value: impl Into<Option<jacquard_common::types::value::Data<'a>>>, 167 + ) -> Self { 168 + self.__unsafe_private_named.1 = value.into(); 169 + self 170 + } 171 + /// Set the `content` field to an Option value (optional) 172 + pub fn maybe_content(mut self, value: Option<jacquard_common::types::value::Data<'a>>) -> Self { 173 + self.__unsafe_private_named.1 = value; 174 + self 175 + } 176 + } 177 + 178 + impl<'a, S: document_state::State> DocumentBuilder<'a, S> { 179 + /// Set the `coverImage` field (optional) 180 + pub fn cover_image( 181 + mut self, 182 + value: impl Into<Option<jacquard_common::types::blob::BlobRef<'a>>>, 183 + ) -> Self { 184 + self.__unsafe_private_named.2 = value.into(); 185 + self 186 + } 187 + /// Set the `coverImage` field to an Option value (optional) 188 + pub fn maybe_cover_image( 189 + mut self, 190 + value: Option<jacquard_common::types::blob::BlobRef<'a>>, 191 + ) -> Self { 192 + self.__unsafe_private_named.2 = value; 193 + self 194 + } 195 + } 196 + 197 + impl<'a, S: document_state::State> DocumentBuilder<'a, S> { 198 + /// Set the `description` field (optional) 199 + pub fn description(mut self, value: impl Into<Option<jacquard_common::CowStr<'a>>>) -> Self { 200 + self.__unsafe_private_named.3 = value.into(); 201 + self 202 + } 203 + /// Set the `description` field to an Option value (optional) 204 + pub fn maybe_description(mut self, value: Option<jacquard_common::CowStr<'a>>) -> Self { 205 + self.__unsafe_private_named.3 = value; 206 + self 207 + } 208 + } 209 + 210 + impl<'a, S: document_state::State> DocumentBuilder<'a, S> { 211 + /// Set the `path` field (optional) 212 + pub fn path(mut self, value: impl Into<Option<jacquard_common::CowStr<'a>>>) -> Self { 213 + self.__unsafe_private_named.4 = value.into(); 214 + self 215 + } 216 + /// Set the `path` field to an Option value (optional) 217 + pub fn maybe_path(mut self, value: Option<jacquard_common::CowStr<'a>>) -> Self { 218 + self.__unsafe_private_named.4 = value; 219 + self 220 + } 221 + } 222 + 223 + impl<'a, S> DocumentBuilder<'a, S> 224 + where 225 + S: document_state::State, 226 + S::PublishedAt: document_state::IsUnset, 227 + { 228 + /// Set the `publishedAt` field (required) 229 + pub fn published_at( 230 + mut self, 231 + value: impl Into<jacquard_common::types::string::Datetime>, 232 + ) -> DocumentBuilder<'a, document_state::SetPublishedAt<S>> { 233 + self.__unsafe_private_named.5 = ::core::option::Option::Some(value.into()); 234 + DocumentBuilder { 235 + _phantom_state: ::core::marker::PhantomData, 236 + __unsafe_private_named: self.__unsafe_private_named, 237 + _phantom: ::core::marker::PhantomData, 238 + } 239 + } 240 + } 241 + 242 + impl<'a, S> DocumentBuilder<'a, S> 243 + where 244 + S: document_state::State, 245 + S::Site: document_state::IsUnset, 246 + { 247 + /// Set the `site` field (required) 248 + pub fn site( 249 + mut self, 250 + value: impl Into<jacquard_common::types::string::Uri<'a>>, 251 + ) -> DocumentBuilder<'a, document_state::SetSite<S>> { 252 + self.__unsafe_private_named.6 = ::core::option::Option::Some(value.into()); 253 + DocumentBuilder { 254 + _phantom_state: ::core::marker::PhantomData, 255 + __unsafe_private_named: self.__unsafe_private_named, 256 + _phantom: ::core::marker::PhantomData, 257 + } 258 + } 259 + } 260 + 261 + impl<'a, S: document_state::State> DocumentBuilder<'a, S> { 262 + /// Set the `tags` field (optional) 263 + pub fn tags(mut self, value: impl Into<Option<Vec<jacquard_common::CowStr<'a>>>>) -> Self { 264 + self.__unsafe_private_named.7 = value.into(); 265 + self 266 + } 267 + /// Set the `tags` field to an Option value (optional) 268 + pub fn maybe_tags(mut self, value: Option<Vec<jacquard_common::CowStr<'a>>>) -> Self { 269 + self.__unsafe_private_named.7 = value; 270 + self 271 + } 272 + } 273 + 274 + impl<'a, S: document_state::State> DocumentBuilder<'a, S> { 275 + /// Set the `textContent` field (optional) 276 + pub fn text_content(mut self, value: impl Into<Option<jacquard_common::CowStr<'a>>>) -> Self { 277 + self.__unsafe_private_named.8 = value.into(); 278 + self 279 + } 280 + /// Set the `textContent` field to an Option value (optional) 281 + pub fn maybe_text_content(mut self, value: Option<jacquard_common::CowStr<'a>>) -> Self { 282 + self.__unsafe_private_named.8 = value; 283 + self 284 + } 285 + } 286 + 287 + impl<'a, S> DocumentBuilder<'a, S> 288 + where 289 + S: document_state::State, 290 + S::Title: document_state::IsUnset, 291 + { 292 + /// Set the `title` field (required) 293 + pub fn title( 294 + mut self, 295 + value: impl Into<jacquard_common::CowStr<'a>>, 296 + ) -> DocumentBuilder<'a, document_state::SetTitle<S>> { 297 + self.__unsafe_private_named.9 = ::core::option::Option::Some(value.into()); 298 + DocumentBuilder { 299 + _phantom_state: ::core::marker::PhantomData, 300 + __unsafe_private_named: self.__unsafe_private_named, 301 + _phantom: ::core::marker::PhantomData, 302 + } 303 + } 304 + } 305 + 306 + impl<'a, S: document_state::State> DocumentBuilder<'a, S> { 307 + /// Set the `updatedAt` field (optional) 308 + pub fn updated_at( 309 + mut self, 310 + value: impl Into<Option<jacquard_common::types::string::Datetime>>, 311 + ) -> Self { 312 + self.__unsafe_private_named.10 = value.into(); 313 + self 314 + } 315 + /// Set the `updatedAt` field to an Option value (optional) 316 + pub fn maybe_updated_at( 317 + mut self, 318 + value: Option<jacquard_common::types::string::Datetime>, 319 + ) -> Self { 320 + self.__unsafe_private_named.10 = value; 321 + self 322 + } 323 + } 324 + 325 + impl<'a, S> DocumentBuilder<'a, S> 326 + where 327 + S: document_state::State, 328 + S::Title: document_state::IsSet, 329 + S::Site: document_state::IsSet, 330 + S::PublishedAt: document_state::IsSet, 331 + { 332 + /// Build the final struct 333 + pub fn build(self) -> Document<'a> { 334 + Document { 335 + bsky_post_ref: self.__unsafe_private_named.0, 336 + content: self.__unsafe_private_named.1, 337 + cover_image: self.__unsafe_private_named.2, 338 + description: self.__unsafe_private_named.3, 339 + path: self.__unsafe_private_named.4, 340 + published_at: self.__unsafe_private_named.5.unwrap(), 341 + site: self.__unsafe_private_named.6.unwrap(), 342 + tags: self.__unsafe_private_named.7, 343 + text_content: self.__unsafe_private_named.8, 344 + title: self.__unsafe_private_named.9.unwrap(), 345 + updated_at: self.__unsafe_private_named.10, 346 + extra_data: Default::default(), 347 + } 348 + } 349 + /// Build the final struct with custom extra_data 350 + pub fn build_with_data( 351 + self, 352 + extra_data: std::collections::BTreeMap< 353 + jacquard_common::smol_str::SmolStr, 354 + jacquard_common::types::value::Data<'a>, 355 + >, 356 + ) -> Document<'a> { 357 + Document { 358 + bsky_post_ref: self.__unsafe_private_named.0, 359 + content: self.__unsafe_private_named.1, 360 + cover_image: self.__unsafe_private_named.2, 361 + description: self.__unsafe_private_named.3, 362 + path: self.__unsafe_private_named.4, 363 + published_at: self.__unsafe_private_named.5.unwrap(), 364 + site: self.__unsafe_private_named.6.unwrap(), 365 + tags: self.__unsafe_private_named.7, 366 + text_content: self.__unsafe_private_named.8, 367 + title: self.__unsafe_private_named.9.unwrap(), 368 + updated_at: self.__unsafe_private_named.10, 369 + extra_data: Some(extra_data), 370 + } 371 + } 372 + } 373 + 374 + impl<'a> Document<'a> { 375 + pub fn uri( 376 + uri: impl Into<jacquard_common::CowStr<'a>>, 377 + ) -> Result< 378 + jacquard_common::types::uri::RecordUri<'a, DocumentRecord>, 379 + jacquard_common::types::uri::UriError, 380 + > { 381 + jacquard_common::types::uri::RecordUri::try_from_uri( 382 + jacquard_common::types::string::AtUri::new_cow(uri.into())?, 383 + ) 384 + } 385 + } 386 + 387 + /// Typed wrapper for GetRecord response with this collection's record type. 388 + #[derive( 389 + serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq, jacquard_derive::IntoStatic, 390 + )] 391 + #[serde(rename_all = "camelCase")] 392 + pub struct DocumentGetRecordOutput<'a> { 393 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 394 + #[serde(borrow)] 395 + pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>, 396 + #[serde(borrow)] 397 + pub uri: jacquard_common::types::string::AtUri<'a>, 398 + #[serde(borrow)] 399 + pub value: Document<'a>, 400 + } 401 + 402 + impl From<DocumentGetRecordOutput<'_>> for Document<'_> { 403 + fn from(output: DocumentGetRecordOutput<'_>) -> Self { 404 + use jacquard_common::IntoStatic; 405 + output.value.into_static() 406 + } 407 + } 408 + 409 + impl jacquard_common::types::collection::Collection for Document<'_> { 410 + const NSID: &'static str = "site.standard.document"; 411 + type Record = DocumentRecord; 412 + } 413 + 414 + /// Marker type for deserializing records from this collection. 415 + #[derive(Debug, serde::Serialize, serde::Deserialize)] 416 + pub struct DocumentRecord; 417 + impl jacquard_common::xrpc::XrpcResp for DocumentRecord { 418 + const NSID: &'static str = "site.standard.document"; 419 + const ENCODING: &'static str = "application/json"; 420 + type Output<'de> = DocumentGetRecordOutput<'de>; 421 + type Err<'de> = jacquard_common::types::collection::RecordError<'de>; 422 + } 423 + 424 + impl jacquard_common::types::collection::Collection for DocumentRecord { 425 + const NSID: &'static str = "site.standard.document"; 426 + type Record = DocumentRecord; 427 + } 428 + 429 + impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Document<'a> { 430 + fn nsid() -> &'static str { 431 + "site.standard.document" 432 + } 433 + fn def_name() -> &'static str { 434 + "main" 435 + } 436 + fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> { 437 + lexicon_doc_site_standard_document() 438 + } 439 + fn validate( 440 + &self, 441 + ) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> { 442 + if let Some(ref value) = self.description { 443 + #[allow(unused_comparisons)] 444 + if <str>::len(value.as_ref()) > 3000usize { 445 + return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength { 446 + path: ::jacquard_lexicon::validation::ValidationPath::from_field("description"), 447 + max: 3000usize, 448 + actual: <str>::len(value.as_ref()), 449 + }); 450 + } 451 + } 452 + if let Some(ref value) = self.description { 453 + { 454 + let count = 455 + ::unicode_segmentation::UnicodeSegmentation::graphemes(value.as_ref(), true) 456 + .count(); 457 + if count > 300usize { 458 + return Err( 459 + ::jacquard_lexicon::validation::ConstraintError::MaxGraphemes { 460 + path: ::jacquard_lexicon::validation::ValidationPath::from_field( 461 + "description", 462 + ), 463 + max: 300usize, 464 + actual: count, 465 + }, 466 + ); 467 + } 468 + } 469 + } 470 + { 471 + let value = &self.title; 472 + #[allow(unused_comparisons)] 473 + if <str>::len(value.as_ref()) > 1280usize { 474 + return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength { 475 + path: ::jacquard_lexicon::validation::ValidationPath::from_field("title"), 476 + max: 1280usize, 477 + actual: <str>::len(value.as_ref()), 478 + }); 479 + } 480 + } 481 + { 482 + let value = &self.title; 483 + { 484 + let count = 485 + ::unicode_segmentation::UnicodeSegmentation::graphemes(value.as_ref(), true) 486 + .count(); 487 + if count > 128usize { 488 + return Err( 489 + ::jacquard_lexicon::validation::ConstraintError::MaxGraphemes { 490 + path: ::jacquard_lexicon::validation::ValidationPath::from_field( 491 + "title", 492 + ), 493 + max: 128usize, 494 + actual: count, 495 + }, 496 + ); 497 + } 498 + } 499 + } 500 + Ok(()) 501 + } 502 + } 503 + 504 + fn lexicon_doc_site_standard_document() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> { 505 + ::jacquard_lexicon::lexicon::LexiconDoc { 506 + lexicon: ::jacquard_lexicon::lexicon::Lexicon::Lexicon1, 507 + id: ::jacquard_common::CowStr::new_static("site.standard.document"), 508 + revision: None, 509 + description: None, 510 + defs: { 511 + let mut map = ::std::collections::BTreeMap::new(); 512 + map.insert( 513 + ::jacquard_common::smol_str::SmolStr::new_static("main"), 514 + ::jacquard_lexicon::lexicon::LexUserType::Record(::jacquard_lexicon::lexicon::LexRecord { 515 + description: None, 516 + key: Some(::jacquard_common::CowStr::new_static("tid")), 517 + record: ::jacquard_lexicon::lexicon::LexRecordRecord::Object(::jacquard_lexicon::lexicon::LexObject { 518 + description: None, 519 + required: Some( 520 + vec![ 521 + ::jacquard_common::smol_str::SmolStr::new_static("site"), 522 + ::jacquard_common::smol_str::SmolStr::new_static("title"), 523 + ::jacquard_common::smol_str::SmolStr::new_static("publishedAt") 524 + ], 525 + ), 526 + nullable: None, 527 + properties: { 528 + #[allow(unused_mut)] 529 + let mut map = ::std::collections::BTreeMap::new(); 530 + map.insert( 531 + ::jacquard_common::smol_str::SmolStr::new_static( 532 + "bskyPostRef", 533 + ), 534 + ::jacquard_lexicon::lexicon::LexObjectProperty::Ref(::jacquard_lexicon::lexicon::LexRef { 535 + description: None, 536 + r#ref: ::jacquard_common::CowStr::new_static( 537 + "com.atproto.repo.strongRef", 538 + ), 539 + }), 540 + ); 541 + map.insert( 542 + ::jacquard_common::smol_str::SmolStr::new_static("content"), 543 + ::jacquard_lexicon::lexicon::LexObjectProperty::Union(::jacquard_lexicon::lexicon::LexRefUnion { 544 + description: None, 545 + refs: vec![], 546 + closed: Some(false), 547 + }), 548 + ); 549 + map.insert( 550 + ::jacquard_common::smol_str::SmolStr::new_static( 551 + "coverImage", 552 + ), 553 + ::jacquard_lexicon::lexicon::LexObjectProperty::Blob(::jacquard_lexicon::lexicon::LexBlob { 554 + description: None, 555 + accept: None, 556 + max_size: None, 557 + }), 558 + ); 559 + map.insert( 560 + ::jacquard_common::smol_str::SmolStr::new_static( 561 + "description", 562 + ), 563 + ::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString { 564 + description: None, 565 + format: None, 566 + default: None, 567 + min_length: None, 568 + max_length: Some(3000usize), 569 + min_graphemes: None, 570 + max_graphemes: Some(300usize), 571 + r#enum: None, 572 + r#const: None, 573 + known_values: None, 574 + }), 575 + ); 576 + map.insert( 577 + ::jacquard_common::smol_str::SmolStr::new_static("path"), 578 + ::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString { 579 + description: Some( 580 + ::jacquard_common::CowStr::new_static( 581 + "combine with the publication url or the document site to construct a full url to the document", 582 + ), 583 + ), 584 + format: None, 585 + default: None, 586 + min_length: None, 587 + max_length: None, 588 + min_graphemes: None, 589 + max_graphemes: None, 590 + r#enum: None, 591 + r#const: None, 592 + known_values: None, 593 + }), 594 + ); 595 + map.insert( 596 + ::jacquard_common::smol_str::SmolStr::new_static( 597 + "publishedAt", 598 + ), 599 + ::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString { 600 + description: None, 601 + format: Some( 602 + ::jacquard_lexicon::lexicon::LexStringFormat::Datetime, 603 + ), 604 + default: None, 605 + min_length: None, 606 + max_length: None, 607 + min_graphemes: None, 608 + max_graphemes: None, 609 + r#enum: None, 610 + r#const: None, 611 + known_values: None, 612 + }), 613 + ); 614 + map.insert( 615 + ::jacquard_common::smol_str::SmolStr::new_static("site"), 616 + ::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString { 617 + description: Some( 618 + ::jacquard_common::CowStr::new_static( 619 + "URI to the site or publication this document belongs to (https or at-uri)", 620 + ), 621 + ), 622 + format: Some( 623 + ::jacquard_lexicon::lexicon::LexStringFormat::Uri, 624 + ), 625 + default: None, 626 + min_length: None, 627 + max_length: None, 628 + min_graphemes: None, 629 + max_graphemes: None, 630 + r#enum: None, 631 + r#const: None, 632 + known_values: None, 633 + }), 634 + ); 635 + map.insert( 636 + ::jacquard_common::smol_str::SmolStr::new_static("tags"), 637 + ::jacquard_lexicon::lexicon::LexObjectProperty::Array(::jacquard_lexicon::lexicon::LexArray { 638 + description: None, 639 + items: ::jacquard_lexicon::lexicon::LexArrayItem::String(::jacquard_lexicon::lexicon::LexString { 640 + description: None, 641 + format: None, 642 + default: None, 643 + min_length: None, 644 + max_length: Some(100usize), 645 + min_graphemes: None, 646 + max_graphemes: Some(50usize), 647 + r#enum: None, 648 + r#const: None, 649 + known_values: None, 650 + }), 651 + min_length: None, 652 + max_length: None, 653 + }), 654 + ); 655 + map.insert( 656 + ::jacquard_common::smol_str::SmolStr::new_static( 657 + "textContent", 658 + ), 659 + ::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString { 660 + description: None, 661 + format: None, 662 + default: None, 663 + min_length: None, 664 + max_length: None, 665 + min_graphemes: None, 666 + max_graphemes: None, 667 + r#enum: None, 668 + r#const: None, 669 + known_values: None, 670 + }), 671 + ); 672 + map.insert( 673 + ::jacquard_common::smol_str::SmolStr::new_static("title"), 674 + ::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString { 675 + description: None, 676 + format: None, 677 + default: None, 678 + min_length: None, 679 + max_length: Some(1280usize), 680 + min_graphemes: None, 681 + max_graphemes: Some(128usize), 682 + r#enum: None, 683 + r#const: None, 684 + known_values: None, 685 + }), 686 + ); 687 + map.insert( 688 + ::jacquard_common::smol_str::SmolStr::new_static( 689 + "updatedAt", 690 + ), 691 + ::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString { 692 + description: None, 693 + format: Some( 694 + ::jacquard_lexicon::lexicon::LexStringFormat::Datetime, 695 + ), 696 + default: None, 697 + min_length: None, 698 + max_length: None, 699 + min_graphemes: None, 700 + max_graphemes: None, 701 + r#enum: None, 702 + r#const: None, 703 + known_values: None, 704 + }), 705 + ); 706 + map 707 + }, 708 + }), 709 + }), 710 + ); 711 + map 712 + }, 713 + } 714 + }
+6
lexicons-example/src/site_standard/graph.rs
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // This file was automatically generated from Lexicon schemas. 4 + // Any manual changes will be overwritten on the next regeneration. 5 + 6 + pub mod subscription;
+255
lexicons-example/src/site_standard/graph/subscription.rs
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // Lexicon: site.standard.graph.subscription 4 + // 5 + // This file was automatically generated from Lexicon schemas. 6 + // Any manual changes will be overwritten on the next regeneration. 7 + 8 + /// Record declaring a subscription to a publication 9 + #[jacquard_derive::lexicon] 10 + #[derive( 11 + serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq, jacquard_derive::IntoStatic, 12 + )] 13 + #[serde(rename_all = "camelCase")] 14 + pub struct Subscription<'a> { 15 + /// AT-URI reference to the publication record being subscribed to (ex: at://did:plc:abc123/site.standard.publication/xyz789). 16 + #[serde(borrow)] 17 + pub publication: jacquard_common::types::string::AtUri<'a>, 18 + } 19 + 20 + pub mod subscription_state { 21 + 22 + pub use crate::builder_types::{IsSet, IsUnset, Set, Unset}; 23 + #[allow(unused)] 24 + use ::core::marker::PhantomData; 25 + mod sealed { 26 + pub trait Sealed {} 27 + } 28 + /// State trait tracking which required fields have been set 29 + pub trait State: sealed::Sealed { 30 + type Publication; 31 + } 32 + /// Empty state - all required fields are unset 33 + pub struct Empty(()); 34 + impl sealed::Sealed for Empty {} 35 + impl State for Empty { 36 + type Publication = Unset; 37 + } 38 + ///State transition - sets the `publication` field to Set 39 + pub struct SetPublication<S: State = Empty>(PhantomData<fn() -> S>); 40 + impl<S: State> sealed::Sealed for SetPublication<S> {} 41 + impl<S: State> State for SetPublication<S> { 42 + type Publication = Set<members::publication>; 43 + } 44 + /// Marker types for field names 45 + #[allow(non_camel_case_types)] 46 + pub mod members { 47 + ///Marker type for the `publication` field 48 + pub struct publication(()); 49 + } 50 + } 51 + 52 + /// Builder for constructing an instance of this type 53 + pub struct SubscriptionBuilder<'a, S: subscription_state::State> { 54 + _phantom_state: ::core::marker::PhantomData<fn() -> S>, 55 + __unsafe_private_named: (::core::option::Option<jacquard_common::types::string::AtUri<'a>>,), 56 + _phantom: ::core::marker::PhantomData<&'a ()>, 57 + } 58 + 59 + impl<'a> Subscription<'a> { 60 + /// Create a new builder for this type 61 + pub fn new() -> SubscriptionBuilder<'a, subscription_state::Empty> { 62 + SubscriptionBuilder::new() 63 + } 64 + } 65 + 66 + impl<'a> SubscriptionBuilder<'a, subscription_state::Empty> { 67 + /// Create a new builder with all fields unset 68 + pub fn new() -> Self { 69 + SubscriptionBuilder { 70 + _phantom_state: ::core::marker::PhantomData, 71 + __unsafe_private_named: (None,), 72 + _phantom: ::core::marker::PhantomData, 73 + } 74 + } 75 + } 76 + 77 + impl<'a, S> SubscriptionBuilder<'a, S> 78 + where 79 + S: subscription_state::State, 80 + S::Publication: subscription_state::IsUnset, 81 + { 82 + /// Set the `publication` field (required) 83 + pub fn publication( 84 + mut self, 85 + value: impl Into<jacquard_common::types::string::AtUri<'a>>, 86 + ) -> SubscriptionBuilder<'a, subscription_state::SetPublication<S>> { 87 + self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into()); 88 + SubscriptionBuilder { 89 + _phantom_state: ::core::marker::PhantomData, 90 + __unsafe_private_named: self.__unsafe_private_named, 91 + _phantom: ::core::marker::PhantomData, 92 + } 93 + } 94 + } 95 + 96 + impl<'a, S> SubscriptionBuilder<'a, S> 97 + where 98 + S: subscription_state::State, 99 + S::Publication: subscription_state::IsSet, 100 + { 101 + /// Build the final struct 102 + pub fn build(self) -> Subscription<'a> { 103 + Subscription { 104 + publication: self.__unsafe_private_named.0.unwrap(), 105 + extra_data: Default::default(), 106 + } 107 + } 108 + /// Build the final struct with custom extra_data 109 + pub fn build_with_data( 110 + self, 111 + extra_data: std::collections::BTreeMap< 112 + jacquard_common::smol_str::SmolStr, 113 + jacquard_common::types::value::Data<'a>, 114 + >, 115 + ) -> Subscription<'a> { 116 + Subscription { 117 + publication: self.__unsafe_private_named.0.unwrap(), 118 + extra_data: Some(extra_data), 119 + } 120 + } 121 + } 122 + 123 + impl<'a> Subscription<'a> { 124 + pub fn uri( 125 + uri: impl Into<jacquard_common::CowStr<'a>>, 126 + ) -> Result< 127 + jacquard_common::types::uri::RecordUri<'a, SubscriptionRecord>, 128 + jacquard_common::types::uri::UriError, 129 + > { 130 + jacquard_common::types::uri::RecordUri::try_from_uri( 131 + jacquard_common::types::string::AtUri::new_cow(uri.into())?, 132 + ) 133 + } 134 + } 135 + 136 + /// Typed wrapper for GetRecord response with this collection's record type. 137 + #[derive( 138 + serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq, jacquard_derive::IntoStatic, 139 + )] 140 + #[serde(rename_all = "camelCase")] 141 + pub struct SubscriptionGetRecordOutput<'a> { 142 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 143 + #[serde(borrow)] 144 + pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>, 145 + #[serde(borrow)] 146 + pub uri: jacquard_common::types::string::AtUri<'a>, 147 + #[serde(borrow)] 148 + pub value: Subscription<'a>, 149 + } 150 + 151 + impl From<SubscriptionGetRecordOutput<'_>> for Subscription<'_> { 152 + fn from(output: SubscriptionGetRecordOutput<'_>) -> Self { 153 + use jacquard_common::IntoStatic; 154 + output.value.into_static() 155 + } 156 + } 157 + 158 + impl jacquard_common::types::collection::Collection for Subscription<'_> { 159 + const NSID: &'static str = "site.standard.graph.subscription"; 160 + type Record = SubscriptionRecord; 161 + } 162 + 163 + /// Marker type for deserializing records from this collection. 164 + #[derive(Debug, serde::Serialize, serde::Deserialize)] 165 + pub struct SubscriptionRecord; 166 + impl jacquard_common::xrpc::XrpcResp for SubscriptionRecord { 167 + const NSID: &'static str = "site.standard.graph.subscription"; 168 + const ENCODING: &'static str = "application/json"; 169 + type Output<'de> = SubscriptionGetRecordOutput<'de>; 170 + type Err<'de> = jacquard_common::types::collection::RecordError<'de>; 171 + } 172 + 173 + impl jacquard_common::types::collection::Collection for SubscriptionRecord { 174 + const NSID: &'static str = "site.standard.graph.subscription"; 175 + type Record = SubscriptionRecord; 176 + } 177 + 178 + impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Subscription<'a> { 179 + fn nsid() -> &'static str { 180 + "site.standard.graph.subscription" 181 + } 182 + fn def_name() -> &'static str { 183 + "main" 184 + } 185 + fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> { 186 + lexicon_doc_site_standard_graph_subscription() 187 + } 188 + fn validate( 189 + &self, 190 + ) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> { 191 + Ok(()) 192 + } 193 + } 194 + 195 + fn lexicon_doc_site_standard_graph_subscription() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> 196 + { 197 + ::jacquard_lexicon::lexicon::LexiconDoc { 198 + lexicon: ::jacquard_lexicon::lexicon::Lexicon::Lexicon1, 199 + id: ::jacquard_common::CowStr::new_static("site.standard.graph.subscription"), 200 + revision: None, 201 + description: None, 202 + defs: { 203 + let mut map = ::std::collections::BTreeMap::new(); 204 + map.insert( 205 + ::jacquard_common::smol_str::SmolStr::new_static("main"), 206 + ::jacquard_lexicon::lexicon::LexUserType::Record(::jacquard_lexicon::lexicon::LexRecord { 207 + description: Some( 208 + ::jacquard_common::CowStr::new_static( 209 + "Record declaring a subscription to a publication", 210 + ), 211 + ), 212 + key: Some(::jacquard_common::CowStr::new_static("tid")), 213 + record: ::jacquard_lexicon::lexicon::LexRecordRecord::Object(::jacquard_lexicon::lexicon::LexObject { 214 + description: None, 215 + required: Some( 216 + vec![ 217 + ::jacquard_common::smol_str::SmolStr::new_static("publication") 218 + ], 219 + ), 220 + nullable: None, 221 + properties: { 222 + #[allow(unused_mut)] 223 + let mut map = ::std::collections::BTreeMap::new(); 224 + map.insert( 225 + ::jacquard_common::smol_str::SmolStr::new_static( 226 + "publication", 227 + ), 228 + ::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString { 229 + description: Some( 230 + ::jacquard_common::CowStr::new_static( 231 + "AT-URI reference to the publication record being subscribed to (ex: at://did:plc:abc123/site.standard.publication/xyz789).", 232 + ), 233 + ), 234 + format: Some( 235 + ::jacquard_lexicon::lexicon::LexStringFormat::AtUri, 236 + ), 237 + default: None, 238 + min_length: None, 239 + max_length: None, 240 + min_graphemes: None, 241 + max_graphemes: None, 242 + r#enum: None, 243 + r#const: None, 244 + known_values: None, 245 + }), 246 + ); 247 + map 248 + }, 249 + }), 250 + }), 251 + ); 252 + map 253 + }, 254 + } 255 + }
+550
lexicons-example/src/site_standard/publication.rs
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // Lexicon: site.standard.publication 4 + // 5 + // This file was automatically generated from Lexicon schemas. 6 + // Any manual changes will be overwritten on the next regeneration. 7 + 8 + #[jacquard_derive::lexicon] 9 + #[derive( 10 + serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq, jacquard_derive::IntoStatic, 11 + )] 12 + #[serde(rename_all = "camelCase")] 13 + pub struct Publication<'a> { 14 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 15 + #[serde(borrow)] 16 + pub basic_theme: std::option::Option<crate::site_standard::theme::basic::Basic<'a>>, 17 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 18 + #[serde(borrow)] 19 + pub description: std::option::Option<jacquard_common::CowStr<'a>>, 20 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 21 + #[serde(borrow)] 22 + pub icon: std::option::Option<jacquard_common::types::blob::BlobRef<'a>>, 23 + #[serde(borrow)] 24 + pub name: jacquard_common::CowStr<'a>, 25 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 26 + #[serde(borrow)] 27 + pub preferences: std::option::Option<crate::site_standard::publication::Preferences<'a>>, 28 + #[serde(borrow)] 29 + pub url: jacquard_common::types::string::Uri<'a>, 30 + } 31 + 32 + pub mod publication_state { 33 + 34 + pub use crate::builder_types::{IsSet, IsUnset, Set, Unset}; 35 + #[allow(unused)] 36 + use ::core::marker::PhantomData; 37 + mod sealed { 38 + pub trait Sealed {} 39 + } 40 + /// State trait tracking which required fields have been set 41 + pub trait State: sealed::Sealed { 42 + type Name; 43 + type Url; 44 + } 45 + /// Empty state - all required fields are unset 46 + pub struct Empty(()); 47 + impl sealed::Sealed for Empty {} 48 + impl State for Empty { 49 + type Name = Unset; 50 + type Url = Unset; 51 + } 52 + ///State transition - sets the `name` field to Set 53 + pub struct SetName<S: State = Empty>(PhantomData<fn() -> S>); 54 + impl<S: State> sealed::Sealed for SetName<S> {} 55 + impl<S: State> State for SetName<S> { 56 + type Name = Set<members::name>; 57 + type Url = S::Url; 58 + } 59 + ///State transition - sets the `url` field to Set 60 + pub struct SetUrl<S: State = Empty>(PhantomData<fn() -> S>); 61 + impl<S: State> sealed::Sealed for SetUrl<S> {} 62 + impl<S: State> State for SetUrl<S> { 63 + type Name = S::Name; 64 + type Url = Set<members::url>; 65 + } 66 + /// Marker types for field names 67 + #[allow(non_camel_case_types)] 68 + pub mod members { 69 + ///Marker type for the `name` field 70 + pub struct name(()); 71 + ///Marker type for the `url` field 72 + pub struct url(()); 73 + } 74 + } 75 + 76 + /// Builder for constructing an instance of this type 77 + pub struct PublicationBuilder<'a, S: publication_state::State> { 78 + _phantom_state: ::core::marker::PhantomData<fn() -> S>, 79 + __unsafe_private_named: ( 80 + ::core::option::Option<crate::site_standard::theme::basic::Basic<'a>>, 81 + ::core::option::Option<jacquard_common::CowStr<'a>>, 82 + ::core::option::Option<jacquard_common::types::blob::BlobRef<'a>>, 83 + ::core::option::Option<jacquard_common::CowStr<'a>>, 84 + ::core::option::Option<crate::site_standard::publication::Preferences<'a>>, 85 + ::core::option::Option<jacquard_common::types::string::Uri<'a>>, 86 + ), 87 + _phantom: ::core::marker::PhantomData<&'a ()>, 88 + } 89 + 90 + impl<'a> Publication<'a> { 91 + /// Create a new builder for this type 92 + pub fn new() -> PublicationBuilder<'a, publication_state::Empty> { 93 + PublicationBuilder::new() 94 + } 95 + } 96 + 97 + impl<'a> PublicationBuilder<'a, publication_state::Empty> { 98 + /// Create a new builder with all fields unset 99 + pub fn new() -> Self { 100 + PublicationBuilder { 101 + _phantom_state: ::core::marker::PhantomData, 102 + __unsafe_private_named: (None, None, None, None, None, None), 103 + _phantom: ::core::marker::PhantomData, 104 + } 105 + } 106 + } 107 + 108 + impl<'a, S: publication_state::State> PublicationBuilder<'a, S> { 109 + /// Set the `basicTheme` field (optional) 110 + pub fn basic_theme( 111 + mut self, 112 + value: impl Into<Option<crate::site_standard::theme::basic::Basic<'a>>>, 113 + ) -> Self { 114 + self.__unsafe_private_named.0 = value.into(); 115 + self 116 + } 117 + /// Set the `basicTheme` field to an Option value (optional) 118 + pub fn maybe_basic_theme( 119 + mut self, 120 + value: Option<crate::site_standard::theme::basic::Basic<'a>>, 121 + ) -> Self { 122 + self.__unsafe_private_named.0 = value; 123 + self 124 + } 125 + } 126 + 127 + impl<'a, S: publication_state::State> PublicationBuilder<'a, S> { 128 + /// Set the `description` field (optional) 129 + pub fn description(mut self, value: impl Into<Option<jacquard_common::CowStr<'a>>>) -> Self { 130 + self.__unsafe_private_named.1 = value.into(); 131 + self 132 + } 133 + /// Set the `description` field to an Option value (optional) 134 + pub fn maybe_description(mut self, value: Option<jacquard_common::CowStr<'a>>) -> Self { 135 + self.__unsafe_private_named.1 = value; 136 + self 137 + } 138 + } 139 + 140 + impl<'a, S: publication_state::State> PublicationBuilder<'a, S> { 141 + /// Set the `icon` field (optional) 142 + pub fn icon( 143 + mut self, 144 + value: impl Into<Option<jacquard_common::types::blob::BlobRef<'a>>>, 145 + ) -> Self { 146 + self.__unsafe_private_named.2 = value.into(); 147 + self 148 + } 149 + /// Set the `icon` field to an Option value (optional) 150 + pub fn maybe_icon(mut self, value: Option<jacquard_common::types::blob::BlobRef<'a>>) -> Self { 151 + self.__unsafe_private_named.2 = value; 152 + self 153 + } 154 + } 155 + 156 + impl<'a, S> PublicationBuilder<'a, S> 157 + where 158 + S: publication_state::State, 159 + S::Name: publication_state::IsUnset, 160 + { 161 + /// Set the `name` field (required) 162 + pub fn name( 163 + mut self, 164 + value: impl Into<jacquard_common::CowStr<'a>>, 165 + ) -> PublicationBuilder<'a, publication_state::SetName<S>> { 166 + self.__unsafe_private_named.3 = ::core::option::Option::Some(value.into()); 167 + PublicationBuilder { 168 + _phantom_state: ::core::marker::PhantomData, 169 + __unsafe_private_named: self.__unsafe_private_named, 170 + _phantom: ::core::marker::PhantomData, 171 + } 172 + } 173 + } 174 + 175 + impl<'a, S: publication_state::State> PublicationBuilder<'a, S> { 176 + /// Set the `preferences` field (optional) 177 + pub fn preferences( 178 + mut self, 179 + value: impl Into<Option<crate::site_standard::publication::Preferences<'a>>>, 180 + ) -> Self { 181 + self.__unsafe_private_named.4 = value.into(); 182 + self 183 + } 184 + /// Set the `preferences` field to an Option value (optional) 185 + pub fn maybe_preferences( 186 + mut self, 187 + value: Option<crate::site_standard::publication::Preferences<'a>>, 188 + ) -> Self { 189 + self.__unsafe_private_named.4 = value; 190 + self 191 + } 192 + } 193 + 194 + impl<'a, S> PublicationBuilder<'a, S> 195 + where 196 + S: publication_state::State, 197 + S::Url: publication_state::IsUnset, 198 + { 199 + /// Set the `url` field (required) 200 + pub fn url( 201 + mut self, 202 + value: impl Into<jacquard_common::types::string::Uri<'a>>, 203 + ) -> PublicationBuilder<'a, publication_state::SetUrl<S>> { 204 + self.__unsafe_private_named.5 = ::core::option::Option::Some(value.into()); 205 + PublicationBuilder { 206 + _phantom_state: ::core::marker::PhantomData, 207 + __unsafe_private_named: self.__unsafe_private_named, 208 + _phantom: ::core::marker::PhantomData, 209 + } 210 + } 211 + } 212 + 213 + impl<'a, S> PublicationBuilder<'a, S> 214 + where 215 + S: publication_state::State, 216 + S::Name: publication_state::IsSet, 217 + S::Url: publication_state::IsSet, 218 + { 219 + /// Build the final struct 220 + pub fn build(self) -> Publication<'a> { 221 + Publication { 222 + basic_theme: self.__unsafe_private_named.0, 223 + description: self.__unsafe_private_named.1, 224 + icon: self.__unsafe_private_named.2, 225 + name: self.__unsafe_private_named.3.unwrap(), 226 + preferences: self.__unsafe_private_named.4, 227 + url: self.__unsafe_private_named.5.unwrap(), 228 + extra_data: Default::default(), 229 + } 230 + } 231 + /// Build the final struct with custom extra_data 232 + pub fn build_with_data( 233 + self, 234 + extra_data: std::collections::BTreeMap< 235 + jacquard_common::smol_str::SmolStr, 236 + jacquard_common::types::value::Data<'a>, 237 + >, 238 + ) -> Publication<'a> { 239 + Publication { 240 + basic_theme: self.__unsafe_private_named.0, 241 + description: self.__unsafe_private_named.1, 242 + icon: self.__unsafe_private_named.2, 243 + name: self.__unsafe_private_named.3.unwrap(), 244 + preferences: self.__unsafe_private_named.4, 245 + url: self.__unsafe_private_named.5.unwrap(), 246 + extra_data: Some(extra_data), 247 + } 248 + } 249 + } 250 + 251 + impl<'a> Publication<'a> { 252 + pub fn uri( 253 + uri: impl Into<jacquard_common::CowStr<'a>>, 254 + ) -> Result< 255 + jacquard_common::types::uri::RecordUri<'a, PublicationRecord>, 256 + jacquard_common::types::uri::UriError, 257 + > { 258 + jacquard_common::types::uri::RecordUri::try_from_uri( 259 + jacquard_common::types::string::AtUri::new_cow(uri.into())?, 260 + ) 261 + } 262 + } 263 + 264 + /// Typed wrapper for GetRecord response with this collection's record type. 265 + #[derive( 266 + serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq, jacquard_derive::IntoStatic, 267 + )] 268 + #[serde(rename_all = "camelCase")] 269 + pub struct PublicationGetRecordOutput<'a> { 270 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 271 + #[serde(borrow)] 272 + pub cid: std::option::Option<jacquard_common::types::string::Cid<'a>>, 273 + #[serde(borrow)] 274 + pub uri: jacquard_common::types::string::AtUri<'a>, 275 + #[serde(borrow)] 276 + pub value: Publication<'a>, 277 + } 278 + 279 + impl From<PublicationGetRecordOutput<'_>> for Publication<'_> { 280 + fn from(output: PublicationGetRecordOutput<'_>) -> Self { 281 + use jacquard_common::IntoStatic; 282 + output.value.into_static() 283 + } 284 + } 285 + 286 + impl jacquard_common::types::collection::Collection for Publication<'_> { 287 + const NSID: &'static str = "site.standard.publication"; 288 + type Record = PublicationRecord; 289 + } 290 + 291 + /// Marker type for deserializing records from this collection. 292 + #[derive(Debug, serde::Serialize, serde::Deserialize)] 293 + pub struct PublicationRecord; 294 + impl jacquard_common::xrpc::XrpcResp for PublicationRecord { 295 + const NSID: &'static str = "site.standard.publication"; 296 + const ENCODING: &'static str = "application/json"; 297 + type Output<'de> = PublicationGetRecordOutput<'de>; 298 + type Err<'de> = jacquard_common::types::collection::RecordError<'de>; 299 + } 300 + 301 + impl jacquard_common::types::collection::Collection for PublicationRecord { 302 + const NSID: &'static str = "site.standard.publication"; 303 + type Record = PublicationRecord; 304 + } 305 + 306 + impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Publication<'a> { 307 + fn nsid() -> &'static str { 308 + "site.standard.publication" 309 + } 310 + fn def_name() -> &'static str { 311 + "main" 312 + } 313 + fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> { 314 + lexicon_doc_site_standard_publication() 315 + } 316 + fn validate( 317 + &self, 318 + ) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> { 319 + if let Some(ref value) = self.description { 320 + #[allow(unused_comparisons)] 321 + if <str>::len(value.as_ref()) > 3000usize { 322 + return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength { 323 + path: ::jacquard_lexicon::validation::ValidationPath::from_field("description"), 324 + max: 3000usize, 325 + actual: <str>::len(value.as_ref()), 326 + }); 327 + } 328 + } 329 + if let Some(ref value) = self.description { 330 + { 331 + let count = 332 + ::unicode_segmentation::UnicodeSegmentation::graphemes(value.as_ref(), true) 333 + .count(); 334 + if count > 300usize { 335 + return Err( 336 + ::jacquard_lexicon::validation::ConstraintError::MaxGraphemes { 337 + path: ::jacquard_lexicon::validation::ValidationPath::from_field( 338 + "description", 339 + ), 340 + max: 300usize, 341 + actual: count, 342 + }, 343 + ); 344 + } 345 + } 346 + } 347 + { 348 + let value = &self.name; 349 + #[allow(unused_comparisons)] 350 + if <str>::len(value.as_ref()) > 1280usize { 351 + return Err(::jacquard_lexicon::validation::ConstraintError::MaxLength { 352 + path: ::jacquard_lexicon::validation::ValidationPath::from_field("name"), 353 + max: 1280usize, 354 + actual: <str>::len(value.as_ref()), 355 + }); 356 + } 357 + } 358 + { 359 + let value = &self.name; 360 + { 361 + let count = 362 + ::unicode_segmentation::UnicodeSegmentation::graphemes(value.as_ref(), true) 363 + .count(); 364 + if count > 128usize { 365 + return Err( 366 + ::jacquard_lexicon::validation::ConstraintError::MaxGraphemes { 367 + path: ::jacquard_lexicon::validation::ValidationPath::from_field( 368 + "name", 369 + ), 370 + max: 128usize, 371 + actual: count, 372 + }, 373 + ); 374 + } 375 + } 376 + } 377 + Ok(()) 378 + } 379 + } 380 + 381 + fn lexicon_doc_site_standard_publication() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> { 382 + ::jacquard_lexicon::lexicon::LexiconDoc { 383 + lexicon: ::jacquard_lexicon::lexicon::Lexicon::Lexicon1, 384 + id: ::jacquard_common::CowStr::new_static("site.standard.publication"), 385 + revision: None, 386 + description: None, 387 + defs: { 388 + let mut map = ::std::collections::BTreeMap::new(); 389 + map.insert( 390 + ::jacquard_common::smol_str::SmolStr::new_static("main"), 391 + ::jacquard_lexicon::lexicon::LexUserType::Record(::jacquard_lexicon::lexicon::LexRecord { 392 + description: None, 393 + key: Some(::jacquard_common::CowStr::new_static("tid")), 394 + record: ::jacquard_lexicon::lexicon::LexRecordRecord::Object(::jacquard_lexicon::lexicon::LexObject { 395 + description: None, 396 + required: Some( 397 + vec![ 398 + ::jacquard_common::smol_str::SmolStr::new_static("url"), 399 + ::jacquard_common::smol_str::SmolStr::new_static("name") 400 + ], 401 + ), 402 + nullable: None, 403 + properties: { 404 + #[allow(unused_mut)] 405 + let mut map = ::std::collections::BTreeMap::new(); 406 + map.insert( 407 + ::jacquard_common::smol_str::SmolStr::new_static( 408 + "basicTheme", 409 + ), 410 + ::jacquard_lexicon::lexicon::LexObjectProperty::Ref(::jacquard_lexicon::lexicon::LexRef { 411 + description: None, 412 + r#ref: ::jacquard_common::CowStr::new_static( 413 + "site.standard.theme.basic", 414 + ), 415 + }), 416 + ); 417 + map.insert( 418 + ::jacquard_common::smol_str::SmolStr::new_static( 419 + "description", 420 + ), 421 + ::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString { 422 + description: None, 423 + format: None, 424 + default: None, 425 + min_length: None, 426 + max_length: Some(3000usize), 427 + min_graphemes: None, 428 + max_graphemes: Some(300usize), 429 + r#enum: None, 430 + r#const: None, 431 + known_values: None, 432 + }), 433 + ); 434 + map.insert( 435 + ::jacquard_common::smol_str::SmolStr::new_static("icon"), 436 + ::jacquard_lexicon::lexicon::LexObjectProperty::Blob(::jacquard_lexicon::lexicon::LexBlob { 437 + description: None, 438 + accept: None, 439 + max_size: None, 440 + }), 441 + ); 442 + map.insert( 443 + ::jacquard_common::smol_str::SmolStr::new_static("name"), 444 + ::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString { 445 + description: None, 446 + format: None, 447 + default: None, 448 + min_length: None, 449 + max_length: Some(1280usize), 450 + min_graphemes: None, 451 + max_graphemes: Some(128usize), 452 + r#enum: None, 453 + r#const: None, 454 + known_values: None, 455 + }), 456 + ); 457 + map.insert( 458 + ::jacquard_common::smol_str::SmolStr::new_static( 459 + "preferences", 460 + ), 461 + ::jacquard_lexicon::lexicon::LexObjectProperty::Ref(::jacquard_lexicon::lexicon::LexRef { 462 + description: None, 463 + r#ref: ::jacquard_common::CowStr::new_static("#preferences"), 464 + }), 465 + ); 466 + map.insert( 467 + ::jacquard_common::smol_str::SmolStr::new_static("url"), 468 + ::jacquard_lexicon::lexicon::LexObjectProperty::String(::jacquard_lexicon::lexicon::LexString { 469 + description: None, 470 + format: Some( 471 + ::jacquard_lexicon::lexicon::LexStringFormat::Uri, 472 + ), 473 + default: None, 474 + min_length: None, 475 + max_length: None, 476 + min_graphemes: None, 477 + max_graphemes: None, 478 + r#enum: None, 479 + r#const: None, 480 + known_values: None, 481 + }), 482 + ); 483 + map 484 + }, 485 + }), 486 + }), 487 + ); 488 + map.insert( 489 + ::jacquard_common::smol_str::SmolStr::new_static("preferences"), 490 + ::jacquard_lexicon::lexicon::LexUserType::Object( 491 + ::jacquard_lexicon::lexicon::LexObject { 492 + description: None, 493 + required: None, 494 + nullable: None, 495 + properties: { 496 + #[allow(unused_mut)] 497 + let mut map = ::std::collections::BTreeMap::new(); 498 + map.insert( 499 + ::jacquard_common::smol_str::SmolStr::new_static("showInDiscover"), 500 + ::jacquard_lexicon::lexicon::LexObjectProperty::Boolean( 501 + ::jacquard_lexicon::lexicon::LexBoolean { 502 + description: None, 503 + default: None, 504 + r#const: None, 505 + }, 506 + ), 507 + ); 508 + map 509 + }, 510 + }, 511 + ), 512 + ); 513 + map 514 + }, 515 + } 516 + } 517 + 518 + #[jacquard_derive::lexicon] 519 + #[derive( 520 + serde::Serialize, 521 + serde::Deserialize, 522 + Debug, 523 + Clone, 524 + PartialEq, 525 + Eq, 526 + jacquard_derive::IntoStatic, 527 + Default, 528 + )] 529 + #[serde(rename_all = "camelCase")] 530 + pub struct Preferences<'a> { 531 + #[serde(skip_serializing_if = "std::option::Option::is_none")] 532 + pub show_in_discover: std::option::Option<bool>, 533 + } 534 + 535 + impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Preferences<'a> { 536 + fn nsid() -> &'static str { 537 + "site.standard.publication" 538 + } 539 + fn def_name() -> &'static str { 540 + "preferences" 541 + } 542 + fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> { 543 + lexicon_doc_site_standard_publication() 544 + } 545 + fn validate( 546 + &self, 547 + ) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> { 548 + Ok(()) 549 + } 550 + }
+7
lexicons-example/src/site_standard/theme.rs
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // This file was automatically generated from Lexicon schemas. 4 + // Any manual changes will be overwritten on the next regeneration. 5 + 6 + pub mod basic; 7 + pub mod color;
+359
lexicons-example/src/site_standard/theme/basic.rs
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // Lexicon: site.standard.theme.basic 4 + // 5 + // This file was automatically generated from Lexicon schemas. 6 + // Any manual changes will be overwritten on the next regeneration. 7 + 8 + /// A simplified theme definition for publications, providing basic color customization for content display across different platforms and applications. 9 + #[jacquard_derive::lexicon] 10 + #[derive( 11 + serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq, jacquard_derive::IntoStatic, 12 + )] 13 + #[serde(rename_all = "camelCase")] 14 + pub struct Basic<'a> { 15 + /// Color used for links and button backgrounds. 16 + #[serde(borrow)] 17 + pub accent: crate::site_standard::theme::color::Rgb<'a>, 18 + /// Color used for button text. 19 + #[serde(borrow)] 20 + pub accent_foreground: crate::site_standard::theme::color::Rgb<'a>, 21 + /// Color used for content background. 22 + #[serde(borrow)] 23 + pub background: crate::site_standard::theme::color::Rgb<'a>, 24 + /// Color used for content text. 25 + #[serde(borrow)] 26 + pub foreground: crate::site_standard::theme::color::Rgb<'a>, 27 + } 28 + 29 + pub mod basic_state { 30 + 31 + pub use crate::builder_types::{IsSet, IsUnset, Set, Unset}; 32 + #[allow(unused)] 33 + use ::core::marker::PhantomData; 34 + mod sealed { 35 + pub trait Sealed {} 36 + } 37 + /// State trait tracking which required fields have been set 38 + pub trait State: sealed::Sealed { 39 + type Background; 40 + type AccentForeground; 41 + type Accent; 42 + type Foreground; 43 + } 44 + /// Empty state - all required fields are unset 45 + pub struct Empty(()); 46 + impl sealed::Sealed for Empty {} 47 + impl State for Empty { 48 + type Background = Unset; 49 + type AccentForeground = Unset; 50 + type Accent = Unset; 51 + type Foreground = Unset; 52 + } 53 + ///State transition - sets the `background` field to Set 54 + pub struct SetBackground<S: State = Empty>(PhantomData<fn() -> S>); 55 + impl<S: State> sealed::Sealed for SetBackground<S> {} 56 + impl<S: State> State for SetBackground<S> { 57 + type Background = Set<members::background>; 58 + type AccentForeground = S::AccentForeground; 59 + type Accent = S::Accent; 60 + type Foreground = S::Foreground; 61 + } 62 + ///State transition - sets the `accent_foreground` field to Set 63 + pub struct SetAccentForeground<S: State = Empty>(PhantomData<fn() -> S>); 64 + impl<S: State> sealed::Sealed for SetAccentForeground<S> {} 65 + impl<S: State> State for SetAccentForeground<S> { 66 + type Background = S::Background; 67 + type AccentForeground = Set<members::accent_foreground>; 68 + type Accent = S::Accent; 69 + type Foreground = S::Foreground; 70 + } 71 + ///State transition - sets the `accent` field to Set 72 + pub struct SetAccent<S: State = Empty>(PhantomData<fn() -> S>); 73 + impl<S: State> sealed::Sealed for SetAccent<S> {} 74 + impl<S: State> State for SetAccent<S> { 75 + type Background = S::Background; 76 + type AccentForeground = S::AccentForeground; 77 + type Accent = Set<members::accent>; 78 + type Foreground = S::Foreground; 79 + } 80 + ///State transition - sets the `foreground` field to Set 81 + pub struct SetForeground<S: State = Empty>(PhantomData<fn() -> S>); 82 + impl<S: State> sealed::Sealed for SetForeground<S> {} 83 + impl<S: State> State for SetForeground<S> { 84 + type Background = S::Background; 85 + type AccentForeground = S::AccentForeground; 86 + type Accent = S::Accent; 87 + type Foreground = Set<members::foreground>; 88 + } 89 + /// Marker types for field names 90 + #[allow(non_camel_case_types)] 91 + pub mod members { 92 + ///Marker type for the `background` field 93 + pub struct background(()); 94 + ///Marker type for the `accent_foreground` field 95 + pub struct accent_foreground(()); 96 + ///Marker type for the `accent` field 97 + pub struct accent(()); 98 + ///Marker type for the `foreground` field 99 + pub struct foreground(()); 100 + } 101 + } 102 + 103 + /// Builder for constructing an instance of this type 104 + pub struct BasicBuilder<'a, S: basic_state::State> { 105 + _phantom_state: ::core::marker::PhantomData<fn() -> S>, 106 + __unsafe_private_named: ( 107 + ::core::option::Option<crate::site_standard::theme::color::Rgb<'a>>, 108 + ::core::option::Option<crate::site_standard::theme::color::Rgb<'a>>, 109 + ::core::option::Option<crate::site_standard::theme::color::Rgb<'a>>, 110 + ::core::option::Option<crate::site_standard::theme::color::Rgb<'a>>, 111 + ), 112 + _phantom: ::core::marker::PhantomData<&'a ()>, 113 + } 114 + 115 + impl<'a> Basic<'a> { 116 + /// Create a new builder for this type 117 + pub fn new() -> BasicBuilder<'a, basic_state::Empty> { 118 + BasicBuilder::new() 119 + } 120 + } 121 + 122 + impl<'a> BasicBuilder<'a, basic_state::Empty> { 123 + /// Create a new builder with all fields unset 124 + pub fn new() -> Self { 125 + BasicBuilder { 126 + _phantom_state: ::core::marker::PhantomData, 127 + __unsafe_private_named: (None, None, None, None), 128 + _phantom: ::core::marker::PhantomData, 129 + } 130 + } 131 + } 132 + 133 + impl<'a, S> BasicBuilder<'a, S> 134 + where 135 + S: basic_state::State, 136 + S::Accent: basic_state::IsUnset, 137 + { 138 + /// Set the `accent` field (required) 139 + pub fn accent( 140 + mut self, 141 + value: impl Into<crate::site_standard::theme::color::Rgb<'a>>, 142 + ) -> BasicBuilder<'a, basic_state::SetAccent<S>> { 143 + self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into()); 144 + BasicBuilder { 145 + _phantom_state: ::core::marker::PhantomData, 146 + __unsafe_private_named: self.__unsafe_private_named, 147 + _phantom: ::core::marker::PhantomData, 148 + } 149 + } 150 + } 151 + 152 + impl<'a, S> BasicBuilder<'a, S> 153 + where 154 + S: basic_state::State, 155 + S::AccentForeground: basic_state::IsUnset, 156 + { 157 + /// Set the `accentForeground` field (required) 158 + pub fn accent_foreground( 159 + mut self, 160 + value: impl Into<crate::site_standard::theme::color::Rgb<'a>>, 161 + ) -> BasicBuilder<'a, basic_state::SetAccentForeground<S>> { 162 + self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into()); 163 + BasicBuilder { 164 + _phantom_state: ::core::marker::PhantomData, 165 + __unsafe_private_named: self.__unsafe_private_named, 166 + _phantom: ::core::marker::PhantomData, 167 + } 168 + } 169 + } 170 + 171 + impl<'a, S> BasicBuilder<'a, S> 172 + where 173 + S: basic_state::State, 174 + S::Background: basic_state::IsUnset, 175 + { 176 + /// Set the `background` field (required) 177 + pub fn background( 178 + mut self, 179 + value: impl Into<crate::site_standard::theme::color::Rgb<'a>>, 180 + ) -> BasicBuilder<'a, basic_state::SetBackground<S>> { 181 + self.__unsafe_private_named.2 = ::core::option::Option::Some(value.into()); 182 + BasicBuilder { 183 + _phantom_state: ::core::marker::PhantomData, 184 + __unsafe_private_named: self.__unsafe_private_named, 185 + _phantom: ::core::marker::PhantomData, 186 + } 187 + } 188 + } 189 + 190 + impl<'a, S> BasicBuilder<'a, S> 191 + where 192 + S: basic_state::State, 193 + S::Foreground: basic_state::IsUnset, 194 + { 195 + /// Set the `foreground` field (required) 196 + pub fn foreground( 197 + mut self, 198 + value: impl Into<crate::site_standard::theme::color::Rgb<'a>>, 199 + ) -> BasicBuilder<'a, basic_state::SetForeground<S>> { 200 + self.__unsafe_private_named.3 = ::core::option::Option::Some(value.into()); 201 + BasicBuilder { 202 + _phantom_state: ::core::marker::PhantomData, 203 + __unsafe_private_named: self.__unsafe_private_named, 204 + _phantom: ::core::marker::PhantomData, 205 + } 206 + } 207 + } 208 + 209 + impl<'a, S> BasicBuilder<'a, S> 210 + where 211 + S: basic_state::State, 212 + S::Background: basic_state::IsSet, 213 + S::AccentForeground: basic_state::IsSet, 214 + S::Accent: basic_state::IsSet, 215 + S::Foreground: basic_state::IsSet, 216 + { 217 + /// Build the final struct 218 + pub fn build(self) -> Basic<'a> { 219 + Basic { 220 + accent: self.__unsafe_private_named.0.unwrap(), 221 + accent_foreground: self.__unsafe_private_named.1.unwrap(), 222 + background: self.__unsafe_private_named.2.unwrap(), 223 + foreground: self.__unsafe_private_named.3.unwrap(), 224 + extra_data: Default::default(), 225 + } 226 + } 227 + /// Build the final struct with custom extra_data 228 + pub fn build_with_data( 229 + self, 230 + extra_data: std::collections::BTreeMap< 231 + jacquard_common::smol_str::SmolStr, 232 + jacquard_common::types::value::Data<'a>, 233 + >, 234 + ) -> Basic<'a> { 235 + Basic { 236 + accent: self.__unsafe_private_named.0.unwrap(), 237 + accent_foreground: self.__unsafe_private_named.1.unwrap(), 238 + background: self.__unsafe_private_named.2.unwrap(), 239 + foreground: self.__unsafe_private_named.3.unwrap(), 240 + extra_data: Some(extra_data), 241 + } 242 + } 243 + } 244 + 245 + fn lexicon_doc_site_standard_theme_basic() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> { 246 + ::jacquard_lexicon::lexicon::LexiconDoc { 247 + lexicon: ::jacquard_lexicon::lexicon::Lexicon::Lexicon1, 248 + id: ::jacquard_common::CowStr::new_static("site.standard.theme.basic"), 249 + revision: None, 250 + description: None, 251 + defs: { 252 + let mut map = ::std::collections::BTreeMap::new(); 253 + map.insert( 254 + ::jacquard_common::smol_str::SmolStr::new_static("main"), 255 + ::jacquard_lexicon::lexicon::LexUserType::Object(::jacquard_lexicon::lexicon::LexObject { 256 + description: Some( 257 + ::jacquard_common::CowStr::new_static( 258 + "A simplified theme definition for publications, providing basic color customization for content display across different platforms and applications.", 259 + ), 260 + ), 261 + required: Some( 262 + vec![ 263 + ::jacquard_common::smol_str::SmolStr::new_static("background"), 264 + ::jacquard_common::smol_str::SmolStr::new_static("foreground"), 265 + ::jacquard_common::smol_str::SmolStr::new_static("accent"), 266 + ::jacquard_common::smol_str::SmolStr::new_static("accentForeground") 267 + ], 268 + ), 269 + nullable: None, 270 + properties: { 271 + #[allow(unused_mut)] 272 + let mut map = ::std::collections::BTreeMap::new(); 273 + map.insert( 274 + ::jacquard_common::smol_str::SmolStr::new_static("accent"), 275 + ::jacquard_lexicon::lexicon::LexObjectProperty::Union(::jacquard_lexicon::lexicon::LexRefUnion { 276 + description: Some( 277 + ::jacquard_common::CowStr::new_static( 278 + "Color used for links and button backgrounds.", 279 + ), 280 + ), 281 + refs: vec![ 282 + ::jacquard_common::CowStr::new_static("site.standard.theme.color#rgb") 283 + ], 284 + closed: None, 285 + }), 286 + ); 287 + map.insert( 288 + ::jacquard_common::smol_str::SmolStr::new_static( 289 + "accentForeground", 290 + ), 291 + ::jacquard_lexicon::lexicon::LexObjectProperty::Union(::jacquard_lexicon::lexicon::LexRefUnion { 292 + description: Some( 293 + ::jacquard_common::CowStr::new_static( 294 + "Color used for button text.", 295 + ), 296 + ), 297 + refs: vec![ 298 + ::jacquard_common::CowStr::new_static("site.standard.theme.color#rgb") 299 + ], 300 + closed: None, 301 + }), 302 + ); 303 + map.insert( 304 + ::jacquard_common::smol_str::SmolStr::new_static( 305 + "background", 306 + ), 307 + ::jacquard_lexicon::lexicon::LexObjectProperty::Union(::jacquard_lexicon::lexicon::LexRefUnion { 308 + description: Some( 309 + ::jacquard_common::CowStr::new_static( 310 + "Color used for content background.", 311 + ), 312 + ), 313 + refs: vec![ 314 + ::jacquard_common::CowStr::new_static("site.standard.theme.color#rgb") 315 + ], 316 + closed: None, 317 + }), 318 + ); 319 + map.insert( 320 + ::jacquard_common::smol_str::SmolStr::new_static( 321 + "foreground", 322 + ), 323 + ::jacquard_lexicon::lexicon::LexObjectProperty::Union(::jacquard_lexicon::lexicon::LexRefUnion { 324 + description: Some( 325 + ::jacquard_common::CowStr::new_static( 326 + "Color used for content text.", 327 + ), 328 + ), 329 + refs: vec![ 330 + ::jacquard_common::CowStr::new_static("site.standard.theme.color#rgb") 331 + ], 332 + closed: None, 333 + }), 334 + ); 335 + map 336 + }, 337 + }), 338 + ); 339 + map 340 + }, 341 + } 342 + } 343 + 344 + impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Basic<'a> { 345 + fn nsid() -> &'static str { 346 + "site.standard.theme.basic" 347 + } 348 + fn def_name() -> &'static str { 349 + "main" 350 + } 351 + fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> { 352 + lexicon_doc_site_standard_theme_basic() 353 + } 354 + fn validate( 355 + &self, 356 + ) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> { 357 + Ok(()) 358 + } 359 + }
+718
lexicons-example/src/site_standard/theme/color.rs
··· 1 + // @generated by jacquard-lexicon. DO NOT EDIT. 2 + // 3 + // Lexicon: site.standard.theme.color 4 + // 5 + // This file was automatically generated from Lexicon schemas. 6 + // Any manual changes will be overwritten on the next regeneration. 7 + 8 + #[jacquard_derive::lexicon] 9 + #[derive( 10 + serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq, jacquard_derive::IntoStatic, 11 + )] 12 + #[serde(rename_all = "camelCase")] 13 + pub struct Rgb<'a> { 14 + pub b: i64, 15 + pub g: i64, 16 + pub r: i64, 17 + } 18 + 19 + pub mod rgb_state { 20 + 21 + pub use crate::builder_types::{IsSet, IsUnset, Set, Unset}; 22 + #[allow(unused)] 23 + use ::core::marker::PhantomData; 24 + mod sealed { 25 + pub trait Sealed {} 26 + } 27 + /// State trait tracking which required fields have been set 28 + pub trait State: sealed::Sealed { 29 + type B; 30 + type R; 31 + type G; 32 + } 33 + /// Empty state - all required fields are unset 34 + pub struct Empty(()); 35 + impl sealed::Sealed for Empty {} 36 + impl State for Empty { 37 + type B = Unset; 38 + type R = Unset; 39 + type G = Unset; 40 + } 41 + ///State transition - sets the `b` field to Set 42 + pub struct SetB<S: State = Empty>(PhantomData<fn() -> S>); 43 + impl<S: State> sealed::Sealed for SetB<S> {} 44 + impl<S: State> State for SetB<S> { 45 + type B = Set<members::b>; 46 + type R = S::R; 47 + type G = S::G; 48 + } 49 + ///State transition - sets the `r` field to Set 50 + pub struct SetR<S: State = Empty>(PhantomData<fn() -> S>); 51 + impl<S: State> sealed::Sealed for SetR<S> {} 52 + impl<S: State> State for SetR<S> { 53 + type B = S::B; 54 + type R = Set<members::r>; 55 + type G = S::G; 56 + } 57 + ///State transition - sets the `g` field to Set 58 + pub struct SetG<S: State = Empty>(PhantomData<fn() -> S>); 59 + impl<S: State> sealed::Sealed for SetG<S> {} 60 + impl<S: State> State for SetG<S> { 61 + type B = S::B; 62 + type R = S::R; 63 + type G = Set<members::g>; 64 + } 65 + /// Marker types for field names 66 + #[allow(non_camel_case_types)] 67 + pub mod members { 68 + ///Marker type for the `b` field 69 + pub struct b(()); 70 + ///Marker type for the `r` field 71 + pub struct r(()); 72 + ///Marker type for the `g` field 73 + pub struct g(()); 74 + } 75 + } 76 + 77 + /// Builder for constructing an instance of this type 78 + pub struct RgbBuilder<'a, S: rgb_state::State> { 79 + _phantom_state: ::core::marker::PhantomData<fn() -> S>, 80 + __unsafe_private_named: ( 81 + ::core::option::Option<i64>, 82 + ::core::option::Option<i64>, 83 + ::core::option::Option<i64>, 84 + ), 85 + _phantom: ::core::marker::PhantomData<&'a ()>, 86 + } 87 + 88 + impl<'a> Rgb<'a> { 89 + /// Create a new builder for this type 90 + pub fn new() -> RgbBuilder<'a, rgb_state::Empty> { 91 + RgbBuilder::new() 92 + } 93 + } 94 + 95 + impl<'a> RgbBuilder<'a, rgb_state::Empty> { 96 + /// Create a new builder with all fields unset 97 + pub fn new() -> Self { 98 + RgbBuilder { 99 + _phantom_state: ::core::marker::PhantomData, 100 + __unsafe_private_named: (None, None, None), 101 + _phantom: ::core::marker::PhantomData, 102 + } 103 + } 104 + } 105 + 106 + impl<'a, S> RgbBuilder<'a, S> 107 + where 108 + S: rgb_state::State, 109 + S::B: rgb_state::IsUnset, 110 + { 111 + /// Set the `b` field (required) 112 + pub fn b(mut self, value: impl Into<i64>) -> RgbBuilder<'a, rgb_state::SetB<S>> { 113 + self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into()); 114 + RgbBuilder { 115 + _phantom_state: ::core::marker::PhantomData, 116 + __unsafe_private_named: self.__unsafe_private_named, 117 + _phantom: ::core::marker::PhantomData, 118 + } 119 + } 120 + } 121 + 122 + impl<'a, S> RgbBuilder<'a, S> 123 + where 124 + S: rgb_state::State, 125 + S::G: rgb_state::IsUnset, 126 + { 127 + /// Set the `g` field (required) 128 + pub fn g(mut self, value: impl Into<i64>) -> RgbBuilder<'a, rgb_state::SetG<S>> { 129 + self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into()); 130 + RgbBuilder { 131 + _phantom_state: ::core::marker::PhantomData, 132 + __unsafe_private_named: self.__unsafe_private_named, 133 + _phantom: ::core::marker::PhantomData, 134 + } 135 + } 136 + } 137 + 138 + impl<'a, S> RgbBuilder<'a, S> 139 + where 140 + S: rgb_state::State, 141 + S::R: rgb_state::IsUnset, 142 + { 143 + /// Set the `r` field (required) 144 + pub fn r(mut self, value: impl Into<i64>) -> RgbBuilder<'a, rgb_state::SetR<S>> { 145 + self.__unsafe_private_named.2 = ::core::option::Option::Some(value.into()); 146 + RgbBuilder { 147 + _phantom_state: ::core::marker::PhantomData, 148 + __unsafe_private_named: self.__unsafe_private_named, 149 + _phantom: ::core::marker::PhantomData, 150 + } 151 + } 152 + } 153 + 154 + impl<'a, S> RgbBuilder<'a, S> 155 + where 156 + S: rgb_state::State, 157 + S::B: rgb_state::IsSet, 158 + S::R: rgb_state::IsSet, 159 + S::G: rgb_state::IsSet, 160 + { 161 + /// Build the final struct 162 + pub fn build(self) -> Rgb<'a> { 163 + Rgb { 164 + b: self.__unsafe_private_named.0.unwrap(), 165 + g: self.__unsafe_private_named.1.unwrap(), 166 + r: self.__unsafe_private_named.2.unwrap(), 167 + extra_data: Default::default(), 168 + } 169 + } 170 + /// Build the final struct with custom extra_data 171 + pub fn build_with_data( 172 + self, 173 + extra_data: std::collections::BTreeMap< 174 + jacquard_common::smol_str::SmolStr, 175 + jacquard_common::types::value::Data<'a>, 176 + >, 177 + ) -> Rgb<'a> { 178 + Rgb { 179 + b: self.__unsafe_private_named.0.unwrap(), 180 + g: self.__unsafe_private_named.1.unwrap(), 181 + r: self.__unsafe_private_named.2.unwrap(), 182 + extra_data: Some(extra_data), 183 + } 184 + } 185 + } 186 + 187 + fn lexicon_doc_site_standard_theme_color() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> { 188 + ::jacquard_lexicon::lexicon::LexiconDoc { 189 + lexicon: ::jacquard_lexicon::lexicon::Lexicon::Lexicon1, 190 + id: ::jacquard_common::CowStr::new_static("site.standard.theme.color"), 191 + revision: None, 192 + description: None, 193 + defs: { 194 + let mut map = ::std::collections::BTreeMap::new(); 195 + map.insert( 196 + ::jacquard_common::smol_str::SmolStr::new_static("rgb"), 197 + ::jacquard_lexicon::lexicon::LexUserType::Object( 198 + ::jacquard_lexicon::lexicon::LexObject { 199 + description: None, 200 + required: Some(vec![ 201 + ::jacquard_common::smol_str::SmolStr::new_static("r"), 202 + ::jacquard_common::smol_str::SmolStr::new_static("g"), 203 + ::jacquard_common::smol_str::SmolStr::new_static("b"), 204 + ]), 205 + nullable: None, 206 + properties: { 207 + #[allow(unused_mut)] 208 + let mut map = ::std::collections::BTreeMap::new(); 209 + map.insert( 210 + ::jacquard_common::smol_str::SmolStr::new_static("b"), 211 + ::jacquard_lexicon::lexicon::LexObjectProperty::Integer( 212 + ::jacquard_lexicon::lexicon::LexInteger { 213 + description: None, 214 + default: None, 215 + minimum: Some(0i64), 216 + maximum: Some(255i64), 217 + r#enum: None, 218 + r#const: None, 219 + }, 220 + ), 221 + ); 222 + map.insert( 223 + ::jacquard_common::smol_str::SmolStr::new_static("g"), 224 + ::jacquard_lexicon::lexicon::LexObjectProperty::Integer( 225 + ::jacquard_lexicon::lexicon::LexInteger { 226 + description: None, 227 + default: None, 228 + minimum: Some(0i64), 229 + maximum: Some(255i64), 230 + r#enum: None, 231 + r#const: None, 232 + }, 233 + ), 234 + ); 235 + map.insert( 236 + ::jacquard_common::smol_str::SmolStr::new_static("r"), 237 + ::jacquard_lexicon::lexicon::LexObjectProperty::Integer( 238 + ::jacquard_lexicon::lexicon::LexInteger { 239 + description: None, 240 + default: None, 241 + minimum: Some(0i64), 242 + maximum: Some(255i64), 243 + r#enum: None, 244 + r#const: None, 245 + }, 246 + ), 247 + ); 248 + map 249 + }, 250 + }, 251 + ), 252 + ); 253 + map.insert( 254 + ::jacquard_common::smol_str::SmolStr::new_static("rgba"), 255 + ::jacquard_lexicon::lexicon::LexUserType::Object( 256 + ::jacquard_lexicon::lexicon::LexObject { 257 + description: None, 258 + required: Some(vec![ 259 + ::jacquard_common::smol_str::SmolStr::new_static("r"), 260 + ::jacquard_common::smol_str::SmolStr::new_static("g"), 261 + ::jacquard_common::smol_str::SmolStr::new_static("b"), 262 + ::jacquard_common::smol_str::SmolStr::new_static("a"), 263 + ]), 264 + nullable: None, 265 + properties: { 266 + #[allow(unused_mut)] 267 + let mut map = ::std::collections::BTreeMap::new(); 268 + map.insert( 269 + ::jacquard_common::smol_str::SmolStr::new_static("a"), 270 + ::jacquard_lexicon::lexicon::LexObjectProperty::Integer( 271 + ::jacquard_lexicon::lexicon::LexInteger { 272 + description: None, 273 + default: None, 274 + minimum: Some(0i64), 275 + maximum: Some(100i64), 276 + r#enum: None, 277 + r#const: None, 278 + }, 279 + ), 280 + ); 281 + map.insert( 282 + ::jacquard_common::smol_str::SmolStr::new_static("b"), 283 + ::jacquard_lexicon::lexicon::LexObjectProperty::Integer( 284 + ::jacquard_lexicon::lexicon::LexInteger { 285 + description: None, 286 + default: None, 287 + minimum: Some(0i64), 288 + maximum: Some(255i64), 289 + r#enum: None, 290 + r#const: None, 291 + }, 292 + ), 293 + ); 294 + map.insert( 295 + ::jacquard_common::smol_str::SmolStr::new_static("g"), 296 + ::jacquard_lexicon::lexicon::LexObjectProperty::Integer( 297 + ::jacquard_lexicon::lexicon::LexInteger { 298 + description: None, 299 + default: None, 300 + minimum: Some(0i64), 301 + maximum: Some(255i64), 302 + r#enum: None, 303 + r#const: None, 304 + }, 305 + ), 306 + ); 307 + map.insert( 308 + ::jacquard_common::smol_str::SmolStr::new_static("r"), 309 + ::jacquard_lexicon::lexicon::LexObjectProperty::Integer( 310 + ::jacquard_lexicon::lexicon::LexInteger { 311 + description: None, 312 + default: None, 313 + minimum: Some(0i64), 314 + maximum: Some(255i64), 315 + r#enum: None, 316 + r#const: None, 317 + }, 318 + ), 319 + ); 320 + map 321 + }, 322 + }, 323 + ), 324 + ); 325 + map 326 + }, 327 + } 328 + } 329 + 330 + impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Rgb<'a> { 331 + fn nsid() -> &'static str { 332 + "site.standard.theme.color" 333 + } 334 + fn def_name() -> &'static str { 335 + "rgb" 336 + } 337 + fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> { 338 + lexicon_doc_site_standard_theme_color() 339 + } 340 + fn validate( 341 + &self, 342 + ) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> { 343 + { 344 + let value = &self.b; 345 + if *value > 255i64 { 346 + return Err(::jacquard_lexicon::validation::ConstraintError::Maximum { 347 + path: ::jacquard_lexicon::validation::ValidationPath::from_field("b"), 348 + max: 255i64, 349 + actual: *value, 350 + }); 351 + } 352 + } 353 + { 354 + let value = &self.b; 355 + if *value < 0i64 { 356 + return Err(::jacquard_lexicon::validation::ConstraintError::Minimum { 357 + path: ::jacquard_lexicon::validation::ValidationPath::from_field("b"), 358 + min: 0i64, 359 + actual: *value, 360 + }); 361 + } 362 + } 363 + { 364 + let value = &self.g; 365 + if *value > 255i64 { 366 + return Err(::jacquard_lexicon::validation::ConstraintError::Maximum { 367 + path: ::jacquard_lexicon::validation::ValidationPath::from_field("g"), 368 + max: 255i64, 369 + actual: *value, 370 + }); 371 + } 372 + } 373 + { 374 + let value = &self.g; 375 + if *value < 0i64 { 376 + return Err(::jacquard_lexicon::validation::ConstraintError::Minimum { 377 + path: ::jacquard_lexicon::validation::ValidationPath::from_field("g"), 378 + min: 0i64, 379 + actual: *value, 380 + }); 381 + } 382 + } 383 + { 384 + let value = &self.r; 385 + if *value > 255i64 { 386 + return Err(::jacquard_lexicon::validation::ConstraintError::Maximum { 387 + path: ::jacquard_lexicon::validation::ValidationPath::from_field("r"), 388 + max: 255i64, 389 + actual: *value, 390 + }); 391 + } 392 + } 393 + { 394 + let value = &self.r; 395 + if *value < 0i64 { 396 + return Err(::jacquard_lexicon::validation::ConstraintError::Minimum { 397 + path: ::jacquard_lexicon::validation::ValidationPath::from_field("r"), 398 + min: 0i64, 399 + actual: *value, 400 + }); 401 + } 402 + } 403 + Ok(()) 404 + } 405 + } 406 + 407 + #[jacquard_derive::lexicon] 408 + #[derive( 409 + serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq, jacquard_derive::IntoStatic, 410 + )] 411 + #[serde(rename_all = "camelCase")] 412 + pub struct Rgba<'a> { 413 + pub a: i64, 414 + pub b: i64, 415 + pub g: i64, 416 + pub r: i64, 417 + } 418 + 419 + pub mod rgba_state { 420 + 421 + pub use crate::builder_types::{IsSet, IsUnset, Set, Unset}; 422 + #[allow(unused)] 423 + use ::core::marker::PhantomData; 424 + mod sealed { 425 + pub trait Sealed {} 426 + } 427 + /// State trait tracking which required fields have been set 428 + pub trait State: sealed::Sealed { 429 + type A; 430 + type R; 431 + type B; 432 + type G; 433 + } 434 + /// Empty state - all required fields are unset 435 + pub struct Empty(()); 436 + impl sealed::Sealed for Empty {} 437 + impl State for Empty { 438 + type A = Unset; 439 + type R = Unset; 440 + type B = Unset; 441 + type G = Unset; 442 + } 443 + ///State transition - sets the `a` field to Set 444 + pub struct SetA<S: State = Empty>(PhantomData<fn() -> S>); 445 + impl<S: State> sealed::Sealed for SetA<S> {} 446 + impl<S: State> State for SetA<S> { 447 + type A = Set<members::a>; 448 + type R = S::R; 449 + type B = S::B; 450 + type G = S::G; 451 + } 452 + ///State transition - sets the `r` field to Set 453 + pub struct SetR<S: State = Empty>(PhantomData<fn() -> S>); 454 + impl<S: State> sealed::Sealed for SetR<S> {} 455 + impl<S: State> State for SetR<S> { 456 + type A = S::A; 457 + type R = Set<members::r>; 458 + type B = S::B; 459 + type G = S::G; 460 + } 461 + ///State transition - sets the `b` field to Set 462 + pub struct SetB<S: State = Empty>(PhantomData<fn() -> S>); 463 + impl<S: State> sealed::Sealed for SetB<S> {} 464 + impl<S: State> State for SetB<S> { 465 + type A = S::A; 466 + type R = S::R; 467 + type B = Set<members::b>; 468 + type G = S::G; 469 + } 470 + ///State transition - sets the `g` field to Set 471 + pub struct SetG<S: State = Empty>(PhantomData<fn() -> S>); 472 + impl<S: State> sealed::Sealed for SetG<S> {} 473 + impl<S: State> State for SetG<S> { 474 + type A = S::A; 475 + type R = S::R; 476 + type B = S::B; 477 + type G = Set<members::g>; 478 + } 479 + /// Marker types for field names 480 + #[allow(non_camel_case_types)] 481 + pub mod members { 482 + ///Marker type for the `a` field 483 + pub struct a(()); 484 + ///Marker type for the `r` field 485 + pub struct r(()); 486 + ///Marker type for the `b` field 487 + pub struct b(()); 488 + ///Marker type for the `g` field 489 + pub struct g(()); 490 + } 491 + } 492 + 493 + /// Builder for constructing an instance of this type 494 + pub struct RgbaBuilder<'a, S: rgba_state::State> { 495 + _phantom_state: ::core::marker::PhantomData<fn() -> S>, 496 + __unsafe_private_named: ( 497 + ::core::option::Option<i64>, 498 + ::core::option::Option<i64>, 499 + ::core::option::Option<i64>, 500 + ::core::option::Option<i64>, 501 + ), 502 + _phantom: ::core::marker::PhantomData<&'a ()>, 503 + } 504 + 505 + impl<'a> Rgba<'a> { 506 + /// Create a new builder for this type 507 + pub fn new() -> RgbaBuilder<'a, rgba_state::Empty> { 508 + RgbaBuilder::new() 509 + } 510 + } 511 + 512 + impl<'a> RgbaBuilder<'a, rgba_state::Empty> { 513 + /// Create a new builder with all fields unset 514 + pub fn new() -> Self { 515 + RgbaBuilder { 516 + _phantom_state: ::core::marker::PhantomData, 517 + __unsafe_private_named: (None, None, None, None), 518 + _phantom: ::core::marker::PhantomData, 519 + } 520 + } 521 + } 522 + 523 + impl<'a, S> RgbaBuilder<'a, S> 524 + where 525 + S: rgba_state::State, 526 + S::A: rgba_state::IsUnset, 527 + { 528 + /// Set the `a` field (required) 529 + pub fn a(mut self, value: impl Into<i64>) -> RgbaBuilder<'a, rgba_state::SetA<S>> { 530 + self.__unsafe_private_named.0 = ::core::option::Option::Some(value.into()); 531 + RgbaBuilder { 532 + _phantom_state: ::core::marker::PhantomData, 533 + __unsafe_private_named: self.__unsafe_private_named, 534 + _phantom: ::core::marker::PhantomData, 535 + } 536 + } 537 + } 538 + 539 + impl<'a, S> RgbaBuilder<'a, S> 540 + where 541 + S: rgba_state::State, 542 + S::B: rgba_state::IsUnset, 543 + { 544 + /// Set the `b` field (required) 545 + pub fn b(mut self, value: impl Into<i64>) -> RgbaBuilder<'a, rgba_state::SetB<S>> { 546 + self.__unsafe_private_named.1 = ::core::option::Option::Some(value.into()); 547 + RgbaBuilder { 548 + _phantom_state: ::core::marker::PhantomData, 549 + __unsafe_private_named: self.__unsafe_private_named, 550 + _phantom: ::core::marker::PhantomData, 551 + } 552 + } 553 + } 554 + 555 + impl<'a, S> RgbaBuilder<'a, S> 556 + where 557 + S: rgba_state::State, 558 + S::G: rgba_state::IsUnset, 559 + { 560 + /// Set the `g` field (required) 561 + pub fn g(mut self, value: impl Into<i64>) -> RgbaBuilder<'a, rgba_state::SetG<S>> { 562 + self.__unsafe_private_named.2 = ::core::option::Option::Some(value.into()); 563 + RgbaBuilder { 564 + _phantom_state: ::core::marker::PhantomData, 565 + __unsafe_private_named: self.__unsafe_private_named, 566 + _phantom: ::core::marker::PhantomData, 567 + } 568 + } 569 + } 570 + 571 + impl<'a, S> RgbaBuilder<'a, S> 572 + where 573 + S: rgba_state::State, 574 + S::R: rgba_state::IsUnset, 575 + { 576 + /// Set the `r` field (required) 577 + pub fn r(mut self, value: impl Into<i64>) -> RgbaBuilder<'a, rgba_state::SetR<S>> { 578 + self.__unsafe_private_named.3 = ::core::option::Option::Some(value.into()); 579 + RgbaBuilder { 580 + _phantom_state: ::core::marker::PhantomData, 581 + __unsafe_private_named: self.__unsafe_private_named, 582 + _phantom: ::core::marker::PhantomData, 583 + } 584 + } 585 + } 586 + 587 + impl<'a, S> RgbaBuilder<'a, S> 588 + where 589 + S: rgba_state::State, 590 + S::A: rgba_state::IsSet, 591 + S::R: rgba_state::IsSet, 592 + S::B: rgba_state::IsSet, 593 + S::G: rgba_state::IsSet, 594 + { 595 + /// Build the final struct 596 + pub fn build(self) -> Rgba<'a> { 597 + Rgba { 598 + a: self.__unsafe_private_named.0.unwrap(), 599 + b: self.__unsafe_private_named.1.unwrap(), 600 + g: self.__unsafe_private_named.2.unwrap(), 601 + r: self.__unsafe_private_named.3.unwrap(), 602 + extra_data: Default::default(), 603 + } 604 + } 605 + /// Build the final struct with custom extra_data 606 + pub fn build_with_data( 607 + self, 608 + extra_data: std::collections::BTreeMap< 609 + jacquard_common::smol_str::SmolStr, 610 + jacquard_common::types::value::Data<'a>, 611 + >, 612 + ) -> Rgba<'a> { 613 + Rgba { 614 + a: self.__unsafe_private_named.0.unwrap(), 615 + b: self.__unsafe_private_named.1.unwrap(), 616 + g: self.__unsafe_private_named.2.unwrap(), 617 + r: self.__unsafe_private_named.3.unwrap(), 618 + extra_data: Some(extra_data), 619 + } 620 + } 621 + } 622 + 623 + impl<'a> ::jacquard_lexicon::schema::LexiconSchema for Rgba<'a> { 624 + fn nsid() -> &'static str { 625 + "site.standard.theme.color" 626 + } 627 + fn def_name() -> &'static str { 628 + "rgba" 629 + } 630 + fn lexicon_doc() -> ::jacquard_lexicon::lexicon::LexiconDoc<'static> { 631 + lexicon_doc_site_standard_theme_color() 632 + } 633 + fn validate( 634 + &self, 635 + ) -> ::std::result::Result<(), ::jacquard_lexicon::validation::ConstraintError> { 636 + { 637 + let value = &self.a; 638 + if *value > 100i64 { 639 + return Err(::jacquard_lexicon::validation::ConstraintError::Maximum { 640 + path: ::jacquard_lexicon::validation::ValidationPath::from_field("a"), 641 + max: 100i64, 642 + actual: *value, 643 + }); 644 + } 645 + } 646 + { 647 + let value = &self.a; 648 + if *value < 0i64 { 649 + return Err(::jacquard_lexicon::validation::ConstraintError::Minimum { 650 + path: ::jacquard_lexicon::validation::ValidationPath::from_field("a"), 651 + min: 0i64, 652 + actual: *value, 653 + }); 654 + } 655 + } 656 + { 657 + let value = &self.b; 658 + if *value > 255i64 { 659 + return Err(::jacquard_lexicon::validation::ConstraintError::Maximum { 660 + path: ::jacquard_lexicon::validation::ValidationPath::from_field("b"), 661 + max: 255i64, 662 + actual: *value, 663 + }); 664 + } 665 + } 666 + { 667 + let value = &self.b; 668 + if *value < 0i64 { 669 + return Err(::jacquard_lexicon::validation::ConstraintError::Minimum { 670 + path: ::jacquard_lexicon::validation::ValidationPath::from_field("b"), 671 + min: 0i64, 672 + actual: *value, 673 + }); 674 + } 675 + } 676 + { 677 + let value = &self.g; 678 + if *value > 255i64 { 679 + return Err(::jacquard_lexicon::validation::ConstraintError::Maximum { 680 + path: ::jacquard_lexicon::validation::ValidationPath::from_field("g"), 681 + max: 255i64, 682 + actual: *value, 683 + }); 684 + } 685 + } 686 + { 687 + let value = &self.g; 688 + if *value < 0i64 { 689 + return Err(::jacquard_lexicon::validation::ConstraintError::Minimum { 690 + path: ::jacquard_lexicon::validation::ValidationPath::from_field("g"), 691 + min: 0i64, 692 + actual: *value, 693 + }); 694 + } 695 + } 696 + { 697 + let value = &self.r; 698 + if *value > 255i64 { 699 + return Err(::jacquard_lexicon::validation::ConstraintError::Maximum { 700 + path: ::jacquard_lexicon::validation::ValidationPath::from_field("r"), 701 + max: 255i64, 702 + actual: *value, 703 + }); 704 + } 705 + } 706 + { 707 + let value = &self.r; 708 + if *value < 0i64 { 709 + return Err(::jacquard_lexicon::validation::ConstraintError::Minimum { 710 + path: ::jacquard_lexicon::validation::ValidationPath::from_field("r"), 711 + min: 0i64, 712 + actual: *value, 713 + }); 714 + } 715 + } 716 + Ok(()) 717 + } 718 + }
+59 -42
src/channel.rs tapped/src/channel.rs
··· 4 4 use serde::Serialize; 5 5 use tokio::sync::mpsc; 6 6 use tokio_tungstenite::{connect_async, tungstenite::Message}; 7 + use tungstenite::protocol::frame::Utf8Bytes; 7 8 use url::Url; 8 9 9 - use crate::types::RawEvent; 10 + use crate::types::{RawEvent, RawEventOwned, RawRecordEventOwned, Record, UnparsedRecord}; 10 11 use crate::{Error, Event, Result}; 11 12 12 13 type WsStream = ··· 23 24 /// closes, `recv()` will return an error and you must create a new 24 25 /// `EventReceiver` via [`TapClient::channel()`](crate::TapClient::channel). 25 26 pub struct EventReceiver { 26 - event_rx: mpsc::Receiver<Result<EventWithAck>>, 27 + event_rx: mpsc::Receiver<EventWithAck>, 27 28 _ack_tx: mpsc::Sender<u64>, 28 29 } 29 30 30 31 struct EventWithAck { 31 - event: Event, 32 + event: Utf8Bytes, 32 33 ack_tx: mpsc::Sender<u64>, 33 34 } 34 35 ··· 60 61 61 62 fn deref(&self) -> &Self::Target { 62 63 &self.event 63 - } 64 - } 65 - 66 - impl std::fmt::Debug for ReceivedEvent { 67 - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 68 - self.event.fmt(f) 69 64 } 70 65 } 71 66 ··· 99 94 100 95 let (write, read) = ws_stream.split(); 101 96 102 - let (event_tx, event_rx) = mpsc::channel::<Result<EventWithAck>>(100); 103 - let (ack_tx, ack_rx) = mpsc::channel::<u64>(1000); 97 + let (event_tx, event_rx) = mpsc::channel(100); 98 + let (ack_tx, ack_rx) = mpsc::channel(1000); 104 99 105 100 let ack_tx_clone = ack_tx.clone(); 106 101 tokio::spawn(async move { ··· 126 121 /// 127 122 /// Returns [`Error::ChannelClosed`] if the WebSocket connection closes. 128 123 pub async fn recv(&mut self) -> Result<ReceivedEvent> { 129 - match self.event_rx.recv().await { 130 - Some(Ok(event_with_ack)) => { 131 - let id = event_with_ack.event.id(); 132 - Ok(ReceivedEvent { 133 - event: event_with_ack.event, 134 - _ack_guard: AckGuard { 135 - id, 136 - ack_tx: Some(event_with_ack.ack_tx), 137 - }, 138 - }) 124 + loop { 125 + match self.event_rx.recv().await { 126 + Some(event_with_ack) => { 127 + let mut raw_event_owned = None::<RawEventOwned>; 128 + let mut raw_record_owned = None::<RawRecordEventOwned>; 129 + let inner_record = Record::new(event_with_ack.event, |json| { 130 + match serde_json::from_str::<RawEvent>(json) { 131 + Ok(mut raw) => { 132 + let inner = if let Some(mut rec) = raw.record.take() { 133 + let inner = rec.record.take(); 134 + raw_record_owned = Some(rec.owned); 135 + inner 136 + } else { 137 + None 138 + }; 139 + raw_event_owned = Some(raw.owned); 140 + UnparsedRecord(inner) 141 + } 142 + Err(e) => { 143 + tracing::warn!("Failed to parse event: {}", e); 144 + UnparsedRecord(None) 145 + } 146 + } 147 + }); 148 + let inner_record = if inner_record.borrow_dependent().0.is_some() { 149 + Some(inner_record) 150 + } else { 151 + None 152 + }; 153 + if let Some(event) = 154 + raw_event_owned.and_then(|r| r.into_event(raw_record_owned, inner_record)) 155 + { 156 + let id = event.id(); 157 + break Ok(ReceivedEvent { 158 + event, 159 + _ack_guard: AckGuard { 160 + id, 161 + ack_tx: Some(event_with_ack.ack_tx), 162 + }, 163 + }); 164 + } 165 + } 166 + None => break Err(Error::ChannelClosed), 139 167 } 140 - Some(Err(e)) => Err(e), 141 - None => Err(Error::ChannelClosed), 142 168 } 143 169 } 144 170 ··· 171 197 /// Reader task: reads events from WebSocket and sends to channel. 172 198 async fn reader_task( 173 199 mut read: WsSource, 174 - event_tx: mpsc::Sender<Result<EventWithAck>>, 200 + event_tx: mpsc::Sender<EventWithAck>, 175 201 ack_tx: mpsc::Sender<u64>, 176 202 ) { 177 203 while let Some(msg_result) = read.next().await { 178 204 match msg_result { 179 - Ok(Message::Text(text)) => match serde_json::from_str::<RawEvent>(&text) { 180 - Ok(raw) => { 181 - if let Some(event) = raw.into_event() { 182 - let event_with_ack = EventWithAck { 183 - event, 184 - ack_tx: ack_tx.clone(), 185 - }; 186 - if event_tx.send(Ok(event_with_ack)).await.is_err() { 187 - break; 188 - } 189 - } 190 - } 191 - Err(e) => { 192 - tracing::warn!("Failed to parse event: {}", e); 205 + Ok(Message::Text(event)) => { 206 + let event_with_ack = EventWithAck { 207 + event, 208 + ack_tx: ack_tx.clone(), 209 + }; 210 + if event_tx.send(event_with_ack).await.is_err() { 211 + break; 193 212 } 194 - }, 213 + } 195 214 Ok(Message::Close(_)) => { 196 - let _ = event_tx.send(Err(Error::ChannelClosed)).await; 197 215 break; 198 216 } 199 217 Ok(_) => { 200 218 // Ignore ping/pong/binary 201 219 } 202 - Err(e) => { 203 - let _ = event_tx.send(Err(Error::WebSocket(Box::new(e)))).await; 220 + Err(_) => { 204 221 break; 205 222 } 206 223 }
-1
src/client.rs tapped/src/client.rs
··· 350 350 /// let mut receiver = client.channel().await?; 351 351 /// 352 352 /// while let Ok(event) = receiver.recv().await { 353 - /// println!("Event: {:?}", event); 354 353 /// // Event is automatically acknowledged when dropped 355 354 /// } 356 355 /// # Ok(())
+1 -1
src/config.rs tapped/src/config.rs
··· 42 42 pub max_db_conns: Option<u32>, 43 43 44 44 // Server 45 - /// HTTP server bind address (e.g., ":2480", "127.0.0.1:2480", or "[::1]:2480") 45 + /// HTTP server bind address (e.g., `":2480"`, `"127.0.0.1:2480"`, or `"[::1]:2480"`) 46 46 pub bind: Option<String>, 47 47 /// Basic auth admin password for all requests 48 48 pub admin_password: Option<String>,
+4
src/error.rs tapped/src/error.rs
··· 64 64 /// URL parse error 65 65 #[error("URL parse error: {0}")] 66 66 UrlParse(#[from] url::ParseError), 67 + 68 + /// No record present in event 69 + #[error("No record present in event")] 70 + NoRecordPresent, 67 71 }
+4 -3
src/handle.rs tapped/src/handle.rs
··· 11 11 /// A convenience type that owns both a tap process and its client. 12 12 /// 13 13 /// `TapHandle` manages the lifecycle of a tap subprocess and provides 14 - /// access to a [`TapClient`] for interacting with it. When dropped, 15 - /// the process is gracefully shut down. 14 + /// access to a [`TapClient`] for interacting with it. The process receives 15 + /// SIGTERM when this handle is dropped. For graceful shutdown with timeout 16 + /// handling, call [`shutdown()`](TapHandle::shutdown) explicitly. 16 17 /// 17 18 /// # Example 18 19 /// ··· 33 34 /// 34 35 /// let mut channel = handle.channel().await?; 35 36 /// while let Ok(event) = channel.recv().await { 36 - /// println!("Event: {:?}", event.event); 37 + /// // Handle event 37 38 /// } 38 39 /// 39 40 /// Ok(())
+2 -3
src/lib.rs tapped/src/lib.rs
··· 32 32 //! // Stream events 33 33 //! let mut receiver = client.channel().await?; 34 34 //! while let Ok(event) = receiver.recv().await { 35 - //! println!("Received event: {:?}", event); 36 35 //! // Event is automatically acknowledged when dropped 37 36 //! } 38 37 //! ··· 55 54 pub use handle::TapHandle; 56 55 pub use process::TapProcess; 57 56 pub use types::{ 58 - AccountStatus, Cursors, DidDocument, Event, IdentityEvent, Record, RecordAction, RecordEvent, 59 - RepoInfo, RepoState, Service, VerificationMethod, 57 + AccountStatus, Cursors, DidDocument, Event, IdentityEvent, RecordAction, RecordEvent, RepoInfo, 58 + RepoState, Service, VerificationMethod, 60 59 }; 61 60 62 61 /// A specialised Result type for tapped operations.
+2 -1
src/process.rs tapped/src/process.rs
··· 12 12 13 13 /// A running tap process. 14 14 /// 15 - /// The process is gracefully shut down when this struct is dropped. 15 + /// The process receives SIGTERM when this struct is dropped. For graceful 16 + /// shutdown with timeout handling, call [`shutdown()`](TapProcess::shutdown) explicitly. 16 17 pub struct TapProcess { 17 18 child: Child, 18 19 url: Url,
+84 -94
src/types.rs tapped/src/types.rs
··· 1 1 //! Type definitions for tap events and API responses. 2 2 3 3 use serde::{Deserialize, Serialize}; 4 + use serde_json::value::RawValue; 4 5 5 - /// A record's JSON data with helper methods. 6 - /// 7 - /// Wraps the raw JSON value and provides convenient accessors. 8 - #[derive(Debug, Clone, Serialize, Deserialize)] 9 - #[serde(transparent)] 10 - pub struct Record(serde_json::Value); 6 + use tungstenite::protocol::frame::Utf8Bytes; 11 7 12 - impl Record { 13 - /// Create a new Record from a JSON value. 14 - pub fn new(value: serde_json::Value) -> Self { 15 - Self(value) 16 - } 8 + use crate::Error; 17 9 18 - /// Access the raw JSON value. 19 - pub fn json(&self) -> &serde_json::Value { 20 - &self.0 21 - } 10 + self_cell::self_cell!( 11 + pub(crate) struct Record { 12 + owner: Utf8Bytes, 22 13 23 - /// Consume and return the inner JSON value. 24 - pub fn into_json(self) -> serde_json::Value { 25 - self.0 14 + #[covariant] 15 + dependent: UnparsedRecord, 26 16 } 17 + ); 27 18 28 - /// Returns the `$type` field (e.g., "app.bsky.feed.post"). 29 - pub fn record_type(&self) -> Option<&str> { 30 - self.0.get("$type")?.as_str() 31 - } 32 - 33 - /// Deserialize the record into a user-provided type. 34 - pub fn deserialize_as<T: serde::de::DeserializeOwned>(&self) -> crate::Result<T> { 35 - Ok(serde_json::from_value(self.0.clone())?) 36 - } 37 - } 19 + pub(crate) struct UnparsedRecord<'a>(pub(crate) Option<&'a RawValue>); 38 20 39 21 /// Action performed on a record. 40 22 #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] ··· 74 56 } 75 57 76 58 /// A record event from the tap stream. 77 - #[derive(Debug, Clone)] 78 59 pub struct RecordEvent { 79 60 /// Unique event ID for acknowledgment. 80 61 pub id: u64, ··· 93 74 /// CID of the record (None on delete). 94 75 pub cid: Option<String>, 95 76 /// The record data (None on delete). 96 - pub record: Option<Record>, 77 + pub(crate) record: Option<Record>, 78 + } 79 + 80 + impl RecordEvent { 81 + /// Get the record's content as a reference to a JSON string 82 + pub fn record_as_str(&self) -> Option<&str> { 83 + self.record 84 + .as_ref() 85 + .and_then(|r| r.borrow_dependent().0) 86 + .map(|rv| rv.get()) 87 + } 88 + 89 + /// Parse the record's content to a compatible struct 90 + pub fn deserialize_as<T>(&self) -> Result<T, Error> 91 + where 92 + for<'de> T: Deserialize<'de>, 93 + { 94 + self.record_as_str() 95 + .map_or(Err(Error::NoRecordPresent), |s| { 96 + serde_json::from_str(s).map_err(Into::into) 97 + }) 98 + } 97 99 } 98 100 99 101 /// An identity event from the tap stream. ··· 112 114 } 113 115 114 116 /// An event from the tap stream. 115 - #[derive(Debug, Clone)] 116 117 #[non_exhaustive] 117 118 pub enum Event { 118 119 /// A record create/update/delete event. ··· 216 217 217 218 // Internal deserialisation structures for parsing tap's JSON format 218 219 219 - #[derive(Deserialize)] 220 - pub(crate) struct RawEvent { 221 - pub id: u64, 220 + #[derive(Deserialize, Clone)] 221 + #[serde(bound(deserialize = "'de: 'a"))] 222 + pub(crate) struct RawEvent<'a> { 223 + #[serde(flatten)] 224 + pub(crate) owned: RawEventOwned, 225 + pub(crate) record: Option<RawRecordEvent<'a>>, 226 + } 227 + 228 + #[derive(Deserialize, Clone)] 229 + pub(crate) struct RawEventOwned { 230 + pub(crate) id: u64, 222 231 #[serde(rename = "type")] 223 - pub type_: String, 224 - pub record: Option<RawRecordEvent>, 225 - pub identity: Option<RawIdentityEvent>, 232 + pub(crate) type_: String, 233 + pub(crate) identity: Option<RawIdentityEvent>, 226 234 } 227 235 228 - #[derive(Deserialize)] 229 - pub(crate) struct RawRecordEvent { 236 + #[derive(Deserialize, Clone)] 237 + #[serde(bound(deserialize = "'de: 'a"))] 238 + pub(crate) struct RawRecordEvent<'a> { 239 + #[serde(flatten)] 240 + pub owned: RawRecordEventOwned, 241 + pub record: Option<&'a RawValue>, 242 + } 243 + 244 + #[derive(Deserialize, Clone)] 245 + pub(crate) struct RawRecordEventOwned { 230 246 pub live: bool, 231 247 pub did: String, 232 248 pub rev: String, ··· 234 250 pub rkey: String, 235 251 pub action: RecordAction, 236 252 pub cid: Option<String>, 237 - pub record: Option<serde_json::Value>, 238 253 } 239 254 240 - #[derive(Deserialize)] 255 + #[derive(Deserialize, Clone)] 241 256 pub(crate) struct RawIdentityEvent { 242 257 pub did: String, 243 258 pub handle: String, ··· 246 261 pub status: AccountStatus, 247 262 } 248 263 249 - impl RawEvent { 264 + impl RawEventOwned { 250 265 /// Convert to the public Event type. 251 - pub fn into_event(self) -> Option<Event> { 266 + pub fn into_event( 267 + self, 268 + raw_record: Option<RawRecordEventOwned>, 269 + inner_record: Option<Record>, 270 + ) -> Option<Event> { 252 271 match self.type_.as_str() { 253 272 "record" => { 254 - let r = self.record?; 273 + let r = raw_record?; 255 274 Some(Event::Record(RecordEvent { 256 275 id: self.id, 257 276 live: r.live, ··· 261 280 rkey: r.rkey, 262 281 action: r.action, 263 282 cid: r.cid, 264 - record: r.record.map(Record::new), 283 + record: inner_record, 265 284 })) 266 285 } 267 286 "identity" => { ··· 311 330 use super::*; 312 331 use serde_json::json; 313 332 314 - #[test] 315 - fn record_type_extraction() { 316 - let record = Record::new(json!({ 317 - "$type": "app.bsky.feed.post", 318 - "text": "Hello, world!", 319 - "createdAt": "2024-01-01T00:00:00Z" 320 - })); 321 - 322 - assert_eq!(record.record_type(), Some("app.bsky.feed.post")); 323 - } 324 - 325 - #[test] 326 - fn record_type_missing() { 327 - let record = Record::new(json!({ 328 - "text": "No type field" 329 - })); 330 - 331 - assert_eq!(record.record_type(), None); 332 - } 333 - 334 - #[test] 335 - fn record_deserialize_as() { 336 - #[derive(Debug, Deserialize, PartialEq)] 337 - struct SimpleRecord { 338 - text: String, 339 - } 340 - 341 - let record = Record::new(json!({ 342 - "$type": "test.record", 343 - "text": "Hello!" 344 - })); 345 - 346 - let parsed: SimpleRecord = record.deserialize_as().unwrap(); 347 - assert_eq!(parsed.text, "Hello!"); 348 - } 349 - 350 333 /// Helper macro for testing enum variant deserialisation. 351 334 macro_rules! assert_deserialize { 352 335 ($type:ty, $($json:literal => $variant:expr),+ $(,)?) => { ··· 491 474 "text": "Hello!" 492 475 } 493 476 } 494 - }); 477 + }) 478 + .to_string(); 495 479 496 - let raw: RawEvent = serde_json::from_value(json).unwrap(); 497 - assert_eq!(raw.id, 12345); 498 - assert_eq!(raw.type_, "record"); 480 + let raw: RawEvent = serde_json::from_str(&json).unwrap(); 481 + assert_eq!(raw.owned.id, 12345); 482 + assert_eq!(raw.owned.type_, "record"); 499 483 500 - let event = raw.into_event().unwrap(); 484 + let event = raw 485 + .owned 486 + .into_event(raw.record.map(|r| r.owned), None) 487 + .unwrap(); 501 488 match event { 502 489 Event::Record(r) => { 503 490 assert_eq!(r.id, 12345); ··· 505 492 assert_eq!(r.did, "did:plc:abc123"); 506 493 assert_eq!(r.collection, "app.bsky.feed.post"); 507 494 assert_eq!(r.action, RecordAction::Create); 508 - assert!(r.record.is_some()); 509 - assert_eq!(r.record.unwrap().record_type(), Some("app.bsky.feed.post")); 510 495 } 511 496 _ => panic!("Expected Record event"), 512 497 } ··· 523 508 "is_active": true, 524 509 "status": "active" 525 510 } 526 - }); 511 + }) 512 + .to_string(); 527 513 528 - let raw: RawEvent = serde_json::from_value(json).unwrap(); 529 - let event = raw.into_event().unwrap(); 514 + let raw: RawEvent = serde_json::from_str(&json).unwrap(); 515 + let event = raw.owned.into_event(None, None).unwrap(); 530 516 531 517 match event { 532 518 Event::Identity(i) => { ··· 555 541 "cid": null, 556 542 "record": null 557 543 } 558 - }); 544 + }) 545 + .to_string(); 559 546 560 - let raw: RawEvent = serde_json::from_value(json).unwrap(); 561 - let event = raw.into_event().unwrap(); 547 + let raw: RawEvent = serde_json::from_str(&json).unwrap(); 548 + let event = raw 549 + .owned 550 + .into_event(raw.record.map(|r| r.owned), None) 551 + .unwrap(); 562 552 563 553 match event { 564 554 Event::Record(r) => {
+24
standard-site-sync/Cargo.toml
··· 1 + [package] 2 + name = "standard-site-sync" 3 + version = "0.1.0" 4 + edition = "2021" 5 + license = "MIT" 6 + description = "Example sync for standard.site publications and documents" 7 + authors = ["Thomas Karpiniec <tom.karpiniec@fastmail.com.au>"] 8 + publish = false 9 + 10 + [[bin]] 11 + name = "standard-site-sync" 12 + path = "src/main.rs" 13 + 14 + [dependencies] 15 + tapped = { path = "../tapped" } 16 + lexicons-example = { path = "../lexicons-example" } 17 + 18 + tokio = { version = "1", features = ["macros", "rt-multi-thread"] } 19 + env_logger = "0.11" 20 + log = "0.4" 21 + serde = { version = "1", features = ["derive"] } 22 + serde_json = "1" 23 + jacquard-common = "0.9.5" 24 + jacquard-lexicon = "0.9.5"
+275
standard-site-sync/src/main.rs
··· 1 + //! Example: Sync site.standard.publication and site.standard.document records. 2 + 3 + use std::collections::HashMap; 4 + use std::fs; 5 + 6 + use jacquard_lexicon::schema::LexiconSchema; 7 + use log::{error, info}; 8 + use serde::{Deserialize, Serialize}; 9 + use tapped::{Event, RecordAction, RecordEvent, TapConfig, TapProcess}; 10 + 11 + use lexicons_example::site_standard::document::Document; 12 + use lexicons_example::site_standard::publication::Publication; 13 + 14 + #[derive(Debug, Clone, Serialize, Deserialize)] 15 + struct CachedPublication { 16 + url: String, 17 + } 18 + 19 + #[derive(Debug, Clone, Serialize, Deserialize)] 20 + struct CachedDocument { 21 + /// Either an at:// URI (for attached docs) or http(s) URL (for floating docs) 22 + site_ref: String, 23 + /// The path within the site 24 + path: Option<String>, 25 + } 26 + 27 + #[derive(Debug, Clone, Default, Serialize, Deserialize)] 28 + struct Cache { 29 + /// Publications keyed by at:// URI 30 + publications: HashMap<String, CachedPublication>, 31 + /// Documents keyed by at:// URI 32 + documents: HashMap<String, CachedDocument>, 33 + } 34 + 35 + /// Construct an at:// URI from a record event. 36 + fn make_at_uri(event: &RecordEvent) -> String { 37 + format!("at://{}/{}/{}", event.did, event.collection, event.rkey) 38 + } 39 + 40 + #[tokio::main] 41 + async fn main() -> Result<(), Box<dyn std::error::Error>> { 42 + env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")) 43 + .format_timestamp_secs() 44 + .init(); 45 + 46 + info!("Starting standard.site sync example"); 47 + 48 + let config = TapConfig::builder() 49 + .database_url("sqlite://./tap-example.db") 50 + .bind(":2480") 51 + .signal_collection("site.standard.document") 52 + .collection_filters(vec![ 53 + "site.standard.publication".to_string(), 54 + "site.standard.document".to_string(), 55 + ]) 56 + .disable_acks(false) 57 + .inherit_stdio(true) 58 + .build(); 59 + 60 + info!("Spawning tap process..."); 61 + 62 + // Spawn tap (looks for ./tap first, then tap on PATH) 63 + let process = TapProcess::spawn_default(config).await?; 64 + info!("Tap running at {}", process.url()); 65 + 66 + let client = process.client()?; 67 + client.health().await?; 68 + info!("Tap is healthy!"); 69 + 70 + let mut receiver = client.channel().await?; 71 + info!("Connected! Waiting for events..."); 72 + 73 + // In-memory cache - load from disk if available 74 + let mut cache: Cache = load_cache_from_disk(); 75 + info!( 76 + "Loaded cache from disk: {} publications, {} documents", 77 + cache.publications.len(), 78 + cache.documents.len() 79 + ); 80 + 81 + let mut live_count = 0u64; 82 + let mut backfill_count = 0u64; 83 + 84 + loop { 85 + match receiver.recv().await { 86 + Ok(received) => { 87 + if let Event::Record(ref record_event) = *received { 88 + // Track live vs backfill 89 + if record_event.live { 90 + live_count += 1; 91 + } else { 92 + backfill_count += 1; 93 + } 94 + 95 + process_record_event(record_event, &mut cache); 96 + write_output_files(&cache)?; 97 + 98 + // Periodically show event source breakdown 99 + if (live_count + backfill_count).is_multiple_of(10) { 100 + info!( 101 + "[Stats] Live events: {}, Backfill events: {}", 102 + live_count, backfill_count 103 + ); 104 + } 105 + } else if let Event::Identity(ref identity_event) = *received { 106 + info!( 107 + "[IDENTITY] {} -> {} (active: {})", 108 + identity_event.did, identity_event.handle, identity_event.is_active 109 + ); 110 + } 111 + // Event is automatically acked when `received` is dropped here 112 + } 113 + Err(e) => { 114 + eprintln!("Error receiving event: {}", e); 115 + break; 116 + } 117 + } 118 + } 119 + 120 + Ok(()) 121 + } 122 + 123 + fn process_record_event(event: &RecordEvent, cache: &mut Cache) { 124 + let at_uri = make_at_uri(event); 125 + let action_str = match event.action { 126 + RecordAction::Create => "CREATE", 127 + RecordAction::Update => "UPDATE", 128 + RecordAction::Delete => "DELETE", 129 + _ => "UNKNOWN", 130 + }; 131 + 132 + // Show whether this is a live or backfill event 133 + let source = if event.live { "LIVE" } else { "BACKFILL" }; 134 + 135 + info!( 136 + "[{} {}] {} {}/{}", 137 + action_str, source, event.did, event.collection, event.rkey 138 + ); 139 + 140 + match event.action { 141 + RecordAction::Create | RecordAction::Update => match event.collection.as_str() { 142 + "site.standard.publication" => { 143 + if let Some(json) = event.record_as_str() { 144 + match serde_json::from_str::<Publication<'_>>(json) { 145 + Ok(publication) => { 146 + match publication.validate() { 147 + Ok(_) => { 148 + info!("publication validation ok"); 149 + } 150 + Err(e) => { 151 + error!("publication couldn't validate {:?}", e); 152 + return; 153 + } 154 + } 155 + 156 + info!( 157 + "Publication: {} ({})", 158 + publication.name.as_str(), 159 + publication.url.as_str() 160 + ); 161 + cache.publications.insert( 162 + at_uri, 163 + CachedPublication { 164 + url: publication.url.as_str().to_owned(), 165 + }, 166 + ); 167 + } 168 + Err(e) => { 169 + error!("publication could not be deserialised: {:?}", e); 170 + } 171 + } 172 + } 173 + } 174 + "site.standard.document" => { 175 + if let Some(json) = event.record_as_str() { 176 + match serde_json::from_str::<Document<'_>>(json) { 177 + Ok(document) => { 178 + match document.validate() { 179 + Ok(_) => { 180 + info!("document validation ok"); 181 + } 182 + Err(e) => { 183 + error!("document couldn't validate {:?}", e); 184 + return; 185 + } 186 + } 187 + info!("Document: {}", document.title); 188 + cache.documents.insert( 189 + at_uri, 190 + CachedDocument { 191 + site_ref: document.site.as_str().to_string(), 192 + path: document.path.map(|p| p.as_str().to_string()), 193 + }, 194 + ); 195 + } 196 + Err(e) => { 197 + error!("document could not be deserialised: {:?}", e); 198 + } 199 + } 200 + } 201 + } 202 + _ => {} 203 + }, 204 + RecordAction::Delete => match event.collection.as_str() { 205 + "site.standard.publication" => { 206 + cache.publications.remove(&at_uri); 207 + } 208 + "site.standard.document" => { 209 + cache.documents.remove(&at_uri); 210 + } 211 + _ => {} 212 + }, 213 + _ => {} 214 + } 215 + 216 + // Log cache stats 217 + info!( 218 + "Cached: {} publications, {} documents", 219 + cache.publications.len(), 220 + cache.documents.len() 221 + ); 222 + } 223 + 224 + fn write_output_files(cache: &Cache) -> Result<(), std::io::Error> { 225 + let mut publication_urls: Vec<&str> = cache 226 + .publications 227 + .values() 228 + .map(|p| p.url.as_str()) 229 + .collect(); 230 + publication_urls.sort(); 231 + fs::write("publications.txt", publication_urls.join("\n"))?; 232 + 233 + let mut document_urls: Vec<String> = Vec::new(); 234 + 235 + for doc in cache.documents.values() { 236 + let Some(path) = &doc.path else { continue }; 237 + 238 + let base_url = if doc.site_ref.starts_with("at://") { 239 + match cache.publications.get(&doc.site_ref) { 240 + Some(pub_record) => &pub_record.url, 241 + None => continue, // Skip if we don't know about this publication 242 + } 243 + } else if doc.site_ref.starts_with("http://") || doc.site_ref.starts_with("https://") { 244 + // Floating document with direct URL 245 + &doc.site_ref 246 + } else { 247 + continue; 248 + }; 249 + 250 + let full_url = format!("{}{}", base_url.trim_end_matches('/'), path); 251 + document_urls.push(full_url); 252 + } 253 + 254 + document_urls.sort(); 255 + fs::write("documents.txt", document_urls.join("\n"))?; 256 + 257 + // Write cache.json for persistence 258 + let cache_json = serde_json::to_string_pretty(cache).map_err(std::io::Error::other)?; 259 + fs::write("cache.json", cache_json)?; 260 + 261 + Ok(()) 262 + } 263 + 264 + fn load_cache_from_disk() -> Cache { 265 + match fs::read_to_string("cache.json") { 266 + Ok(content) => match serde_json::from_str::<Cache>(&content) { 267 + Ok(cache) => cache, 268 + Err(e) => { 269 + log::warn!("Failed to parse cache.json: {}", e); 270 + Cache::default() 271 + } 272 + }, 273 + Err(_) => Cache::default(), 274 + } 275 + }
+28
tapped/Cargo.toml
··· 1 + [package] 2 + name = "tapped" 3 + version = "0.2.0" 4 + edition = "2021" 5 + description = "Rust wrapper for the tap ATProto utility" 6 + license = "MIT" 7 + readme = "../README.md" 8 + authors = ["Thomas Karpiniec <tom.karpiniec@fastmail.com.au>"] 9 + keywords = ["atproto", "tap"] 10 + repository = "https://tangled.org/octet-stream.net/tapped" 11 + 12 + [dependencies] 13 + tokio = { version = "1", features = ["net", "process", "rt", "sync", "time"] } 14 + reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json"] } 15 + tokio-tungstenite = { version = "0.28", features = ["rustls-tls-native-roots"] } 16 + tungstenite = "0.28" 17 + serde = { version = "1", features = ["derive"] } 18 + serde_json = { version = "1", features = ["raw_value"] } 19 + thiserror = "2" 20 + url = { version = "2", features = ["serde"] } 21 + futures-util = "0.3" 22 + tracing = "0.1" 23 + base64 = "0.22" 24 + libc = "0.2" 25 + self_cell = "1.2.2" 26 + 27 + [dev-dependencies] 28 + tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
-32
tests/integration.rs tapped/tests/integration.rs
··· 6 6 //! 7 7 //! Run with: `cargo test --test integration -- --ignored` 8 8 9 - use std::path::Path; 10 9 use std::sync::atomic::{AtomicU16, Ordering}; 11 10 use std::time::Duration; 12 11 use tapped::{TapClient, TapConfig, TapHandle, TapProcess}; ··· 22 21 let id = TEST_COUNTER.fetch_add(1, Ordering::SeqCst); 23 22 let db_url = format!("sqlite:///tmp/tap-test-{}.db", id); 24 23 (id, db_url) 25 - } 26 - 27 - /// Check if tap binary is available. 28 - fn tap_available() -> bool { 29 - Path::new("./tap").exists() || which::which("tap").is_ok() 30 - } 31 - 32 - /// Skip test if tap is not available. 33 - macro_rules! require_tap { 34 - () => { 35 - if !tap_available() { 36 - eprintln!("Skipping test: tap binary not found"); 37 - return; 38 - } 39 - }; 40 24 } 41 25 42 26 #[tokio::test] 43 27 #[ignore = "requires tap binary"] 44 28 async fn test_process_spawn_default() { 45 - require_tap!(); 46 - 47 29 let (port, db_url) = unique_test_config(); 48 30 let config = TapConfig::builder() 49 31 .database_url(db_url) ··· 66 48 #[tokio::test] 67 49 #[ignore = "requires tap binary"] 68 50 async fn test_stats_endpoints() { 69 - require_tap!(); 70 - 71 51 let (port, db_url) = unique_test_config(); 72 52 let config = TapConfig::builder() 73 53 .database_url(db_url) ··· 98 78 #[tokio::test] 99 79 #[ignore = "requires tap binary"] 100 80 async fn test_add_and_query_repos() { 101 - require_tap!(); 102 - 103 81 let (port, db_url) = unique_test_config(); 104 82 let config = TapConfig::builder() 105 83 .database_url(db_url) ··· 137 115 #[tokio::test] 138 116 #[ignore = "requires tap binary"] 139 117 async fn test_resolve_did() { 140 - require_tap!(); 141 - 142 118 let (port, db_url) = unique_test_config(); 143 119 let config = TapConfig::builder() 144 120 .database_url(db_url) ··· 162 138 #[tokio::test] 163 139 #[ignore = "requires tap binary"] 164 140 async fn test_channel_connection() { 165 - require_tap!(); 166 - 167 141 let (port, db_url) = unique_test_config(); 168 142 let config = TapConfig::builder() 169 143 .database_url(db_url) ··· 181 155 #[tokio::test] 182 156 #[ignore = "requires tap binary"] 183 157 async fn test_graceful_shutdown() { 184 - require_tap!(); 185 - 186 158 let (port, db_url) = unique_test_config(); 187 159 let config = TapConfig::builder() 188 160 .database_url(db_url) ··· 205 177 #[tokio::test] 206 178 #[ignore = "requires tap binary"] 207 179 async fn test_client_from_url() { 208 - require_tap!(); 209 - 210 180 let (port, db_url) = unique_test_config(); 211 181 let config = TapConfig::builder() 212 182 .database_url(db_url) ··· 226 196 #[tokio::test] 227 197 #[ignore = "requires tap binary"] 228 198 async fn test_multiple_collection_filters() { 229 - require_tap!(); 230 - 231 199 let (port, db_url) = unique_test_config(); 232 200 let config = TapConfig::builder() 233 201 .database_url(db_url)