My personal-knowledge-system, with deeply integrated task tracking and long term goal planning capabilities.
2
fork

Configure Feed

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

Merge pull request #1 from suri-codes/db

Db

authored by

Surendra Jammishetti and committed by
GitHub
75f2a8ad 0f43e827

+5769 -45
+2 -1
.config/config.kdl
··· 1 1 2 2 keymap { 3 + 3 4 Home { 4 - <q> Quit // Quit the application 5 + q Quit // Quit the application 5 6 <Ctrl-c> Quit // Another way to quit 6 7 <Ctrl-z> Suspend // Suspend the application 7 8 }
+2432 -18
Cargo.lock
··· 18 18 checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" 19 19 20 20 [[package]] 21 + name = "ahash" 22 + version = "0.7.8" 23 + source = "registry+https://github.com/rust-lang/crates.io-index" 24 + checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" 25 + dependencies = [ 26 + "getrandom 0.2.17", 27 + "once_cell", 28 + "version_check", 29 + ] 30 + 31 + [[package]] 32 + name = "ahash" 33 + version = "0.8.12" 34 + source = "registry+https://github.com/rust-lang/crates.io-index" 35 + checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" 36 + dependencies = [ 37 + "cfg-if", 38 + "const-random", 39 + "getrandom 0.3.4", 40 + "once_cell", 41 + "version_check", 42 + "zerocopy", 43 + ] 44 + 45 + [[package]] 21 46 name = "aho-corasick" 22 47 version = "1.1.4" 23 48 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 27 52 ] 28 53 29 54 [[package]] 55 + name = "aliasable" 56 + version = "0.1.3" 57 + source = "registry+https://github.com/rust-lang/crates.io-index" 58 + checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" 59 + 60 + [[package]] 30 61 name = "allocator-api2" 31 62 version = "0.2.21" 32 63 source = "registry+https://github.com/rust-lang/crates.io-index" 33 64 checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" 34 65 35 66 [[package]] 67 + name = "android_system_properties" 68 + version = "0.1.5" 69 + source = "registry+https://github.com/rust-lang/crates.io-index" 70 + checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 71 + dependencies = [ 72 + "libc", 73 + ] 74 + 75 + [[package]] 36 76 name = "anstream" 37 77 version = "0.6.21" 38 78 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 98 138 ] 99 139 100 140 [[package]] 141 + name = "arrayvec" 142 + version = "0.7.6" 143 + source = "registry+https://github.com/rust-lang/crates.io-index" 144 + checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" 145 + 146 + [[package]] 147 + name = "arrow" 148 + version = "57.3.0" 149 + source = "registry+https://github.com/rust-lang/crates.io-index" 150 + checksum = "e4754a624e5ae42081f464514be454b39711daae0458906dacde5f4c632f33a8" 151 + dependencies = [ 152 + "arrow-arith", 153 + "arrow-array", 154 + "arrow-buffer", 155 + "arrow-cast", 156 + "arrow-data", 157 + "arrow-ord", 158 + "arrow-row", 159 + "arrow-schema", 160 + "arrow-select", 161 + "arrow-string", 162 + ] 163 + 164 + [[package]] 165 + name = "arrow-arith" 166 + version = "57.3.0" 167 + source = "registry+https://github.com/rust-lang/crates.io-index" 168 + checksum = "f7b3141e0ec5145a22d8694ea8b6d6f69305971c4fa1c1a13ef0195aef2d678b" 169 + dependencies = [ 170 + "arrow-array", 171 + "arrow-buffer", 172 + "arrow-data", 173 + "arrow-schema", 174 + "chrono", 175 + "num-traits", 176 + ] 177 + 178 + [[package]] 179 + name = "arrow-array" 180 + version = "57.3.0" 181 + source = "registry+https://github.com/rust-lang/crates.io-index" 182 + checksum = "4c8955af33b25f3b175ee10af580577280b4bd01f7e823d94c7cdef7cf8c9aef" 183 + dependencies = [ 184 + "ahash 0.8.12", 185 + "arrow-buffer", 186 + "arrow-data", 187 + "arrow-schema", 188 + "chrono", 189 + "half", 190 + "hashbrown 0.16.1", 191 + "num-complex", 192 + "num-integer", 193 + "num-traits", 194 + ] 195 + 196 + [[package]] 197 + name = "arrow-buffer" 198 + version = "57.3.0" 199 + source = "registry+https://github.com/rust-lang/crates.io-index" 200 + checksum = "c697ddca96183182f35b3a18e50b9110b11e916d7b7799cbfd4d34662f2c56c2" 201 + dependencies = [ 202 + "bytes", 203 + "half", 204 + "num-bigint", 205 + "num-traits", 206 + ] 207 + 208 + [[package]] 209 + name = "arrow-cast" 210 + version = "57.3.0" 211 + source = "registry+https://github.com/rust-lang/crates.io-index" 212 + checksum = "646bbb821e86fd57189c10b4fcdaa941deaf4181924917b0daa92735baa6ada5" 213 + dependencies = [ 214 + "arrow-array", 215 + "arrow-buffer", 216 + "arrow-data", 217 + "arrow-ord", 218 + "arrow-schema", 219 + "arrow-select", 220 + "atoi", 221 + "base64", 222 + "chrono", 223 + "half", 224 + "lexical-core", 225 + "num-traits", 226 + "ryu", 227 + ] 228 + 229 + [[package]] 230 + name = "arrow-data" 231 + version = "57.3.0" 232 + source = "registry+https://github.com/rust-lang/crates.io-index" 233 + checksum = "1fdd994a9d28e6365aa78e15da3f3950c0fdcea6b963a12fa1c391afb637b304" 234 + dependencies = [ 235 + "arrow-buffer", 236 + "arrow-schema", 237 + "half", 238 + "num-integer", 239 + "num-traits", 240 + ] 241 + 242 + [[package]] 243 + name = "arrow-ord" 244 + version = "57.3.0" 245 + source = "registry+https://github.com/rust-lang/crates.io-index" 246 + checksum = "f7d8f1870e03d4cbed632959498bcc84083b5a24bded52905ae1695bd29da45b" 247 + dependencies = [ 248 + "arrow-array", 249 + "arrow-buffer", 250 + "arrow-data", 251 + "arrow-schema", 252 + "arrow-select", 253 + ] 254 + 255 + [[package]] 256 + name = "arrow-row" 257 + version = "57.3.0" 258 + source = "registry+https://github.com/rust-lang/crates.io-index" 259 + checksum = "18228633bad92bff92a95746bbeb16e5fc318e8382b75619dec26db79e4de4c0" 260 + dependencies = [ 261 + "arrow-array", 262 + "arrow-buffer", 263 + "arrow-data", 264 + "arrow-schema", 265 + "half", 266 + ] 267 + 268 + [[package]] 269 + name = "arrow-schema" 270 + version = "57.3.0" 271 + source = "registry+https://github.com/rust-lang/crates.io-index" 272 + checksum = "8c872d36b7bf2a6a6a2b40de9156265f0242910791db366a2c17476ba8330d68" 273 + 274 + [[package]] 275 + name = "arrow-select" 276 + version = "57.3.0" 277 + source = "registry+https://github.com/rust-lang/crates.io-index" 278 + checksum = "68bf3e3efbd1278f770d67e5dc410257300b161b93baedb3aae836144edcaf4b" 279 + dependencies = [ 280 + "ahash 0.8.12", 281 + "arrow-array", 282 + "arrow-buffer", 283 + "arrow-data", 284 + "arrow-schema", 285 + "num-traits", 286 + ] 287 + 288 + [[package]] 289 + name = "arrow-string" 290 + version = "57.3.0" 291 + source = "registry+https://github.com/rust-lang/crates.io-index" 292 + checksum = "85e968097061b3c0e9fe3079cf2e703e487890700546b5b0647f60fca1b5a8d8" 293 + dependencies = [ 294 + "arrow-array", 295 + "arrow-buffer", 296 + "arrow-data", 297 + "arrow-schema", 298 + "arrow-select", 299 + "memchr", 300 + "num-traits", 301 + "regex", 302 + "regex-syntax", 303 + ] 304 + 305 + [[package]] 306 + name = "async-attributes" 307 + version = "1.1.2" 308 + source = "registry+https://github.com/rust-lang/crates.io-index" 309 + checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" 310 + dependencies = [ 311 + "quote", 312 + "syn 1.0.109", 313 + ] 314 + 315 + [[package]] 316 + name = "async-channel" 317 + version = "1.9.0" 318 + source = "registry+https://github.com/rust-lang/crates.io-index" 319 + checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" 320 + dependencies = [ 321 + "concurrent-queue", 322 + "event-listener 2.5.3", 323 + "futures-core", 324 + ] 325 + 326 + [[package]] 327 + name = "async-channel" 328 + version = "2.5.0" 329 + source = "registry+https://github.com/rust-lang/crates.io-index" 330 + checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" 331 + dependencies = [ 332 + "concurrent-queue", 333 + "event-listener-strategy", 334 + "futures-core", 335 + "pin-project-lite", 336 + ] 337 + 338 + [[package]] 339 + name = "async-executor" 340 + version = "1.14.0" 341 + source = "registry+https://github.com/rust-lang/crates.io-index" 342 + checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" 343 + dependencies = [ 344 + "async-task", 345 + "concurrent-queue", 346 + "fastrand", 347 + "futures-lite", 348 + "pin-project-lite", 349 + "slab", 350 + ] 351 + 352 + [[package]] 353 + name = "async-global-executor" 354 + version = "2.4.1" 355 + source = "registry+https://github.com/rust-lang/crates.io-index" 356 + checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" 357 + dependencies = [ 358 + "async-channel 2.5.0", 359 + "async-executor", 360 + "async-io", 361 + "async-lock", 362 + "blocking", 363 + "futures-lite", 364 + "once_cell", 365 + "tokio", 366 + ] 367 + 368 + [[package]] 369 + name = "async-io" 370 + version = "2.6.0" 371 + source = "registry+https://github.com/rust-lang/crates.io-index" 372 + checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" 373 + dependencies = [ 374 + "autocfg", 375 + "cfg-if", 376 + "concurrent-queue", 377 + "futures-io", 378 + "futures-lite", 379 + "parking", 380 + "polling", 381 + "rustix", 382 + "slab", 383 + "windows-sys 0.61.2", 384 + ] 385 + 386 + [[package]] 387 + name = "async-lock" 388 + version = "3.4.2" 389 + source = "registry+https://github.com/rust-lang/crates.io-index" 390 + checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" 391 + dependencies = [ 392 + "event-listener 5.4.1", 393 + "event-listener-strategy", 394 + "pin-project-lite", 395 + ] 396 + 397 + [[package]] 398 + name = "async-std" 399 + version = "1.13.2" 400 + source = "registry+https://github.com/rust-lang/crates.io-index" 401 + checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b" 402 + dependencies = [ 403 + "async-attributes", 404 + "async-channel 1.9.0", 405 + "async-global-executor", 406 + "async-io", 407 + "async-lock", 408 + "crossbeam-utils", 409 + "futures-channel", 410 + "futures-core", 411 + "futures-io", 412 + "futures-lite", 413 + "gloo-timers", 414 + "kv-log-macro", 415 + "log", 416 + "memchr", 417 + "once_cell", 418 + "pin-project-lite", 419 + "pin-utils", 420 + "slab", 421 + "wasm-bindgen-futures", 422 + ] 423 + 424 + [[package]] 425 + name = "async-stream" 426 + version = "0.3.6" 427 + source = "registry+https://github.com/rust-lang/crates.io-index" 428 + checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" 429 + dependencies = [ 430 + "async-stream-impl", 431 + "futures-core", 432 + "pin-project-lite", 433 + ] 434 + 435 + [[package]] 436 + name = "async-stream-impl" 437 + version = "0.3.6" 438 + source = "registry+https://github.com/rust-lang/crates.io-index" 439 + checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" 440 + dependencies = [ 441 + "proc-macro2", 442 + "quote", 443 + "syn 2.0.117", 444 + ] 445 + 446 + [[package]] 447 + name = "async-task" 448 + version = "4.7.1" 449 + source = "registry+https://github.com/rust-lang/crates.io-index" 450 + checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" 451 + 452 + [[package]] 453 + name = "async-trait" 454 + version = "0.1.89" 455 + source = "registry+https://github.com/rust-lang/crates.io-index" 456 + checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" 457 + dependencies = [ 458 + "proc-macro2", 459 + "quote", 460 + "syn 2.0.117", 461 + ] 462 + 463 + [[package]] 464 + name = "atoi" 465 + version = "2.0.0" 466 + source = "registry+https://github.com/rust-lang/crates.io-index" 467 + checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" 468 + dependencies = [ 469 + "num-traits", 470 + ] 471 + 472 + [[package]] 101 473 name = "atomic" 102 474 version = "0.6.1" 103 475 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 107 479 ] 108 480 109 481 [[package]] 482 + name = "atomic-waker" 483 + version = "1.1.2" 484 + source = "registry+https://github.com/rust-lang/crates.io-index" 485 + checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" 486 + 487 + [[package]] 110 488 name = "autocfg" 111 489 version = "1.5.0" 112 490 source = "registry+https://github.com/rust-lang/crates.io-index" 113 491 checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" 114 492 115 493 [[package]] 494 + name = "automerge" 495 + version = "0.7.4" 496 + source = "registry+https://github.com/rust-lang/crates.io-index" 497 + checksum = "3f4f9b5e81602f033fac828dafb4fef91742f6f01adfdb8ee5b8bc804cfac7bb" 498 + dependencies = [ 499 + "cfg-if", 500 + "flate2", 501 + "getrandom 0.3.4", 502 + "hex", 503 + "hexane", 504 + "itertools", 505 + "leb128", 506 + "rand 0.9.2", 507 + "rustc-hash", 508 + "serde", 509 + "sha2 0.11.0-rc.5", 510 + "smol_str", 511 + "thiserror 2.0.18", 512 + "tinyvec", 513 + "tracing", 514 + "unicode-segmentation", 515 + ] 516 + 517 + [[package]] 518 + name = "autosurgeon" 519 + version = "0.10.1" 520 + source = "registry+https://github.com/rust-lang/crates.io-index" 521 + checksum = "87b6547a9a35fbf5e5b1305a56c42196ae2cfb456897f1cab97d4829f1096550" 522 + dependencies = [ 523 + "automerge", 524 + "autosurgeon-derive", 525 + "similar", 526 + "thiserror 1.0.69", 527 + ] 528 + 529 + [[package]] 530 + name = "autosurgeon-derive" 531 + version = "0.10.1" 532 + source = "registry+https://github.com/rust-lang/crates.io-index" 533 + checksum = "f99b54090e5aca6915313efcf065f9873c9ca9d39c875cfc956f30523075d49f" 534 + dependencies = [ 535 + "proc-macro2", 536 + "quote", 537 + "syn 2.0.117", 538 + "thiserror 1.0.69", 539 + ] 540 + 541 + [[package]] 116 542 name = "backtrace" 117 543 version = "0.3.76" 118 544 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 132 558 version = "0.22.1" 133 559 source = "registry+https://github.com/rust-lang/crates.io-index" 134 560 checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 561 + 562 + [[package]] 563 + name = "base64ct" 564 + version = "1.8.3" 565 + source = "registry+https://github.com/rust-lang/crates.io-index" 566 + checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" 135 567 136 568 [[package]] 137 569 name = "better-panic" ··· 144 576 ] 145 577 146 578 [[package]] 579 + name = "bigdecimal" 580 + version = "0.4.10" 581 + source = "registry+https://github.com/rust-lang/crates.io-index" 582 + checksum = "4d6867f1565b3aad85681f1015055b087fcfd840d6aeee6eee7f2da317603695" 583 + dependencies = [ 584 + "autocfg", 585 + "libm", 586 + "num-bigint", 587 + "num-integer", 588 + "num-traits", 589 + "serde", 590 + ] 591 + 592 + [[package]] 147 593 name = "bit-set" 148 594 version = "0.5.3" 149 595 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 169 615 version = "2.11.0" 170 616 source = "registry+https://github.com/rust-lang/crates.io-index" 171 617 checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" 618 + dependencies = [ 619 + "serde_core", 620 + ] 621 + 622 + [[package]] 623 + name = "bitvec" 624 + version = "1.0.1" 625 + source = "registry+https://github.com/rust-lang/crates.io-index" 626 + checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" 627 + dependencies = [ 628 + "funty", 629 + "radium", 630 + "tap", 631 + "wyz", 632 + ] 172 633 173 634 [[package]] 174 635 name = "block-buffer" ··· 180 641 ] 181 642 182 643 [[package]] 644 + name = "block-buffer" 645 + version = "0.12.0" 646 + source = "registry+https://github.com/rust-lang/crates.io-index" 647 + checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" 648 + dependencies = [ 649 + "hybrid-array", 650 + ] 651 + 652 + [[package]] 653 + name = "blocking" 654 + version = "1.6.2" 655 + source = "registry+https://github.com/rust-lang/crates.io-index" 656 + checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" 657 + dependencies = [ 658 + "async-channel 2.5.0", 659 + "async-task", 660 + "futures-io", 661 + "futures-lite", 662 + "piper", 663 + ] 664 + 665 + [[package]] 666 + name = "borsh" 667 + version = "1.6.0" 668 + source = "registry+https://github.com/rust-lang/crates.io-index" 669 + checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" 670 + dependencies = [ 671 + "borsh-derive", 672 + "cfg_aliases", 673 + ] 674 + 675 + [[package]] 676 + name = "borsh-derive" 677 + version = "1.6.0" 678 + source = "registry+https://github.com/rust-lang/crates.io-index" 679 + checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" 680 + dependencies = [ 681 + "once_cell", 682 + "proc-macro-crate", 683 + "proc-macro2", 684 + "quote", 685 + "syn 2.0.117", 686 + ] 687 + 688 + [[package]] 183 689 name = "bstr" 184 690 version = "1.12.1" 185 691 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 195 701 version = "3.20.2" 196 702 source = "registry+https://github.com/rust-lang/crates.io-index" 197 703 checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" 704 + 705 + [[package]] 706 + name = "bytecheck" 707 + version = "0.6.12" 708 + source = "registry+https://github.com/rust-lang/crates.io-index" 709 + checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" 710 + dependencies = [ 711 + "bytecheck_derive", 712 + "ptr_meta", 713 + "simdutf8", 714 + ] 715 + 716 + [[package]] 717 + name = "bytecheck_derive" 718 + version = "0.6.12" 719 + source = "registry+https://github.com/rust-lang/crates.io-index" 720 + checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" 721 + dependencies = [ 722 + "proc-macro2", 723 + "quote", 724 + "syn 1.0.109", 725 + ] 198 726 199 727 [[package]] 200 728 name = "bytemuck" ··· 257 785 ] 258 786 259 787 [[package]] 788 + name = "cc" 789 + version = "1.2.57" 790 + source = "registry+https://github.com/rust-lang/crates.io-index" 791 + checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" 792 + dependencies = [ 793 + "find-msvc-tools", 794 + "shlex", 795 + ] 796 + 797 + [[package]] 260 798 name = "cfg-if" 261 799 version = "1.0.4" 262 800 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 269 807 checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 270 808 271 809 [[package]] 810 + name = "chacha20" 811 + version = "0.10.0" 812 + source = "registry+https://github.com/rust-lang/crates.io-index" 813 + checksum = "6f8d983286843e49675a4b7a2d174efe136dc93a18d69130dd18198a6c167601" 814 + dependencies = [ 815 + "cfg-if", 816 + "cpufeatures 0.3.0", 817 + "rand_core 0.10.0", 818 + ] 819 + 820 + [[package]] 821 + name = "chrono" 822 + version = "0.4.44" 823 + source = "registry+https://github.com/rust-lang/crates.io-index" 824 + checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" 825 + dependencies = [ 826 + "iana-time-zone", 827 + "num-traits", 828 + "serde", 829 + "windows-link 0.2.1", 830 + ] 831 + 832 + [[package]] 272 833 name = "clap" 273 834 version = "4.5.60" 274 835 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 299 860 source = "registry+https://github.com/rust-lang/crates.io-index" 300 861 checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" 301 862 dependencies = [ 302 - "heck", 863 + "heck 0.5.0", 303 864 "proc-macro2", 304 865 "quote", 305 866 "syn 2.0.117", ··· 368 929 ] 369 930 370 931 [[package]] 932 + name = "concurrent-queue" 933 + version = "2.5.0" 934 + source = "registry+https://github.com/rust-lang/crates.io-index" 935 + checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" 936 + dependencies = [ 937 + "crossbeam-utils", 938 + ] 939 + 940 + [[package]] 371 941 name = "console" 372 942 version = "0.15.11" 373 943 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 380 950 ] 381 951 382 952 [[package]] 953 + name = "const-oid" 954 + version = "0.9.6" 955 + source = "registry+https://github.com/rust-lang/crates.io-index" 956 + checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" 957 + 958 + [[package]] 959 + name = "const-oid" 960 + version = "0.10.2" 961 + source = "registry+https://github.com/rust-lang/crates.io-index" 962 + checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" 963 + 964 + [[package]] 965 + name = "const-random" 966 + version = "0.1.18" 967 + source = "registry+https://github.com/rust-lang/crates.io-index" 968 + checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" 969 + dependencies = [ 970 + "const-random-macro", 971 + ] 972 + 973 + [[package]] 974 + name = "const-random-macro" 975 + version = "0.1.16" 976 + source = "registry+https://github.com/rust-lang/crates.io-index" 977 + checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" 978 + dependencies = [ 979 + "getrandom 0.2.17", 980 + "once_cell", 981 + "tiny-keccak", 982 + ] 983 + 984 + [[package]] 383 985 name = "convert_case" 384 986 version = "0.10.0" 385 987 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 389 991 ] 390 992 391 993 [[package]] 994 + name = "core-foundation-sys" 995 + version = "0.8.7" 996 + source = "registry+https://github.com/rust-lang/crates.io-index" 997 + checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 998 + 999 + [[package]] 392 1000 name = "cpufeatures" 393 1001 version = "0.2.17" 394 1002 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 398 1006 ] 399 1007 400 1008 [[package]] 1009 + name = "cpufeatures" 1010 + version = "0.3.0" 1011 + source = "registry+https://github.com/rust-lang/crates.io-index" 1012 + checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" 1013 + dependencies = [ 1014 + "libc", 1015 + ] 1016 + 1017 + [[package]] 1018 + name = "crc" 1019 + version = "3.4.0" 1020 + source = "registry+https://github.com/rust-lang/crates.io-index" 1021 + checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" 1022 + dependencies = [ 1023 + "crc-catalog", 1024 + ] 1025 + 1026 + [[package]] 1027 + name = "crc-catalog" 1028 + version = "2.4.0" 1029 + source = "registry+https://github.com/rust-lang/crates.io-index" 1030 + checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" 1031 + 1032 + [[package]] 401 1033 name = "crc32fast" 402 1034 version = "1.5.0" 403 1035 source = "registry+https://github.com/rust-lang/crates.io-index" 404 1036 checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" 405 1037 dependencies = [ 406 1038 "cfg-if", 1039 + ] 1040 + 1041 + [[package]] 1042 + name = "crossbeam-queue" 1043 + version = "0.3.12" 1044 + source = "registry+https://github.com/rust-lang/crates.io-index" 1045 + checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" 1046 + dependencies = [ 1047 + "crossbeam-utils", 407 1048 ] 408 1049 409 1050 [[package]] ··· 441 1082 ] 442 1083 443 1084 [[package]] 1085 + name = "crunchy" 1086 + version = "0.2.4" 1087 + source = "registry+https://github.com/rust-lang/crates.io-index" 1088 + checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" 1089 + 1090 + [[package]] 444 1091 name = "crypto-common" 445 1092 version = "0.1.7" 446 1093 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 451 1098 ] 452 1099 453 1100 [[package]] 1101 + name = "crypto-common" 1102 + version = "0.2.1" 1103 + source = "registry+https://github.com/rust-lang/crates.io-index" 1104 + checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" 1105 + dependencies = [ 1106 + "hybrid-array", 1107 + ] 1108 + 1109 + [[package]] 454 1110 name = "csscolorparser" 455 1111 version = "0.6.2" 456 1112 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 541 1197 "lock_api", 542 1198 "once_cell", 543 1199 "parking_lot_core", 1200 + ] 1201 + 1202 + [[package]] 1203 + name = "db" 1204 + version = "0.1.0" 1205 + dependencies = [ 1206 + "anyhow", 1207 + "migration", 1208 + "rand 0.10.0", 1209 + "sea-orm", 1210 + "thiserror 2.0.18", 1211 + "tokio", 1212 + "tracing", 544 1213 ] 545 1214 546 1215 [[package]] ··· 550 1219 checksum = "5729f5117e208430e437df2f4843f5e5952997175992d1414f94c57d61e270b4" 551 1220 552 1221 [[package]] 1222 + name = "der" 1223 + version = "0.7.10" 1224 + source = "registry+https://github.com/rust-lang/crates.io-index" 1225 + checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" 1226 + dependencies = [ 1227 + "const-oid 0.9.6", 1228 + "pem-rfc7468", 1229 + "zeroize", 1230 + ] 1231 + 1232 + [[package]] 553 1233 name = "deranged" 554 1234 version = "0.5.8" 555 1235 source = "registry+https://github.com/rust-lang/crates.io-index" 556 1236 checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" 557 1237 dependencies = [ 558 1238 "powerfmt", 1239 + "serde_core", 559 1240 ] 560 1241 561 1242 [[package]] ··· 609 1290 "quote", 610 1291 "rustc_version", 611 1292 "syn 2.0.117", 1293 + "unicode-xid", 612 1294 ] 613 1295 614 1296 [[package]] ··· 617 1299 source = "registry+https://github.com/rust-lang/crates.io-index" 618 1300 checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 619 1301 dependencies = [ 620 - "block-buffer", 621 - "crypto-common", 1302 + "block-buffer 0.10.4", 1303 + "const-oid 0.9.6", 1304 + "crypto-common 0.1.7", 1305 + "subtle", 1306 + ] 1307 + 1308 + [[package]] 1309 + name = "digest" 1310 + version = "0.11.2" 1311 + source = "registry+https://github.com/rust-lang/crates.io-index" 1312 + checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" 1313 + dependencies = [ 1314 + "block-buffer 0.12.0", 1315 + "const-oid 0.10.2", 1316 + "crypto-common 0.2.1", 622 1317 ] 623 1318 624 1319 [[package]] ··· 643 1338 ] 644 1339 645 1340 [[package]] 1341 + name = "displaydoc" 1342 + version = "0.2.5" 1343 + source = "registry+https://github.com/rust-lang/crates.io-index" 1344 + checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 1345 + dependencies = [ 1346 + "proc-macro2", 1347 + "quote", 1348 + "syn 2.0.117", 1349 + ] 1350 + 1351 + [[package]] 646 1352 name = "document-features" 647 1353 version = "0.2.12" 648 1354 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 652 1358 ] 653 1359 654 1360 [[package]] 1361 + name = "dotenvy" 1362 + version = "0.15.7" 1363 + source = "registry+https://github.com/rust-lang/crates.io-index" 1364 + checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" 1365 + 1366 + [[package]] 655 1367 name = "dunce" 656 1368 version = "1.0.5" 657 1369 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 662 1374 version = "1.15.0" 663 1375 source = "registry+https://github.com/rust-lang/crates.io-index" 664 1376 checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 1377 + dependencies = [ 1378 + "serde", 1379 + ] 665 1380 666 1381 [[package]] 667 1382 name = "encode_unicode" ··· 695 1410 ] 696 1411 697 1412 [[package]] 1413 + name = "etcetera" 1414 + version = "0.8.0" 1415 + source = "registry+https://github.com/rust-lang/crates.io-index" 1416 + checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" 1417 + dependencies = [ 1418 + "cfg-if", 1419 + "home", 1420 + "windows-sys 0.48.0", 1421 + ] 1422 + 1423 + [[package]] 698 1424 name = "euclid" 699 1425 version = "0.22.13" 700 1426 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 704 1430 ] 705 1431 706 1432 [[package]] 1433 + name = "event-listener" 1434 + version = "2.5.3" 1435 + source = "registry+https://github.com/rust-lang/crates.io-index" 1436 + checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" 1437 + 1438 + [[package]] 1439 + name = "event-listener" 1440 + version = "5.4.1" 1441 + source = "registry+https://github.com/rust-lang/crates.io-index" 1442 + checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" 1443 + dependencies = [ 1444 + "concurrent-queue", 1445 + "parking", 1446 + "pin-project-lite", 1447 + ] 1448 + 1449 + [[package]] 1450 + name = "event-listener-strategy" 1451 + version = "0.5.4" 1452 + source = "registry+https://github.com/rust-lang/crates.io-index" 1453 + checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" 1454 + dependencies = [ 1455 + "event-listener 5.4.1", 1456 + "pin-project-lite", 1457 + ] 1458 + 1459 + [[package]] 707 1460 name = "eyre" 708 1461 version = "0.6.12" 709 1462 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 748 1501 "clap", 749 1502 "color-eyre", 750 1503 "crossterm", 1504 + "db", 751 1505 "directories", 752 1506 "futures", 753 1507 "human-panic", ··· 785 1539 "libc", 786 1540 "libredox", 787 1541 ] 1542 + 1543 + [[package]] 1544 + name = "find-msvc-tools" 1545 + version = "0.1.9" 1546 + source = "registry+https://github.com/rust-lang/crates.io-index" 1547 + checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" 788 1548 789 1549 [[package]] 790 1550 name = "finl_unicode" ··· 799 1559 checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" 800 1560 801 1561 [[package]] 1562 + name = "flate2" 1563 + version = "1.1.9" 1564 + source = "registry+https://github.com/rust-lang/crates.io-index" 1565 + checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" 1566 + dependencies = [ 1567 + "crc32fast", 1568 + "miniz_oxide", 1569 + ] 1570 + 1571 + [[package]] 1572 + name = "flume" 1573 + version = "0.11.1" 1574 + source = "registry+https://github.com/rust-lang/crates.io-index" 1575 + checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" 1576 + dependencies = [ 1577 + "futures-core", 1578 + "futures-sink", 1579 + "spin", 1580 + ] 1581 + 1582 + [[package]] 802 1583 name = "fnv" 803 1584 version = "1.0.7" 804 1585 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 817 1598 checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" 818 1599 819 1600 [[package]] 1601 + name = "form_urlencoded" 1602 + version = "1.2.2" 1603 + source = "registry+https://github.com/rust-lang/crates.io-index" 1604 + checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" 1605 + dependencies = [ 1606 + "percent-encoding", 1607 + ] 1608 + 1609 + [[package]] 1610 + name = "funty" 1611 + version = "2.0.0" 1612 + source = "registry+https://github.com/rust-lang/crates.io-index" 1613 + checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" 1614 + 1615 + [[package]] 820 1616 name = "futures" 821 1617 version = "0.3.32" 822 1618 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 859 1655 ] 860 1656 861 1657 [[package]] 1658 + name = "futures-intrusive" 1659 + version = "0.5.0" 1660 + source = "registry+https://github.com/rust-lang/crates.io-index" 1661 + checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" 1662 + dependencies = [ 1663 + "futures-core", 1664 + "lock_api", 1665 + "parking_lot", 1666 + ] 1667 + 1668 + [[package]] 862 1669 name = "futures-io" 863 1670 version = "0.3.32" 864 1671 source = "registry+https://github.com/rust-lang/crates.io-index" 865 1672 checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" 1673 + 1674 + [[package]] 1675 + name = "futures-lite" 1676 + version = "2.6.1" 1677 + source = "registry+https://github.com/rust-lang/crates.io-index" 1678 + checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" 1679 + dependencies = [ 1680 + "fastrand", 1681 + "futures-core", 1682 + "futures-io", 1683 + "parking", 1684 + "pin-project-lite", 1685 + ] 866 1686 867 1687 [[package]] 868 1688 name = "futures-macro" ··· 946 1766 "cfg-if", 947 1767 "libc", 948 1768 "r-efi 6.0.0", 1769 + "rand_core 0.10.0", 949 1770 "wasip2", 950 1771 "wasip3", 951 1772 ] ··· 1696 2517 ] 1697 2518 1698 2519 [[package]] 2520 + name = "glob" 2521 + version = "0.3.3" 2522 + source = "registry+https://github.com/rust-lang/crates.io-index" 2523 + checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" 2524 + 2525 + [[package]] 2526 + name = "gloo-timers" 2527 + version = "0.3.0" 2528 + source = "registry+https://github.com/rust-lang/crates.io-index" 2529 + checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" 2530 + dependencies = [ 2531 + "futures-channel", 2532 + "futures-core", 2533 + "js-sys", 2534 + "wasm-bindgen", 2535 + ] 2536 + 2537 + [[package]] 2538 + name = "half" 2539 + version = "2.7.1" 2540 + source = "registry+https://github.com/rust-lang/crates.io-index" 2541 + checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" 2542 + dependencies = [ 2543 + "cfg-if", 2544 + "crunchy", 2545 + "num-traits", 2546 + "zerocopy", 2547 + ] 2548 + 2549 + [[package]] 1699 2550 name = "hash32" 1700 2551 version = "0.3.1" 1701 2552 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1706 2557 1707 2558 [[package]] 1708 2559 name = "hashbrown" 2560 + version = "0.12.3" 2561 + source = "registry+https://github.com/rust-lang/crates.io-index" 2562 + checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 2563 + dependencies = [ 2564 + "ahash 0.7.8", 2565 + ] 2566 + 2567 + [[package]] 2568 + name = "hashbrown" 1709 2569 version = "0.14.5" 1710 2570 source = "registry+https://github.com/rust-lang/crates.io-index" 1711 2571 checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" ··· 1716 2576 source = "registry+https://github.com/rust-lang/crates.io-index" 1717 2577 checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" 1718 2578 dependencies = [ 2579 + "allocator-api2", 2580 + "equivalent", 1719 2581 "foldhash 0.1.5", 1720 2582 ] 1721 2583 ··· 1731 2593 ] 1732 2594 1733 2595 [[package]] 2596 + name = "hashlink" 2597 + version = "0.10.0" 2598 + source = "registry+https://github.com/rust-lang/crates.io-index" 2599 + checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" 2600 + dependencies = [ 2601 + "hashbrown 0.15.5", 2602 + ] 2603 + 2604 + [[package]] 1734 2605 name = "heapless" 1735 2606 version = "0.8.0" 1736 2607 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1742 2613 1743 2614 [[package]] 1744 2615 name = "heck" 2616 + version = "0.4.1" 2617 + source = "registry+https://github.com/rust-lang/crates.io-index" 2618 + checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 2619 + 2620 + [[package]] 2621 + name = "heck" 1745 2622 version = "0.5.0" 1746 2623 source = "registry+https://github.com/rust-lang/crates.io-index" 1747 2624 checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 1748 2625 1749 2626 [[package]] 2627 + name = "hermit-abi" 2628 + version = "0.5.2" 2629 + source = "registry+https://github.com/rust-lang/crates.io-index" 2630 + checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" 2631 + 2632 + [[package]] 1750 2633 name = "hex" 1751 2634 version = "0.4.3" 1752 2635 source = "registry+https://github.com/rust-lang/crates.io-index" 1753 2636 checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 1754 2637 1755 2638 [[package]] 2639 + name = "hexane" 2640 + version = "0.1.7" 2641 + source = "registry+https://github.com/rust-lang/crates.io-index" 2642 + checksum = "8ab946df174dbf65fc07610c1f936b3e40b9ca7cfd09c0f827f9509a62e93a39" 2643 + dependencies = [ 2644 + "leb128", 2645 + "thiserror 2.0.18", 2646 + ] 2647 + 2648 + [[package]] 2649 + name = "hkdf" 2650 + version = "0.12.4" 2651 + source = "registry+https://github.com/rust-lang/crates.io-index" 2652 + checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" 2653 + dependencies = [ 2654 + "hmac", 2655 + ] 2656 + 2657 + [[package]] 2658 + name = "hmac" 2659 + version = "0.12.1" 2660 + source = "registry+https://github.com/rust-lang/crates.io-index" 2661 + checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 2662 + dependencies = [ 2663 + "digest 0.10.7", 2664 + ] 2665 + 2666 + [[package]] 2667 + name = "home" 2668 + version = "0.5.12" 2669 + source = "registry+https://github.com/rust-lang/crates.io-index" 2670 + checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" 2671 + dependencies = [ 2672 + "windows-sys 0.61.2", 2673 + ] 2674 + 2675 + [[package]] 1756 2676 name = "human-panic" 1757 2677 version = "2.0.6" 1758 2678 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1769 2689 ] 1770 2690 1771 2691 [[package]] 2692 + name = "hybrid-array" 2693 + version = "0.4.8" 2694 + source = "registry+https://github.com/rust-lang/crates.io-index" 2695 + checksum = "8655f91cd07f2b9d0c24137bd650fe69617773435ee5ec83022377777ce65ef1" 2696 + dependencies = [ 2697 + "typenum", 2698 + ] 2699 + 2700 + [[package]] 2701 + name = "iana-time-zone" 2702 + version = "0.1.65" 2703 + source = "registry+https://github.com/rust-lang/crates.io-index" 2704 + checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" 2705 + dependencies = [ 2706 + "android_system_properties", 2707 + "core-foundation-sys", 2708 + "iana-time-zone-haiku", 2709 + "js-sys", 2710 + "log", 2711 + "wasm-bindgen", 2712 + "windows-core", 2713 + ] 2714 + 2715 + [[package]] 2716 + name = "iana-time-zone-haiku" 2717 + version = "0.1.2" 2718 + source = "registry+https://github.com/rust-lang/crates.io-index" 2719 + checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 2720 + dependencies = [ 2721 + "cc", 2722 + ] 2723 + 2724 + [[package]] 2725 + name = "icu_collections" 2726 + version = "2.1.1" 2727 + source = "registry+https://github.com/rust-lang/crates.io-index" 2728 + checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" 2729 + dependencies = [ 2730 + "displaydoc", 2731 + "potential_utf", 2732 + "yoke", 2733 + "zerofrom", 2734 + "zerovec", 2735 + ] 2736 + 2737 + [[package]] 2738 + name = "icu_locale_core" 2739 + version = "2.1.1" 2740 + source = "registry+https://github.com/rust-lang/crates.io-index" 2741 + checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" 2742 + dependencies = [ 2743 + "displaydoc", 2744 + "litemap", 2745 + "tinystr", 2746 + "writeable", 2747 + "zerovec", 2748 + ] 2749 + 2750 + [[package]] 2751 + name = "icu_normalizer" 2752 + version = "2.1.1" 2753 + source = "registry+https://github.com/rust-lang/crates.io-index" 2754 + checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" 2755 + dependencies = [ 2756 + "icu_collections", 2757 + "icu_normalizer_data", 2758 + "icu_properties", 2759 + "icu_provider", 2760 + "smallvec", 2761 + "zerovec", 2762 + ] 2763 + 2764 + [[package]] 2765 + name = "icu_normalizer_data" 2766 + version = "2.1.1" 2767 + source = "registry+https://github.com/rust-lang/crates.io-index" 2768 + checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" 2769 + 2770 + [[package]] 2771 + name = "icu_properties" 2772 + version = "2.1.2" 2773 + source = "registry+https://github.com/rust-lang/crates.io-index" 2774 + checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" 2775 + dependencies = [ 2776 + "icu_collections", 2777 + "icu_locale_core", 2778 + "icu_properties_data", 2779 + "icu_provider", 2780 + "zerotrie", 2781 + "zerovec", 2782 + ] 2783 + 2784 + [[package]] 2785 + name = "icu_properties_data" 2786 + version = "2.1.2" 2787 + source = "registry+https://github.com/rust-lang/crates.io-index" 2788 + checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" 2789 + 2790 + [[package]] 2791 + name = "icu_provider" 2792 + version = "2.1.1" 2793 + source = "registry+https://github.com/rust-lang/crates.io-index" 2794 + checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" 2795 + dependencies = [ 2796 + "displaydoc", 2797 + "icu_locale_core", 2798 + "writeable", 2799 + "yoke", 2800 + "zerofrom", 2801 + "zerotrie", 2802 + "zerovec", 2803 + ] 2804 + 2805 + [[package]] 1772 2806 name = "id-arena" 1773 2807 version = "2.3.0" 1774 2808 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1781 2815 checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 1782 2816 1783 2817 [[package]] 2818 + name = "idna" 2819 + version = "1.1.0" 2820 + source = "registry+https://github.com/rust-lang/crates.io-index" 2821 + checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" 2822 + dependencies = [ 2823 + "idna_adapter", 2824 + "smallvec", 2825 + "utf8_iter", 2826 + ] 2827 + 2828 + [[package]] 2829 + name = "idna_adapter" 2830 + version = "1.2.1" 2831 + source = "registry+https://github.com/rust-lang/crates.io-index" 2832 + checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" 2833 + dependencies = [ 2834 + "icu_normalizer", 2835 + "icu_properties", 2836 + ] 2837 + 2838 + [[package]] 1784 2839 name = "imara-diff" 1785 2840 version = "0.1.8" 1786 2841 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1814 2869 checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" 1815 2870 dependencies = [ 1816 2871 "rustversion", 2872 + ] 2873 + 2874 + [[package]] 2875 + name = "inherent" 2876 + version = "1.0.13" 2877 + source = "registry+https://github.com/rust-lang/crates.io-index" 2878 + checksum = "c727f80bfa4a6c6e2508d2f05b6f4bfce242030bd88ed15ae5331c5b5d30fba7" 2879 + dependencies = [ 2880 + "proc-macro2", 2881 + "quote", 2882 + "syn 2.0.117", 1817 2883 ] 1818 2884 1819 2885 [[package]] ··· 1933 2999 ] 1934 3000 1935 3001 [[package]] 3002 + name = "kv-log-macro" 3003 + version = "1.0.7" 3004 + source = "registry+https://github.com/rust-lang/crates.io-index" 3005 + checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" 3006 + dependencies = [ 3007 + "log", 3008 + ] 3009 + 3010 + [[package]] 1936 3011 name = "lab" 1937 3012 version = "0.11.0" 1938 3013 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1943 3018 version = "1.5.0" 1944 3019 source = "registry+https://github.com/rust-lang/crates.io-index" 1945 3020 checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 3021 + dependencies = [ 3022 + "spin", 3023 + ] 3024 + 3025 + [[package]] 3026 + name = "leb128" 3027 + version = "0.2.5" 3028 + source = "registry+https://github.com/rust-lang/crates.io-index" 3029 + checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" 1946 3030 1947 3031 [[package]] 1948 3032 name = "leb128fmt" ··· 1951 3035 checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" 1952 3036 1953 3037 [[package]] 3038 + name = "lexical-core" 3039 + version = "1.0.6" 3040 + source = "registry+https://github.com/rust-lang/crates.io-index" 3041 + checksum = "7d8d125a277f807e55a77304455eb7b1cb52f2b18c143b60e766c120bd64a594" 3042 + dependencies = [ 3043 + "lexical-parse-float", 3044 + "lexical-parse-integer", 3045 + "lexical-util", 3046 + "lexical-write-float", 3047 + "lexical-write-integer", 3048 + ] 3049 + 3050 + [[package]] 3051 + name = "lexical-parse-float" 3052 + version = "1.0.6" 3053 + source = "registry+https://github.com/rust-lang/crates.io-index" 3054 + checksum = "52a9f232fbd6f550bc0137dcb5f99ab674071ac2d690ac69704593cb4abbea56" 3055 + dependencies = [ 3056 + "lexical-parse-integer", 3057 + "lexical-util", 3058 + ] 3059 + 3060 + [[package]] 3061 + name = "lexical-parse-integer" 3062 + version = "1.0.6" 3063 + source = "registry+https://github.com/rust-lang/crates.io-index" 3064 + checksum = "9a7a039f8fb9c19c996cd7b2fcce303c1b2874fe1aca544edc85c4a5f8489b34" 3065 + dependencies = [ 3066 + "lexical-util", 3067 + ] 3068 + 3069 + [[package]] 3070 + name = "lexical-util" 3071 + version = "1.0.7" 3072 + source = "registry+https://github.com/rust-lang/crates.io-index" 3073 + checksum = "2604dd126bb14f13fb5d1bd6a66155079cb9fa655b37f875b3a742c705dbed17" 3074 + 3075 + [[package]] 3076 + name = "lexical-write-float" 3077 + version = "1.0.6" 3078 + source = "registry+https://github.com/rust-lang/crates.io-index" 3079 + checksum = "50c438c87c013188d415fbabbb1dceb44249ab81664efbd31b14ae55dabb6361" 3080 + dependencies = [ 3081 + "lexical-util", 3082 + "lexical-write-integer", 3083 + ] 3084 + 3085 + [[package]] 3086 + name = "lexical-write-integer" 3087 + version = "1.0.6" 3088 + source = "registry+https://github.com/rust-lang/crates.io-index" 3089 + checksum = "409851a618475d2d5796377cad353802345cba92c867d9fbcde9cf4eac4e14df" 3090 + dependencies = [ 3091 + "lexical-util", 3092 + ] 3093 + 3094 + [[package]] 1954 3095 name = "libc" 1955 3096 version = "0.2.182" 1956 3097 source = "registry+https://github.com/rust-lang/crates.io-index" 1957 3098 checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" 1958 3099 1959 3100 [[package]] 3101 + name = "libm" 3102 + version = "0.2.16" 3103 + source = "registry+https://github.com/rust-lang/crates.io-index" 3104 + checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" 3105 + 3106 + [[package]] 1960 3107 name = "libredox" 1961 3108 version = "0.1.14" 1962 3109 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1969 3116 ] 1970 3117 1971 3118 [[package]] 3119 + name = "libsqlite3-sys" 3120 + version = "0.30.1" 3121 + source = "registry+https://github.com/rust-lang/crates.io-index" 3122 + checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" 3123 + dependencies = [ 3124 + "cc", 3125 + "pkg-config", 3126 + "vcpkg", 3127 + ] 3128 + 3129 + [[package]] 1972 3130 name = "line-clipping" 1973 3131 version = "0.3.5" 1974 3132 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1984 3142 checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" 1985 3143 1986 3144 [[package]] 3145 + name = "litemap" 3146 + version = "0.8.1" 3147 + source = "registry+https://github.com/rust-lang/crates.io-index" 3148 + checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" 3149 + 3150 + [[package]] 1987 3151 name = "litrs" 1988 3152 version = "1.0.0" 1989 3153 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2003 3167 version = "0.4.29" 2004 3168 source = "registry+https://github.com/rust-lang/crates.io-index" 2005 3169 checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" 3170 + dependencies = [ 3171 + "value-bag", 3172 + ] 2006 3173 2007 3174 [[package]] 2008 3175 name = "lru" ··· 2020 3187 checksum = "c0aeb26bf5e836cc1c341c8106051b573f1766dfa05aa87f0b98be5e51b02303" 2021 3188 dependencies = [ 2022 3189 "nix", 3190 + "serde", 2023 3191 "winapi", 2024 3192 ] 2025 3193 ··· 2044 3212 ] 2045 3213 2046 3214 [[package]] 3215 + name = "md-5" 3216 + version = "0.10.6" 3217 + source = "registry+https://github.com/rust-lang/crates.io-index" 3218 + checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" 3219 + dependencies = [ 3220 + "cfg-if", 3221 + "digest 0.10.7", 3222 + ] 3223 + 3224 + [[package]] 2047 3225 name = "memchr" 2048 3226 version = "2.8.0" 2049 3227 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2084 3262 ] 2085 3263 2086 3264 [[package]] 3265 + name = "migration" 3266 + version = "0.1.0" 3267 + dependencies = [ 3268 + "async-std", 3269 + "nanoid", 3270 + "sea-orm", 3271 + "sea-orm-migration", 3272 + ] 3273 + 3274 + [[package]] 2087 3275 name = "minimal-lexical" 2088 3276 version = "0.2.1" 2089 3277 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2096 3284 checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" 2097 3285 dependencies = [ 2098 3286 "adler2", 3287 + "simd-adler32", 2099 3288 ] 2100 3289 2101 3290 [[package]] ··· 2108 3297 "log", 2109 3298 "wasi", 2110 3299 "windows-sys 0.61.2", 3300 + ] 3301 + 3302 + [[package]] 3303 + name = "nanoid" 3304 + version = "0.4.0" 3305 + source = "registry+https://github.com/rust-lang/crates.io-index" 3306 + checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8" 3307 + dependencies = [ 3308 + "rand 0.8.5", 2111 3309 ] 2112 3310 2113 3311 [[package]] ··· 2176 3374 ] 2177 3375 2178 3376 [[package]] 3377 + name = "num-bigint-dig" 3378 + version = "0.8.6" 3379 + source = "registry+https://github.com/rust-lang/crates.io-index" 3380 + checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" 3381 + dependencies = [ 3382 + "lazy_static", 3383 + "libm", 3384 + "num-integer", 3385 + "num-iter", 3386 + "num-traits", 3387 + "rand 0.8.5", 3388 + "smallvec", 3389 + "zeroize", 3390 + ] 3391 + 3392 + [[package]] 2179 3393 name = "num-complex" 2180 3394 version = "0.4.6" 2181 3395 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2239 3453 checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 2240 3454 dependencies = [ 2241 3455 "autocfg", 3456 + "libm", 2242 3457 ] 2243 3458 2244 3459 [[package]] ··· 2306 3521 ] 2307 3522 2308 3523 [[package]] 3524 + name = "ouroboros" 3525 + version = "0.18.5" 3526 + source = "registry+https://github.com/rust-lang/crates.io-index" 3527 + checksum = "1e0f050db9c44b97a94723127e6be766ac5c340c48f2c4bb3ffa11713744be59" 3528 + dependencies = [ 3529 + "aliasable", 3530 + "ouroboros_macro", 3531 + "static_assertions", 3532 + ] 3533 + 3534 + [[package]] 3535 + name = "ouroboros_macro" 3536 + version = "0.18.5" 3537 + source = "registry+https://github.com/rust-lang/crates.io-index" 3538 + checksum = "3c7028bdd3d43083f6d8d4d5187680d0d3560d54df4cc9d752005268b41e64d0" 3539 + dependencies = [ 3540 + "heck 0.4.1", 3541 + "proc-macro2", 3542 + "proc-macro2-diagnostics", 3543 + "quote", 3544 + "syn 2.0.117", 3545 + ] 3546 + 3547 + [[package]] 2309 3548 name = "owo-colors" 2310 3549 version = "4.3.0" 2311 3550 source = "registry+https://github.com/rust-lang/crates.io-index" 2312 3551 checksum = "d211803b9b6b570f68772237e415a029d5a50c65d382910b879fb19d3271f94d" 2313 3552 2314 3553 [[package]] 3554 + name = "parking" 3555 + version = "2.2.1" 3556 + source = "registry+https://github.com/rust-lang/crates.io-index" 3557 + checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" 3558 + 3559 + [[package]] 2315 3560 name = "parking_lot" 2316 3561 version = "0.12.5" 2317 3562 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2332 3577 "redox_syscall 0.5.18", 2333 3578 "smallvec", 2334 3579 "windows-link 0.2.1", 3580 + ] 3581 + 3582 + [[package]] 3583 + name = "pem-rfc7468" 3584 + version = "0.7.0" 3585 + source = "registry+https://github.com/rust-lang/crates.io-index" 3586 + checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" 3587 + dependencies = [ 3588 + "base64ct", 2335 3589 ] 2336 3590 2337 3591 [[package]] ··· 2380 3634 checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220" 2381 3635 dependencies = [ 2382 3636 "pest", 2383 - "sha2", 3637 + "sha2 0.10.9", 3638 + ] 3639 + 3640 + [[package]] 3641 + name = "pgvector" 3642 + version = "0.4.1" 3643 + source = "registry+https://github.com/rust-lang/crates.io-index" 3644 + checksum = "fc58e2d255979a31caa7cabfa7aac654af0354220719ab7a68520ae7a91e8c0b" 3645 + dependencies = [ 3646 + "serde", 2384 3647 ] 2385 3648 2386 3649 [[package]] ··· 2410 3673 checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" 2411 3674 dependencies = [ 2412 3675 "phf_shared", 2413 - "rand", 3676 + "rand 0.8.5", 2414 3677 ] 2415 3678 2416 3679 [[package]] ··· 2442 3705 checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" 2443 3706 2444 3707 [[package]] 3708 + name = "pin-utils" 3709 + version = "0.1.0" 3710 + source = "registry+https://github.com/rust-lang/crates.io-index" 3711 + checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 3712 + 3713 + [[package]] 3714 + name = "piper" 3715 + version = "0.2.5" 3716 + source = "registry+https://github.com/rust-lang/crates.io-index" 3717 + checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" 3718 + dependencies = [ 3719 + "atomic-waker", 3720 + "fastrand", 3721 + "futures-io", 3722 + ] 3723 + 3724 + [[package]] 3725 + name = "pkcs1" 3726 + version = "0.7.5" 3727 + source = "registry+https://github.com/rust-lang/crates.io-index" 3728 + checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" 3729 + dependencies = [ 3730 + "der", 3731 + "pkcs8", 3732 + "spki", 3733 + ] 3734 + 3735 + [[package]] 3736 + name = "pkcs8" 3737 + version = "0.10.2" 3738 + source = "registry+https://github.com/rust-lang/crates.io-index" 3739 + checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" 3740 + dependencies = [ 3741 + "der", 3742 + "spki", 3743 + ] 3744 + 3745 + [[package]] 3746 + name = "pkg-config" 3747 + version = "0.3.32" 3748 + source = "registry+https://github.com/rust-lang/crates.io-index" 3749 + checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" 3750 + 3751 + [[package]] 2445 3752 name = "plain" 2446 3753 version = "0.2.3" 2447 3754 source = "registry+https://github.com/rust-lang/crates.io-index" 2448 3755 checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" 3756 + 3757 + [[package]] 3758 + name = "pluralizer" 3759 + version = "0.5.0" 3760 + source = "registry+https://github.com/rust-lang/crates.io-index" 3761 + checksum = "4b3eba432a00a1f6c16f39147847a870e94e2e9b992759b503e330efec778cbe" 3762 + dependencies = [ 3763 + "once_cell", 3764 + "regex", 3765 + ] 3766 + 3767 + [[package]] 3768 + name = "polling" 3769 + version = "3.11.0" 3770 + source = "registry+https://github.com/rust-lang/crates.io-index" 3771 + checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" 3772 + dependencies = [ 3773 + "cfg-if", 3774 + "concurrent-queue", 3775 + "hermit-abi", 3776 + "pin-project-lite", 3777 + "rustix", 3778 + "windows-sys 0.61.2", 3779 + ] 2449 3780 2450 3781 [[package]] 2451 3782 name = "portable-atomic" ··· 2463 3794 ] 2464 3795 2465 3796 [[package]] 3797 + name = "potential_utf" 3798 + version = "0.1.4" 3799 + source = "registry+https://github.com/rust-lang/crates.io-index" 3800 + checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" 3801 + dependencies = [ 3802 + "zerovec", 3803 + ] 3804 + 3805 + [[package]] 2466 3806 name = "powerfmt" 2467 3807 version = "0.2.0" 2468 3808 source = "registry+https://github.com/rust-lang/crates.io-index" 2469 3809 checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 2470 3810 2471 3811 [[package]] 3812 + name = "ppv-lite86" 3813 + version = "0.2.21" 3814 + source = "registry+https://github.com/rust-lang/crates.io-index" 3815 + checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" 3816 + dependencies = [ 3817 + "zerocopy", 3818 + ] 3819 + 3820 + [[package]] 2472 3821 name = "prettyplease" 2473 3822 version = "0.2.37" 2474 3823 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2479 3828 ] 2480 3829 2481 3830 [[package]] 3831 + name = "proc-macro-crate" 3832 + version = "3.5.0" 3833 + source = "registry+https://github.com/rust-lang/crates.io-index" 3834 + checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" 3835 + dependencies = [ 3836 + "toml_edit", 3837 + ] 3838 + 3839 + [[package]] 3840 + name = "proc-macro-error-attr2" 3841 + version = "2.0.0" 3842 + source = "registry+https://github.com/rust-lang/crates.io-index" 3843 + checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" 3844 + dependencies = [ 3845 + "proc-macro2", 3846 + "quote", 3847 + ] 3848 + 3849 + [[package]] 3850 + name = "proc-macro-error2" 3851 + version = "2.0.1" 3852 + source = "registry+https://github.com/rust-lang/crates.io-index" 3853 + checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" 3854 + dependencies = [ 3855 + "proc-macro-error-attr2", 3856 + "proc-macro2", 3857 + "quote", 3858 + "syn 2.0.117", 3859 + ] 3860 + 3861 + [[package]] 2482 3862 name = "proc-macro2" 2483 3863 version = "1.0.106" 2484 3864 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2488 3868 ] 2489 3869 2490 3870 [[package]] 3871 + name = "proc-macro2-diagnostics" 3872 + version = "0.10.1" 3873 + source = "registry+https://github.com/rust-lang/crates.io-index" 3874 + checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" 3875 + dependencies = [ 3876 + "proc-macro2", 3877 + "quote", 3878 + "syn 2.0.117", 3879 + "version_check", 3880 + "yansi", 3881 + ] 3882 + 3883 + [[package]] 2491 3884 name = "prodash" 2492 3885 version = "30.0.1" 2493 3886 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2497 3890 ] 2498 3891 2499 3892 [[package]] 3893 + name = "ptr_meta" 3894 + version = "0.1.4" 3895 + source = "registry+https://github.com/rust-lang/crates.io-index" 3896 + checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" 3897 + dependencies = [ 3898 + "ptr_meta_derive", 3899 + ] 3900 + 3901 + [[package]] 3902 + name = "ptr_meta_derive" 3903 + version = "0.1.4" 3904 + source = "registry+https://github.com/rust-lang/crates.io-index" 3905 + checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" 3906 + dependencies = [ 3907 + "proc-macro2", 3908 + "quote", 3909 + "syn 1.0.109", 3910 + ] 3911 + 3912 + [[package]] 2500 3913 name = "quote" 2501 3914 version = "1.0.45" 2502 3915 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2518 3931 checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" 2519 3932 2520 3933 [[package]] 3934 + name = "radium" 3935 + version = "0.7.0" 3936 + source = "registry+https://github.com/rust-lang/crates.io-index" 3937 + checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" 3938 + 3939 + [[package]] 2521 3940 name = "rand" 2522 3941 version = "0.8.5" 2523 3942 source = "registry+https://github.com/rust-lang/crates.io-index" 2524 3943 checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 2525 3944 dependencies = [ 2526 - "rand_core", 3945 + "libc", 3946 + "rand_chacha 0.3.1", 3947 + "rand_core 0.6.4", 3948 + ] 3949 + 3950 + [[package]] 3951 + name = "rand" 3952 + version = "0.9.2" 3953 + source = "registry+https://github.com/rust-lang/crates.io-index" 3954 + checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" 3955 + dependencies = [ 3956 + "rand_chacha 0.9.0", 3957 + "rand_core 0.9.5", 3958 + ] 3959 + 3960 + [[package]] 3961 + name = "rand" 3962 + version = "0.10.0" 3963 + source = "registry+https://github.com/rust-lang/crates.io-index" 3964 + checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" 3965 + dependencies = [ 3966 + "chacha20", 3967 + "getrandom 0.4.2", 3968 + "rand_core 0.10.0", 3969 + ] 3970 + 3971 + [[package]] 3972 + name = "rand_chacha" 3973 + version = "0.3.1" 3974 + source = "registry+https://github.com/rust-lang/crates.io-index" 3975 + checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 3976 + dependencies = [ 3977 + "ppv-lite86", 3978 + "rand_core 0.6.4", 3979 + ] 3980 + 3981 + [[package]] 3982 + name = "rand_chacha" 3983 + version = "0.9.0" 3984 + source = "registry+https://github.com/rust-lang/crates.io-index" 3985 + checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 3986 + dependencies = [ 3987 + "ppv-lite86", 3988 + "rand_core 0.9.5", 2527 3989 ] 2528 3990 2529 3991 [[package]] ··· 2531 3993 version = "0.6.4" 2532 3994 source = "registry+https://github.com/rust-lang/crates.io-index" 2533 3995 checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 3996 + dependencies = [ 3997 + "getrandom 0.2.17", 3998 + ] 3999 + 4000 + [[package]] 4001 + name = "rand_core" 4002 + version = "0.9.5" 4003 + source = "registry+https://github.com/rust-lang/crates.io-index" 4004 + checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" 4005 + dependencies = [ 4006 + "getrandom 0.3.4", 4007 + ] 4008 + 4009 + [[package]] 4010 + name = "rand_core" 4011 + version = "0.10.0" 4012 + source = "registry+https://github.com/rust-lang/crates.io-index" 4013 + checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" 2534 4014 2535 4015 [[package]] 2536 4016 name = "ratatui" ··· 2676 4156 checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" 2677 4157 2678 4158 [[package]] 4159 + name = "rend" 4160 + version = "0.4.2" 4161 + source = "registry+https://github.com/rust-lang/crates.io-index" 4162 + checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" 4163 + dependencies = [ 4164 + "bytecheck", 4165 + ] 4166 + 4167 + [[package]] 4168 + name = "rkyv" 4169 + version = "0.7.46" 4170 + source = "registry+https://github.com/rust-lang/crates.io-index" 4171 + checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" 4172 + dependencies = [ 4173 + "bitvec", 4174 + "bytecheck", 4175 + "bytes", 4176 + "hashbrown 0.12.3", 4177 + "ptr_meta", 4178 + "rend", 4179 + "rkyv_derive", 4180 + "seahash", 4181 + "tinyvec", 4182 + "uuid", 4183 + ] 4184 + 4185 + [[package]] 4186 + name = "rkyv_derive" 4187 + version = "0.7.46" 4188 + source = "registry+https://github.com/rust-lang/crates.io-index" 4189 + checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" 4190 + dependencies = [ 4191 + "proc-macro2", 4192 + "quote", 4193 + "syn 1.0.109", 4194 + ] 4195 + 4196 + [[package]] 4197 + name = "rsa" 4198 + version = "0.9.10" 4199 + source = "registry+https://github.com/rust-lang/crates.io-index" 4200 + checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" 4201 + dependencies = [ 4202 + "const-oid 0.9.6", 4203 + "digest 0.10.7", 4204 + "num-bigint-dig", 4205 + "num-integer", 4206 + "num-traits", 4207 + "pkcs1", 4208 + "pkcs8", 4209 + "rand_core 0.6.4", 4210 + "signature", 4211 + "spki", 4212 + "subtle", 4213 + "zeroize", 4214 + ] 4215 + 4216 + [[package]] 4217 + name = "rust_decimal" 4218 + version = "1.40.0" 4219 + source = "registry+https://github.com/rust-lang/crates.io-index" 4220 + checksum = "61f703d19852dbf87cbc513643fa81428361eb6940f1ac14fd58155d295a3eb0" 4221 + dependencies = [ 4222 + "arrayvec", 4223 + "borsh", 4224 + "bytes", 4225 + "num-traits", 4226 + "rand 0.8.5", 4227 + "rkyv", 4228 + "serde", 4229 + "serde_json", 4230 + ] 4231 + 4232 + [[package]] 2679 4233 name = "rustc-demangle" 2680 4234 version = "0.1.27" 2681 4235 source = "registry+https://github.com/rust-lang/crates.io-index" 2682 4236 checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" 2683 4237 2684 4238 [[package]] 4239 + name = "rustc-hash" 4240 + version = "2.1.1" 4241 + source = "registry+https://github.com/rust-lang/crates.io-index" 4242 + checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" 4243 + 4244 + [[package]] 2685 4245 name = "rustc_version" 2686 4246 version = "0.4.1" 2687 4247 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2716 4276 checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" 2717 4277 2718 4278 [[package]] 4279 + name = "sakura" 4280 + version = "0.1.0" 4281 + dependencies = [ 4282 + "automerge", 4283 + "autosurgeon", 4284 + "serde", 4285 + ] 4286 + 4287 + [[package]] 2719 4288 name = "same-file" 2720 4289 version = "1.0.6" 2721 4290 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2731 4300 checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 2732 4301 2733 4302 [[package]] 4303 + name = "sea-bae" 4304 + version = "0.2.1" 4305 + source = "registry+https://github.com/rust-lang/crates.io-index" 4306 + checksum = "f694a6ab48f14bc063cfadff30ab551d3c7e46d8f81836c51989d548f44a2a25" 4307 + dependencies = [ 4308 + "heck 0.4.1", 4309 + "proc-macro-error2", 4310 + "proc-macro2", 4311 + "quote", 4312 + "syn 2.0.117", 4313 + ] 4314 + 4315 + [[package]] 4316 + name = "sea-orm" 4317 + version = "2.0.0-rc.37" 4318 + source = "registry+https://github.com/rust-lang/crates.io-index" 4319 + checksum = "4b846dc1c7fefbea372c03765ff08307d68894bbad8c73b66176dcd53a3ee131" 4320 + dependencies = [ 4321 + "async-stream", 4322 + "async-trait", 4323 + "bigdecimal", 4324 + "chrono", 4325 + "derive_more", 4326 + "futures-util", 4327 + "itertools", 4328 + "log", 4329 + "mac_address", 4330 + "ouroboros", 4331 + "pgvector", 4332 + "rust_decimal", 4333 + "sea-orm-arrow", 4334 + "sea-orm-macros", 4335 + "sea-query", 4336 + "sea-query-sqlx", 4337 + "sea-schema", 4338 + "serde", 4339 + "serde_json", 4340 + "sqlx", 4341 + "strum 0.27.2", 4342 + "thiserror 2.0.18", 4343 + "time", 4344 + "tracing", 4345 + "url", 4346 + "uuid", 4347 + ] 4348 + 4349 + [[package]] 4350 + name = "sea-orm-arrow" 4351 + version = "2.0.0-rc.3" 4352 + source = "registry+https://github.com/rust-lang/crates.io-index" 4353 + checksum = "5c2eee8405f16c1f337fe3a83389361caea83c928d14dbd666a480407072c365" 4354 + dependencies = [ 4355 + "arrow", 4356 + "sea-query", 4357 + "thiserror 2.0.18", 4358 + ] 4359 + 4360 + [[package]] 4361 + name = "sea-orm-cli" 4362 + version = "2.0.0-rc.37" 4363 + source = "registry+https://github.com/rust-lang/crates.io-index" 4364 + checksum = "cd9b34d4c8e615079c04eb7863a429c2d2a8bf9c934eb9eeb580f51f36367124" 4365 + dependencies = [ 4366 + "chrono", 4367 + "clap", 4368 + "dotenvy", 4369 + "glob", 4370 + "indoc", 4371 + "regex", 4372 + "sea-schema", 4373 + "sqlx", 4374 + "tokio", 4375 + "tracing", 4376 + "tracing-subscriber", 4377 + "url", 4378 + ] 4379 + 4380 + [[package]] 4381 + name = "sea-orm-macros" 4382 + version = "2.0.0-rc.37" 4383 + source = "registry+https://github.com/rust-lang/crates.io-index" 4384 + checksum = "b449fe660e4d365f335222025df97ae01e670ef7ad788b3c67db9183b6cb0474" 4385 + dependencies = [ 4386 + "heck 0.5.0", 4387 + "itertools", 4388 + "pluralizer", 4389 + "proc-macro2", 4390 + "quote", 4391 + "sea-bae", 4392 + "syn 2.0.117", 4393 + "unicode-ident", 4394 + ] 4395 + 4396 + [[package]] 4397 + name = "sea-orm-migration" 4398 + version = "2.0.0-rc.37" 4399 + source = "registry+https://github.com/rust-lang/crates.io-index" 4400 + checksum = "b3ceb928aac8be83332d34d1fdbc827d43696135a800723ffeb2e0b33b7b495e" 4401 + dependencies = [ 4402 + "async-trait", 4403 + "clap", 4404 + "dotenvy", 4405 + "sea-orm", 4406 + "sea-orm-cli", 4407 + "sea-schema", 4408 + "tracing", 4409 + "tracing-subscriber", 4410 + ] 4411 + 4412 + [[package]] 4413 + name = "sea-query" 4414 + version = "1.0.0-rc.31" 4415 + source = "registry+https://github.com/rust-lang/crates.io-index" 4416 + checksum = "58decdaaaf2a698170af2fa1b2e8f7b43a970e7768bf18aebaab113bada46354" 4417 + dependencies = [ 4418 + "chrono", 4419 + "inherent", 4420 + "ordered-float", 4421 + "rust_decimal", 4422 + "sea-query-derive", 4423 + "serde_json", 4424 + "time", 4425 + "uuid", 4426 + ] 4427 + 4428 + [[package]] 4429 + name = "sea-query-derive" 4430 + version = "1.0.0-rc.12" 4431 + source = "registry+https://github.com/rust-lang/crates.io-index" 4432 + checksum = "8d88ad44b6ad9788c8b9476b6b91f94c7461d1e19d39cd8ea37838b1e6ff5aa8" 4433 + dependencies = [ 4434 + "darling 0.20.11", 4435 + "heck 0.4.1", 4436 + "proc-macro2", 4437 + "quote", 4438 + "syn 2.0.117", 4439 + "thiserror 2.0.18", 4440 + ] 4441 + 4442 + [[package]] 4443 + name = "sea-query-sqlx" 4444 + version = "0.8.0-rc.14" 4445 + source = "registry+https://github.com/rust-lang/crates.io-index" 4446 + checksum = "e4377164b09a11bb692dec6966eb0e6908d63d768defef0be689b39e02cf8544" 4447 + dependencies = [ 4448 + "sea-query", 4449 + "sqlx", 4450 + ] 4451 + 4452 + [[package]] 4453 + name = "sea-schema" 4454 + version = "0.17.0-rc.17" 4455 + source = "registry+https://github.com/rust-lang/crates.io-index" 4456 + checksum = "b363dd21c20fe4d1488819cb2bc7f8d4696c62dd9f39554f97639f54d57dd0ab" 4457 + dependencies = [ 4458 + "async-trait", 4459 + "sea-query", 4460 + "sea-query-sqlx", 4461 + "sea-schema-derive", 4462 + "sqlx", 4463 + ] 4464 + 4465 + [[package]] 4466 + name = "sea-schema-derive" 4467 + version = "0.3.0" 4468 + source = "registry+https://github.com/rust-lang/crates.io-index" 4469 + checksum = "debdc8729c37fdbf88472f97fd470393089f997a909e535ff67c544d18cfccf0" 4470 + dependencies = [ 4471 + "heck 0.4.1", 4472 + "proc-macro2", 4473 + "quote", 4474 + "syn 2.0.117", 4475 + ] 4476 + 4477 + [[package]] 4478 + name = "seahash" 4479 + version = "4.1.0" 4480 + source = "registry+https://github.com/rust-lang/crates.io-index" 4481 + checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" 4482 + 4483 + [[package]] 2734 4484 name = "semver" 2735 4485 version = "1.0.27" 2736 4486 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2793 4543 ] 2794 4544 2795 4545 [[package]] 4546 + name = "serde_urlencoded" 4547 + version = "0.7.1" 4548 + source = "registry+https://github.com/rust-lang/crates.io-index" 4549 + checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 4550 + dependencies = [ 4551 + "form_urlencoded", 4552 + "itoa", 4553 + "ryu", 4554 + "serde", 4555 + ] 4556 + 4557 + [[package]] 2796 4558 name = "sha1" 2797 4559 version = "0.10.6" 2798 4560 source = "registry+https://github.com/rust-lang/crates.io-index" 2799 4561 checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" 2800 4562 dependencies = [ 2801 4563 "cfg-if", 2802 - "cpufeatures", 2803 - "digest", 4564 + "cpufeatures 0.2.17", 4565 + "digest 0.10.7", 2804 4566 ] 2805 4567 2806 4568 [[package]] ··· 2809 4571 source = "registry+https://github.com/rust-lang/crates.io-index" 2810 4572 checksum = "89f599ac0c323ebb1c6082821a54962b839832b03984598375bff3975b804423" 2811 4573 dependencies = [ 2812 - "digest", 4574 + "digest 0.10.7", 2813 4575 "sha1", 2814 4576 ] 2815 4577 ··· 2820 4582 checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" 2821 4583 dependencies = [ 2822 4584 "cfg-if", 2823 - "cpufeatures", 2824 - "digest", 4585 + "cpufeatures 0.2.17", 4586 + "digest 0.10.7", 4587 + ] 4588 + 4589 + [[package]] 4590 + name = "sha2" 4591 + version = "0.11.0-rc.5" 4592 + source = "registry+https://github.com/rust-lang/crates.io-index" 4593 + checksum = "7c5f3b1e2dc8aad28310d8410bd4d7e180eca65fca176c52ab00d364475d0024" 4594 + dependencies = [ 4595 + "cfg-if", 4596 + "cpufeatures 0.2.17", 4597 + "digest 0.11.2", 2825 4598 ] 2826 4599 2827 4600 [[package]] ··· 2840 4613 checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" 2841 4614 2842 4615 [[package]] 4616 + name = "shlex" 4617 + version = "1.3.0" 4618 + source = "registry+https://github.com/rust-lang/crates.io-index" 4619 + checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 4620 + 4621 + [[package]] 2843 4622 name = "signal-hook" 2844 4623 version = "0.3.18" 2845 4624 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2881 4660 ] 2882 4661 2883 4662 [[package]] 4663 + name = "signature" 4664 + version = "2.2.0" 4665 + source = "registry+https://github.com/rust-lang/crates.io-index" 4666 + checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" 4667 + dependencies = [ 4668 + "digest 0.10.7", 4669 + "rand_core 0.6.4", 4670 + ] 4671 + 4672 + [[package]] 4673 + name = "simd-adler32" 4674 + version = "0.3.8" 4675 + source = "registry+https://github.com/rust-lang/crates.io-index" 4676 + checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" 4677 + 4678 + [[package]] 4679 + name = "simdutf8" 4680 + version = "0.1.5" 4681 + source = "registry+https://github.com/rust-lang/crates.io-index" 4682 + checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" 4683 + 4684 + [[package]] 4685 + name = "similar" 4686 + version = "2.7.0" 4687 + source = "registry+https://github.com/rust-lang/crates.io-index" 4688 + checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" 4689 + dependencies = [ 4690 + "bstr", 4691 + "unicode-segmentation", 4692 + ] 4693 + 4694 + [[package]] 2884 4695 name = "siphasher" 2885 4696 version = "1.0.2" 2886 4697 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2897 4708 version = "1.15.1" 2898 4709 source = "registry+https://github.com/rust-lang/crates.io-index" 2899 4710 checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 4711 + dependencies = [ 4712 + "serde", 4713 + ] 4714 + 4715 + [[package]] 4716 + name = "smol_str" 4717 + version = "0.3.6" 4718 + source = "registry+https://github.com/rust-lang/crates.io-index" 4719 + checksum = "4aaa7368fcf4852a4c2dd92df0cace6a71f2091ca0a23391ce7f3a31833f1523" 4720 + dependencies = [ 4721 + "borsh", 4722 + "serde_core", 4723 + ] 2900 4724 2901 4725 [[package]] 2902 4726 name = "socket2" ··· 2909 4733 ] 2910 4734 2911 4735 [[package]] 4736 + name = "spin" 4737 + version = "0.9.8" 4738 + source = "registry+https://github.com/rust-lang/crates.io-index" 4739 + checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 4740 + dependencies = [ 4741 + "lock_api", 4742 + ] 4743 + 4744 + [[package]] 4745 + name = "spki" 4746 + version = "0.7.3" 4747 + source = "registry+https://github.com/rust-lang/crates.io-index" 4748 + checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" 4749 + dependencies = [ 4750 + "base64ct", 4751 + "der", 4752 + ] 4753 + 4754 + [[package]] 4755 + name = "sqlx" 4756 + version = "0.8.6" 4757 + source = "registry+https://github.com/rust-lang/crates.io-index" 4758 + checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" 4759 + dependencies = [ 4760 + "sqlx-core", 4761 + "sqlx-macros", 4762 + "sqlx-mysql", 4763 + "sqlx-postgres", 4764 + "sqlx-sqlite", 4765 + ] 4766 + 4767 + [[package]] 4768 + name = "sqlx-core" 4769 + version = "0.8.6" 4770 + source = "registry+https://github.com/rust-lang/crates.io-index" 4771 + checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" 4772 + dependencies = [ 4773 + "base64", 4774 + "bytes", 4775 + "chrono", 4776 + "crc", 4777 + "crossbeam-queue", 4778 + "either", 4779 + "event-listener 5.4.1", 4780 + "futures-core", 4781 + "futures-intrusive", 4782 + "futures-io", 4783 + "futures-util", 4784 + "hashbrown 0.15.5", 4785 + "hashlink", 4786 + "indexmap", 4787 + "log", 4788 + "memchr", 4789 + "once_cell", 4790 + "percent-encoding", 4791 + "rust_decimal", 4792 + "serde", 4793 + "serde_json", 4794 + "sha2 0.10.9", 4795 + "smallvec", 4796 + "thiserror 2.0.18", 4797 + "time", 4798 + "tokio", 4799 + "tokio-stream", 4800 + "tracing", 4801 + "url", 4802 + "uuid", 4803 + ] 4804 + 4805 + [[package]] 4806 + name = "sqlx-macros" 4807 + version = "0.8.6" 4808 + source = "registry+https://github.com/rust-lang/crates.io-index" 4809 + checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" 4810 + dependencies = [ 4811 + "proc-macro2", 4812 + "quote", 4813 + "sqlx-core", 4814 + "sqlx-macros-core", 4815 + "syn 2.0.117", 4816 + ] 4817 + 4818 + [[package]] 4819 + name = "sqlx-macros-core" 4820 + version = "0.8.6" 4821 + source = "registry+https://github.com/rust-lang/crates.io-index" 4822 + checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" 4823 + dependencies = [ 4824 + "dotenvy", 4825 + "either", 4826 + "heck 0.5.0", 4827 + "hex", 4828 + "once_cell", 4829 + "proc-macro2", 4830 + "quote", 4831 + "serde", 4832 + "serde_json", 4833 + "sha2 0.10.9", 4834 + "sqlx-core", 4835 + "sqlx-mysql", 4836 + "sqlx-postgres", 4837 + "sqlx-sqlite", 4838 + "syn 2.0.117", 4839 + "tokio", 4840 + "url", 4841 + ] 4842 + 4843 + [[package]] 4844 + name = "sqlx-mysql" 4845 + version = "0.8.6" 4846 + source = "registry+https://github.com/rust-lang/crates.io-index" 4847 + checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" 4848 + dependencies = [ 4849 + "atoi", 4850 + "base64", 4851 + "bitflags 2.11.0", 4852 + "byteorder", 4853 + "bytes", 4854 + "chrono", 4855 + "crc", 4856 + "digest 0.10.7", 4857 + "dotenvy", 4858 + "either", 4859 + "futures-channel", 4860 + "futures-core", 4861 + "futures-io", 4862 + "futures-util", 4863 + "generic-array", 4864 + "hex", 4865 + "hkdf", 4866 + "hmac", 4867 + "itoa", 4868 + "log", 4869 + "md-5", 4870 + "memchr", 4871 + "once_cell", 4872 + "percent-encoding", 4873 + "rand 0.8.5", 4874 + "rsa", 4875 + "rust_decimal", 4876 + "serde", 4877 + "sha1", 4878 + "sha2 0.10.9", 4879 + "smallvec", 4880 + "sqlx-core", 4881 + "stringprep", 4882 + "thiserror 2.0.18", 4883 + "time", 4884 + "tracing", 4885 + "uuid", 4886 + "whoami", 4887 + ] 4888 + 4889 + [[package]] 4890 + name = "sqlx-postgres" 4891 + version = "0.8.6" 4892 + source = "registry+https://github.com/rust-lang/crates.io-index" 4893 + checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" 4894 + dependencies = [ 4895 + "atoi", 4896 + "base64", 4897 + "bitflags 2.11.0", 4898 + "byteorder", 4899 + "chrono", 4900 + "crc", 4901 + "dotenvy", 4902 + "etcetera", 4903 + "futures-channel", 4904 + "futures-core", 4905 + "futures-util", 4906 + "hex", 4907 + "hkdf", 4908 + "hmac", 4909 + "home", 4910 + "itoa", 4911 + "log", 4912 + "md-5", 4913 + "memchr", 4914 + "once_cell", 4915 + "rand 0.8.5", 4916 + "rust_decimal", 4917 + "serde", 4918 + "serde_json", 4919 + "sha2 0.10.9", 4920 + "smallvec", 4921 + "sqlx-core", 4922 + "stringprep", 4923 + "thiserror 2.0.18", 4924 + "time", 4925 + "tracing", 4926 + "uuid", 4927 + "whoami", 4928 + ] 4929 + 4930 + [[package]] 4931 + name = "sqlx-sqlite" 4932 + version = "0.8.6" 4933 + source = "registry+https://github.com/rust-lang/crates.io-index" 4934 + checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" 4935 + dependencies = [ 4936 + "atoi", 4937 + "chrono", 4938 + "flume", 4939 + "futures-channel", 4940 + "futures-core", 4941 + "futures-executor", 4942 + "futures-intrusive", 4943 + "futures-util", 4944 + "libsqlite3-sys", 4945 + "log", 4946 + "percent-encoding", 4947 + "serde", 4948 + "serde_urlencoded", 4949 + "sqlx-core", 4950 + "thiserror 2.0.18", 4951 + "time", 4952 + "tracing", 4953 + "url", 4954 + "uuid", 4955 + ] 4956 + 4957 + [[package]] 2912 4958 name = "stable_deref_trait" 2913 4959 version = "1.2.1" 2914 4960 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2921 4967 checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 2922 4968 2923 4969 [[package]] 4970 + name = "stringprep" 4971 + version = "0.1.5" 4972 + source = "registry+https://github.com/rust-lang/crates.io-index" 4973 + checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" 4974 + dependencies = [ 4975 + "unicode-bidi", 4976 + "unicode-normalization", 4977 + "unicode-properties", 4978 + ] 4979 + 4980 + [[package]] 2924 4981 name = "strsim" 2925 4982 version = "0.11.1" 2926 4983 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2950 5007 source = "registry+https://github.com/rust-lang/crates.io-index" 2951 5008 checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" 2952 5009 dependencies = [ 2953 - "heck", 5010 + "heck 0.5.0", 2954 5011 "proc-macro2", 2955 5012 "quote", 2956 5013 "syn 2.0.117", ··· 2962 5019 source = "registry+https://github.com/rust-lang/crates.io-index" 2963 5020 checksum = "ab85eea0270ee17587ed4156089e10b9e6880ee688791d45a905f5b1ca36f664" 2964 5021 dependencies = [ 2965 - "heck", 5022 + "heck 0.5.0", 2966 5023 "proc-macro2", 2967 5024 "quote", 2968 5025 "syn 2.0.117", 2969 5026 ] 2970 5027 2971 5028 [[package]] 5029 + name = "subtle" 5030 + version = "2.6.1" 5031 + source = "registry+https://github.com/rust-lang/crates.io-index" 5032 + checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 5033 + 5034 + [[package]] 2972 5035 name = "syn" 2973 5036 version = "1.0.109" 2974 5037 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 2991 5054 ] 2992 5055 2993 5056 [[package]] 5057 + name = "synstructure" 5058 + version = "0.13.2" 5059 + source = "registry+https://github.com/rust-lang/crates.io-index" 5060 + checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" 5061 + dependencies = [ 5062 + "proc-macro2", 5063 + "quote", 5064 + "syn 2.0.117", 5065 + ] 5066 + 5067 + [[package]] 2994 5068 name = "sysinfo" 2995 5069 version = "0.37.2" 2996 5070 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3003 5077 "objc2-io-kit", 3004 5078 "windows", 3005 5079 ] 5080 + 5081 + [[package]] 5082 + name = "tap" 5083 + version = "1.0.1" 5084 + source = "registry+https://github.com/rust-lang/crates.io-index" 5085 + checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" 3006 5086 3007 5087 [[package]] 3008 5088 name = "tempfile" ··· 3073 5153 "pest", 3074 5154 "pest_derive", 3075 5155 "phf", 3076 - "sha2", 5156 + "sha2 0.10.9", 3077 5157 "signal-hook 0.3.18", 3078 5158 "siphasher", 3079 5159 "terminfo", ··· 3173 5253 ] 3174 5254 3175 5255 [[package]] 5256 + name = "tiny-keccak" 5257 + version = "2.0.2" 5258 + source = "registry+https://github.com/rust-lang/crates.io-index" 5259 + checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" 5260 + dependencies = [ 5261 + "crunchy", 5262 + ] 5263 + 5264 + [[package]] 5265 + name = "tinystr" 5266 + version = "0.8.2" 5267 + source = "registry+https://github.com/rust-lang/crates.io-index" 5268 + checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" 5269 + dependencies = [ 5270 + "displaydoc", 5271 + "zerovec", 5272 + ] 5273 + 5274 + [[package]] 3176 5275 name = "tinyvec" 3177 5276 version = "1.10.0" 3178 5277 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3216 5315 ] 3217 5316 3218 5317 [[package]] 5318 + name = "tokio-stream" 5319 + version = "0.1.18" 5320 + source = "registry+https://github.com/rust-lang/crates.io-index" 5321 + checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" 5322 + dependencies = [ 5323 + "futures-core", 5324 + "pin-project-lite", 5325 + "tokio", 5326 + ] 5327 + 5328 + [[package]] 3219 5329 name = "tokio-util" 3220 5330 version = "0.7.18" 3221 5331 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3236 5346 dependencies = [ 3237 5347 "serde_core", 3238 5348 "serde_spanned", 3239 - "toml_datetime", 5349 + "toml_datetime 0.7.5+spec-1.1.0", 3240 5350 "toml_writer", 3241 5351 ] 3242 5352 ··· 3250 5360 ] 3251 5361 3252 5362 [[package]] 5363 + name = "toml_datetime" 5364 + version = "1.0.0+spec-1.1.0" 5365 + source = "registry+https://github.com/rust-lang/crates.io-index" 5366 + checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e" 5367 + dependencies = [ 5368 + "serde_core", 5369 + ] 5370 + 5371 + [[package]] 5372 + name = "toml_edit" 5373 + version = "0.25.4+spec-1.1.0" 5374 + source = "registry+https://github.com/rust-lang/crates.io-index" 5375 + checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2" 5376 + dependencies = [ 5377 + "indexmap", 5378 + "toml_datetime 1.0.0+spec-1.1.0", 5379 + "toml_parser", 5380 + "winnow 0.7.15", 5381 + ] 5382 + 5383 + [[package]] 5384 + name = "toml_parser" 5385 + version = "1.0.9+spec-1.1.0" 5386 + source = "registry+https://github.com/rust-lang/crates.io-index" 5387 + checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" 5388 + dependencies = [ 5389 + "winnow 0.7.15", 5390 + ] 5391 + 5392 + [[package]] 3253 5393 name = "toml_writer" 3254 5394 version = "1.0.6+spec-1.1.0" 3255 5395 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3261 5401 source = "registry+https://github.com/rust-lang/crates.io-index" 3262 5402 checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" 3263 5403 dependencies = [ 5404 + "log", 3264 5405 "pin-project-lite", 3265 5406 "tracing-attributes", 3266 5407 "tracing-core", ··· 3345 5486 checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" 3346 5487 3347 5488 [[package]] 5489 + name = "unicode-bidi" 5490 + version = "0.3.18" 5491 + source = "registry+https://github.com/rust-lang/crates.io-index" 5492 + checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" 5493 + 5494 + [[package]] 3348 5495 name = "unicode-bom" 3349 5496 version = "2.0.3" 3350 5497 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3364 5511 dependencies = [ 3365 5512 "tinyvec", 3366 5513 ] 5514 + 5515 + [[package]] 5516 + name = "unicode-properties" 5517 + version = "0.1.4" 5518 + source = "registry+https://github.com/rust-lang/crates.io-index" 5519 + checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" 3367 5520 3368 5521 [[package]] 3369 5522 name = "unicode-segmentation" ··· 3401 5554 checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" 3402 5555 3403 5556 [[package]] 5557 + name = "url" 5558 + version = "2.5.8" 5559 + source = "registry+https://github.com/rust-lang/crates.io-index" 5560 + checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" 5561 + dependencies = [ 5562 + "form_urlencoded", 5563 + "idna", 5564 + "percent-encoding", 5565 + "serde", 5566 + ] 5567 + 5568 + [[package]] 5569 + name = "utf8_iter" 5570 + version = "1.0.4" 5571 + source = "registry+https://github.com/rust-lang/crates.io-index" 5572 + checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 5573 + 5574 + [[package]] 3404 5575 name = "utf8parse" 3405 5576 version = "0.2.2" 3406 5577 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3415 5586 "atomic", 3416 5587 "getrandom 0.4.2", 3417 5588 "js-sys", 5589 + "serde_core", 3418 5590 "wasm-bindgen", 3419 5591 ] 3420 5592 ··· 3423 5595 version = "0.1.1" 3424 5596 source = "registry+https://github.com/rust-lang/crates.io-index" 3425 5597 checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" 5598 + 5599 + [[package]] 5600 + name = "value-bag" 5601 + version = "1.12.0" 5602 + source = "registry+https://github.com/rust-lang/crates.io-index" 5603 + checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" 5604 + 5605 + [[package]] 5606 + name = "vcpkg" 5607 + version = "0.2.15" 5608 + source = "registry+https://github.com/rust-lang/crates.io-index" 5609 + checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" 3426 5610 3427 5611 [[package]] 3428 5612 name = "vergen" ··· 3515 5699 ] 3516 5700 3517 5701 [[package]] 5702 + name = "wasite" 5703 + version = "0.1.0" 5704 + source = "registry+https://github.com/rust-lang/crates.io-index" 5705 + checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" 5706 + 5707 + [[package]] 3518 5708 name = "wasm-bindgen" 3519 5709 version = "0.2.114" 3520 5710 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3528 5718 ] 3529 5719 3530 5720 [[package]] 5721 + name = "wasm-bindgen-futures" 5722 + version = "0.4.64" 5723 + source = "registry+https://github.com/rust-lang/crates.io-index" 5724 + checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" 5725 + dependencies = [ 5726 + "cfg-if", 5727 + "futures-util", 5728 + "js-sys", 5729 + "once_cell", 5730 + "wasm-bindgen", 5731 + "web-sys", 5732 + ] 5733 + 5734 + [[package]] 3531 5735 name = "wasm-bindgen-macro" 3532 5736 version = "0.2.114" 3533 5737 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3594 5798 ] 3595 5799 3596 5800 [[package]] 5801 + name = "web-sys" 5802 + version = "0.3.91" 5803 + source = "registry+https://github.com/rust-lang/crates.io-index" 5804 + checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" 5805 + dependencies = [ 5806 + "js-sys", 5807 + "wasm-bindgen", 5808 + ] 5809 + 5810 + [[package]] 3597 5811 name = "wezterm-bidi" 3598 5812 version = "0.2.3" 3599 5813 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 3611 5825 dependencies = [ 3612 5826 "getrandom 0.3.4", 3613 5827 "mac_address", 3614 - "sha2", 5828 + "sha2 0.10.9", 3615 5829 "thiserror 1.0.69", 3616 5830 "uuid", 3617 5831 ] ··· 3663 5877 "lazy_static", 3664 5878 "serde", 3665 5879 "wezterm-dynamic", 5880 + ] 5881 + 5882 + [[package]] 5883 + name = "whoami" 5884 + version = "1.6.1" 5885 + source = "registry+https://github.com/rust-lang/crates.io-index" 5886 + checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" 5887 + dependencies = [ 5888 + "libredox", 5889 + "wasite", 3666 5890 ] 3667 5891 3668 5892 [[package]] ··· 3806 6030 3807 6031 [[package]] 3808 6032 name = "windows-sys" 6033 + version = "0.48.0" 6034 + source = "registry+https://github.com/rust-lang/crates.io-index" 6035 + checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 6036 + dependencies = [ 6037 + "windows-targets 0.48.5", 6038 + ] 6039 + 6040 + [[package]] 6041 + name = "windows-sys" 3809 6042 version = "0.59.0" 3810 6043 source = "registry+https://github.com/rust-lang/crates.io-index" 3811 6044 checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" ··· 3833 6066 3834 6067 [[package]] 3835 6068 name = "windows-targets" 6069 + version = "0.48.5" 6070 + source = "registry+https://github.com/rust-lang/crates.io-index" 6071 + checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 6072 + dependencies = [ 6073 + "windows_aarch64_gnullvm 0.48.5", 6074 + "windows_aarch64_msvc 0.48.5", 6075 + "windows_i686_gnu 0.48.5", 6076 + "windows_i686_msvc 0.48.5", 6077 + "windows_x86_64_gnu 0.48.5", 6078 + "windows_x86_64_gnullvm 0.48.5", 6079 + "windows_x86_64_msvc 0.48.5", 6080 + ] 6081 + 6082 + [[package]] 6083 + name = "windows-targets" 3836 6084 version = "0.52.6" 3837 6085 source = "registry+https://github.com/rust-lang/crates.io-index" 3838 6086 checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" ··· 3875 6123 3876 6124 [[package]] 3877 6125 name = "windows_aarch64_gnullvm" 6126 + version = "0.48.5" 6127 + source = "registry+https://github.com/rust-lang/crates.io-index" 6128 + checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 6129 + 6130 + [[package]] 6131 + name = "windows_aarch64_gnullvm" 3878 6132 version = "0.52.6" 3879 6133 source = "registry+https://github.com/rust-lang/crates.io-index" 3880 6134 checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" ··· 3887 6141 3888 6142 [[package]] 3889 6143 name = "windows_aarch64_msvc" 6144 + version = "0.48.5" 6145 + source = "registry+https://github.com/rust-lang/crates.io-index" 6146 + checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 6147 + 6148 + [[package]] 6149 + name = "windows_aarch64_msvc" 3890 6150 version = "0.52.6" 3891 6151 source = "registry+https://github.com/rust-lang/crates.io-index" 3892 6152 checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" ··· 3899 6159 3900 6160 [[package]] 3901 6161 name = "windows_i686_gnu" 6162 + version = "0.48.5" 6163 + source = "registry+https://github.com/rust-lang/crates.io-index" 6164 + checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 6165 + 6166 + [[package]] 6167 + name = "windows_i686_gnu" 3902 6168 version = "0.52.6" 3903 6169 source = "registry+https://github.com/rust-lang/crates.io-index" 3904 6170 checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" ··· 3923 6189 3924 6190 [[package]] 3925 6191 name = "windows_i686_msvc" 6192 + version = "0.48.5" 6193 + source = "registry+https://github.com/rust-lang/crates.io-index" 6194 + checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 6195 + 6196 + [[package]] 6197 + name = "windows_i686_msvc" 3926 6198 version = "0.52.6" 3927 6199 source = "registry+https://github.com/rust-lang/crates.io-index" 3928 6200 checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" ··· 3935 6207 3936 6208 [[package]] 3937 6209 name = "windows_x86_64_gnu" 6210 + version = "0.48.5" 6211 + source = "registry+https://github.com/rust-lang/crates.io-index" 6212 + checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 6213 + 6214 + [[package]] 6215 + name = "windows_x86_64_gnu" 3938 6216 version = "0.52.6" 3939 6217 source = "registry+https://github.com/rust-lang/crates.io-index" 3940 6218 checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" ··· 3947 6225 3948 6226 [[package]] 3949 6227 name = "windows_x86_64_gnullvm" 6228 + version = "0.48.5" 6229 + source = "registry+https://github.com/rust-lang/crates.io-index" 6230 + checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 6231 + 6232 + [[package]] 6233 + name = "windows_x86_64_gnullvm" 3950 6234 version = "0.52.6" 3951 6235 source = "registry+https://github.com/rust-lang/crates.io-index" 3952 6236 checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" ··· 3959 6243 3960 6244 [[package]] 3961 6245 name = "windows_x86_64_msvc" 6246 + version = "0.48.5" 6247 + source = "registry+https://github.com/rust-lang/crates.io-index" 6248 + checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 6249 + 6250 + [[package]] 6251 + name = "windows_x86_64_msvc" 3962 6252 version = "0.52.6" 3963 6253 source = "registry+https://github.com/rust-lang/crates.io-index" 3964 6254 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" ··· 4003 6293 checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" 4004 6294 dependencies = [ 4005 6295 "anyhow", 4006 - "heck", 6296 + "heck 0.5.0", 4007 6297 "wit-parser", 4008 6298 ] 4009 6299 ··· 4014 6304 checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" 4015 6305 dependencies = [ 4016 6306 "anyhow", 4017 - "heck", 6307 + "heck 0.5.0", 4018 6308 "indexmap", 4019 6309 "prettyplease", 4020 6310 "syn 2.0.117", ··· 4073 6363 "serde_json", 4074 6364 "unicode-xid", 4075 6365 "wasmparser", 6366 + ] 6367 + 6368 + [[package]] 6369 + name = "writeable" 6370 + version = "0.6.2" 6371 + source = "registry+https://github.com/rust-lang/crates.io-index" 6372 + checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" 6373 + 6374 + [[package]] 6375 + name = "wyz" 6376 + version = "0.5.1" 6377 + source = "registry+https://github.com/rust-lang/crates.io-index" 6378 + checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" 6379 + dependencies = [ 6380 + "tap", 6381 + ] 6382 + 6383 + [[package]] 6384 + name = "yansi" 6385 + version = "1.0.1" 6386 + source = "registry+https://github.com/rust-lang/crates.io-index" 6387 + checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" 6388 + 6389 + [[package]] 6390 + name = "yoke" 6391 + version = "0.8.1" 6392 + source = "registry+https://github.com/rust-lang/crates.io-index" 6393 + checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" 6394 + dependencies = [ 6395 + "stable_deref_trait", 6396 + "yoke-derive", 6397 + "zerofrom", 6398 + ] 6399 + 6400 + [[package]] 6401 + name = "yoke-derive" 6402 + version = "0.8.1" 6403 + source = "registry+https://github.com/rust-lang/crates.io-index" 6404 + checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" 6405 + dependencies = [ 6406 + "proc-macro2", 6407 + "quote", 6408 + "syn 2.0.117", 6409 + "synstructure", 6410 + ] 6411 + 6412 + [[package]] 6413 + name = "zerocopy" 6414 + version = "0.8.42" 6415 + source = "registry+https://github.com/rust-lang/crates.io-index" 6416 + checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" 6417 + dependencies = [ 6418 + "zerocopy-derive", 6419 + ] 6420 + 6421 + [[package]] 6422 + name = "zerocopy-derive" 6423 + version = "0.8.42" 6424 + source = "registry+https://github.com/rust-lang/crates.io-index" 6425 + checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" 6426 + dependencies = [ 6427 + "proc-macro2", 6428 + "quote", 6429 + "syn 2.0.117", 6430 + ] 6431 + 6432 + [[package]] 6433 + name = "zerofrom" 6434 + version = "0.1.6" 6435 + source = "registry+https://github.com/rust-lang/crates.io-index" 6436 + checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" 6437 + dependencies = [ 6438 + "zerofrom-derive", 6439 + ] 6440 + 6441 + [[package]] 6442 + name = "zerofrom-derive" 6443 + version = "0.1.6" 6444 + source = "registry+https://github.com/rust-lang/crates.io-index" 6445 + checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" 6446 + dependencies = [ 6447 + "proc-macro2", 6448 + "quote", 6449 + "syn 2.0.117", 6450 + "synstructure", 6451 + ] 6452 + 6453 + [[package]] 6454 + name = "zeroize" 6455 + version = "1.8.2" 6456 + source = "registry+https://github.com/rust-lang/crates.io-index" 6457 + checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" 6458 + 6459 + [[package]] 6460 + name = "zerotrie" 6461 + version = "0.2.3" 6462 + source = "registry+https://github.com/rust-lang/crates.io-index" 6463 + checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" 6464 + dependencies = [ 6465 + "displaydoc", 6466 + "yoke", 6467 + "zerofrom", 6468 + ] 6469 + 6470 + [[package]] 6471 + name = "zerovec" 6472 + version = "0.11.5" 6473 + source = "registry+https://github.com/rust-lang/crates.io-index" 6474 + checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" 6475 + dependencies = [ 6476 + "yoke", 6477 + "zerofrom", 6478 + "zerovec-derive", 6479 + ] 6480 + 6481 + [[package]] 6482 + name = "zerovec-derive" 6483 + version = "0.11.2" 6484 + source = "registry+https://github.com/rust-lang/crates.io-index" 6485 + checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" 6486 + dependencies = [ 6487 + "proc-macro2", 6488 + "quote", 6489 + "syn 2.0.117", 4076 6490 ] 4077 6491 4078 6492 [[package]]
+9 -2
Cargo.toml
··· 1 1 [workspace] 2 - members = [] 2 + members = [ 3 + "crates/db", 4 + "crates/db/migration", 5 + "crates/sakura" 6 + ] 3 7 4 8 5 9 [workspace.package] ··· 26 30 27 31 [workspace.dependencies] 28 32 snafu = "0.9.0" 33 + serde = "1.0.228" 29 34 tracing = "0.1.44" 35 + tokio = { version = "1.50.0", features = ["full"] } 30 36 31 37 [package] 32 38 name = "filaments" ··· 49 55 color-eyre = "0.6.5" 50 56 human-panic = "2.0.6" 51 57 better-panic = "0.3.0" 58 + tokio = {workspace = true} 52 59 crossterm = { version = "0.29.0", features = ["event-stream"] } 53 60 futures = "0.3.32" 54 61 ratatui = "0.30.0" 55 62 serde = { version = "1.0.228", features = ["derive"] } 56 - tokio = { version = "1.50.0", features = ["full"] } 57 63 tokio-util = "0.7.18" 58 64 signal-hook = "0.4.3" 59 65 strum = { version = "0.28.0", features = ["derive"] } ··· 62 68 tracing-error = "0.2.1" 63 69 clap = { version = "4.5.60", features = ["derive", "cargo", "wrap_help", "unicode", "string", "unstable-styles"] } 64 70 kdl = "6.5.0" 71 + db = {path="./crates/db"} 65 72 66 73 [build-dependencies] 67 74 anyhow = "1.0.102"
+29
crates/db/Cargo.toml
··· 1 + [package] 2 + name = "db" 3 + version.workspace = true 4 + edition.workspace = true 5 + authors.workspace = true 6 + description.workspace = true 7 + license.workspace = true 8 + repository.workspace = true 9 + readme.workspace = true 10 + keywords.workspace = true 11 + rust-version.workspace = true 12 + 13 + [dependencies] 14 + sea-orm = {version = "2.0.0-rc", features = ["sqlx-sqlite", "runtime-tokio", "macros", "with-chrono"]} 15 + tracing = {workspace = true} 16 + thiserror = "2.0.18" 17 + migration = {path="migration"} 18 + 19 + 20 + 21 + [dev-dependencies] 22 + tokio = {workspace = true} 23 + anyhow = "1.0.102" 24 + rand = "0.10.0" 25 + 26 + 27 + [lints] 28 + # a lot of autogenerated things, lints arent very useful 29 + # workspace = true
+24
crates/db/migration/Cargo.toml
··· 1 + [package] 2 + name = "migration" 3 + version = "0.1.0" 4 + edition = "2024" 5 + publish = false 6 + 7 + [lib] 8 + name = "migration" 9 + path = "src/lib.rs" 10 + 11 + [dependencies] 12 + async-std = { version = "1", features = ["attributes", "tokio1"] } 13 + nanoid = "0.4.0" 14 + sea-orm = "2.0.0-rc" 15 + 16 + [dependencies.sea-orm-migration] 17 + version = "2.0.0-rc" 18 + features = [ 19 + # Enable at least one `ASYNC_RUNTIME` and `DATABASE_DRIVER` feature if you want to run migration via CLI. 20 + # View the list of supported features at https://www.sea-ql.org/SeaORM/docs/install-and-config/database-and-async-runtime. 21 + # e.g. 22 + "runtime-tokio", # `ASYNC_RUNTIME` feature 23 + "sqlx-sqlite", # `DATABASE_DRIVER` feature 24 + ]
+41
crates/db/migration/README.md
··· 1 + # Running Migrator CLI 2 + 3 + - Generate a new migration file 4 + ```sh 5 + cargo run -- generate MIGRATION_NAME 6 + ``` 7 + - Apply all pending migrations 8 + ```sh 9 + cargo run 10 + ``` 11 + ```sh 12 + cargo run -- up 13 + ``` 14 + - Apply first 10 pending migrations 15 + ```sh 16 + cargo run -- up -n 10 17 + ``` 18 + - Rollback last applied migrations 19 + ```sh 20 + cargo run -- down 21 + ``` 22 + - Rollback last 10 applied migrations 23 + ```sh 24 + cargo run -- down -n 10 25 + ``` 26 + - Drop all tables from the database, then reapply all migrations 27 + ```sh 28 + cargo run -- fresh 29 + ``` 30 + - Rollback all applied migrations, then reapply all migrations 31 + ```sh 32 + cargo run -- refresh 33 + ``` 34 + - Rollback all applied migrations 35 + ```sh 36 + cargo run -- reset 37 + ``` 38 + - Check the status of all migrations 39 + ```sh 40 + cargo run -- status 41 + ```
+18
crates/db/migration/src/lib.rs
··· 1 + pub use sea_orm_migration::prelude::*; 2 + 3 + pub mod types; 4 + 5 + mod m20260318_233726_group_table; 6 + mod m20260319_002245_task_table; 7 + 8 + pub struct Migrator; 9 + 10 + #[async_trait::async_trait] 11 + impl MigratorTrait for Migrator { 12 + fn migrations() -> Vec<Box<dyn MigrationTrait>> { 13 + vec![ 14 + Box::new(m20260318_233726_group_table::Migration), 15 + Box::new(m20260319_002245_task_table::Migration), 16 + ] 17 + } 18 + }
+102
crates/db/migration/src/m20260318_233726_group_table.rs
··· 1 + use sea_orm_migration::{prelude::*, schema::*}; 2 + 3 + use crate::types::{NANO_ID_LEN, NanoId, Priority}; 4 + 5 + #[derive(DeriveMigrationName)] 6 + pub struct Migration; 7 + 8 + #[async_trait::async_trait] 9 + impl MigrationTrait for Migration { 10 + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { 11 + manager 12 + .create_table( 13 + Table::create() 14 + .table(Group::Table) 15 + .if_not_exists() 16 + .col(pk_auto(Group::Id)) 17 + .col( 18 + string(Group::NanoId) 19 + .string_len(NANO_ID_LEN as u32) 20 + .unique_key() 21 + .not_null() 22 + .default(NanoId::default().0), 23 + ) 24 + .col(string(Group::Name).not_null()) 25 + //Note: Color is a hex color with the leading # 26 + .col(string(Group::Color).not_null()) 27 + .col(string(Group::DescriptionPath).not_null()) 28 + .col( 29 + string(Group::Priority) 30 + .not_null() 31 + .default(Priority::default().to_string()), 32 + ) 33 + .col(timestamp(Group::CreatedAt).default(Expr::current_timestamp())) 34 + .col(timestamp(Group::ModifiedAt).default(Expr::current_timestamp())) 35 + .col(string_null(Group::ParentGroupId)) 36 + .foreign_key( 37 + ForeignKey::create() 38 + .name("fk_group_parent_id") // unique constraint name 39 + .from(Group::Table, Group::ParentGroupId) 40 + .to(Group::Table, Group::NanoId) // self-referential to the nano-id 41 + .on_update(ForeignKeyAction::Cascade) 42 + .on_delete(ForeignKeyAction::Cascade), 43 + ) 44 + .to_owned(), 45 + ) 46 + .await?; 47 + 48 + manager 49 + .create_index( 50 + Index::create() 51 + .name("idx_groups_pub_id") 52 + .table(Group::Table) 53 + .col(Group::NanoId) 54 + .to_owned(), 55 + ) 56 + .await 57 + } 58 + 59 + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { 60 + manager 61 + .drop_index(Index::drop().name("idx_groups_pub_id").to_owned()) 62 + .await?; 63 + 64 + manager 65 + .drop_table(Table::drop().table(Group::Table).to_owned()) 66 + .await 67 + } 68 + } 69 + 70 + #[derive(DeriveIden)] 71 + pub enum Group { 72 + Table, 73 + 74 + /// Unique integer id 75 + Id, 76 + 77 + /// Unique nano-id that is userfacing 78 + NanoId, 79 + 80 + /// Nano-id of the parent of this group 81 + ParentGroupId, 82 + 83 + /// Name of the group 84 + Name, 85 + 86 + /// Color of this group 87 + /// NOTE: color is a string that looks like "#FFFFFF" 88 + Color, 89 + 90 + /// Priority level of the group 91 + Priority, 92 + 93 + /// The relative file path to the location of 94 + /// the description note for this task 95 + DescriptionPath, 96 + 97 + /// Creation time 98 + CreatedAt, 99 + 100 + /// Last modified 101 + ModifiedAt, 102 + }
+131
crates/db/migration/src/m20260319_002245_task_table.rs
··· 1 + use sea_orm_migration::{prelude::*, schema::*}; 2 + 3 + use crate::{ 4 + m20260318_233726_group_table::Group, 5 + types::{NANO_ID_LEN, NanoId, Priority}, 6 + }; 7 + 8 + #[derive(DeriveMigrationName)] 9 + pub struct Migration; 10 + 11 + #[async_trait::async_trait] 12 + impl MigrationTrait for Migration { 13 + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { 14 + manager 15 + .create_table( 16 + Table::create() 17 + .table(Task::Table) 18 + .if_not_exists() 19 + .col(pk_auto(Task::Id)) 20 + .col( 21 + string(Task::NanoId) 22 + .string_len(NANO_ID_LEN as u32) 23 + .unique_key() 24 + .not_null() 25 + .default(NanoId::default().0), 26 + ) 27 + .col(string(Task::Name).not_null()) 28 + .col(string(Task::DescriptionPath).not_null()) 29 + .col( 30 + string(Task::Priority) 31 + .not_null() 32 + .default(Priority::default().to_string()), 33 + ) 34 + .col(timestamp(Task::Due).null()) 35 + .col(timestamp(Task::CreatedAt).default(Expr::current_timestamp())) 36 + .col(timestamp(Task::ModifiedAt).default(Expr::current_timestamp())) 37 + .col(string(Task::GroupId).not_null()) 38 + .foreign_key( 39 + ForeignKey::create() 40 + .name("fk_task_group_id") // unique constraint name 41 + .from(Task::Table, Task::GroupId) 42 + .to(Group::Table, Group::NanoId) // self-referential to the nano-id 43 + .on_update(ForeignKeyAction::Cascade) 44 + .on_delete(ForeignKeyAction::Cascade), 45 + ) 46 + .to_owned(), 47 + ) 48 + .await?; 49 + 50 + manager 51 + .create_index( 52 + Index::create() 53 + .name("idx_tasks_pub_id") 54 + .table(Task::Table) 55 + .col(Task::NanoId) 56 + .to_owned(), 57 + ) 58 + .await?; 59 + 60 + manager 61 + .create_index( 62 + Index::create() 63 + .name("idx_tasks_group_id") 64 + .table(Task::Table) 65 + .col(Task::GroupId) 66 + .to_owned(), 67 + ) 68 + .await?; 69 + 70 + manager 71 + .create_index( 72 + Index::create() 73 + .name("idx_tasks_due") 74 + .table(Task::Table) 75 + .col(Task::Due) 76 + .to_owned(), 77 + ) 78 + .await 79 + } 80 + 81 + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { 82 + manager 83 + .drop_index(Index::drop().name("idx_tasks_due").to_owned()) 84 + .await?; 85 + 86 + manager 87 + .drop_index(Index::drop().name("idx_tasks_group_id").to_owned()) 88 + .await?; 89 + 90 + manager 91 + .drop_index(Index::drop().name("idx_tasks_pub_id").to_owned()) 92 + .await?; 93 + 94 + manager 95 + .drop_table(Table::drop().table(Task::Table).to_owned()) 96 + .await 97 + } 98 + } 99 + 100 + #[derive(DeriveIden)] 101 + enum Task { 102 + Table, 103 + 104 + /// Unique integer id 105 + Id, 106 + 107 + /// Unique nano-id that is userfacing 108 + NanoId, 109 + 110 + /// Nano-id of the group this task is a part of 111 + GroupId, 112 + 113 + /// Name of the Task 114 + Name, 115 + 116 + /// Priority level of the group 117 + Priority, 118 + 119 + /// The relative file path to the location of 120 + /// the description note for this task 121 + DescriptionPath, 122 + 123 + /// The duedate for this task 124 + Due, 125 + 126 + /// Creation time 127 + CreatedAt, 128 + 129 + /// Last modified 130 + ModifiedAt, 131 + }
+6
crates/db/migration/src/main.rs
··· 1 + use sea_orm_migration::prelude::*; 2 + 3 + #[async_std::main] 4 + async fn main() { 5 + cli::run_cli(migration::Migrator).await; 6 + }
+6
crates/db/migration/src/types/mod.rs
··· 1 + mod priority; 2 + pub use priority::Priority; 3 + 4 + mod nano_id; 5 + pub(crate) use nano_id::NANO_ID_LEN; 6 + pub use nano_id::NanoId;
+46
crates/db/migration/src/types/nano_id.rs
··· 1 + use nanoid::nanoid; 2 + use sea_orm::DeriveValueType; 3 + 4 + #[derive(Clone, Debug, PartialEq, Eq, DeriveValueType)] 5 + #[sea_orm(value_type = "String")] 6 + pub struct NanoId(pub(crate) String); 7 + 8 + const ALPHABET: [char; 26] = [ 9 + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 10 + 't', 'u', 'v', 'w', 'x', 'y', 'z', 11 + ]; 12 + 13 + pub const NANO_ID_LEN: usize = 6; 14 + 15 + impl Default for NanoId { 16 + fn default() -> Self { 17 + Self(nanoid!(NANO_ID_LEN, &ALPHABET)) 18 + } 19 + } 20 + 21 + #[derive(Debug)] 22 + pub struct NanoIdParseError { 23 + bad: String, 24 + } 25 + 26 + impl std::error::Error for NanoIdParseError {} 27 + 28 + impl std::fmt::Display for NanoIdParseError { 29 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 30 + write!(f, "{} is not a valid NanoId!", self.bad) 31 + } 32 + } 33 + 34 + impl std::fmt::Display for NanoId { 35 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 36 + write!(f, "{}", self.0) 37 + } 38 + } 39 + 40 + impl std::str::FromStr for NanoId { 41 + type Err = NanoIdParseError; 42 + 43 + fn from_str(s: &str) -> Result<Self, Self::Err> { 44 + Ok(Self(s.to_owned())) 45 + } 46 + }
+56
crates/db/migration/src/types/priority.rs
··· 1 + use sea_orm::DeriveValueType; 2 + 3 + #[derive(Clone, Debug, PartialEq, Eq, DeriveValueType, Default)] 4 + #[sea_orm(value_type = "String")] 5 + pub enum Priority { 6 + Asap, 7 + High, 8 + #[default] 9 + Medium, 10 + Low, 11 + Far, 12 + } 13 + 14 + #[derive(Debug)] 15 + pub struct PriorityParseError { 16 + bad: String, 17 + } 18 + 19 + impl std::error::Error for PriorityParseError {} 20 + 21 + impl std::fmt::Display for PriorityParseError { 22 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 23 + write!(f, "{} is not a valid Priority!", self.bad) 24 + } 25 + } 26 + 27 + impl std::fmt::Display for Priority { 28 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 29 + let str = match self { 30 + Priority::Asap => "ASAP", 31 + Priority::High => "High", 32 + Priority::Medium => "Medium", 33 + Priority::Low => "Low", 34 + Priority::Far => "Far", 35 + }; 36 + 37 + write!(f, "{str}") 38 + } 39 + } 40 + 41 + impl std::str::FromStr for Priority { 42 + type Err = PriorityParseError; 43 + 44 + fn from_str(s: &str) -> Result<Self, Self::Err> { 45 + let v = match s { 46 + "ASAP" => Self::Asap, 47 + "High" => Self::High, 48 + "Medium" => Priority::Medium, 49 + "Low" => Self::Low, 50 + "Far" => Self::Far, 51 + _ => return Err(PriorityParseError { bad: s.to_owned() }), 52 + }; 53 + 54 + Ok(v) 55 + } 56 + }
+34
crates/db/src/entity/group.rs
··· 1 + //! `SeaORM` Entity, @generated by sea-orm-codegen 2.0 2 + 3 + use sea_orm::entity::prelude::*; 4 + use migration::types::*; 5 + 6 + #[sea_orm::model] 7 + #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] 8 + #[sea_orm(table_name = "group")] 9 + pub struct Model { 10 + #[sea_orm(primary_key)] 11 + pub id: i64, 12 + #[sea_orm(unique)] 13 + pub nano_id: NanoId, 14 + pub name: String, 15 + pub color: String, 16 + pub description_path: String, 17 + pub priority: Priority, 18 + pub created_at: DateTimeUtc, 19 + pub modified_at: DateTimeUtc, 20 + pub parent_group_id: Option<NanoId>, 21 + #[sea_orm( 22 + self_ref, 23 + relation_enum = "SelfRef", 24 + from = "parent_group_id", 25 + to = "nano_id", 26 + on_update = "Cascade", 27 + on_delete = "Cascade" 28 + )] 29 + pub group: HasOne<Entity>, 30 + #[sea_orm(has_many)] 31 + pub tasks: HasMany<super::task::Entity>, 32 + } 33 + 34 + impl ActiveModelBehavior for ActiveModel {}
+6
crates/db/src/entity/mod.rs
··· 1 + //! `SeaORM` Entity, @generated by sea-orm-codegen 2.0 2 + 3 + pub mod prelude; 4 + 5 + pub mod group; 6 + pub mod task;
+4
crates/db/src/entity/prelude.rs
··· 1 + //! `SeaORM` Entity, @generated by sea-orm-codegen 2.0 2 + 3 + pub use super::group::Entity as Group; 4 + pub use super::task::Entity as Task;
+31
crates/db/src/entity/task.rs
··· 1 + //! `SeaORM` Entity, @generated by sea-orm-codegen 2.0 2 + 3 + use migration::types::*; 4 + use sea_orm::entity::prelude::*; 5 + 6 + #[sea_orm::model] 7 + #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)] 8 + #[sea_orm(table_name = "task")] 9 + pub struct Model { 10 + #[sea_orm(primary_key)] 11 + pub id: i64, 12 + #[sea_orm(unique)] 13 + pub nano_id: NanoId, 14 + pub name: String, 15 + pub description_path: String, 16 + pub priority: Priority, 17 + pub due: Option<DateTimeUtc>, 18 + pub created_at: DateTimeUtc, 19 + pub modified_at: DateTimeUtc, 20 + pub group_id: NanoId, 21 + #[sea_orm( 22 + belongs_to, 23 + from = "group_id", 24 + to = "nano_id", 25 + on_update = "Cascade", 26 + on_delete = "Cascade" 27 + )] 28 + pub group: HasOne<super::group::Entity>, 29 + } 30 + 31 + impl ActiveModelBehavior for ActiveModel {}
+11
crates/db/src/errors.rs
··· 1 + use thiserror::Error; 2 + 3 + pub type DbResult<T> = Result<T, crate::errors::DbError>; 4 + 5 + #[derive(Debug, Error)] 6 + pub enum DbError { 7 + #[error("database file not found, tried looking at {not_found_at}")] 8 + NotFound { not_found_at: String }, 9 + #[error("Seaorm Error")] 10 + SeaOrm(#[from] sea_orm::error::DbErr), 11 + }
+85
crates/db/src/lib.rs
··· 1 + //! The database abstraction for the different actions `Filaments` requires 2 + //! from a database service. 3 + 4 + use std::path::PathBuf; 5 + 6 + use migration::{Migrator, MigratorTrait}; 7 + use sea_orm::{Database, DatabaseConnection}; 8 + use tracing::debug; 9 + 10 + use crate::errors::{DbError, DbResult}; 11 + 12 + /// Database Errors 13 + mod errors; 14 + 15 + /// Database entities 16 + pub mod entity; 17 + 18 + /// Types defined in migration 19 + pub use migration::types::*; 20 + 21 + pub use sea_orm::ActiveValue; 22 + 23 + #[expect(unused_imports)] 24 + pub use errors::*; 25 + 26 + /// Database struct 27 + #[derive(Debug)] 28 + pub struct Db { 29 + conn: DatabaseConnection, 30 + } 31 + 32 + impl AsRef<DatabaseConnection> for Db { 33 + fn as_ref(&self) -> &DatabaseConnection { 34 + &self.conn 35 + } 36 + } 37 + 38 + impl Db { 39 + /// Connects to the database to the database at `path`. 40 + /// 41 + /// # Errors 42 + /// Will error if `path` is not a valid file. 43 + pub async fn connect(path: impl Into<PathBuf>) -> DbResult<Self> { 44 + let path = path.into(); 45 + 46 + let connection_string = format!( 47 + "sqlite://{}", 48 + path.canonicalize() 49 + .map_err(|_| DbError::NotFound { 50 + not_found_at: path.to_string_lossy().to_string() 51 + })? 52 + .to_string_lossy() 53 + ); 54 + 55 + debug!("connecting to {connection_string}"); 56 + 57 + let conn = Database::connect(connection_string).await?; 58 + 59 + // run all migrations on connection 60 + Migrator::up(&conn, None).await?; 61 + 62 + Ok(Self { conn }) 63 + } 64 + } 65 + 66 + #[cfg(test)] 67 + mod tests { 68 + use std::{ 69 + fs::{File, create_dir_all}, 70 + path::PathBuf, 71 + }; 72 + 73 + use crate::Db; 74 + 75 + #[tokio::test] 76 + async fn test_connect() { 77 + let path = PathBuf::new(); 78 + let _ = Db::connect(&path).await.expect_err("not found"); 79 + 80 + let path = PathBuf::from("/tmp/filaments/test_db.sqlite"); 81 + create_dir_all(path.parent().unwrap()).unwrap(); 82 + let _ = File::create(&path).unwrap(); 83 + let _db = Db::connect(&path).await.unwrap(); 84 + } 85 + }
+24
crates/db/tests/common/mod.rs
··· 1 + use std::{ 2 + fs::{File, create_dir_all}, 3 + path::PathBuf, 4 + }; 5 + 6 + use db::Db; 7 + use rand::RngExt; 8 + 9 + pub async fn fresh_test_db() -> Db { 10 + let rand_id = { 11 + let mut rng = rand::rng(); 12 + let mut rand_id = [0_u8; 4]; 13 + rand_id.fill_with(|| rng.sample(rand::distr::Alphanumeric)); 14 + 15 + String::from_utf8(rand_id.to_vec()).unwrap() 16 + }; 17 + 18 + let path = PathBuf::from(format!("/tmp/filaments/test_db_{rand_id}")); 19 + 20 + create_dir_all(path.parent().unwrap()).unwrap(); 21 + 22 + let _ = File::create(&path).unwrap(); 23 + Db::connect(&path).await.unwrap() 24 + }
+48
crates/db/tests/task.rs
··· 1 + //! Testing task functionality with the database abstraction. 2 + 3 + use db::entity::{group, prelude::*}; 4 + use db::{ActiveValue::Set, entity::task}; 5 + use sea_orm::ActiveModelTrait; 6 + mod common; 7 + 8 + #[tokio::test] 9 + async fn test_group_task_insert() { 10 + let db = common::fresh_test_db().await; 11 + 12 + let group = group::ActiveModel { 13 + name: Set("something".to_owned()), 14 + color: Set("color".to_owned()), 15 + description_path: Set("something".to_owned()), 16 + ..Default::default() 17 + }; 18 + 19 + let group: group::Model = group.insert(db.as_ref()).await.unwrap(); 20 + 21 + let task = task::ActiveModel { 22 + name: Set("something".to_owned()), 23 + description_path: Set("something".to_owned()), 24 + group_id: Set(group.nano_id.to_owned()), 25 + ..Default::default() 26 + }; 27 + 28 + let task: task::Model = task.insert(db.as_ref()).await.unwrap(); 29 + 30 + let task = Task::find_by_nano_id(task.nano_id) 31 + .inner_join(Group) 32 + // .reverse_join(Group) 33 + // .find_with_related(Group) 34 + .all(db.as_ref()) 35 + .await 36 + .unwrap(); 37 + 38 + let task = Task::load() 39 + .filter_by_nano_id(task.first().unwrap().nano_id.clone()) 40 + .with(Group) 41 + .one(db.as_ref()) 42 + .await 43 + .unwrap() 44 + .unwrap(); 45 + 46 + println!("{group:#?}"); 47 + println!("{task:#?}"); 48 + }
+18
crates/sakura/Cargo.toml
··· 1 + [package] 2 + name = "sakura" 3 + version = "0.1.0" 4 + authors.workspace = true 5 + edition.workspace = true 6 + rust-version.workspace = true 7 + repository.workspace = true 8 + license.workspace = true 9 + 10 + [dependencies] 11 + automerge = "0.7.3" 12 + autosurgeon = "0.10.1" 13 + serde.workspace = true 14 + 15 + 16 + [lints.clippy] 17 + pedantic = "deny" 18 + nursery = "deny"
+188
crates/sakura/src/behaviors.rs
··· 1 + use super::NodeId; 2 + 3 + /// Describes the possible behaviors of the `Tree::insert` method. 4 + pub enum InsertBehavior<'a> { 5 + /// Insert the `Node` as the root of the tree. 6 + /// 7 + /// If there is already a root `Node` in the tree, then that `Node` will 8 + /// be set as the first child as the new root `Node`. 9 + /// 10 + /// ``` 11 + /// use sakura::*; 12 + /// use sakura::InsertBehavior::*; 13 + /// 14 + /// let mut tree: Tree<i32> = Tree::new(); 15 + /// let root_node = Node::new(1); 16 + /// 17 + /// tree.insert(root_node, AsRoot).unwrap(); 18 + /// 19 + /// ``` 20 + AsRoot, 21 + 22 + /// Inserts the `Node` under the `Node` that has the provided `NodeId`. 23 + /// 24 + /// Note: Adds the new `Node` to the end of its children. 25 + /// 26 + /// # Returns 27 + /// `Result` containing the `NodeId` of the child that was added or a `NodeIdError` 28 + /// 29 + /// ``` 30 + /// use sakura::*; 31 + /// use sakura::InsertBehavior::*; 32 + /// 33 + /// let root_node = Node::new(1); 34 + /// let child_node = Node::new(2); 35 + /// 36 + /// let mut tree: Tree<i32> = Tree::new(); 37 + /// let mut root_id = tree.insert(root_node, AsRoot).unwrap(); 38 + /// 39 + /// tree.insert(child_node, UnderNode(&root_id)).unwrap(); 40 + /// 41 + /// ``` 42 + UnderNode(&'a NodeId), 43 + } 44 + 45 + pub enum RemoveBehavior { 46 + /// The entire subtree of the `Node` being removed will be 47 + /// dropped from the tree, effectively meaning that all children 48 + /// will be dropped recursively. 49 + /// 50 + /// Those `Node`'s will no longer exist and cannot be accessed even 51 + /// if you hold a `NodeId` for them, so use this behavior with caution. 52 + /// 53 + /// 54 + /// ``` 55 + /// use sakura::*; 56 + /// use sakura::InsertBehavior::*; 57 + /// use sakura::RemoveBehavior::*; 58 + /// 59 + /// let mut tree: Tree<i32> = Tree::new(); 60 + /// 61 + /// let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); 62 + /// let child_id = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 63 + /// let grandchild_id = tree.insert(Node::new(2), UnderNode(&child_id)).unwrap(); 64 + /// 65 + /// let child = tree.remove_node(child_id, DropChildren).ok().unwrap(); 66 + /// 67 + /// assert!(tree.get(&grandchild_id).is_err()); 68 + /// assert_eq!(tree.get(&root_id).unwrap().children().len(), 0); 69 + /// assert_eq!(child.children().len(), 0); 70 + /// assert_eq!(child.parent(), None); 71 + /// ``` 72 + /// 73 + DropChildren, 74 + 75 + /// 76 + /// 77 + /// If the removed `Node` (say `A`) has a parent `A'`, then `A'` will 78 + /// become the parent of `A`'s children. 79 + /// 80 + /// If `A` doesn't have a parent, then this behaves exactly like 81 + /// `RemoveBehavior::OrphanChildren`. 82 + /// ``` 83 + /// use sakura::*; 84 + /// use sakura::InsertBehavior::*; 85 + /// use sakura::RemoveBehavior::*; 86 + /// 87 + /// let mut tree: Tree<i32> = Tree::new(); 88 + /// 89 + /// let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); 90 + /// let child_id = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 91 + /// let grandchild_id = tree.insert(Node::new(2), UnderNode(&child_id)).unwrap(); 92 + /// 93 + /// let child = tree.remove_node(child_id, LiftChildren).ok().unwrap(); 94 + /// 95 + /// assert!(tree.get(&grandchild_id).is_ok()); 96 + /// assert!(tree.get(&root_id).unwrap().children().contains(&grandchild_id)); 97 + /// assert_eq!(child.children().len(), 0); 98 + /// assert_eq!(child.parent(), None); 99 + /// ``` 100 + /// 101 + LiftChildren, 102 + 103 + /// All children will have their parent references cleared. Nothing 104 + /// will point to them, but they will still exist in the tree. 105 + /// Those `Node`s can still be accessed if you still have their 106 + /// `NodeId`'s. 107 + /// 108 + /// ``` 109 + /// use sakura::*; 110 + /// use sakura::InsertBehavior::*; 111 + /// use sakura::RemoveBehavior::*; 112 + /// 113 + /// let mut tree: Tree<i32> = Tree::new(); 114 + /// 115 + /// let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); 116 + /// let child_id = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 117 + /// let grandchild_id = tree.insert(Node::new(2), UnderNode(&child_id)).unwrap(); 118 + /// 119 + /// let child = tree.remove_node(child_id, OrphanChildren).ok().unwrap(); 120 + /// 121 + /// assert!(tree.get(&grandchild_id).is_ok()); 122 + /// assert_eq!(tree.get(&root_id).unwrap().children().len(), 0); 123 + /// assert_eq!(child.children().len(), 0); 124 + /// assert_eq!(child.parent(), None); 125 + /// ``` 126 + /// 127 + OrphanChildren, 128 + } 129 + 130 + pub enum MoveBehavior<'a> { 131 + /// Sets the `Node` as the new root `Node`, while having all their children 132 + /// travel with them. 133 + /// 134 + /// If there is already a root `Node` in place, it will be attached as the 135 + /// last child of the new root `Node`. 136 + /// 137 + /// ``` 138 + /// use sakura::*; 139 + /// use sakura::InsertBehavior::*; 140 + /// use sakura::MoveBehavior::*; 141 + /// 142 + /// let mut tree: Tree<i32> = Tree::new(); 143 + /// 144 + /// let root_id = tree.insert(Node::new(1), AsRoot).unwrap(); 145 + /// let child_id = tree.insert(Node::new(2), UnderNode(&root_id)).unwrap(); 146 + /// let grandchild_id = tree.insert(Node::new(3), UnderNode(&child_id)).unwrap(); 147 + /// 148 + /// tree.move_node(&grandchild_id, ToRoot).unwrap(); 149 + /// 150 + /// assert_eq!(tree.root_node_id(), Some(&grandchild_id)); 151 + /// assert!(tree.get(&grandchild_id).unwrap().children().contains(&root_id)); 152 + /// assert!(!tree.get(&child_id).unwrap().children().contains(&grandchild_id)); 153 + /// ``` 154 + /// 155 + ToRoot, 156 + 157 + /// 158 + /// Moves a `Node` in the `Tree` to a new parent, while leaving 159 + /// all children in their place. 160 + /// 161 + /// If the new parent (lets say `A'`) is a descendant of the `Node` being 162 + /// moved (`A`), then the direct child of `A` on the path from `A` to 163 + /// `A'` will be shifted upwards to take the place of its parent (`A`). 164 + /// All other children of `A` will be left alone, so they will travel 165 + /// with `A`. 166 + /// 167 + /// NOTE: During the shift-up part of the above scenario, the `Node` being 168 + /// shifted up will always be added as the last child of its new parent. 169 + /// ``` 170 + /// use sakura::*; 171 + /// use sakura::InsertBehavior::*; 172 + /// use sakura::MoveBehavior::*; 173 + /// 174 + /// let mut tree: Tree<i32> = Tree::new(); 175 + /// 176 + /// let root_id = tree.insert(Node::new(1), AsRoot).ok().unwrap(); 177 + /// let first_child_id = tree.insert(Node::new(2), UnderNode(&root_id)).unwrap(); 178 + /// let second_child_id = tree.insert(Node::new(3), UnderNode(&root_id)).unwrap(); 179 + /// let grandchild_id = tree.insert(Node::new(4), UnderNode(&first_child_id)).unwrap(); 180 + /// 181 + /// tree.move_node(&grandchild_id, ToParent(&second_child_id)).unwrap(); 182 + /// 183 + /// assert!(!tree.get(&first_child_id).unwrap().children().contains(&grandchild_id)); 184 + /// assert!(tree.get(&second_child_id).unwrap().children().contains(&grandchild_id)); 185 + /// ``` 186 + /// 187 + ToParent(&'a NodeId), 188 + }
+27
crates/sakura/src/error.rs
··· 1 + use std::{error::Error, fmt::Display}; 2 + 3 + /// Enum for all possible `NodeId` errors that could happen. 4 + #[derive(Debug, PartialEq, Eq)] 5 + pub enum NodeIdError { 6 + /// Occurs when a `NodeId` is used on a `Tree` after the corresponding 7 + /// `Node` has been removed. 8 + NodeIdNoLongerValid, 9 + } 10 + 11 + impl NodeIdError { 12 + const fn to_string(&self) -> &str { 13 + match *self { 14 + Self::NodeIdNoLongerValid => { 15 + "The given NodeId is no longer valid. The Node in question has been removed." 16 + } 17 + } 18 + } 19 + } 20 + 21 + impl Display for NodeIdError { 22 + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 23 + write!(f, "NodeIdError: {}", self.to_string()) 24 + } 25 + } 26 + 27 + impl Error for NodeIdError {}
+261
crates/sakura/src/iterators.rs
··· 1 + use std::{collections::VecDeque, slice::Iter}; 2 + 3 + use crate::{Node, NodeId, Tree}; 4 + 5 + /// An `Iterator` over the children of a `Node`. 6 + /// 7 + /// Iterates over the child `Node`s of a given `Node` in the `Tree`. 8 + /// Each call to `next` will return an immutable 9 + /// reference to the next child `Node`. 10 + pub struct Children<'a, T: 'a> { 11 + tree: &'a Tree<T>, 12 + child_ids: Iter<'a, NodeId>, 13 + } 14 + 15 + impl<'a, T> Children<'a, T> { 16 + // we actually want to 17 + #[allow(clippy::use_self)] 18 + pub(crate) fn new(tree: &'a Tree<T>, node_id: &NodeId) -> Children<'a, T> { 19 + Children { 20 + tree, 21 + child_ids: tree 22 + .get(node_id) 23 + .expect( 24 + "Function is crate specific, expecting to only be used 25 + with a valid node_id", 26 + ) 27 + .children() 28 + .as_slice() 29 + .iter(), 30 + } 31 + } 32 + } 33 + 34 + impl<'a, T> Iterator for Children<'a, T> { 35 + type Item = &'a Node<T>; 36 + 37 + fn next(&mut self) -> Option<Self::Item> { 38 + self.child_ids 39 + .next() 40 + .and_then(|child_id| self.tree.get(child_id).ok()) 41 + } 42 + } 43 + 44 + impl<T> Clone for Children<'_, T> { 45 + fn clone(&self) -> Self { 46 + Children { 47 + tree: self.tree, 48 + child_ids: self.child_ids.clone(), 49 + } 50 + } 51 + } 52 + 53 + /// An `Iterator` over the children of a `Node`. 54 + /// 55 + /// Iterates over the child `NodeId`s of a given `NodeId` in the `Tree`. 56 + /// Each call to `next` will return an immutable 57 + /// reference to the next child `NodeId`. 58 + pub struct ChildrenIds<'a> { 59 + child_ids: Iter<'a, NodeId>, 60 + } 61 + 62 + impl<'a> ChildrenIds<'a> { 63 + #[allow(clippy::use_self)] 64 + pub(crate) fn new<T>(tree: &'a Tree<T>, node_id: &NodeId) -> ChildrenIds<'a> { 65 + ChildrenIds { 66 + child_ids: tree 67 + .get(node_id) 68 + .expect( 69 + "Function is crate specific, expecting to only be used 70 + with a valid node_id", 71 + ) 72 + .children() 73 + .as_slice() 74 + .iter(), 75 + } 76 + } 77 + } 78 + 79 + impl<'a> Iterator for ChildrenIds<'a> { 80 + type Item = &'a NodeId; 81 + 82 + fn next(&mut self) -> Option<Self::Item> { 83 + self.child_ids.next() 84 + } 85 + } 86 + 87 + /// An `Iterator` over the ancestors of a `Node`. 88 + /// 89 + /// Iterates over the ancestor `Node`s of given `Node` in the `Tree`. 90 + /// Each call to `next` will return an immutable reference to the next 91 + /// `Node` up the `Tree`. 92 + pub struct Ancestors<'a, T: 'a> { 93 + tree: &'a Tree<T>, 94 + node_id: Option<NodeId>, 95 + } 96 + 97 + impl<'a, T> Ancestors<'a, T> { 98 + #[allow(clippy::use_self)] 99 + pub(crate) const fn new(tree: &'a Tree<T>, node_id: NodeId) -> Ancestors<'a, T> { 100 + Ancestors { 101 + tree, 102 + node_id: Some(node_id), 103 + } 104 + } 105 + } 106 + 107 + impl<'a, T> Iterator for Ancestors<'a, T> { 108 + type Item = &'a Node<T>; 109 + 110 + fn next(&mut self) -> Option<&'a Node<T>> { 111 + self.node_id 112 + .take() 113 + .and_then(|current_id| self.tree.get(&current_id).ok()) 114 + .and_then(|node_ref| node_ref.parent()) 115 + .and_then(|parent_id| { 116 + self.node_id = Some(parent_id.clone()); 117 + self.tree.get(parent_id).ok() 118 + }) 119 + } 120 + } 121 + 122 + impl<T> Clone for Ancestors<'_, T> { 123 + fn clone(&self) -> Self { 124 + Ancestors { 125 + tree: self.tree, 126 + node_id: self.node_id.clone(), 127 + } 128 + } 129 + } 130 + 131 + /// An `Iterator` over the ancestors of a `Node`. 132 + /// 133 + /// Iterates over `NodeId`s instead of over `Node`s themselves. 134 + pub struct AncestorsIds<'a, T: 'a> { 135 + tree: &'a Tree<T>, 136 + node_id: Option<NodeId>, 137 + } 138 + 139 + impl<'a, T> AncestorsIds<'a, T> { 140 + #[allow(clippy::use_self)] 141 + pub(crate) const fn new(tree: &'a Tree<T>, node_id: NodeId) -> AncestorsIds<'a, T> { 142 + AncestorsIds { 143 + tree, 144 + node_id: Some(node_id), 145 + } 146 + } 147 + } 148 + 149 + impl<'a, T> Iterator for AncestorsIds<'a, T> { 150 + type Item = &'a NodeId; 151 + 152 + fn next(&mut self) -> Option<&'a NodeId> { 153 + self.node_id 154 + .take() 155 + .and_then(|current_id| self.tree.get(&current_id).ok()) 156 + .and_then(|node_ref| node_ref.parent()) 157 + .inspect(|parent_id| { 158 + self.node_id = Some((*parent_id).clone()); 159 + }) 160 + } 161 + } 162 + 163 + impl<T> Clone for AncestorsIds<'_, T> { 164 + fn clone(&self) -> Self { 165 + AncestorsIds { 166 + tree: self.tree, 167 + node_id: self.node_id.clone(), 168 + } 169 + } 170 + } 171 + 172 + /// An iterator over the subtree relative to a given `Node`. 173 + /// 174 + /// Each call to `next` will return an immutable reference to the 175 + /// next `Node` in Pre-Order Traversal order. 176 + pub struct PreOrderTraversal<'a, T: 'a> { 177 + tree: &'a Tree<T>, 178 + data: VecDeque<NodeId>, 179 + } 180 + 181 + impl<'a, T> PreOrderTraversal<'a, T> { 182 + #[allow(clippy::use_self)] 183 + pub(crate) fn new(tree: &'a Tree<T>, node_id: NodeId) -> PreOrderTraversal<'a, T> { 184 + let mut data = VecDeque::with_capacity(tree.capacity()); 185 + data.push_front(node_id); 186 + 187 + PreOrderTraversal { tree, data } 188 + } 189 + } 190 + 191 + impl<'a, T> Iterator for PreOrderTraversal<'a, T> { 192 + type Item = &'a Node<T>; 193 + 194 + fn next(&mut self) -> Option<Self::Item> { 195 + self.data 196 + .pop_front() 197 + .and_then(|node_id| self.tree.get(&node_id).ok()) 198 + .inspect(|node_ref| { 199 + for child_id in node_ref.children().iter().rev() { 200 + self.data.push_front(child_id.clone()); 201 + } 202 + }) 203 + } 204 + } 205 + 206 + impl<T> Clone for PreOrderTraversal<'_, T> { 207 + fn clone(&self) -> Self { 208 + PreOrderTraversal { 209 + tree: self.tree, 210 + data: self.data.clone(), 211 + } 212 + } 213 + } 214 + 215 + /// An Iterator over the subtree relative to a given `Node`. 216 + /// 217 + /// Each call to `next` will return an immutable reference to the 218 + /// next `NodeId` in Pre-Order Traversal order. 219 + /// 220 + pub struct PreOrderTraversalIds<'a, T: 'a> { 221 + tree: &'a Tree<T>, 222 + data: VecDeque<NodeId>, 223 + } 224 + 225 + impl<'a, T> PreOrderTraversalIds<'a, T> { 226 + #[allow(clippy::use_self)] 227 + pub(crate) fn new(tree: &'a Tree<T>, node_id: NodeId) -> PreOrderTraversalIds<'a, T> { 228 + // Over allocating, but all at once instead of resizing and reallocating as we go. 229 + let mut data = VecDeque::with_capacity(tree.capacity()); 230 + 231 + data.push_front(node_id); 232 + 233 + PreOrderTraversalIds { tree, data } 234 + } 235 + } 236 + 237 + impl<T> Iterator for PreOrderTraversalIds<'_, T> { 238 + type Item = NodeId; 239 + 240 + fn next(&mut self) -> Option<NodeId> { 241 + self.data.pop_front().and_then(|node_id| { 242 + self.tree.get(&node_id).ok().map(|node_ref| { 243 + // prepend child_ids 244 + for child_id in node_ref.children().iter().rev() { 245 + self.data.push_front(child_id.clone()); 246 + } 247 + 248 + node_id 249 + }) 250 + }) 251 + } 252 + } 253 + 254 + impl<T> Clone for PreOrderTraversalIds<'_, T> { 255 + fn clone(&self) -> Self { 256 + PreOrderTraversalIds { 257 + tree: self.tree, 258 + data: self.data.clone(), 259 + } 260 + } 261 + }
+50
crates/sakura/src/lib.rs
··· 1 + #![forbid(unsafe_code)] 2 + //! A purpose-built library for CASE, to hold the internal tree-like 3 + //! data structure that holds tasks and groups. Additionally, this 4 + //! data structure is compatible with `AutoMerge`, via `AutoSurgeon` 5 + //! 6 + //! TODO: add example usage 7 + 8 + use autosurgeon::{Hydrate, Reconcile}; 9 + use serde::{Deserialize, Serialize}; 10 + 11 + mod behaviors; 12 + mod error; 13 + mod iterators; 14 + mod node; 15 + mod tree; 16 + 17 + pub use node::Node; 18 + 19 + pub use tree::Tree; 20 + pub use tree::TreeBuilder; 21 + 22 + pub use behaviors::InsertBehavior; 23 + pub use behaviors::MoveBehavior; 24 + pub use behaviors::RemoveBehavior; 25 + 26 + pub use iterators::Ancestors; 27 + pub use iterators::Children; 28 + pub use iterators::ChildrenIds; 29 + pub use iterators::PreOrderTraversal; 30 + pub use iterators::PreOrderTraversalIds; 31 + 32 + pub use error::NodeIdError; 33 + 34 + /// A Node Id 35 + #[derive( 36 + Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Reconcile, Hydrate, 37 + )] 38 + pub struct NodeId { 39 + index: u32, 40 + } 41 + 42 + impl NodeId { 43 + // This is okay since we are practically never reaching 2^32. 44 + #[allow(clippy::cast_possible_truncation)] 45 + pub(crate) const fn new(index: usize) -> Self { 46 + Self { 47 + index: index as u32, 48 + } 49 + } 50 + }
+204
crates/sakura/src/node.rs
··· 1 + use autosurgeon::{Hydrate, Reconcile}; 2 + use serde::{Deserialize, Serialize}; 3 + 4 + use crate::NodeId; 5 + 6 + #[derive(Debug, Serialize, Deserialize, Reconcile, Hydrate, Ord, Eq, PartialOrd)] 7 + pub struct Node<T> { 8 + pub(crate) data: T, 9 + pub(crate) parent: Option<NodeId>, 10 + pub(crate) children: Vec<NodeId>, 11 + } 12 + 13 + impl<T> PartialEq for Node<T> 14 + where 15 + T: PartialEq, 16 + { 17 + // We only care if node data is equivalent. 18 + fn eq(&self, other: &Self) -> bool { 19 + self.data == other.data 20 + } 21 + } 22 + 23 + impl<T> Node<T> { 24 + /// Creates a new `Node` with the provided data 25 + /// 26 + /// ``` 27 + /// use sakura::Node; 28 + /// 29 + /// let _one: Node<i32> = Node::new(1); 30 + /// ``` 31 + /// 32 + #[allow(clippy::use_self)] 33 + pub const fn new(data: T) -> Node<T> { 34 + Self { 35 + parent: None, 36 + data, 37 + children: vec![], 38 + } 39 + } 40 + 41 + /// Returns a reference to the data inside the `Node` 42 + /// 43 + /// ``` 44 + /// use sakura::Node; 45 + /// 46 + /// let x = 10; 47 + /// let node: Node<i32> = Node::new(x); 48 + /// # assert_eq!(node.data(), &10); 49 + /// ``` 50 + pub const fn data(&self) -> &T { 51 + &self.data 52 + } 53 + 54 + /// Returns a mutable reference to the data inside the `Node` 55 + /// 56 + /// ``` 57 + /// use sakura::Node; 58 + /// 59 + /// let x = 10; 60 + /// let mut node: Node<i32> = Node::new(x); 61 + /// # assert_eq!(node.data_mut(), &mut 10); 62 + /// ``` 63 + pub const fn data_mut(&mut self) -> &mut T { 64 + &mut self.data 65 + } 66 + 67 + /// Replaces this `Node`s data with the provided data 68 + /// 69 + /// Returns the data previously in the node 70 + /// 71 + /// ``` 72 + /// use sakura::Node; 73 + /// 74 + /// let x = 10; 75 + /// let mut y = 15; 76 + /// 77 + /// let mut node_x: Node<i32> = Node::new(x); 78 + /// let replaced_x = node_x.replace_data(y); 79 + /// let new_x = node_x.data(); 80 + /// 81 + /// # assert_eq!(*new_x, y); 82 + /// # assert_eq!(replaced_x, x); 83 + /// ``` 84 + pub const fn replace_data(&mut self, mut data: T) -> T { 85 + ::std::mem::swap(&mut data, self.data_mut()); 86 + data 87 + } 88 + 89 + /// Returns the parent of this `Node`, if it has one. 90 + /// 91 + /// ``` 92 + /// use sakura::Node; 93 + /// 94 + /// let node: Node<i32> = Node::new(1); 95 + /// # assert_eq!(node.parent(), None); 96 + /// ``` 97 + pub const fn parent(&self) -> Option<&NodeId> { 98 + self.parent.as_ref() 99 + } 100 + 101 + /// Returns the children of this `Node` 102 + /// 103 + /// ``` 104 + /// use sakura::Node; 105 + /// 106 + /// let node: Node<i32> = Node::new(0); 107 + /// # assert_eq!(node.children().len(), 0); 108 + /// ``` 109 + pub const fn children(&self) -> &Vec<NodeId> { 110 + &self.children 111 + } 112 + 113 + pub(crate) const fn children_mut(&mut self) -> &mut Vec<NodeId> { 114 + &mut self.children 115 + } 116 + 117 + pub(crate) const fn set_parent(&mut self, parent: Option<NodeId>) { 118 + self.parent = parent; 119 + } 120 + 121 + pub(crate) fn add_child(&mut self, child: NodeId) { 122 + self.children.push(child); 123 + } 124 + 125 + pub(crate) fn set_children(&mut self, children: Vec<NodeId>) { 126 + self.children = children; 127 + } 128 + 129 + pub(crate) fn take_children(&mut self) -> Vec<NodeId> { 130 + use std::mem; 131 + 132 + let mut empty = Vec::with_capacity(0); 133 + mem::swap(&mut self.children, &mut empty); 134 + // post-swap this holds children 135 + empty 136 + } 137 + } 138 + 139 + #[cfg(test)] 140 + mod node_tests { 141 + 142 + use super::super::NodeId; 143 + use super::Node; 144 + 145 + #[test] 146 + fn test_new() { 147 + let node = Node::new(10); 148 + assert_eq!(node.children.capacity(), 0); 149 + } 150 + 151 + #[test] 152 + fn test_data() { 153 + let data = 0; 154 + let node = Node::new(data); 155 + 156 + assert_eq!(node.data(), &data); 157 + } 158 + 159 + #[test] 160 + fn test_data_mut() { 161 + let mut data = 0; 162 + let mut node = Node::new(data); 163 + 164 + assert_eq!(node.data_mut(), &mut data); 165 + } 166 + 167 + #[test] 168 + fn test_parent() { 169 + let mut node = Node::new(0); 170 + 171 + assert!(node.parent().is_none()); 172 + 173 + let parent_id: NodeId = NodeId { index: 100 }; 174 + 175 + node.set_parent(Some(parent_id.clone())); 176 + 177 + assert_eq!(node.parent, Some(parent_id)); 178 + } 179 + 180 + #[test] 181 + fn test_children() { 182 + let mut node = Node::new(0); 183 + assert!(node.children.is_empty()); 184 + 185 + let child_id: NodeId = NodeId { index: 1 }; 186 + 187 + node.add_child(child_id.clone()); 188 + 189 + assert_eq!(node.children.len(), 1); 190 + assert_eq!(node.children.first().unwrap(), &child_id); 191 + } 192 + 193 + #[test] 194 + fn test_partial_eq() { 195 + let node1 = Node::new(32); 196 + let node2 = Node::new(32); 197 + let node3 = Node::new(64); 198 + 199 + assert_eq!(node1, node2); 200 + 201 + assert_ne!(node1, node3); 202 + assert_ne!(node2, node3); 203 + } 204 + }
+1732
crates/sakura/src/tree.rs
··· 1 + use std::cmp::Ordering; 2 + 3 + use autosurgeon::{Hydrate, Reconcile}; 4 + use serde::{Deserialize, Serialize}; 5 + 6 + use crate::{ 7 + Ancestors, Children, ChildrenIds, InsertBehavior, MoveBehavior, Node, NodeId, 8 + PreOrderTraversal, PreOrderTraversalIds, RemoveBehavior, error::NodeIdError, 9 + iterators::AncestorsIds, 10 + }; 11 + 12 + /// A `Tree` builder to assist with building a `Tree`, with more control. 13 + pub struct TreeBuilder<T> { 14 + root: Option<Node<T>>, 15 + node_capacity: usize, 16 + swap_capacity: usize, 17 + } 18 + 19 + impl<T> Default for TreeBuilder<T> { 20 + fn default() -> Self { 21 + Self::new() 22 + } 23 + } 24 + 25 + impl<T> TreeBuilder<T> { 26 + /// Creates a new `TreeBuilder` with default settings. 27 + /// 28 + /// ``` 29 + /// use sakura::TreeBuilder; 30 + /// 31 + /// let _tree_builder: TreeBuilder<i32> = TreeBuilder::new(); 32 + /// 33 + /// ``` 34 + #[allow(clippy::use_self)] 35 + #[must_use] 36 + pub const fn new() -> TreeBuilder<T> { 37 + TreeBuilder { 38 + root: None, 39 + node_capacity: 0, 40 + swap_capacity: 0, 41 + } 42 + } 43 + 44 + /// Sets the root `Node` for the resulting `Tree` from this `TreeBuilder`. 45 + /// 46 + /// ``` 47 + /// use sakura::TreeBuilder; 48 + /// use sakura::Node; 49 + /// 50 + /// let _tree_builder: TreeBuilder<i32> = TreeBuilder::new().with_root(Node::new(1)); 51 + /// ``` 52 + #[must_use] 53 + #[allow(clippy::use_self)] 54 + pub fn with_root(mut self, root: Node<T>) -> TreeBuilder<T> { 55 + self.root = Some(root); 56 + self 57 + } 58 + 59 + /// Sets the `node_capacity` for `TreeBuilder`. 60 + /// 61 + /// Since `Tree`'s own their `Node`'s, they must allocate 62 + /// storage for `Node`'s ahead of time, so that the 63 + /// space allocations don't happen as the `Node`'s are inserted. 64 + /// 65 + /// _Configure this variable if you know the **maximum** number of `Node`'s 66 + /// that your `Tree` will **contain** at **any given time**._ 67 + /// 68 + /// ``` 69 + /// use sakura::TreeBuilder; 70 + /// 71 + /// let _tree_builder: TreeBuilder<i32> = TreeBuilder::new().with_node_capacity(1); 72 + /// 73 + /// ``` 74 + #[must_use] 75 + #[allow(clippy::use_self)] 76 + pub const fn with_node_capacity(mut self, node_capacity: usize) -> TreeBuilder<T> { 77 + self.node_capacity = node_capacity; 78 + self 79 + } 80 + 81 + /// Sets the `swap_capacity` for `TreeBuilder`. 82 + /// 83 + /// `Tree`'s attempt to save time by reusing storage space 84 + /// when `Node`'s are removed (instead of shuffling `Node`'s around internally). 85 + /// To do this, the `Tree` must store information about the space left behind when a `Node` 86 + /// is removed. Using this setting allows the `Tree` to pre-allocate this storage 87 + /// space instead of doing so as `Node`'s are removed from the `Tree`. 88 + /// 89 + /// _Use of this setting is recommended if you know the **maximum "net number 90 + /// of removals"** that have occurred at **any given time**._ 91 + /// 92 + /// 93 + /// For example: 94 + /// --- 95 + /// In **Scenario 1**: 96 + /// 97 + /// * Add 3 `Node`s, Remove 2 `Node`s, Add 1 `Node`. 98 + /// 99 + /// The maximum amount of nodes that have been removed at any given time is **2**. 100 + /// 101 + /// But in **Scenario 2**: 102 + /// 103 + /// * Add 3 `Node`s, Remove 2 `Node`s, Add 1 `Node`, Remove 2 `Node`s. 104 + /// 105 + /// The maximum amount of nodes that have been removed at any given time is **3**. 106 + /// 107 + /// ``` 108 + /// use sakura::TreeBuilder; 109 + /// 110 + /// let _tree_builder: TreeBuilder<i32> = TreeBuilder::new().with_node_capacity(1); 111 + /// 112 + /// ``` 113 + #[must_use] 114 + #[allow(clippy::use_self)] 115 + pub const fn with_swap_capacity(mut self, swap_capacity: usize) -> TreeBuilder<T> { 116 + self.swap_capacity = swap_capacity; 117 + self 118 + } 119 + 120 + /// 121 + /// Build a `Tree` based upon the current settings in the `TreeBuilder`. 122 + /// 123 + /// ``` 124 + /// use sakura::TreeBuilder; 125 + /// use sakura::Tree; 126 + /// use sakura::Node; 127 + /// 128 + /// let _tree: Tree<i32> = TreeBuilder::new() 129 + /// .with_root(Node::new(5)) 130 + /// .with_node_capacity(3) 131 + /// .with_swap_capacity(2) 132 + /// .build(); 133 + /// ``` 134 + pub fn build(mut self) -> Tree<T> { 135 + let mut tree = Tree { 136 + root: None, 137 + nodes: Vec::with_capacity(self.node_capacity), 138 + free_ids: Vec::with_capacity(self.swap_capacity), 139 + }; 140 + 141 + if self.root.is_some() { 142 + let node_id = NodeId { index: 0 }; 143 + 144 + tree.nodes.push(self.root.take()); 145 + 146 + tree.root = Some(node_id); 147 + } 148 + 149 + tree 150 + } 151 + } 152 + 153 + /// A tree structure made up of `Node`'s. 154 + /// 155 + /// # Panics 156 + /// Any function that takes a `NodeId` can `panic`, but this should 157 + /// only happen with improper `NodeId` management within `Sakura`, and 158 + /// should have nothing to do with library user's code. 159 + #[derive(Debug, Serialize, Deserialize, Reconcile, Hydrate)] 160 + pub struct Tree<T> { 161 + root: Option<NodeId>, 162 + pub(crate) nodes: Vec<Option<Node<T>>>, 163 + free_ids: Vec<NodeId>, 164 + } 165 + 166 + impl<T> Default for Tree<T> { 167 + fn default() -> Self { 168 + Self::new() 169 + } 170 + } 171 + 172 + impl<T> PartialEq for Tree<T> 173 + where 174 + T: PartialEq, 175 + { 176 + fn eq(&self, other: &Self) -> bool { 177 + if self.nodes.iter().filter(|x| x.is_some()).count() 178 + != other.nodes.iter().filter(|x| x.is_some()).count() 179 + { 180 + return false; 181 + } 182 + 183 + for ((i, node1), (j, node2)) in self 184 + .nodes 185 + .iter() 186 + .enumerate() 187 + .filter_map(|(i, x)| (*x).as_ref().map(|x| (i, x))) 188 + .zip( 189 + other 190 + .nodes 191 + .iter() 192 + .enumerate() 193 + .filter_map(|(i, x)| (*x).as_ref().map(|x| (i, x))), 194 + ) 195 + { 196 + let parent1_node = node1.parent.as_ref().and_then(|x| self.get(x).ok()); 197 + let parent2_node = node2.parent.as_ref().and_then(|x| other.get(x).ok()); 198 + 199 + if i != j || node1 != node2 || parent1_node != parent2_node { 200 + return false; 201 + } 202 + } 203 + 204 + true 205 + } 206 + } 207 + 208 + impl<T> Tree<T> { 209 + /// Creates a new `Tree` with default settings (no root `Node` and no space pre-allocation) 210 + /// 211 + /// ``` 212 + /// use sakura::Tree; 213 + /// 214 + /// let _tree: Tree<i32> = Tree::new(); 215 + /// ``` 216 + #[must_use] 217 + #[allow(clippy::use_self)] 218 + pub fn new() -> Tree<T> { 219 + TreeBuilder::new().build() 220 + } 221 + 222 + /// 223 + /// Returns the number of elements the tree can hold without reallocating. 224 + /// 225 + #[must_use] 226 + pub const fn capacity(&self) -> usize { 227 + self.nodes.capacity() 228 + } 229 + 230 + /// Returns a `Some` value containing the `NodeId` of the root `Node` if 231 + /// it exists. Otherwise, a `None` is returned. 232 + /// 233 + /// ``` 234 + /// use sakura::*; 235 + /// use sakura::InsertBehavior::*; 236 + /// 237 + /// let mut tree: Tree<i32> = Tree::new(); 238 + /// let root_id = tree.insert(Node::new(5), AsRoot).unwrap(); 239 + /// 240 + /// # assert_eq!(&root_id, tree.root_node_id().unwrap()); 241 + /// ``` 242 + /// 243 + #[must_use] 244 + pub const fn root_node_id(&self) -> Option<&NodeId> { 245 + self.root.as_ref() 246 + } 247 + 248 + /// Returns the maximum height of the `Tree`. 249 + /// 250 + /// ``` 251 + /// use sakura::*; 252 + /// use sakura::InsertBehavior::*; 253 + /// 254 + /// let mut tree: Tree<i32> = Tree::new(); 255 + /// # assert_eq!(0, tree.height()); 256 + /// 257 + /// let root_id = tree.insert(Node::new(1), AsRoot).unwrap(); 258 + /// # assert_eq!(1, tree.height()); 259 + /// 260 + /// tree.insert(Node::new(2), UnderNode(&root_id)).unwrap(); 261 + /// # assert_eq!(2, tree.height()); 262 + /// ``` 263 + #[must_use] 264 + pub fn height(&self) -> usize { 265 + self.root 266 + .as_ref() 267 + .map_or_else(|| 0, |id| self.height_of_node(id)) 268 + } 269 + 270 + fn height_of_node(&self, node: &NodeId) -> usize { 271 + let mut h = 0; 272 + for n in self.children_ids(node).unwrap() { 273 + h = std::cmp::max(h, self.height_of_node(n)); 274 + } 275 + 276 + h + 1 277 + } 278 + 279 + /// Gets a reference `Node` from the `Tree` 280 + /// 281 + /// # Errors 282 + /// 283 + /// Can error if the given `NodeId` is not valid (i.e. it was removed from the `Tree`.) 284 + /// 285 + /// # Panics 286 + /// 287 + /// Can panic if the `NodeId` does not exist in the `Tree`, but this would 288 + /// be a bug in `Sakura` 289 + /// 290 + /// ``` 291 + /// use sakura::*; 292 + /// use sakura::InsertBehavior::*; 293 + /// 294 + /// let mut tree: Tree<i32> = Tree::new(); 295 + /// let root_id = tree.insert(Node::new(5), AsRoot).unwrap(); 296 + /// 297 + /// let root_node: &Node<i32> = tree.get(&root_id).unwrap(); 298 + /// 299 + /// # assert_eq!(root_node.data(), &5); 300 + /// ``` 301 + /// 302 + pub fn get(&self, node_id: &NodeId) -> Result<&Node<T>, NodeIdError> { 303 + // Returns if node id isn't valid. 304 + let () = self.is_valid_node_id(node_id)?; 305 + 306 + self.nodes 307 + .get(node_id.index as usize) 308 + .expect( 309 + "index must 310 + exist in tree", 311 + ) 312 + .as_ref() 313 + // Since we are given a node id, and that entry in the nodes 314 + // vec isn't an actual node, the node_id is no longer valid. 315 + .ok_or(NodeIdError::NodeIdNoLongerValid) 316 + } 317 + 318 + /// Gets a mutable reference to a `Node` from the `Tree` 319 + /// 320 + /// # Errors 321 + /// 322 + /// Can error if the given `NodeId` is not valid (i.e. it was removed from the `Tree`.) 323 + /// 324 + /// # Panics 325 + /// 326 + /// Can panic if the `NodeId` does not exist in the `Tree`, but this would 327 + /// be a bug in `Sakura` 328 + /// 329 + /// ``` 330 + /// use sakura::*; 331 + /// use sakura::InsertBehavior::*; 332 + /// 333 + /// let mut tree: Tree<i32> = Tree::new(); 334 + /// let root_id = tree.insert(Node::new(5), AsRoot).unwrap(); 335 + /// 336 + /// let root_node: &mut Node<i32> = tree.get_mut(&root_id).unwrap(); 337 + /// 338 + /// # assert_eq!(root_node.data(), &5); 339 + /// ``` 340 + /// 341 + pub fn get_mut(&mut self, node_id: &NodeId) -> Result<&mut Node<T>, NodeIdError> { 342 + // Returns if node id isn't valid. 343 + let () = self.is_valid_node_id(node_id)?; 344 + 345 + self.nodes 346 + .get_mut(node_id.index as usize) 347 + .expect( 348 + "index must 349 + exist in tree", 350 + ) 351 + .as_mut() 352 + // Since we are given a node id, and that entry in the nodes 353 + // vec isn't an actual node, the node_id is no longer valid. 354 + .ok_or(NodeIdError::NodeIdNoLongerValid) 355 + } 356 + 357 + /// Inserts a `Node` into the `Tree`, via the provided `InsertBehavior` 358 + /// 359 + /// # Errors 360 + /// 361 + /// Can error if the given `NodeId` is not valid (i.e. it was removed from the `Tree`.) 362 + /// 363 + /// # Panics 364 + /// 365 + /// Can panic if the `NodeId` does not exist in the `Tree`, but this would 366 + /// be a bug in `Sakura` 367 + /// 368 + /// ``` 369 + /// use sakura::*; 370 + /// use sakura::InsertBehavior::*; 371 + /// 372 + /// let root_node = Node::new(1); 373 + /// let child_node = Node::new(2); 374 + /// 375 + /// let mut tree: Tree<i32> = Tree::new(); 376 + /// let root_id = tree.insert(root_node, AsRoot).unwrap(); 377 + /// 378 + /// tree.insert(child_node, UnderNode(&root_id)).unwrap(); 379 + /// ``` 380 + #[allow(clippy::needless_pass_by_value)] 381 + pub fn insert( 382 + &mut self, 383 + node: Node<T>, 384 + behavior: InsertBehavior, 385 + ) -> Result<NodeId, NodeIdError> { 386 + match behavior { 387 + InsertBehavior::AsRoot => Ok(self.set_root(node)), 388 + InsertBehavior::UnderNode(parent_id) => { 389 + self.is_valid_node_id(parent_id)?; 390 + Ok(self.insert_with_parent(node, parent_id)) 391 + } 392 + } 393 + } 394 + 395 + /// Removes a `Node` from the `Tree`, via the provided `RemoveBehavior` 396 + /// 397 + /// # Errors 398 + /// 399 + /// Can error if the given `NodeId` is not valid (i.e. it was removed from the `Tree`.) 400 + /// 401 + /// # Panics 402 + /// 403 + /// Can panic if the `NodeId` does not exist in the `Tree`, but this would 404 + /// be a bug in `Sakura` 405 + /// 406 + /// 407 + /// ``` 408 + /// use sakura::*; 409 + /// use sakura::InsertBehavior::*; 410 + /// use sakura::RemoveBehavior::*; 411 + /// 412 + /// let mut tree: Tree<i32> = Tree::new(); 413 + /// let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); 414 + /// 415 + /// let child_id = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 416 + /// let grandchild_id = tree.insert(Node::new(2), UnderNode(&child_id)).unwrap(); 417 + /// 418 + /// let child = tree.remove_node(child_id, DropChildren).unwrap(); 419 + /// 420 + /// # assert!(tree.get(&grandchild_id).is_err()); 421 + /// # assert_eq!(tree.get(&root_id).unwrap().children().len(), 0); 422 + /// # assert_eq!(child.children().len(), 0); 423 + /// # assert_eq!(child.parent(), None); 424 + /// ``` 425 + #[allow(clippy::needless_pass_by_value)] 426 + pub fn remove_node( 427 + &mut self, 428 + node_id: NodeId, 429 + behavior: RemoveBehavior, 430 + ) -> Result<Node<T>, NodeIdError> { 431 + self.is_valid_node_id(&node_id)?; 432 + 433 + match behavior { 434 + RemoveBehavior::DropChildren => Ok(self.remove_node_drop_children(node_id)), 435 + RemoveBehavior::LiftChildren => Ok(self.remove_node_lift_children(node_id)), 436 + RemoveBehavior::OrphanChildren => Ok(self.remove_node_orphan_children(node_id)), 437 + } 438 + } 439 + 440 + /// Remove a `Node` from the `Tree`, while transferring all of its children 441 + /// to its parent. 442 + fn remove_node_lift_children(&mut self, node_id: NodeId) -> Node<T> { 443 + if let Some(parent_id) = self 444 + .get(&node_id) 445 + .expect("Tree::remove_node_lift_children: Expecting node_id to be valid.") 446 + .parent() 447 + .cloned() 448 + { 449 + for child_id in self 450 + .get(&node_id) 451 + .expect("Tree::remove_node_lift_children: Expecting node_id to be valid.") 452 + .children() 453 + .clone() 454 + { 455 + self.set_as_parent_and_child(&parent_id, &child_id); 456 + } 457 + } else { 458 + self.clear_parent_of_children(&node_id); 459 + } 460 + 461 + self.remove_node_internal(node_id) 462 + } 463 + 464 + /// Remove a `Node` from the `Tree` including all of its children recursively. 465 + fn remove_node_drop_children(&mut self, node_id: NodeId) -> Node<T> { 466 + let children = self 467 + .get_mut(&node_id) 468 + .expect("Tree::remove_node_drop_children: Expecting node_id to be valid.") 469 + .take_children(); 470 + 471 + for child in children { 472 + self.remove_node_drop_children(child); 473 + } 474 + self.remove_node_internal(node_id) 475 + } 476 + 477 + /// Remove a `node` from the `Tree` and leave all of its children in the `Tree` 478 + fn remove_node_orphan_children(&mut self, node_id: NodeId) -> Node<T> { 479 + self.clear_parent_of_children(&node_id); 480 + self.remove_node_internal(node_id) 481 + } 482 + 483 + /// Moves a `Node` in the `Tree`, via the provided `MoveBehavior` 484 + /// 485 + /// # Errors 486 + /// 487 + /// Can error if the given `NodeId` is not valid (i.e. it was removed from the `Tree`.) 488 + /// 489 + /// # Panics 490 + /// 491 + /// Can panic if the `NodeId` does not exist in the `Tree`, but this would 492 + /// be a bug in `Sakura` 493 + /// 494 + #[allow(clippy::needless_pass_by_value)] 495 + pub fn move_node( 496 + &mut self, 497 + node_id: &NodeId, 498 + behavior: MoveBehavior, 499 + ) -> Result<(), NodeIdError> { 500 + self.is_valid_node_id(node_id)?; 501 + 502 + match behavior { 503 + MoveBehavior::ToRoot => { 504 + self.move_node_to_root(node_id); 505 + Ok(()) 506 + } 507 + MoveBehavior::ToParent(parent_id) => { 508 + self.move_node_to_parent(node_id, parent_id); 509 + Ok(()) 510 + } 511 + } 512 + } 513 + 514 + fn move_node_to_parent(&mut self, node_id: &NodeId, parent_id: &NodeId) { 515 + if let Some(subtree_root_id) = self 516 + .find_subtree_root_between_ids(parent_id, node_id) 517 + .cloned() 518 + { 519 + // node_id is above parent_id, this is a move "down" the tree 520 + let root = self.root.clone(); 521 + 522 + if root.as_ref() == Some(node_id) { 523 + // We're moving the root down the tree. 524 + // Also we know the root exists. 525 + 526 + // Detach subtree_root from node. 527 + self.detach_from_parent(node_id, &subtree_root_id); 528 + 529 + // Set subtree_root as Tree root. 530 + self.clear_parent(&subtree_root_id); 531 + self.root = Some(subtree_root_id); 532 + } else { 533 + // We're moving some other node down the tree. 534 + 535 + if let Some(old_parent) = self 536 + .get(node_id) 537 + .expect("Tree::move_node_to_parent: Expecting valid node_id") 538 + .parent() 539 + .cloned() 540 + { 541 + // Detach from old parent. 542 + self.detach_from_parent(&old_parent, node_id); 543 + 544 + //Connect old parent and subtree root. 545 + self.set_as_parent_and_child(&old_parent, &subtree_root_id); 546 + } else { 547 + // Node is orphaned, need to set subtree_root's parent to None (same as node's). 548 + 549 + self.clear_parent(&subtree_root_id); 550 + } 551 + 552 + // Detach subtree_root from node. 553 + self.detach_from_parent(node_id, &subtree_root_id); 554 + } 555 + } else { 556 + // this is a move "across" or "up" the tree 557 + 558 + // detach from old parent 559 + 560 + if let Some(old_parent) = self 561 + .get(node_id) 562 + .expect("Tree::move_node_to_parent: Expecting valid node_id") 563 + .parent() 564 + .cloned() 565 + { 566 + self.detach_from_parent(&old_parent, node_id); 567 + } 568 + } 569 + self.set_as_parent_and_child(parent_id, node_id); 570 + } 571 + 572 + /// Sorts the children of a `Node`, in-place, using compare to compare 573 + /// the nodes 574 + /// 575 + /// This sort is stable and O(n log n) worst case but allocates 576 + /// approximately 2 * n where n is the length of children 577 + /// 578 + /// # Errors 579 + /// 580 + /// Can error if the given `NodeId` is not valid (i.e. it was removed from the `Tree`.) 581 + /// 582 + /// # Panics 583 + /// 584 + /// Can panic if the `NodeId` does not exist in the `Tree`, but this would 585 + /// be a bug in `Sakura` 586 + /// 587 + /// ``` 588 + /// use sakura::*; 589 + /// use sakura::InsertBehavior::*; 590 + /// 591 + /// let mut tree: Tree<i32> = Tree::new(); 592 + /// 593 + /// let root_id = tree.insert(Node::new(100), AsRoot).unwrap(); 594 + /// tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 595 + /// tree.insert(Node::new(2), UnderNode(&root_id)).unwrap(); 596 + /// tree.insert(Node::new(0), UnderNode(&root_id)).unwrap(); 597 + /// 598 + /// tree.sort_children_by(&root_id, |a, b| a.data().cmp(b.data())).unwrap(); 599 + /// 600 + /// # for (i, id) in tree.get(&root_id).unwrap().children().iter().enumerate() { 601 + /// # assert_eq!(*tree.get(&id).unwrap().data(), i as i32); 602 + /// # } 603 + /// ``` 604 + pub fn sort_children_by<F>( 605 + &mut self, 606 + node_id: &NodeId, 607 + mut compare: F, 608 + ) -> Result<(), NodeIdError> 609 + where 610 + F: FnMut(&Node<T>, &Node<T>) -> Ordering, 611 + { 612 + self.is_valid_node_id(node_id)?; 613 + 614 + let mut children = self 615 + .get_mut(node_id) 616 + .expect("Tree::sort_children_by: expecting to be passed in a valid node_id") 617 + .take_children(); 618 + 619 + children.sort_by(|a, b| { 620 + compare( 621 + self.get(a) 622 + .expect("Tree::sort_children_by: expecting to be passed in a valid node_id"), 623 + self.get(b) 624 + .expect("Tree::sort_children_by: expecting to be passed in a valid node_id"), 625 + ) 626 + }); 627 + 628 + self.get_mut(node_id) 629 + .expect("Tree::sort_children_by: expecting to be passed in a valid node_id") 630 + .set_children(children); 631 + 632 + Ok(()) 633 + } 634 + 635 + /// Sorts the children of a `Node`, in-place, using their data. 636 + /// 637 + /// This sort is stable and O(n log n) worst case but allocates 638 + /// approximately 2 * n where n is the length of children 639 + /// 640 + /// # Errors 641 + /// 642 + /// Can error if the given `NodeId` is not valid (i.e. it was removed from the `Tree`.) 643 + /// 644 + /// # Panics 645 + /// 646 + /// Can panic if the `NodeId` does not exist in the `Tree`, but this would 647 + /// be a bug in `Sakura` 648 + /// 649 + /// ``` 650 + /// use sakura::*; 651 + /// use sakura::InsertBehavior::*; 652 + /// 653 + /// let mut tree: Tree<i32> = Tree::new(); 654 + /// 655 + /// let root_id = tree.insert(Node::new(100), AsRoot).unwrap(); 656 + /// tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 657 + /// tree.insert(Node::new(2), UnderNode(&root_id)).unwrap(); 658 + /// tree.insert(Node::new(0), UnderNode(&root_id)).unwrap(); 659 + /// 660 + /// tree.sort_children_by_data(&root_id).unwrap(); 661 + /// 662 + /// # for (i, id) in tree.get(&root_id).unwrap().children().iter().enumerate() { 663 + /// # assert_eq!(*tree.get(&id).unwrap().data(), i as i32); 664 + /// # } 665 + /// ``` 666 + /// 667 + pub fn sort_children_by_data(&mut self, node_id: &NodeId) -> Result<(), NodeIdError> 668 + where 669 + T: Ord, 670 + { 671 + self.is_valid_node_id(node_id)?; 672 + 673 + let mut children = self 674 + .get_mut(node_id) 675 + .expect("Tree::sort_children_by: expecting to be passed in a valid node_id") 676 + .take_children(); 677 + 678 + children.sort_by_key(|a| { 679 + self.get(a) 680 + .expect("Tree::sort_children_by: expecting to be passed in a valid node_id") 681 + }); 682 + 683 + self.get_mut(node_id) 684 + .expect("Tree::sort_children_by: expecting to be passed in a valid node_id") 685 + .set_children(children); 686 + 687 + Ok(()) 688 + } 689 + 690 + /// Returns an `Ancestors` iterator 691 + /// 692 + /// # Errors 693 + /// 694 + /// Can error if the given `NodeId` is not valid (i.e. it was removed from the `Tree`.) 695 + /// 696 + /// # Panics 697 + /// 698 + /// Can panic if the `NodeId` does not exist in the `Tree`, but this would 699 + /// be a bug in `Sakura` 700 + /// 701 + /// ``` 702 + /// use sakura::*; 703 + /// use sakura::InsertBehavior::*; 704 + /// 705 + /// let mut tree: Tree<i32> = Tree::new(); 706 + /// let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); 707 + /// let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 708 + /// 709 + /// let mut ancestors = tree.ancestors(&node_1).unwrap(); 710 + /// 711 + /// # assert_eq!(ancestors.next().unwrap().data(), &0); 712 + /// # assert!(ancestors.next().is_none()); 713 + /// ``` 714 + pub fn ancestors(&self, node_id: &NodeId) -> Result<Ancestors<'_, T>, NodeIdError> { 715 + self.is_valid_node_id(node_id)?; 716 + Ok(Ancestors::new(self, node_id.clone())) 717 + } 718 + 719 + /// Returns an `AncestorIds` iterator 720 + /// 721 + /// 722 + /// # Errors 723 + /// 724 + /// Can error if the given `NodeId` is not valid (i.e. it was removed from the `Tree`.) 725 + /// 726 + /// # Panics 727 + /// 728 + /// Can panic if the `NodeId` does not exist in the `Tree`, but this would 729 + /// be a bug in `Sakura` 730 + /// 731 + /// 732 + /// ``` 733 + /// use sakura::*; 734 + /// use sakura::InsertBehavior::*; 735 + /// 736 + /// let mut tree: Tree<i32> = Tree::new(); 737 + /// let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); 738 + /// let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 739 + /// 740 + /// let mut ancestor_ids = tree.ancestor_ids(&node_1).unwrap(); 741 + /// 742 + /// # assert_eq!(ancestor_ids.next().unwrap(), &root_id); 743 + /// # assert!(ancestor_ids.next().is_none()); 744 + /// ``` 745 + /// 746 + pub fn ancestor_ids(&self, node_id: &NodeId) -> Result<AncestorsIds<'_, T>, NodeIdError> { 747 + self.is_valid_node_id(node_id)?; 748 + 749 + Ok(AncestorsIds::new(self, node_id.clone())) 750 + } 751 + 752 + /// Returns an `Children` iterator for a given `NodeId` 753 + /// 754 + /// # Errors 755 + /// 756 + /// Can error if the given `NodeId` is not valid (i.e. it was removed from the `Tree`.) 757 + /// 758 + /// # Panics 759 + /// 760 + /// Can panic if the `NodeId` does not exist in the `Tree`, but this would 761 + /// be a bug in `Sakura` 762 + /// 763 + /// ``` 764 + /// use sakura::*; 765 + /// use sakura::InsertBehavior::*; 766 + /// 767 + /// let mut tree: Tree<i32> = Tree::new(); 768 + /// let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); 769 + /// tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 770 + /// 771 + /// let mut children = tree.children(&root_id).unwrap(); 772 + /// 773 + /// # assert_eq!(children.next().unwrap().data(), &1); 774 + /// # assert!(children.next().is_none()); 775 + /// ``` 776 + pub fn children(&self, node_id: &NodeId) -> Result<Children<'_, T>, NodeIdError> { 777 + self.is_valid_node_id(node_id)?; 778 + Ok(Children::new(self, node_id)) 779 + } 780 + 781 + /// Returns an `Children` iterator for a given `NodeId` 782 + /// 783 + /// # Errors 784 + /// 785 + /// Can error if the given `NodeId` is not valid (i.e. it was removed from the `Tree`.) 786 + /// 787 + /// # Panics 788 + /// 789 + /// Can panic if the `NodeId` does not exist in the `Tree`, but this would 790 + /// be a bug in `Sakura` 791 + /// 792 + /// ``` 793 + /// use sakura::*; 794 + /// use sakura::InsertBehavior::*; 795 + /// 796 + /// let mut tree: Tree<i32> = Tree::new(); 797 + /// let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); 798 + /// let node_1 = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 799 + /// 800 + /// let mut children_ids = tree.children_ids(&root_id).unwrap(); 801 + /// 802 + /// # assert_eq!(children_ids.next().unwrap(), &node_1); 803 + /// # assert!(children_ids.next().is_none()); 804 + /// ``` 805 + pub fn children_ids(&self, node_id: &NodeId) -> Result<ChildrenIds<'_>, NodeIdError> { 806 + self.is_valid_node_id(node_id)?; 807 + Ok(ChildrenIds::new(self, node_id)) 808 + } 809 + 810 + /// Returns a `PreOrderTraversal` iterator 811 + /// 812 + /// # Errors 813 + /// 814 + /// Can error if the given `NodeId` is not valid (i.e. it was removed from the `Tree`.) 815 + /// 816 + /// # Panics 817 + /// 818 + /// Can panic if the `NodeId` does not exist in the `Tree`, but this would 819 + /// be a bug in `Sakura` 820 + /// 821 + /// ``` 822 + /// use sakura::*; 823 + /// use sakura::InsertBehavior::*; 824 + /// 825 + /// let mut tree: Tree<i32> = Tree::new(); 826 + /// let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); 827 + /// tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 828 + /// 829 + /// let mut nodes = tree.traverse_pre_order(&root_id).unwrap(); 830 + /// 831 + /// # assert_eq!(nodes.next().unwrap().data(), &0); 832 + /// # assert_eq!(nodes.next().unwrap().data(), &1); 833 + /// # assert!(nodes.next().is_none()); 834 + /// ``` 835 + /// 836 + pub fn traverse_pre_order( 837 + &self, 838 + node_id: &NodeId, 839 + ) -> Result<PreOrderTraversal<'_, T>, NodeIdError> { 840 + self.is_valid_node_id(node_id)?; 841 + 842 + Ok(PreOrderTraversal::new(self, node_id.clone())) 843 + } 844 + 845 + /// Returns a `PreOrderTraversalIds` iterator 846 + /// 847 + /// # Errors 848 + /// 849 + /// Can error if the given `NodeId` is not valid (i.e. it was removed from the `Tree`.) 850 + /// 851 + /// # Panics 852 + /// 853 + /// Can panic if the `NodeId` does not exist in the `Tree`, but this would 854 + /// be a bug in `Sakura` 855 + /// 856 + /// ``` 857 + /// use sakura::*; 858 + /// use sakura::InsertBehavior::*; 859 + /// 860 + /// let mut tree: Tree<i32> = Tree::new(); 861 + /// let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); 862 + /// tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 863 + /// 864 + /// let mut nodes = tree.traverse_pre_order_ids(&root_id).unwrap(); 865 + /// 866 + /// assert_eq!(tree.get(&nodes.next().unwrap()).unwrap().data(), &0); 867 + /// assert_eq!(tree.get(&nodes.next().unwrap()).unwrap().data(), &1); 868 + /// assert!(nodes.next().is_none()); 869 + /// ``` 870 + /// 871 + pub fn traverse_pre_order_ids( 872 + &self, 873 + node_id: &NodeId, 874 + ) -> Result<PreOrderTraversalIds<'_, T>, NodeIdError> { 875 + self.is_valid_node_id(node_id)?; 876 + 877 + Ok(PreOrderTraversalIds::new(self, node_id.clone())) 878 + } 879 + 880 + fn move_node_to_root(&mut self, node_id: &NodeId) { 881 + let old_root = self.root.clone(); 882 + 883 + if let Some(parent_id) = self 884 + .get(node_id) 885 + .expect("Tree::move_node_to_root Expected a valid NodeId") 886 + .parent 887 + .clone() 888 + { 889 + self.detach_from_parent(&parent_id, node_id); 890 + } 891 + 892 + self.clear_parent(node_id); 893 + 894 + self.root = Some(node_id.clone()); 895 + 896 + if let Some(old_root) = old_root { 897 + self.move_node_to_parent(&old_root, node_id); 898 + } 899 + } 900 + 901 + fn insert_with_parent(&mut self, child: Node<T>, parent_id: &NodeId) -> NodeId { 902 + let new_child_id = self.insert_new_node(child); 903 + self.set_as_parent_and_child(parent_id, &new_child_id); 904 + new_child_id 905 + } 906 + 907 + fn set_root(&mut self, new_root: Node<T>) -> NodeId { 908 + let new_root_id = self.insert_new_node(new_root); 909 + 910 + if let Some(current_root_node_id) = self.root.clone() { 911 + self.set_as_parent_and_child(&new_root_id, &current_root_node_id); 912 + } 913 + 914 + self.root = Some(new_root_id.clone()); 915 + 916 + new_root_id 917 + } 918 + 919 + fn find_subtree_root_between_ids<'a>( 920 + &'a self, 921 + lower_id: &'a NodeId, 922 + upper_id: &'a NodeId, 923 + ) -> Option<&'a NodeId> { 924 + if let Some(lower_parent) = self.get(lower_id).unwrap().parent() { 925 + if lower_parent == upper_id { 926 + return Some(lower_id); 927 + } 928 + return self.find_subtree_root_between_ids(lower_parent, upper_id); 929 + } 930 + 931 + None 932 + } 933 + 934 + fn set_as_parent_and_child(&mut self, parent_id: &NodeId, child_id: &NodeId) { 935 + self.get_mut(parent_id) 936 + .expect("Tree::set_as_parent_and_child: parent_id should be inside the Tree.") 937 + .add_child(child_id.clone()); 938 + 939 + self.get_mut(child_id) 940 + .expect("Tree::set_as_parent_and_child: child_id should be inside the Tree.") 941 + .set_parent(Some(parent_id.clone())); 942 + } 943 + 944 + fn detach_from_parent(&mut self, parent_id: &NodeId, node_id: &NodeId) { 945 + self.get_mut(parent_id) 946 + .expect("Tree::detach_from_parent: parent_id must be present in tree") 947 + .children_mut() 948 + .retain(|child_id| *child_id != *node_id); 949 + } 950 + 951 + fn insert_new_node(&mut self, new_node: Node<T>) -> NodeId { 952 + if self.free_ids.is_empty() { 953 + let new_node_idx = self.nodes.len(); 954 + self.nodes.push(Some(new_node)); 955 + NodeId::new(new_node_idx) 956 + } else { 957 + let new_node_id = self 958 + .free_ids 959 + .pop() 960 + .expect("Tree::insert_new_node: Couldn't pop from vec with len() > 0."); 961 + 962 + self.nodes.push(Some(new_node)); 963 + self.nodes.swap_remove(new_node_id.index as usize); 964 + new_node_id 965 + } 966 + } 967 + 968 + fn is_valid_node_id(&self, node_id: &NodeId) -> Result<(), NodeIdError> { 969 + let idx = node_id.index as usize; 970 + 971 + assert!( 972 + idx <= self.nodes.len(), 973 + "NodeId: {node_id:?} is out of bounds. This is a bug inside 974 + Sakura.", 975 + ); 976 + 977 + if self.nodes.get(idx).is_none() { 978 + return Err(NodeIdError::NodeIdNoLongerValid); 979 + } 980 + 981 + Ok(()) 982 + } 983 + 984 + // We want to have the node_id be consumed by this remove function. 985 + #[allow(clippy::needless_pass_by_value)] 986 + fn remove_node_internal(&mut self, node_id: NodeId) -> Node<T> { 987 + if let Some(root_id) = &self.root 988 + && node_id == *root_id 989 + { 990 + self.root = None; 991 + } 992 + 993 + let mut node = self.take_node(node_id.clone()); 994 + 995 + if let Some(parent_id) = node.parent() { 996 + self.get_mut(parent_id) 997 + .expect( 998 + "Tree::remove_node_internal: expecting 999 + parent_id to be a valid node_id!", 1000 + ) 1001 + .children_mut() 1002 + .retain(|child_id| *child_id != node_id); 1003 + } 1004 + 1005 + node.children_mut().clear(); 1006 + node.set_parent(None); 1007 + 1008 + node 1009 + } 1010 + 1011 + fn take_node(&mut self, node_id: NodeId) -> Node<T> { 1012 + self.nodes.push(None); 1013 + 1014 + let node = self 1015 + .nodes 1016 + .swap_remove(node_id.index as usize) 1017 + .expect("Tree::take_node: expecting node_id to be a valid node_id!"); 1018 + 1019 + self.free_ids.push(node_id); 1020 + 1021 + node 1022 + } 1023 + 1024 + fn clear_parent(&mut self, node_id: &NodeId) { 1025 + self.set_parent(node_id, None); 1026 + } 1027 + 1028 + fn set_parent(&mut self, node_id: &NodeId, parent_id: Option<NodeId>) { 1029 + self.get_mut(node_id) 1030 + .expect( 1031 + "Tree::set_parent: expecting node_id to 1032 + be present inside tree!", 1033 + ) 1034 + .set_parent(parent_id); 1035 + } 1036 + 1037 + fn clear_parent_of_children(&mut self, node_id: &NodeId) { 1038 + self.set_parent_of_children(node_id, None); 1039 + } 1040 + 1041 + fn set_parent_of_children(&mut self, node_id: &NodeId, new_parent: Option<&NodeId>) { 1042 + for child_id in self 1043 + .get(node_id) 1044 + .expect("Tree::set_parent_of_child: expect node_id to be a valid node inside tree.") 1045 + .children 1046 + .clone() 1047 + { 1048 + self.set_parent(&child_id, new_parent.cloned()); 1049 + } 1050 + } 1051 + } 1052 + 1053 + impl<T: std::fmt::Debug> Tree<T> { 1054 + /// Write formatted tree representation and nodes with debug formatting. 1055 + /// 1056 + /// 1057 + /// # Errors 1058 + /// 1059 + /// Function can error if something goes wrong during debug! 1060 + /// 1061 + /// # Panics 1062 + /// 1063 + /// Function can error if something goes wrong during debug! 1064 + /// 1065 + /// ``` 1066 + /// use sakura::Tree; 1067 + /// use sakura::Node; 1068 + /// use sakura::InsertBehavior::*; 1069 + /// 1070 + /// let mut tree = Tree::<i32>::new(); 1071 + /// let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); 1072 + /// let first_child_id = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 1073 + /// let _ = tree.insert(Node::new(2), UnderNode(&first_child_id)).unwrap(); 1074 + /// let _ = tree.insert(Node::new(3), UnderNode(&root_id)).unwrap(); 1075 + /// let mut s = String::new(); 1076 + /// tree.write_formatted(&mut s).unwrap(); 1077 + /// assert_eq!(&s, "\ 1078 + /// 0 1079 + /// ├── 1 1080 + /// │ └── 2 1081 + /// └── 3 1082 + /// "); 1083 + /// ``` 1084 + /// 1085 + /// Writes nothing if the tree is empty. 1086 + /// 1087 + /// ``` 1088 + /// use sakura::Tree; 1089 + /// 1090 + /// let tree = Tree::<i32>::new(); 1091 + /// let mut s = String::new(); 1092 + /// tree.write_formatted(&mut s).unwrap(); 1093 + /// # assert_eq!(&s, ""); 1094 + /// ``` 1095 + pub fn write_formatted<W: std::fmt::Write>(&self, w: &mut W) -> std::fmt::Result { 1096 + if let Some(node_id) = self.root_node_id() { 1097 + let childn = 0; 1098 + let level = 0; 1099 + let last = vec![]; 1100 + let mut stack = vec![(node_id, childn, level, last)]; 1101 + while let Some((node_id, childn, level, last)) = stack.pop() { 1102 + debug_assert_eq!( 1103 + last.len(), 1104 + level, 1105 + "each previous level should indicate whether it has reached the last node" 1106 + ); 1107 + let node = self 1108 + .get(node_id) 1109 + .expect("getting node of existing node ref id"); 1110 + if childn == 0 { 1111 + for i in 1..level { 1112 + if last[i - 1] { 1113 + write!(w, " ")?; 1114 + } else { 1115 + write!(w, "│ ")?; 1116 + } 1117 + } 1118 + if level > 0 { 1119 + if last[level - 1] { 1120 + write!(w, "└── ")?; 1121 + } else { 1122 + write!(w, "├── ")?; 1123 + } 1124 + } 1125 + writeln!(w, "{:?}", node.data())?; 1126 + } 1127 + let mut children = node.children().iter().skip(childn); 1128 + if let Some(child_id) = children.next() { 1129 + let mut next_last = last.clone(); 1130 + if children.next().is_some() { 1131 + stack.push((node_id, childn + 1, level, last)); 1132 + next_last.push(false); 1133 + } else { 1134 + next_last.push(true); 1135 + } 1136 + stack.push((child_id, 0, level + 1, next_last)); 1137 + } 1138 + } 1139 + } 1140 + Ok(()) 1141 + } 1142 + } 1143 + 1144 + #[cfg(test)] 1145 + mod tree_builder_tests { 1146 + use super::super::Node; 1147 + use super::TreeBuilder; 1148 + 1149 + #[test] 1150 + fn test_new() { 1151 + let tb: TreeBuilder<i32> = TreeBuilder::new(); 1152 + assert!(tb.root.is_none()); 1153 + assert_eq!(tb.node_capacity, 0); 1154 + assert_eq!(tb.swap_capacity, 0); 1155 + } 1156 + 1157 + #[test] 1158 + fn test_with_root() { 1159 + let tb: TreeBuilder<i32> = TreeBuilder::new().with_root(Node::new(5)); 1160 + 1161 + assert_eq!(tb.root.unwrap().data(), &5); 1162 + assert_eq!(tb.node_capacity, 0); 1163 + assert_eq!(tb.swap_capacity, 0); 1164 + } 1165 + 1166 + #[test] 1167 + fn test_with_node_capacity() { 1168 + let tb: TreeBuilder<i32> = TreeBuilder::new().with_node_capacity(10); 1169 + 1170 + assert!(tb.root.is_none()); 1171 + assert_eq!(tb.node_capacity, 10); 1172 + assert_eq!(tb.swap_capacity, 0); 1173 + } 1174 + 1175 + #[test] 1176 + fn test_with_swap_capacity() { 1177 + let tb: TreeBuilder<i32> = TreeBuilder::new().with_swap_capacity(10); 1178 + 1179 + assert!(tb.root.is_none()); 1180 + assert_eq!(tb.node_capacity, 0); 1181 + assert_eq!(tb.swap_capacity, 10); 1182 + } 1183 + 1184 + #[test] 1185 + fn test_with_all_settings() { 1186 + let tb: TreeBuilder<i32> = TreeBuilder::new() 1187 + .with_root(Node::new(5)) 1188 + .with_node_capacity(10) 1189 + .with_swap_capacity(3); 1190 + 1191 + assert_eq!(tb.root.unwrap().data(), &5); 1192 + assert_eq!(tb.node_capacity, 10); 1193 + assert_eq!(tb.swap_capacity, 3); 1194 + } 1195 + 1196 + #[test] 1197 + fn test_build() { 1198 + let tree = TreeBuilder::new() 1199 + .with_root(Node::new(5)) 1200 + .with_node_capacity(10) 1201 + .with_swap_capacity(3) 1202 + .build(); 1203 + 1204 + let root = tree.get(tree.root_node_id().unwrap()).unwrap(); 1205 + 1206 + assert_eq!(root.data(), &5); 1207 + assert_eq!(tree.capacity(), 10); 1208 + assert_eq!(tree.free_ids.capacity(), 3); 1209 + } 1210 + } 1211 + 1212 + #[cfg(test)] 1213 + #[allow(clippy::similar_names)] 1214 + mod tree_tests { 1215 + use crate::InsertBehavior; 1216 + use crate::MoveBehavior; 1217 + use crate::RemoveBehavior; 1218 + 1219 + use super::super::Node; 1220 + use super::super::NodeId; 1221 + use super::Tree; 1222 + use super::TreeBuilder; 1223 + 1224 + #[test] 1225 + fn test_new() { 1226 + let tree: Tree<i32> = Tree::new(); 1227 + 1228 + assert_eq!(tree.root, None); 1229 + assert_eq!(tree.nodes.len(), 0); 1230 + assert_eq!(tree.free_ids.len(), 0); 1231 + } 1232 + 1233 + #[test] 1234 + fn test_get() { 1235 + let tree = TreeBuilder::new().with_root(Node::new(5)).build(); 1236 + 1237 + let root_id = tree.root.clone().unwrap(); 1238 + let root = tree.get(&root_id).unwrap(); 1239 + 1240 + assert_eq!(root.data(), &5); 1241 + } 1242 + 1243 + #[test] 1244 + fn test_get_mut() { 1245 + let mut tree = TreeBuilder::new().with_root(Node::new(5)).build(); 1246 + 1247 + let root_id = tree.root.clone().unwrap(); 1248 + 1249 + { 1250 + let root = tree.get(&root_id).unwrap(); 1251 + assert_eq!(root.data(), &5); 1252 + } 1253 + 1254 + { 1255 + let root = tree.get_mut(&root_id).unwrap(); 1256 + *root.data_mut() = 6; 1257 + } 1258 + 1259 + let root = tree.get(&root_id).unwrap(); 1260 + assert_eq!(root.data(), &6); 1261 + } 1262 + 1263 + #[test] 1264 + fn test_set_root() { 1265 + use InsertBehavior::*; 1266 + 1267 + let a = 5; 1268 + let b = 6; 1269 + let node_a = Node::new(a); 1270 + let node_b = Node::new(b); 1271 + 1272 + let mut tree = TreeBuilder::new().build(); 1273 + 1274 + let node_a_id = tree.insert(node_a, AsRoot).unwrap(); 1275 + let root_id = tree.root.clone().unwrap(); 1276 + assert_eq!(node_a_id, root_id); 1277 + 1278 + { 1279 + let node_a_ref = tree.get(&node_a_id).unwrap(); 1280 + let root_ref = tree.get(&root_id).unwrap(); 1281 + assert_eq!(node_a_ref.data(), &a); 1282 + assert_eq!(root_ref.data(), &a); 1283 + } 1284 + 1285 + let node_b_id = tree.insert(node_b, AsRoot).unwrap(); 1286 + let root_id = tree.root.clone().unwrap(); 1287 + assert_eq!(node_b_id, root_id); 1288 + 1289 + { 1290 + let node_b_ref = tree.get(&node_b_id).unwrap(); 1291 + let root_ref = tree.get(&root_id).unwrap(); 1292 + assert_eq!(node_b_ref.data(), &b); 1293 + assert_eq!(root_ref.data(), &b); 1294 + 1295 + let node_b_child_id = node_b_ref.children().first().unwrap(); 1296 + let node_b_child_ref = tree.get(node_b_child_id).unwrap(); 1297 + assert_eq!(node_b_child_ref.data(), &a); 1298 + } 1299 + } 1300 + 1301 + #[test] 1302 + fn test_root_node_id() { 1303 + let tree = TreeBuilder::new().with_root(Node::new(5)).build(); 1304 + 1305 + let root_id = tree.root.clone().unwrap(); 1306 + let root_node_id = tree.root_node_id().unwrap(); 1307 + 1308 + assert_eq!(&root_id, root_node_id); 1309 + } 1310 + 1311 + #[test] 1312 + fn test_insert_with_parent() { 1313 + use InsertBehavior::*; 1314 + 1315 + let a = 1; 1316 + let b = 2; 1317 + let r = 5; 1318 + 1319 + let mut tree = TreeBuilder::new().with_root(Node::new(r)).build(); 1320 + 1321 + let node_a = Node::new(a); 1322 + let node_b = Node::new(b); 1323 + 1324 + let root_id = tree.root.clone().unwrap(); 1325 + let node_a_id = tree.insert(node_a, UnderNode(&root_id)).unwrap(); 1326 + let node_b_id = tree.insert(node_b, UnderNode(&root_id)).unwrap(); 1327 + 1328 + let node_a_ref = tree.get(&node_a_id).unwrap(); 1329 + let node_b_ref = tree.get(&node_b_id).unwrap(); 1330 + assert_eq!(node_a_ref.data(), &a); 1331 + assert_eq!(node_b_ref.data(), &b); 1332 + 1333 + assert_eq!(node_a_ref.parent().unwrap().clone(), root_id); 1334 + assert_eq!(node_b_ref.parent().unwrap().clone(), root_id); 1335 + 1336 + let root_node_ref = tree.get(&root_id).unwrap(); 1337 + let root_children: &Vec<NodeId> = root_node_ref.children(); 1338 + 1339 + let child_1_id = root_children.first().unwrap(); 1340 + let child_2_id = root_children.get(1).unwrap(); 1341 + 1342 + let child_1_ref = tree.get(child_1_id).unwrap(); 1343 + let child_2_ref = tree.get(child_2_id).unwrap(); 1344 + 1345 + assert_eq!(child_1_ref.data(), &a); 1346 + assert_eq!(child_2_ref.data(), &b); 1347 + } 1348 + 1349 + #[test] 1350 + fn test_remove_node_lift_children() { 1351 + use InsertBehavior::*; 1352 + use RemoveBehavior::*; 1353 + 1354 + let mut tree = TreeBuilder::new().with_root(Node::new(5)).build(); 1355 + 1356 + let root_id = tree.root.clone().unwrap(); 1357 + 1358 + let node_1_id = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 1359 + let node_2_id = tree.insert(Node::new(2), UnderNode(&node_1_id)).unwrap(); 1360 + let node_3_id = tree.insert(Node::new(3), UnderNode(&node_1_id)).unwrap(); 1361 + 1362 + let node_1 = tree.remove_node(node_1_id.clone(), LiftChildren).unwrap(); 1363 + 1364 + assert_eq!(Some(&root_id), tree.root_node_id()); 1365 + 1366 + assert_eq!(node_1.data(), &1); 1367 + assert_eq!(node_1.children().len(), 0); 1368 + assert!(node_1.parent().is_none()); 1369 + assert!(tree.get(&node_1_id).is_err()); 1370 + 1371 + let root_ref = tree.get(&root_id).unwrap(); 1372 + let node_2_ref = tree.get(&node_2_id).unwrap(); 1373 + let node_3_ref = tree.get(&node_3_id).unwrap(); 1374 + 1375 + assert_eq!(node_2_ref.data(), &2); 1376 + assert_eq!(node_3_ref.data(), &3); 1377 + 1378 + assert_eq!(node_2_ref.parent().unwrap(), &root_id); 1379 + assert_eq!(node_3_ref.parent().unwrap(), &root_id); 1380 + 1381 + assert!(root_ref.children().contains(&node_2_id)); 1382 + assert!(root_ref.children().contains(&node_3_id)); 1383 + } 1384 + 1385 + #[test] 1386 + fn test_remove_node_orphan_children() { 1387 + use InsertBehavior::*; 1388 + use RemoveBehavior::*; 1389 + 1390 + let mut tree = TreeBuilder::new().with_root(Node::new(5)).build(); 1391 + 1392 + let root_id = tree.root.clone().unwrap(); 1393 + 1394 + let node_1_id = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 1395 + let node_2_id = tree.insert(Node::new(2), UnderNode(&node_1_id)).unwrap(); 1396 + let node_3_id = tree.insert(Node::new(3), UnderNode(&node_1_id)).unwrap(); 1397 + 1398 + let node_1 = tree.remove_node(node_1_id.clone(), OrphanChildren).unwrap(); 1399 + 1400 + assert_eq!(Some(&root_id), tree.root_node_id()); 1401 + 1402 + assert_eq!(node_1.data(), &1); 1403 + assert_eq!(node_1.children().len(), 0); 1404 + assert!(node_1.parent().is_none()); 1405 + assert!(tree.get(&node_1_id).is_err()); 1406 + 1407 + let node_2_ref = tree.get(&node_2_id).unwrap(); 1408 + let node_3_ref = tree.get(&node_3_id).unwrap(); 1409 + 1410 + assert_eq!(node_2_ref.data(), &2); 1411 + assert_eq!(node_3_ref.data(), &3); 1412 + 1413 + assert!(node_2_ref.parent().is_none()); 1414 + assert!(node_3_ref.parent().is_none()); 1415 + } 1416 + 1417 + #[test] 1418 + fn test_remove_root() { 1419 + use RemoveBehavior::*; 1420 + 1421 + let mut tree = TreeBuilder::new().with_root(Node::new(5)).build(); 1422 + 1423 + let root_id = tree.root.clone().unwrap(); 1424 + tree.remove_node(root_id, OrphanChildren).unwrap(); 1425 + assert_eq!(None, tree.root_node_id()); 1426 + 1427 + let mut tree = TreeBuilder::new().with_root(Node::new(5)).build(); 1428 + 1429 + let root_id = tree.root.clone().unwrap(); 1430 + tree.remove_node(root_id, LiftChildren).unwrap(); 1431 + assert_eq!(None, tree.root_node_id()); 1432 + } 1433 + 1434 + #[test] 1435 + fn test_move_node_to_parent() { 1436 + use InsertBehavior::*; 1437 + use MoveBehavior::*; 1438 + 1439 + let mut tree = Tree::new(); 1440 + 1441 + let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); 1442 + let node_1_id = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 1443 + let node_2_id = tree.insert(Node::new(2), UnderNode(&root_id)).unwrap(); 1444 + let node_3_id = tree.insert(Node::new(3), UnderNode(&node_1_id)).unwrap(); 1445 + 1446 + // Move 3 "across" the tree. 1447 + tree.move_node(&node_3_id, ToParent(&node_2_id)).unwrap(); 1448 + assert!(tree.get(&root_id).unwrap().children().contains(&node_1_id)); 1449 + assert!(tree.get(&root_id).unwrap().children().contains(&node_2_id)); 1450 + assert!( 1451 + tree.get(&node_2_id,) 1452 + .unwrap() 1453 + .children() 1454 + .contains(&node_3_id,) 1455 + ); 1456 + 1457 + // Move 3 "up" the tree. 1458 + tree.move_node(&node_3_id, ToParent(&root_id)).unwrap(); 1459 + assert!(tree.get(&root_id).unwrap().children().contains(&node_1_id)); 1460 + assert!(tree.get(&root_id).unwrap().children().contains(&node_2_id)); 1461 + assert!(tree.get(&root_id).unwrap().children().contains(&node_3_id)); 1462 + 1463 + // Move 3 "down" (really this is across though) the tree. 1464 + tree.move_node(&node_3_id, ToParent(&node_1_id)).unwrap(); 1465 + assert!(tree.get(&root_id).unwrap().children().contains(&node_1_id)); 1466 + assert!(tree.get(&root_id).unwrap().children().contains(&node_2_id)); 1467 + assert!( 1468 + tree.get(&node_1_id,) 1469 + .unwrap() 1470 + .children() 1471 + .contains(&node_3_id,) 1472 + ); 1473 + 1474 + // Move 1 "down" the tree. 1475 + tree.move_node(&node_1_id, ToParent(&node_3_id)).unwrap(); 1476 + assert!(tree.get(&root_id).unwrap().children().contains(&node_2_id)); 1477 + assert!(tree.get(&root_id).unwrap().children().contains(&node_3_id)); 1478 + assert!( 1479 + tree.get(&node_3_id,) 1480 + .unwrap() 1481 + .children() 1482 + .contains(&node_1_id,) 1483 + ); 1484 + 1485 + // Note: node_1 is at the lowest point in the tree before these insertions. 1486 + let node_4_id = tree.insert(Node::new(4), UnderNode(&node_1_id)).unwrap(); 1487 + let node_5_id = tree.insert(Node::new(5), UnderNode(&node_4_id)).unwrap(); 1488 + 1489 + // move 3 "down" the tree 1490 + tree.move_node(&node_3_id, ToParent(&node_5_id)).unwrap(); 1491 + assert!(tree.get(&root_id).unwrap().children().contains(&node_2_id)); 1492 + assert!(tree.get(&root_id).unwrap().children().contains(&node_1_id)); 1493 + assert!( 1494 + tree.get(&node_1_id,) 1495 + .unwrap() 1496 + .children() 1497 + .contains(&node_4_id,) 1498 + ); 1499 + assert!( 1500 + tree.get(&node_4_id,) 1501 + .unwrap() 1502 + .children() 1503 + .contains(&node_5_id,) 1504 + ); 1505 + assert!( 1506 + tree.get(&node_5_id,) 1507 + .unwrap() 1508 + .children() 1509 + .contains(&node_3_id,) 1510 + ); 1511 + 1512 + // move root "down" the tree 1513 + tree.move_node(&root_id, ToParent(&node_2_id)).unwrap(); 1514 + assert!(tree.get(&node_2_id).unwrap().children().contains(&root_id)); 1515 + assert!(tree.get(&root_id).unwrap().children().contains(&node_1_id)); 1516 + assert!( 1517 + tree.get(&node_1_id,) 1518 + .unwrap() 1519 + .children() 1520 + .contains(&node_4_id,) 1521 + ); 1522 + assert!( 1523 + tree.get(&node_4_id,) 1524 + .unwrap() 1525 + .children() 1526 + .contains(&node_5_id,) 1527 + ); 1528 + assert!( 1529 + tree.get(&node_5_id,) 1530 + .unwrap() 1531 + .children() 1532 + .contains(&node_3_id,) 1533 + ); 1534 + assert_eq!(tree.root_node_id(), Some(&node_2_id)); 1535 + } 1536 + 1537 + #[test] 1538 + fn test_move_node_to_root() { 1539 + use InsertBehavior::*; 1540 + 1541 + // test move with existing root 1542 + { 1543 + let mut tree = Tree::new(); 1544 + let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); 1545 + let node_1_id = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 1546 + let node_2_id = tree.insert(Node::new(2), UnderNode(&node_1_id)).unwrap(); 1547 + 1548 + tree.move_node_to_root(&node_2_id); 1549 + 1550 + assert_eq!(tree.root_node_id(), Some(&node_2_id)); 1551 + assert!(tree.get(&node_2_id).unwrap().children().contains(&root_id)); 1552 + assert!( 1553 + !tree 1554 + .get(&node_1_id,) 1555 + .unwrap() 1556 + .children() 1557 + .contains(&node_2_id,) 1558 + ); 1559 + } 1560 + 1561 + // Test move with existing root and with orphan. 1562 + { 1563 + let mut tree = Tree::new(); 1564 + let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); 1565 + let node_1_id = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 1566 + let node_2_id = tree.insert(Node::new(2), UnderNode(&node_1_id)).unwrap(); 1567 + 1568 + tree.remove_node_orphan_children(node_1_id); 1569 + tree.move_node_to_root(&node_2_id); 1570 + 1571 + assert_eq!(tree.root_node_id(), Some(&node_2_id)); 1572 + assert!(tree.get(&node_2_id).unwrap().children().contains(&root_id)); 1573 + assert_eq!(tree.get(&root_id).unwrap().children().len(), 0); 1574 + } 1575 + 1576 + // Test move without root and with orphan. 1577 + { 1578 + let mut tree = Tree::new(); 1579 + let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); 1580 + let node_1_id = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 1581 + let node_2_id = tree.insert(Node::new(2), UnderNode(&node_1_id)).unwrap(); 1582 + 1583 + tree.remove_node_orphan_children(root_id); 1584 + tree.move_node_to_root(&node_1_id); 1585 + 1586 + assert_eq!(tree.root_node_id(), Some(&node_1_id)); 1587 + assert!( 1588 + tree.get(&node_1_id,) 1589 + .unwrap() 1590 + .children() 1591 + .contains(&node_2_id,) 1592 + ); 1593 + assert_eq!(tree.get(&node_1_id).unwrap().children().len(), 1); 1594 + } 1595 + } 1596 + 1597 + #[test] 1598 + fn test_find_subtree_root_below_upper_id() { 1599 + use InsertBehavior::*; 1600 + 1601 + let mut tree = Tree::new(); 1602 + 1603 + let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); 1604 + let node_1_id = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 1605 + let node_2_id = tree.insert(Node::new(2), UnderNode(&node_1_id)).unwrap(); 1606 + let node_3_id = tree.insert(Node::new(3), UnderNode(&node_1_id)).unwrap(); 1607 + let node_4_id = tree.insert(Node::new(4), UnderNode(&node_2_id)).unwrap(); 1608 + 1609 + let sub_root = tree.find_subtree_root_between_ids(&node_1_id, &root_id); 1610 + assert_eq!(sub_root, Some(&node_1_id)); 1611 + let sub_root = tree.find_subtree_root_between_ids(&root_id, &node_1_id); //invert for None 1612 + assert_eq!(sub_root, None); 1613 + 1614 + let sub_root = tree.find_subtree_root_between_ids(&node_2_id, &root_id); 1615 + assert_eq!(sub_root, Some(&node_1_id)); 1616 + let sub_root = tree.find_subtree_root_between_ids(&root_id, &node_2_id); //invert for None 1617 + assert_eq!(sub_root, None); 1618 + 1619 + let sub_root = tree.find_subtree_root_between_ids(&node_3_id, &node_1_id); 1620 + assert_eq!(sub_root, Some(&node_3_id)); 1621 + let sub_root = tree.find_subtree_root_between_ids(&node_1_id, &node_3_id); //invert for None 1622 + assert_eq!(sub_root, None); 1623 + 1624 + let sub_root = tree.find_subtree_root_between_ids(&node_4_id, &root_id); 1625 + assert_eq!(sub_root, Some(&node_1_id)); 1626 + let sub_root = tree.find_subtree_root_between_ids(&root_id, &node_4_id); //invert for None 1627 + assert_eq!(sub_root, None); 1628 + } 1629 + 1630 + #[test] 1631 + fn test_tree_height() { 1632 + use InsertBehavior::*; 1633 + use RemoveBehavior::*; 1634 + 1635 + // Empty tree. 1636 + let mut tree = Tree::new(); 1637 + assert_eq!(0, tree.height()); 1638 + 1639 + // The tree with single root node. 1640 + let root_id = tree.insert(Node::new(1), AsRoot).unwrap(); 1641 + assert_eq!(1, tree.height()); 1642 + 1643 + // Root node with single child. 1644 + let child_1_id = tree.insert(Node::new(2), UnderNode(&root_id)).unwrap(); 1645 + assert_eq!(2, tree.height()); 1646 + 1647 + // Root node with two children. 1648 + let child_2_id = tree.insert(Node::new(3), UnderNode(&root_id)).unwrap(); 1649 + assert_eq!(2, tree.height()); 1650 + 1651 + // Grandson. 1652 + tree.insert(Node::new(4), UnderNode(&child_1_id)).unwrap(); 1653 + assert_eq!(3, tree.height()); 1654 + 1655 + // Remove child_1 and grandchild. 1656 + tree.remove_node(child_1_id, DropChildren).unwrap(); 1657 + assert_eq!(2, tree.height()); 1658 + 1659 + // Remove child_2. 1660 + tree.remove_node(child_2_id, LiftChildren).unwrap(); 1661 + assert_eq!(1, tree.height()); 1662 + } 1663 + 1664 + #[test] 1665 + fn test_partial_eq() { 1666 + use InsertBehavior::*; 1667 + 1668 + let mut tree = Tree::new(); 1669 + let root_id = tree.insert(Node::new(0), AsRoot).unwrap(); 1670 + let node_1_id = tree.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 1671 + tree.insert(Node::new(2), UnderNode(&root_id)).unwrap(); 1672 + tree.insert(Node::new(3), UnderNode(&node_1_id)).unwrap(); 1673 + 1674 + // Ensure PartialEq doesn't work when the number of used nodes are not equal. 1675 + { 1676 + let mut other = Tree::new(); 1677 + let root_id = other.insert(Node::new(0), AsRoot).unwrap(); 1678 + other.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 1679 + other.insert(Node::new(2), UnderNode(&root_id)).unwrap(); 1680 + assert_ne!(tree, other); 1681 + } 1682 + 1683 + // Ensure PartialEq doesn't work when the data is not equal. 1684 + { 1685 + let mut other = Tree::new(); 1686 + let root_id = other.insert(Node::new(0), AsRoot).unwrap(); 1687 + let id = other.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 1688 + other.insert(Node::new(2), UnderNode(&root_id)).unwrap(); 1689 + other.insert(Node::new(4), UnderNode(&id)).unwrap(); 1690 + assert_ne!(tree, other); 1691 + } 1692 + 1693 + // Ensure PartialEq doesn't work when the parents aren't equal. 1694 + { 1695 + let mut other = Tree::new(); 1696 + let root_id = other.insert(Node::new(0), AsRoot).unwrap(); 1697 + other.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 1698 + let id = other.insert(Node::new(2), UnderNode(&root_id)).unwrap(); 1699 + other.insert(Node::new(3), UnderNode(&id)).unwrap(); 1700 + assert_ne!(tree, other); 1701 + } 1702 + 1703 + // Ensure PartialEq works even if the number of free spots in Tree. 1704 + // Node is different. 1705 + { 1706 + let mut other = Tree::new(); 1707 + let root_id = other.insert(Node::new(0), AsRoot).unwrap(); 1708 + let id = other.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 1709 + other.insert(Node::new(2), UnderNode(&root_id)).unwrap(); 1710 + other.insert(Node::new(3), UnderNode(&id)).unwrap(); 1711 + let to_delete = other.insert(Node::new(42), UnderNode(&root_id)).unwrap(); 1712 + other.take_node(to_delete); 1713 + assert_ne!( 1714 + tree.nodes.iter().filter(|x| x.is_none()).count(), 1715 + other.nodes.iter().filter(|x| x.is_none()).count() 1716 + ); 1717 + assert_eq!(tree, other); 1718 + } 1719 + 1720 + // Ensure PartialEq doesn't work when the Node's index are different. 1721 + { 1722 + let mut other = Tree::new(); 1723 + let root_id = other.insert(Node::new(0), AsRoot).unwrap(); 1724 + let to_delete = other.insert(Node::new(42), UnderNode(&root_id)).unwrap(); 1725 + let id = other.insert(Node::new(1), UnderNode(&root_id)).unwrap(); 1726 + other.insert(Node::new(2), UnderNode(&root_id)).unwrap(); 1727 + other.insert(Node::new(3), UnderNode(&id)).unwrap(); 1728 + other.take_node(to_delete); 1729 + assert_ne!(tree, other); 1730 + } 1731 + } 1732 + }
+2
doc/act1.md
··· 58 58 59 59 So for now let's get a basic notes set up. 60 60 61 + 62 + ok so lets get a seaorm set up
+17 -16
flake.lock
··· 8 8 "rust-analyzer-src": "rust-analyzer-src" 9 9 }, 10 10 "locked": { 11 - "lastModified": 1772348640, 12 - "narHash": "sha256-caiKs7O4khFydpKyg8O8/nmvw/NfN4fn/4spageGoig=", 13 - "rev": "47c5355eaba0b08836e720d5d545c8ea1e1783db", 14 - "revCount": 2572, 15 - "type": "tarball", 16 - "url": "https://api.flakehub.com/f/pinned/nix-community/fenix/0.1.2572%2Brev-47c5355eaba0b08836e720d5d545c8ea1e1783db/019ca881-cb35-7cd1-8b46-98117609f8b6/source.tar.gz" 11 + "lastModified": 1774163246, 12 + "narHash": "sha256-gzlqyLjP44LWraUd3Zn4xrQKOtK+zcBJ77pnsSUsxcM=", 13 + "owner": "nix-community", 14 + "repo": "fenix", 15 + "rev": "4cd28929c68cae521589bc21958d3793904ed1e2", 16 + "type": "github" 17 17 }, 18 18 "original": { 19 - "type": "tarball", 20 - "url": "https://flakehub.com/f/nix-community/fenix/0.1" 19 + "owner": "nix-community", 20 + "repo": "fenix", 21 + "type": "github" 21 22 } 22 23 }, 23 24 "nixpkgs": { 24 25 "locked": { 25 - "lastModified": 1772773019, 26 - "narHash": "sha256-E1bxHxNKfDoQUuvriG71+f+s/NT0qWkImXsYZNFFfCs=", 27 - "rev": "aca4d95fce4914b3892661bcb80b8087293536c6", 28 - "revCount": 958961, 26 + "lastModified": 1773821835, 27 + "narHash": "sha256-TJ3lSQtW0E2JrznGVm8hOQGVpXjJyXY2guAxku2O9A4=", 28 + "rev": "b40629efe5d6ec48dd1efba650c797ddbd39ace0", 29 + "revCount": 964859, 29 30 "type": "tarball", 30 - "url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.1.958961%2Brev-aca4d95fce4914b3892661bcb80b8087293536c6/019cc7ad-65c5-7d4e-9860-842d09d8f4fa/source.tar.gz" 31 + "url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.1.964859%2Brev-b40629efe5d6ec48dd1efba650c797ddbd39ace0/019d03e9-2959-7276-adaa-d074e96422de/source.tar.gz" 31 32 }, 32 33 "original": { 33 34 "type": "tarball", ··· 43 44 "rust-analyzer-src": { 44 45 "flake": false, 45 46 "locked": { 46 - "lastModified": 1772310333, 47 - "narHash": "sha256-njFwHnxYcfQINwSa+XWhenv8s8PMg/j5ID0HpIa49xM=", 47 + "lastModified": 1774097238, 48 + "narHash": "sha256-hcujm/qEX4RUybdBCrQKdQNqTRYDItmnbjJRP5ky5vc=", 48 49 "owner": "rust-lang", 49 50 "repo": "rust-analyzer", 50 - "rev": "a96b6a9b887008bae01839543f9ca8e1f67f4ebe", 51 + "rev": "76de1de27c0ca1329bc41324edab22c82d69e779", 51 52 "type": "github" 52 53 }, 53 54 "original": {
+27 -3
flake.nix
··· 7 7 nixpkgs.url = "https://flakehub.com/f/NixOS/nixpkgs/0.1"; # unstable Nixpkgs 8 8 9 9 fenix = { 10 - url = "https://flakehub.com/f/nix-community/fenix/0.1"; 10 + url = "github:nix-community/fenix"; 11 11 inputs.nixpkgs.follows = "nixpkgs"; 12 12 }; 13 13 }; ··· 43 43 { 44 44 45 45 overlays.default = final: prev: { 46 + 47 + sea-orm-cli = final.rustPlatform.buildRustPackage rec { 48 + pname = "sea-orm-cli"; 49 + version = "2.0.0-rc.37"; 50 + 51 + src = final.fetchCrate { 52 + inherit pname version; 53 + 54 + sha256 = "sha256-YbP85rVO41S7ZPWSpVz3jICLAEU8H/a2axJBtdFRuWY="; 55 + 56 + }; 57 + 58 + cargoHash = "sha256-6lOXyaNxrIfCI3T9nIPR76rhQXvRzSVQUsPRjo5abmI="; 59 + 60 + nativeBuildInputs = [ final.pkg-config ]; 61 + 62 + buildInputs = [ 63 + final.openssl 64 + ]; 65 + 66 + doCheck = false; # Skip tests to speed up the build 67 + }; 68 + 46 69 rustToolchain = 47 70 with inputs.fenix.packages.${prev.stdenv.hostPlatform.system}; 48 71 combine ( ··· 73 96 cargo-watch 74 97 rust-analyzer 75 98 76 - typst 77 - typstyle 99 + sea-orm-cli 100 + 101 + bacon 78 102 ]; 79 103 80 104 # Set any environment variables for your dev shell
+44 -1
justfile
··· 18 18 19 19 # Run all tests 20 20 test: 21 - cargo test {{_cargo_flags}} --all 21 + cargo test {{_cargo_flags}} 22 + 23 + 24 + # Only used to build / generate entities 25 + dev-db := justfile_directory() + "/target/dev.db" 26 + dev-db-url := "sqlite:///" + dev-db 27 + 28 + # build entities from migrations 29 + [working-directory:"crates/db"] 30 + entity: 31 + # create the dev db 32 + rm -f {{dev-db}} 33 + touch {{dev-db}} 34 + 35 + # run the migration 36 + cd migration && cargo run -- -u {{dev-db-url}} 37 + 38 + # generate entity files based off the migraiton 39 + sea-orm-cli generate entity \ 40 + --database-url {{dev-db-url}} \ 41 + --output-dir ./src/entity \ 42 + --entity-format=dense # add flag if expanded format is needed for debugging 43 + 44 + # add migraton::types to every file in entity 45 + sed -i '4i use migration::types::*;' ./src/entity/*.rs 46 + 47 + # replace elementary types with specific ones 48 + sed -i 's/pub nano_id: String/pub nano_id: NanoId/g' ./src/entity/*.rs 49 + sed -i 's/pub priority: String/pub priority: Priority/g' ./src/entity/*.rs 50 + 51 + # replace parent_group_id with proper nano_id 52 + sed -i 's/pub parent_group_id: Option<String>/pub parent_group_id: Option<NanoId>/g' ./src/entity/*.rs 53 + 54 + # replace group_id with nano_id 55 + sed -i 's/pub group_id: String/pub group_id: NanoId/g' ./src/entity/*.rs 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 +
+39 -1
src/cli.rs
··· 1 - use clap::Parser; 1 + use clap::{Parser, Subcommand}; 2 2 3 3 use crate::config::{get_config_dir, get_data_dir}; 4 4 ··· 12 12 /// Frame rate, i.e. number of frames per second 13 13 #[arg(short, long, value_name = "FLOAT", default_value_t = 60.0)] 14 14 pub frame_rate: f64, 15 + 16 + #[command(subcommand)] 17 + pub command: Option<Commands>, 15 18 } 19 + 20 + #[derive(Subcommand, Debug)] 21 + pub enum Commands { 22 + /// Manage TARS groups. 23 + // #[command(subcommand)] 24 + // Group(GroupSubcommand), 25 + 26 + /// Manage TARS tasks. 27 + // #[command(subcommand)] 28 + // Task(TaskSubcommand), 29 + 30 + /// simple testing stuff 31 + Test, 32 + // Imports bulk data into TARS 33 + // NOTE: By default the importer will fill in fields with 34 + // default values if they arent present / aren't able to be 35 + // parsed properly 36 + // Import(ImportArgs), 37 + } 38 + 39 + // #[derive(Subcommand, Debug)] 40 + // /// Subcommand to manage tars groups. 41 + // pub enum GroupSubcommand { 42 + // /// Add a group. 43 + // Add(GroupAddArgs), 44 + // /// List groups. 45 + // List(GroupListArgs), 46 + // } 47 + 48 + // #[derive(Debug, Args)] 49 + // pub struct ExportArgs { 50 + // #[arg(short, long, default_value = "./tars.json")] 51 + // /// The file-path for data to pe put into. 52 + // pub out_file: PathBuf, 53 + // } 16 54 17 55 const VERSION_MESSAGE: &str = concat!( 18 56 env!("CARGO_PKG_VERSION"),
+15 -3
src/main.rs
··· 2 2 //! My (suri.codes) personal-knowledge-system, with deeply integrated task tracking and long term goal planning capabilities. 3 3 //! 4 4 5 + use crate::{app::App, cli::Cli}; 5 6 use clap::Parser; 6 - use crate::{app::App, cli::Cli}; 7 + use db::Db; 7 8 8 9 mod app; 9 10 mod cli; ··· 21 22 logging::init()?; 22 23 23 24 let args = Cli::parse(); 24 - let mut app = App::new(args.tick_rate, args.frame_rate); 25 25 26 - app.run().await?; 26 + let _db = Db::connect("/tmp/filaments/test_db.sqlite").await?; 27 + 28 + // if there is any subcommand, we want to execute that, otherwise we 29 + // just run the app 27 30 31 + if let Some(command) = args.command { 32 + match command { 33 + cli::Commands::Test => {} 34 + } 35 + } else { 36 + let mut app = App::new(args.tick_rate, args.frame_rate); 37 + 38 + app.run().await?; 39 + } 28 40 Ok(()) 29 41 }