├── .github ├── FUNDING.yml └── workflows │ └── ci.yml ├── .gitignore ├── .gitmodules ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── docker-compose.yml ├── roogle-engine ├── Cargo.toml └── src │ ├── compare.rs │ ├── lib.rs │ ├── query │ ├── mod.rs │ └── parse.rs │ └── search.rs ├── roogle-util ├── Cargo.toml └── src │ └── lib.rs └── roogle ├── Cargo.toml └── src └── main.rs /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: hkmatsumoto 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | check: 14 | name: check 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | - uses: actions-rs/toolchain@v1 19 | with: 20 | profile: minimal 21 | toolchain: stable 22 | override: true 23 | - uses: actions-rs/cargo@v1 24 | with: 25 | command: check 26 | 27 | test: 28 | name: test 29 | runs-on: ubuntu-latest 30 | steps: 31 | - uses: actions/checkout@v2 32 | - uses: actions-rs/toolchain@v1 33 | with: 34 | profile: minimal 35 | toolchain: stable 36 | override: true 37 | - uses: actions-rs/cargo@v1 38 | with: 39 | command: test 40 | 41 | fmt: 42 | name: fmt 43 | runs-on: ubuntu-latest 44 | steps: 45 | - uses: actions/checkout@v2 46 | - uses: actions-rs/toolchain@v1 47 | with: 48 | profile: minimal 49 | toolchain: stable 50 | override: true 51 | - uses: actions-rs/cargo@v1 52 | with: 53 | command: fmt 54 | args: --all -- --check 55 | 56 | clippy: 57 | name: clippy 58 | runs-on: ubuntu-latest 59 | steps: 60 | - uses: actions/checkout@v2 61 | - uses: actions-rs/toolchain@v1 62 | with: 63 | profile: minimal 64 | toolchain: stable 65 | override: true 66 | - uses: actions-rs/cargo@v1 67 | with: 68 | command: clippy 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "roogle-index"] 2 | path = roogle-index 3 | url = https://github.com/roogle-rs/roogle-index.git 4 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "ansi_term" 7 | version = "0.11.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 10 | dependencies = [ 11 | "winapi", 12 | ] 13 | 14 | [[package]] 15 | name = "ansi_term" 16 | version = "0.12.1" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" 19 | dependencies = [ 20 | "winapi", 21 | ] 22 | 23 | [[package]] 24 | name = "anyhow" 25 | version = "1.0.44" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" 28 | 29 | [[package]] 30 | name = "async-stream" 31 | version = "0.3.2" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625" 34 | dependencies = [ 35 | "async-stream-impl", 36 | "futures-core", 37 | ] 38 | 39 | [[package]] 40 | name = "async-stream-impl" 41 | version = "0.3.2" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" 44 | dependencies = [ 45 | "proc-macro2", 46 | "quote", 47 | "syn", 48 | ] 49 | 50 | [[package]] 51 | name = "async-trait" 52 | version = "0.1.51" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" 55 | dependencies = [ 56 | "proc-macro2", 57 | "quote", 58 | "syn", 59 | ] 60 | 61 | [[package]] 62 | name = "atomic" 63 | version = "0.5.0" 64 | source = "registry+https://github.com/rust-lang/crates.io-index" 65 | checksum = "c3410529e8288c463bedb5930f82833bc0c90e5d2fe639a56582a4d09220b281" 66 | dependencies = [ 67 | "autocfg", 68 | ] 69 | 70 | [[package]] 71 | name = "atty" 72 | version = "0.2.14" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 75 | dependencies = [ 76 | "hermit-abi", 77 | "libc", 78 | "winapi", 79 | ] 80 | 81 | [[package]] 82 | name = "autocfg" 83 | version = "1.0.1" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 86 | 87 | [[package]] 88 | name = "base-x" 89 | version = "0.2.8" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" 92 | 93 | [[package]] 94 | name = "binascii" 95 | version = "0.1.4" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" 98 | 99 | [[package]] 100 | name = "bitflags" 101 | version = "1.3.2" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 104 | 105 | [[package]] 106 | name = "bumpalo" 107 | version = "3.7.1" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "d9df67f7bf9ef8498769f994239c45613ef0c5899415fb58e9add412d2c1a538" 110 | 111 | [[package]] 112 | name = "bytes" 113 | version = "1.1.0" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" 116 | 117 | [[package]] 118 | name = "cc" 119 | version = "1.0.71" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" 122 | 123 | [[package]] 124 | name = "cfg-if" 125 | version = "1.0.0" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 128 | 129 | [[package]] 130 | name = "chrono" 131 | version = "0.4.19" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" 134 | dependencies = [ 135 | "libc", 136 | "num-integer", 137 | "num-traits", 138 | "winapi", 139 | ] 140 | 141 | [[package]] 142 | name = "clap" 143 | version = "2.33.3" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" 146 | dependencies = [ 147 | "ansi_term 0.11.0", 148 | "atty", 149 | "bitflags", 150 | "strsim", 151 | "textwrap", 152 | "unicode-width", 153 | "vec_map", 154 | ] 155 | 156 | [[package]] 157 | name = "const_fn" 158 | version = "0.4.8" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7" 161 | 162 | [[package]] 163 | name = "cookie" 164 | version = "0.15.1" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "d5f1c7727e460397e56abc4bddc1d49e07a1ad78fc98eb2e1c8f032a58a2f80d" 167 | dependencies = [ 168 | "percent-encoding", 169 | "time", 170 | "version_check", 171 | ] 172 | 173 | [[package]] 174 | name = "devise" 175 | version = "0.3.1" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | checksum = "50c7580b072f1c8476148f16e0a0d5dedddab787da98d86c5082c5e9ed8ab595" 178 | dependencies = [ 179 | "devise_codegen", 180 | "devise_core", 181 | ] 182 | 183 | [[package]] 184 | name = "devise_codegen" 185 | version = "0.3.1" 186 | source = "registry+https://github.com/rust-lang/crates.io-index" 187 | checksum = "123c73e7a6e51b05c75fe1a1b2f4e241399ea5740ed810b0e3e6cacd9db5e7b2" 188 | dependencies = [ 189 | "devise_core", 190 | "quote", 191 | ] 192 | 193 | [[package]] 194 | name = "devise_core" 195 | version = "0.3.1" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "841ef46f4787d9097405cac4e70fb8644fc037b526e8c14054247c0263c400d0" 198 | dependencies = [ 199 | "bitflags", 200 | "proc-macro2", 201 | "proc-macro2-diagnostics", 202 | "quote", 203 | "syn", 204 | ] 205 | 206 | [[package]] 207 | name = "discard" 208 | version = "1.0.4" 209 | source = "registry+https://github.com/rust-lang/crates.io-index" 210 | checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" 211 | 212 | [[package]] 213 | name = "either" 214 | version = "1.6.1" 215 | source = "registry+https://github.com/rust-lang/crates.io-index" 216 | checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" 217 | 218 | [[package]] 219 | name = "encoding_rs" 220 | version = "0.8.29" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "a74ea89a0a1b98f6332de42c95baff457ada66d1cb4030f9ff151b2041a1c746" 223 | dependencies = [ 224 | "cfg-if", 225 | ] 226 | 227 | [[package]] 228 | name = "figment" 229 | version = "0.10.6" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "790b4292c72618abbab50f787a477014fe15634f96291de45672ce46afe122df" 232 | dependencies = [ 233 | "atomic", 234 | "pear", 235 | "serde", 236 | "toml", 237 | "uncased", 238 | "version_check", 239 | ] 240 | 241 | [[package]] 242 | name = "fnv" 243 | version = "1.0.7" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 246 | 247 | [[package]] 248 | name = "futures" 249 | version = "0.3.17" 250 | source = "registry+https://github.com/rust-lang/crates.io-index" 251 | checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" 252 | dependencies = [ 253 | "futures-channel", 254 | "futures-core", 255 | "futures-executor", 256 | "futures-io", 257 | "futures-sink", 258 | "futures-task", 259 | "futures-util", 260 | ] 261 | 262 | [[package]] 263 | name = "futures-channel" 264 | version = "0.3.17" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" 267 | dependencies = [ 268 | "futures-core", 269 | "futures-sink", 270 | ] 271 | 272 | [[package]] 273 | name = "futures-core" 274 | version = "0.3.17" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" 277 | 278 | [[package]] 279 | name = "futures-executor" 280 | version = "0.3.17" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" 283 | dependencies = [ 284 | "futures-core", 285 | "futures-task", 286 | "futures-util", 287 | ] 288 | 289 | [[package]] 290 | name = "futures-io" 291 | version = "0.3.17" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" 294 | 295 | [[package]] 296 | name = "futures-macro" 297 | version = "0.3.17" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" 300 | dependencies = [ 301 | "autocfg", 302 | "proc-macro-hack", 303 | "proc-macro2", 304 | "quote", 305 | "syn", 306 | ] 307 | 308 | [[package]] 309 | name = "futures-sink" 310 | version = "0.3.17" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" 313 | 314 | [[package]] 315 | name = "futures-task" 316 | version = "0.3.17" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" 319 | 320 | [[package]] 321 | name = "futures-util" 322 | version = "0.3.17" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" 325 | dependencies = [ 326 | "autocfg", 327 | "futures-channel", 328 | "futures-core", 329 | "futures-io", 330 | "futures-macro", 331 | "futures-sink", 332 | "futures-task", 333 | "memchr", 334 | "pin-project-lite", 335 | "pin-utils", 336 | "proc-macro-hack", 337 | "proc-macro-nested", 338 | "slab", 339 | ] 340 | 341 | [[package]] 342 | name = "generator" 343 | version = "0.7.0" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "c1d9279ca822891c1a4dae06d185612cf8fc6acfe5dff37781b41297811b12ee" 346 | dependencies = [ 347 | "cc", 348 | "libc", 349 | "log", 350 | "rustversion", 351 | "winapi", 352 | ] 353 | 354 | [[package]] 355 | name = "getrandom" 356 | version = "0.2.3" 357 | source = "registry+https://github.com/rust-lang/crates.io-index" 358 | checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" 359 | dependencies = [ 360 | "cfg-if", 361 | "libc", 362 | "wasi", 363 | ] 364 | 365 | [[package]] 366 | name = "glob" 367 | version = "0.3.0" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" 370 | 371 | [[package]] 372 | name = "h2" 373 | version = "0.3.6" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "6c06815895acec637cd6ed6e9662c935b866d20a106f8361892893a7d9234964" 376 | dependencies = [ 377 | "bytes", 378 | "fnv", 379 | "futures-core", 380 | "futures-sink", 381 | "futures-util", 382 | "http", 383 | "indexmap", 384 | "slab", 385 | "tokio", 386 | "tokio-util", 387 | "tracing", 388 | ] 389 | 390 | [[package]] 391 | name = "hashbrown" 392 | version = "0.11.2" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" 395 | 396 | [[package]] 397 | name = "heck" 398 | version = "0.3.3" 399 | source = "registry+https://github.com/rust-lang/crates.io-index" 400 | checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" 401 | dependencies = [ 402 | "unicode-segmentation", 403 | ] 404 | 405 | [[package]] 406 | name = "hermit-abi" 407 | version = "0.1.19" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" 410 | dependencies = [ 411 | "libc", 412 | ] 413 | 414 | [[package]] 415 | name = "http" 416 | version = "0.2.5" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" 419 | dependencies = [ 420 | "bytes", 421 | "fnv", 422 | "itoa", 423 | ] 424 | 425 | [[package]] 426 | name = "http-body" 427 | version = "0.4.3" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "399c583b2979440c60be0821a6199eca73bc3c8dcd9d070d75ac726e2c6186e5" 430 | dependencies = [ 431 | "bytes", 432 | "http", 433 | "pin-project-lite", 434 | ] 435 | 436 | [[package]] 437 | name = "httparse" 438 | version = "1.5.1" 439 | source = "registry+https://github.com/rust-lang/crates.io-index" 440 | checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" 441 | 442 | [[package]] 443 | name = "httpdate" 444 | version = "1.0.1" 445 | source = "registry+https://github.com/rust-lang/crates.io-index" 446 | checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" 447 | 448 | [[package]] 449 | name = "hyper" 450 | version = "0.14.13" 451 | source = "registry+https://github.com/rust-lang/crates.io-index" 452 | checksum = "15d1cfb9e4f68655fa04c01f59edb405b6074a0f7118ea881e5026e4a1cd8593" 453 | dependencies = [ 454 | "bytes", 455 | "futures-channel", 456 | "futures-core", 457 | "futures-util", 458 | "h2", 459 | "http", 460 | "http-body", 461 | "httparse", 462 | "httpdate", 463 | "itoa", 464 | "pin-project-lite", 465 | "socket2", 466 | "tokio", 467 | "tower-service", 468 | "tracing", 469 | "want", 470 | ] 471 | 472 | [[package]] 473 | name = "indexmap" 474 | version = "1.7.0" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" 477 | dependencies = [ 478 | "autocfg", 479 | "hashbrown", 480 | "serde", 481 | ] 482 | 483 | [[package]] 484 | name = "inlinable_string" 485 | version = "0.1.14" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "3094308123a0e9fd59659ce45e22de9f53fc1d2ac6e1feb9fef988e4f76cad77" 488 | 489 | [[package]] 490 | name = "instant" 491 | version = "0.1.12" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 494 | dependencies = [ 495 | "cfg-if", 496 | ] 497 | 498 | [[package]] 499 | name = "itoa" 500 | version = "0.4.8" 501 | source = "registry+https://github.com/rust-lang/crates.io-index" 502 | checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" 503 | 504 | [[package]] 505 | name = "lazy_static" 506 | version = "1.4.0" 507 | source = "registry+https://github.com/rust-lang/crates.io-index" 508 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 509 | 510 | [[package]] 511 | name = "levenshtein" 512 | version = "1.0.5" 513 | source = "registry+https://github.com/rust-lang/crates.io-index" 514 | checksum = "db13adb97ab515a3691f56e4dbab09283d0b86cb45abd991d8634a9d6f501760" 515 | 516 | [[package]] 517 | name = "libc" 518 | version = "0.2.104" 519 | source = "registry+https://github.com/rust-lang/crates.io-index" 520 | checksum = "7b2f96d100e1cf1929e7719b7edb3b90ab5298072638fccd77be9ce942ecdfce" 521 | 522 | [[package]] 523 | name = "lock_api" 524 | version = "0.4.5" 525 | source = "registry+https://github.com/rust-lang/crates.io-index" 526 | checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" 527 | dependencies = [ 528 | "scopeguard", 529 | ] 530 | 531 | [[package]] 532 | name = "log" 533 | version = "0.4.14" 534 | source = "registry+https://github.com/rust-lang/crates.io-index" 535 | checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" 536 | dependencies = [ 537 | "cfg-if", 538 | ] 539 | 540 | [[package]] 541 | name = "loom" 542 | version = "0.5.2" 543 | source = "registry+https://github.com/rust-lang/crates.io-index" 544 | checksum = "b2b9df80a3804094bf49bb29881d18f6f05048db72127e84e09c26fc7c2324f5" 545 | dependencies = [ 546 | "cfg-if", 547 | "generator", 548 | "scoped-tls", 549 | "serde", 550 | "serde_json", 551 | "tracing", 552 | "tracing-subscriber", 553 | ] 554 | 555 | [[package]] 556 | name = "matchers" 557 | version = "0.0.1" 558 | source = "registry+https://github.com/rust-lang/crates.io-index" 559 | checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" 560 | dependencies = [ 561 | "regex-automata", 562 | ] 563 | 564 | [[package]] 565 | name = "memchr" 566 | version = "2.4.1" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 569 | 570 | [[package]] 571 | name = "mime" 572 | version = "0.3.16" 573 | source = "registry+https://github.com/rust-lang/crates.io-index" 574 | checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" 575 | 576 | [[package]] 577 | name = "minimal-lexical" 578 | version = "0.1.4" 579 | source = "registry+https://github.com/rust-lang/crates.io-index" 580 | checksum = "9c64630dcdd71f1a64c435f54885086a0de5d6a12d104d69b165fb7d5286d677" 581 | 582 | [[package]] 583 | name = "mio" 584 | version = "0.7.14" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" 587 | dependencies = [ 588 | "libc", 589 | "log", 590 | "miow", 591 | "ntapi", 592 | "winapi", 593 | ] 594 | 595 | [[package]] 596 | name = "miow" 597 | version = "0.3.7" 598 | source = "registry+https://github.com/rust-lang/crates.io-index" 599 | checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" 600 | dependencies = [ 601 | "winapi", 602 | ] 603 | 604 | [[package]] 605 | name = "multer" 606 | version = "2.0.1" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "408327e2999b839cd1af003fc01b2019a6c10a1361769542203f6fedc5179680" 609 | dependencies = [ 610 | "bytes", 611 | "encoding_rs", 612 | "futures-util", 613 | "http", 614 | "httparse", 615 | "log", 616 | "mime", 617 | "spin", 618 | "tokio", 619 | "tokio-util", 620 | "twoway", 621 | "version_check", 622 | ] 623 | 624 | [[package]] 625 | name = "nom" 626 | version = "7.0.0" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1" 629 | dependencies = [ 630 | "memchr", 631 | "minimal-lexical", 632 | "version_check", 633 | ] 634 | 635 | [[package]] 636 | name = "ntapi" 637 | version = "0.3.6" 638 | source = "registry+https://github.com/rust-lang/crates.io-index" 639 | checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" 640 | dependencies = [ 641 | "winapi", 642 | ] 643 | 644 | [[package]] 645 | name = "num-integer" 646 | version = "0.1.44" 647 | source = "registry+https://github.com/rust-lang/crates.io-index" 648 | checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" 649 | dependencies = [ 650 | "autocfg", 651 | "num-traits", 652 | ] 653 | 654 | [[package]] 655 | name = "num-traits" 656 | version = "0.2.14" 657 | source = "registry+https://github.com/rust-lang/crates.io-index" 658 | checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" 659 | dependencies = [ 660 | "autocfg", 661 | ] 662 | 663 | [[package]] 664 | name = "num_cpus" 665 | version = "1.13.0" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" 668 | dependencies = [ 669 | "hermit-abi", 670 | "libc", 671 | ] 672 | 673 | [[package]] 674 | name = "once_cell" 675 | version = "1.8.0" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" 678 | 679 | [[package]] 680 | name = "parking_lot" 681 | version = "0.11.2" 682 | source = "registry+https://github.com/rust-lang/crates.io-index" 683 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 684 | dependencies = [ 685 | "instant", 686 | "lock_api", 687 | "parking_lot_core", 688 | ] 689 | 690 | [[package]] 691 | name = "parking_lot_core" 692 | version = "0.8.5" 693 | source = "registry+https://github.com/rust-lang/crates.io-index" 694 | checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" 695 | dependencies = [ 696 | "cfg-if", 697 | "instant", 698 | "libc", 699 | "redox_syscall", 700 | "smallvec", 701 | "winapi", 702 | ] 703 | 704 | [[package]] 705 | name = "pear" 706 | version = "0.2.3" 707 | source = "registry+https://github.com/rust-lang/crates.io-index" 708 | checksum = "15e44241c5e4c868e3eaa78b7c1848cadd6344ed4f54d029832d32b415a58702" 709 | dependencies = [ 710 | "inlinable_string", 711 | "pear_codegen", 712 | "yansi", 713 | ] 714 | 715 | [[package]] 716 | name = "pear_codegen" 717 | version = "0.2.3" 718 | source = "registry+https://github.com/rust-lang/crates.io-index" 719 | checksum = "82a5ca643c2303ecb740d506539deba189e16f2754040a42901cd8105d0282d0" 720 | dependencies = [ 721 | "proc-macro2", 722 | "proc-macro2-diagnostics", 723 | "quote", 724 | "syn", 725 | ] 726 | 727 | [[package]] 728 | name = "percent-encoding" 729 | version = "2.1.0" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 732 | 733 | [[package]] 734 | name = "pin-project-lite" 735 | version = "0.2.7" 736 | source = "registry+https://github.com/rust-lang/crates.io-index" 737 | checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" 738 | 739 | [[package]] 740 | name = "pin-utils" 741 | version = "0.1.0" 742 | source = "registry+https://github.com/rust-lang/crates.io-index" 743 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 744 | 745 | [[package]] 746 | name = "ppv-lite86" 747 | version = "0.2.14" 748 | source = "registry+https://github.com/rust-lang/crates.io-index" 749 | checksum = "c3ca011bd0129ff4ae15cd04c4eef202cadf6c51c21e47aba319b4e0501db741" 750 | 751 | [[package]] 752 | name = "proc-macro-error" 753 | version = "1.0.4" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 756 | dependencies = [ 757 | "proc-macro-error-attr", 758 | "proc-macro2", 759 | "quote", 760 | "syn", 761 | "version_check", 762 | ] 763 | 764 | [[package]] 765 | name = "proc-macro-error-attr" 766 | version = "1.0.4" 767 | source = "registry+https://github.com/rust-lang/crates.io-index" 768 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 769 | dependencies = [ 770 | "proc-macro2", 771 | "quote", 772 | "version_check", 773 | ] 774 | 775 | [[package]] 776 | name = "proc-macro-hack" 777 | version = "0.5.19" 778 | source = "registry+https://github.com/rust-lang/crates.io-index" 779 | checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" 780 | 781 | [[package]] 782 | name = "proc-macro-nested" 783 | version = "0.1.7" 784 | source = "registry+https://github.com/rust-lang/crates.io-index" 785 | checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" 786 | 787 | [[package]] 788 | name = "proc-macro2" 789 | version = "1.0.30" 790 | source = "registry+https://github.com/rust-lang/crates.io-index" 791 | checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70" 792 | dependencies = [ 793 | "unicode-xid", 794 | ] 795 | 796 | [[package]] 797 | name = "proc-macro2-diagnostics" 798 | version = "0.9.1" 799 | source = "registry+https://github.com/rust-lang/crates.io-index" 800 | checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" 801 | dependencies = [ 802 | "proc-macro2", 803 | "quote", 804 | "syn", 805 | "version_check", 806 | "yansi", 807 | ] 808 | 809 | [[package]] 810 | name = "quote" 811 | version = "1.0.10" 812 | source = "registry+https://github.com/rust-lang/crates.io-index" 813 | checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" 814 | dependencies = [ 815 | "proc-macro2", 816 | ] 817 | 818 | [[package]] 819 | name = "rand" 820 | version = "0.8.4" 821 | source = "registry+https://github.com/rust-lang/crates.io-index" 822 | checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" 823 | dependencies = [ 824 | "libc", 825 | "rand_chacha", 826 | "rand_core", 827 | "rand_hc", 828 | ] 829 | 830 | [[package]] 831 | name = "rand_chacha" 832 | version = "0.3.1" 833 | source = "registry+https://github.com/rust-lang/crates.io-index" 834 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 835 | dependencies = [ 836 | "ppv-lite86", 837 | "rand_core", 838 | ] 839 | 840 | [[package]] 841 | name = "rand_core" 842 | version = "0.6.3" 843 | source = "registry+https://github.com/rust-lang/crates.io-index" 844 | checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" 845 | dependencies = [ 846 | "getrandom", 847 | ] 848 | 849 | [[package]] 850 | name = "rand_hc" 851 | version = "0.3.1" 852 | source = "registry+https://github.com/rust-lang/crates.io-index" 853 | checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" 854 | dependencies = [ 855 | "rand_core", 856 | ] 857 | 858 | [[package]] 859 | name = "redox_syscall" 860 | version = "0.2.10" 861 | source = "registry+https://github.com/rust-lang/crates.io-index" 862 | checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" 863 | dependencies = [ 864 | "bitflags", 865 | ] 866 | 867 | [[package]] 868 | name = "ref-cast" 869 | version = "1.0.6" 870 | source = "registry+https://github.com/rust-lang/crates.io-index" 871 | checksum = "300f2a835d808734ee295d45007adacb9ebb29dd3ae2424acfa17930cae541da" 872 | dependencies = [ 873 | "ref-cast-impl", 874 | ] 875 | 876 | [[package]] 877 | name = "ref-cast-impl" 878 | version = "1.0.6" 879 | source = "registry+https://github.com/rust-lang/crates.io-index" 880 | checksum = "4c38e3aecd2b21cb3959637b883bb3714bc7e43f0268b9a29d3743ee3e55cdd2" 881 | dependencies = [ 882 | "proc-macro2", 883 | "quote", 884 | "syn", 885 | ] 886 | 887 | [[package]] 888 | name = "regex" 889 | version = "1.5.4" 890 | source = "registry+https://github.com/rust-lang/crates.io-index" 891 | checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" 892 | dependencies = [ 893 | "regex-syntax", 894 | ] 895 | 896 | [[package]] 897 | name = "regex-automata" 898 | version = "0.1.10" 899 | source = "registry+https://github.com/rust-lang/crates.io-index" 900 | checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" 901 | dependencies = [ 902 | "regex-syntax", 903 | ] 904 | 905 | [[package]] 906 | name = "regex-syntax" 907 | version = "0.6.25" 908 | source = "registry+https://github.com/rust-lang/crates.io-index" 909 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 910 | 911 | [[package]] 912 | name = "remove_dir_all" 913 | version = "0.5.3" 914 | source = "registry+https://github.com/rust-lang/crates.io-index" 915 | checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" 916 | dependencies = [ 917 | "winapi", 918 | ] 919 | 920 | [[package]] 921 | name = "rocket" 922 | version = "0.5.0-rc.1" 923 | source = "registry+https://github.com/rust-lang/crates.io-index" 924 | checksum = "0a71c18c42a0eb15bf3816831caf0dad11e7966f2a41aaf486a701979c4dd1f2" 925 | dependencies = [ 926 | "async-stream", 927 | "async-trait", 928 | "atomic", 929 | "atty", 930 | "binascii", 931 | "bytes", 932 | "either", 933 | "figment", 934 | "futures", 935 | "indexmap", 936 | "log", 937 | "memchr", 938 | "multer", 939 | "num_cpus", 940 | "parking_lot", 941 | "pin-project-lite", 942 | "rand", 943 | "ref-cast", 944 | "rocket_codegen", 945 | "rocket_http", 946 | "serde", 947 | "state", 948 | "tempfile", 949 | "time", 950 | "tokio", 951 | "tokio-stream", 952 | "tokio-util", 953 | "ubyte", 954 | "version_check", 955 | "yansi", 956 | ] 957 | 958 | [[package]] 959 | name = "rocket_codegen" 960 | version = "0.5.0-rc.1" 961 | source = "registry+https://github.com/rust-lang/crates.io-index" 962 | checksum = "66f5fa462f7eb958bba8710c17c5d774bbbd59809fa76fb1957af7e545aea8bb" 963 | dependencies = [ 964 | "devise", 965 | "glob", 966 | "indexmap", 967 | "proc-macro2", 968 | "quote", 969 | "rocket_http", 970 | "syn", 971 | "unicode-xid", 972 | ] 973 | 974 | [[package]] 975 | name = "rocket_http" 976 | version = "0.5.0-rc.1" 977 | source = "registry+https://github.com/rust-lang/crates.io-index" 978 | checksum = "23c8b7d512d2fcac2316ebe590cde67573844b99e6cc9ee0f53375fa16e25ebd" 979 | dependencies = [ 980 | "cookie", 981 | "either", 982 | "http", 983 | "hyper", 984 | "indexmap", 985 | "log", 986 | "memchr", 987 | "mime", 988 | "parking_lot", 989 | "pear", 990 | "percent-encoding", 991 | "pin-project-lite", 992 | "ref-cast", 993 | "serde", 994 | "smallvec", 995 | "stable-pattern", 996 | "state", 997 | "time", 998 | "tokio", 999 | "uncased", 1000 | ] 1001 | 1002 | [[package]] 1003 | name = "roogle" 1004 | version = "1.0.0" 1005 | dependencies = [ 1006 | "anyhow", 1007 | "rocket", 1008 | "roogle-engine", 1009 | "roogle-util", 1010 | "rustdoc-types", 1011 | "serde", 1012 | "serde_json", 1013 | "structopt", 1014 | "tracing", 1015 | "tracing-subscriber", 1016 | "tracing-tree", 1017 | ] 1018 | 1019 | [[package]] 1020 | name = "roogle-engine" 1021 | version = "1.0.2" 1022 | dependencies = [ 1023 | "levenshtein", 1024 | "nom", 1025 | "rustdoc-types", 1026 | "serde", 1027 | "serde_json", 1028 | "thiserror", 1029 | "tracing", 1030 | ] 1031 | 1032 | [[package]] 1033 | name = "roogle-util" 1034 | version = "0.1.0" 1035 | dependencies = [ 1036 | "rustdoc-types", 1037 | ] 1038 | 1039 | [[package]] 1040 | name = "rustc_version" 1041 | version = "0.2.3" 1042 | source = "registry+https://github.com/rust-lang/crates.io-index" 1043 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 1044 | dependencies = [ 1045 | "semver", 1046 | ] 1047 | 1048 | [[package]] 1049 | name = "rustdoc-types" 1050 | version = "0.5.0" 1051 | source = "registry+https://github.com/rust-lang/crates.io-index" 1052 | checksum = "c827d666a869ec2774bab0eab417ae1f3fa00f735814778929212cb25b84028b" 1053 | dependencies = [ 1054 | "serde", 1055 | ] 1056 | 1057 | [[package]] 1058 | name = "rustversion" 1059 | version = "1.0.5" 1060 | source = "registry+https://github.com/rust-lang/crates.io-index" 1061 | checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" 1062 | 1063 | [[package]] 1064 | name = "ryu" 1065 | version = "1.0.5" 1066 | source = "registry+https://github.com/rust-lang/crates.io-index" 1067 | checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" 1068 | 1069 | [[package]] 1070 | name = "scoped-tls" 1071 | version = "1.0.0" 1072 | source = "registry+https://github.com/rust-lang/crates.io-index" 1073 | checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" 1074 | 1075 | [[package]] 1076 | name = "scopeguard" 1077 | version = "1.1.0" 1078 | source = "registry+https://github.com/rust-lang/crates.io-index" 1079 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 1080 | 1081 | [[package]] 1082 | name = "semver" 1083 | version = "0.9.0" 1084 | source = "registry+https://github.com/rust-lang/crates.io-index" 1085 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 1086 | dependencies = [ 1087 | "semver-parser", 1088 | ] 1089 | 1090 | [[package]] 1091 | name = "semver-parser" 1092 | version = "0.7.0" 1093 | source = "registry+https://github.com/rust-lang/crates.io-index" 1094 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 1095 | 1096 | [[package]] 1097 | name = "serde" 1098 | version = "1.0.130" 1099 | source = "registry+https://github.com/rust-lang/crates.io-index" 1100 | checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" 1101 | dependencies = [ 1102 | "serde_derive", 1103 | ] 1104 | 1105 | [[package]] 1106 | name = "serde_derive" 1107 | version = "1.0.130" 1108 | source = "registry+https://github.com/rust-lang/crates.io-index" 1109 | checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" 1110 | dependencies = [ 1111 | "proc-macro2", 1112 | "quote", 1113 | "syn", 1114 | ] 1115 | 1116 | [[package]] 1117 | name = "serde_json" 1118 | version = "1.0.69" 1119 | source = "registry+https://github.com/rust-lang/crates.io-index" 1120 | checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8" 1121 | dependencies = [ 1122 | "itoa", 1123 | "ryu", 1124 | "serde", 1125 | ] 1126 | 1127 | [[package]] 1128 | name = "sha1" 1129 | version = "0.6.0" 1130 | source = "registry+https://github.com/rust-lang/crates.io-index" 1131 | checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" 1132 | 1133 | [[package]] 1134 | name = "sharded-slab" 1135 | version = "0.1.4" 1136 | source = "registry+https://github.com/rust-lang/crates.io-index" 1137 | checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" 1138 | dependencies = [ 1139 | "lazy_static", 1140 | ] 1141 | 1142 | [[package]] 1143 | name = "signal-hook-registry" 1144 | version = "1.4.0" 1145 | source = "registry+https://github.com/rust-lang/crates.io-index" 1146 | checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" 1147 | dependencies = [ 1148 | "libc", 1149 | ] 1150 | 1151 | [[package]] 1152 | name = "slab" 1153 | version = "0.4.5" 1154 | source = "registry+https://github.com/rust-lang/crates.io-index" 1155 | checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" 1156 | 1157 | [[package]] 1158 | name = "smallvec" 1159 | version = "1.7.0" 1160 | source = "registry+https://github.com/rust-lang/crates.io-index" 1161 | checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" 1162 | 1163 | [[package]] 1164 | name = "socket2" 1165 | version = "0.4.2" 1166 | source = "registry+https://github.com/rust-lang/crates.io-index" 1167 | checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" 1168 | dependencies = [ 1169 | "libc", 1170 | "winapi", 1171 | ] 1172 | 1173 | [[package]] 1174 | name = "spin" 1175 | version = "0.9.2" 1176 | source = "registry+https://github.com/rust-lang/crates.io-index" 1177 | checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" 1178 | 1179 | [[package]] 1180 | name = "stable-pattern" 1181 | version = "0.1.0" 1182 | source = "registry+https://github.com/rust-lang/crates.io-index" 1183 | checksum = "4564168c00635f88eaed410d5efa8131afa8d8699a612c80c455a0ba05c21045" 1184 | dependencies = [ 1185 | "memchr", 1186 | ] 1187 | 1188 | [[package]] 1189 | name = "standback" 1190 | version = "0.2.17" 1191 | source = "registry+https://github.com/rust-lang/crates.io-index" 1192 | checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" 1193 | dependencies = [ 1194 | "version_check", 1195 | ] 1196 | 1197 | [[package]] 1198 | name = "state" 1199 | version = "0.5.2" 1200 | source = "registry+https://github.com/rust-lang/crates.io-index" 1201 | checksum = "87cf4f5369e6d3044b5e365c9690f451516ac8f0954084622b49ea3fde2f6de5" 1202 | dependencies = [ 1203 | "loom", 1204 | ] 1205 | 1206 | [[package]] 1207 | name = "stdweb" 1208 | version = "0.4.20" 1209 | source = "registry+https://github.com/rust-lang/crates.io-index" 1210 | checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" 1211 | dependencies = [ 1212 | "discard", 1213 | "rustc_version", 1214 | "stdweb-derive", 1215 | "stdweb-internal-macros", 1216 | "stdweb-internal-runtime", 1217 | "wasm-bindgen", 1218 | ] 1219 | 1220 | [[package]] 1221 | name = "stdweb-derive" 1222 | version = "0.5.3" 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" 1224 | checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" 1225 | dependencies = [ 1226 | "proc-macro2", 1227 | "quote", 1228 | "serde", 1229 | "serde_derive", 1230 | "syn", 1231 | ] 1232 | 1233 | [[package]] 1234 | name = "stdweb-internal-macros" 1235 | version = "0.2.9" 1236 | source = "registry+https://github.com/rust-lang/crates.io-index" 1237 | checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" 1238 | dependencies = [ 1239 | "base-x", 1240 | "proc-macro2", 1241 | "quote", 1242 | "serde", 1243 | "serde_derive", 1244 | "serde_json", 1245 | "sha1", 1246 | "syn", 1247 | ] 1248 | 1249 | [[package]] 1250 | name = "stdweb-internal-runtime" 1251 | version = "0.1.5" 1252 | source = "registry+https://github.com/rust-lang/crates.io-index" 1253 | checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" 1254 | 1255 | [[package]] 1256 | name = "strsim" 1257 | version = "0.8.0" 1258 | source = "registry+https://github.com/rust-lang/crates.io-index" 1259 | checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" 1260 | 1261 | [[package]] 1262 | name = "structopt" 1263 | version = "0.3.25" 1264 | source = "registry+https://github.com/rust-lang/crates.io-index" 1265 | checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c" 1266 | dependencies = [ 1267 | "clap", 1268 | "lazy_static", 1269 | "structopt-derive", 1270 | ] 1271 | 1272 | [[package]] 1273 | name = "structopt-derive" 1274 | version = "0.4.18" 1275 | source = "registry+https://github.com/rust-lang/crates.io-index" 1276 | checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" 1277 | dependencies = [ 1278 | "heck", 1279 | "proc-macro-error", 1280 | "proc-macro2", 1281 | "quote", 1282 | "syn", 1283 | ] 1284 | 1285 | [[package]] 1286 | name = "syn" 1287 | version = "1.0.80" 1288 | source = "registry+https://github.com/rust-lang/crates.io-index" 1289 | checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194" 1290 | dependencies = [ 1291 | "proc-macro2", 1292 | "quote", 1293 | "unicode-xid", 1294 | ] 1295 | 1296 | [[package]] 1297 | name = "tempfile" 1298 | version = "3.2.0" 1299 | source = "registry+https://github.com/rust-lang/crates.io-index" 1300 | checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" 1301 | dependencies = [ 1302 | "cfg-if", 1303 | "libc", 1304 | "rand", 1305 | "redox_syscall", 1306 | "remove_dir_all", 1307 | "winapi", 1308 | ] 1309 | 1310 | [[package]] 1311 | name = "termcolor" 1312 | version = "1.1.2" 1313 | source = "registry+https://github.com/rust-lang/crates.io-index" 1314 | checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" 1315 | dependencies = [ 1316 | "winapi-util", 1317 | ] 1318 | 1319 | [[package]] 1320 | name = "textwrap" 1321 | version = "0.11.0" 1322 | source = "registry+https://github.com/rust-lang/crates.io-index" 1323 | checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" 1324 | dependencies = [ 1325 | "unicode-width", 1326 | ] 1327 | 1328 | [[package]] 1329 | name = "thiserror" 1330 | version = "1.0.30" 1331 | source = "registry+https://github.com/rust-lang/crates.io-index" 1332 | checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" 1333 | dependencies = [ 1334 | "thiserror-impl", 1335 | ] 1336 | 1337 | [[package]] 1338 | name = "thiserror-impl" 1339 | version = "1.0.30" 1340 | source = "registry+https://github.com/rust-lang/crates.io-index" 1341 | checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" 1342 | dependencies = [ 1343 | "proc-macro2", 1344 | "quote", 1345 | "syn", 1346 | ] 1347 | 1348 | [[package]] 1349 | name = "thread_local" 1350 | version = "1.1.3" 1351 | source = "registry+https://github.com/rust-lang/crates.io-index" 1352 | checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" 1353 | dependencies = [ 1354 | "once_cell", 1355 | ] 1356 | 1357 | [[package]] 1358 | name = "time" 1359 | version = "0.2.27" 1360 | source = "registry+https://github.com/rust-lang/crates.io-index" 1361 | checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" 1362 | dependencies = [ 1363 | "const_fn", 1364 | "libc", 1365 | "standback", 1366 | "stdweb", 1367 | "time-macros", 1368 | "version_check", 1369 | "winapi", 1370 | ] 1371 | 1372 | [[package]] 1373 | name = "time-macros" 1374 | version = "0.1.1" 1375 | source = "registry+https://github.com/rust-lang/crates.io-index" 1376 | checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" 1377 | dependencies = [ 1378 | "proc-macro-hack", 1379 | "time-macros-impl", 1380 | ] 1381 | 1382 | [[package]] 1383 | name = "time-macros-impl" 1384 | version = "0.1.2" 1385 | source = "registry+https://github.com/rust-lang/crates.io-index" 1386 | checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" 1387 | dependencies = [ 1388 | "proc-macro-hack", 1389 | "proc-macro2", 1390 | "quote", 1391 | "standback", 1392 | "syn", 1393 | ] 1394 | 1395 | [[package]] 1396 | name = "tokio" 1397 | version = "1.12.0" 1398 | source = "registry+https://github.com/rust-lang/crates.io-index" 1399 | checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc" 1400 | dependencies = [ 1401 | "autocfg", 1402 | "bytes", 1403 | "libc", 1404 | "memchr", 1405 | "mio", 1406 | "num_cpus", 1407 | "once_cell", 1408 | "pin-project-lite", 1409 | "signal-hook-registry", 1410 | "tokio-macros", 1411 | "winapi", 1412 | ] 1413 | 1414 | [[package]] 1415 | name = "tokio-macros" 1416 | version = "1.5.0" 1417 | source = "registry+https://github.com/rust-lang/crates.io-index" 1418 | checksum = "b2dd85aeaba7b68df939bd357c6afb36c87951be9e80bf9c859f2fc3e9fca0fd" 1419 | dependencies = [ 1420 | "proc-macro2", 1421 | "quote", 1422 | "syn", 1423 | ] 1424 | 1425 | [[package]] 1426 | name = "tokio-stream" 1427 | version = "0.1.7" 1428 | source = "registry+https://github.com/rust-lang/crates.io-index" 1429 | checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f" 1430 | dependencies = [ 1431 | "futures-core", 1432 | "pin-project-lite", 1433 | "tokio", 1434 | ] 1435 | 1436 | [[package]] 1437 | name = "tokio-util" 1438 | version = "0.6.8" 1439 | source = "registry+https://github.com/rust-lang/crates.io-index" 1440 | checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd" 1441 | dependencies = [ 1442 | "bytes", 1443 | "futures-core", 1444 | "futures-sink", 1445 | "log", 1446 | "pin-project-lite", 1447 | "tokio", 1448 | ] 1449 | 1450 | [[package]] 1451 | name = "toml" 1452 | version = "0.5.8" 1453 | source = "registry+https://github.com/rust-lang/crates.io-index" 1454 | checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" 1455 | dependencies = [ 1456 | "serde", 1457 | ] 1458 | 1459 | [[package]] 1460 | name = "tower-service" 1461 | version = "0.3.1" 1462 | source = "registry+https://github.com/rust-lang/crates.io-index" 1463 | checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" 1464 | 1465 | [[package]] 1466 | name = "tracing" 1467 | version = "0.1.29" 1468 | source = "registry+https://github.com/rust-lang/crates.io-index" 1469 | checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" 1470 | dependencies = [ 1471 | "cfg-if", 1472 | "pin-project-lite", 1473 | "tracing-attributes", 1474 | "tracing-core", 1475 | ] 1476 | 1477 | [[package]] 1478 | name = "tracing-attributes" 1479 | version = "0.1.18" 1480 | source = "registry+https://github.com/rust-lang/crates.io-index" 1481 | checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e" 1482 | dependencies = [ 1483 | "proc-macro2", 1484 | "quote", 1485 | "syn", 1486 | ] 1487 | 1488 | [[package]] 1489 | name = "tracing-core" 1490 | version = "0.1.21" 1491 | source = "registry+https://github.com/rust-lang/crates.io-index" 1492 | checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" 1493 | dependencies = [ 1494 | "lazy_static", 1495 | ] 1496 | 1497 | [[package]] 1498 | name = "tracing-log" 1499 | version = "0.1.2" 1500 | source = "registry+https://github.com/rust-lang/crates.io-index" 1501 | checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" 1502 | dependencies = [ 1503 | "lazy_static", 1504 | "log", 1505 | "tracing-core", 1506 | ] 1507 | 1508 | [[package]] 1509 | name = "tracing-serde" 1510 | version = "0.1.2" 1511 | source = "registry+https://github.com/rust-lang/crates.io-index" 1512 | checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b" 1513 | dependencies = [ 1514 | "serde", 1515 | "tracing-core", 1516 | ] 1517 | 1518 | [[package]] 1519 | name = "tracing-subscriber" 1520 | version = "0.2.25" 1521 | source = "registry+https://github.com/rust-lang/crates.io-index" 1522 | checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" 1523 | dependencies = [ 1524 | "ansi_term 0.12.1", 1525 | "chrono", 1526 | "lazy_static", 1527 | "matchers", 1528 | "regex", 1529 | "serde", 1530 | "serde_json", 1531 | "sharded-slab", 1532 | "smallvec", 1533 | "thread_local", 1534 | "tracing", 1535 | "tracing-core", 1536 | "tracing-log", 1537 | "tracing-serde", 1538 | ] 1539 | 1540 | [[package]] 1541 | name = "tracing-tree" 1542 | version = "0.1.10" 1543 | source = "registry+https://github.com/rust-lang/crates.io-index" 1544 | checksum = "4d850f81a21b3877d4360a079c35b7b78f2674f2dafa5c9d381c53c65acebea3" 1545 | dependencies = [ 1546 | "ansi_term 0.12.1", 1547 | "atty", 1548 | "termcolor", 1549 | "tracing-core", 1550 | "tracing-log", 1551 | "tracing-subscriber", 1552 | ] 1553 | 1554 | [[package]] 1555 | name = "try-lock" 1556 | version = "0.2.3" 1557 | source = "registry+https://github.com/rust-lang/crates.io-index" 1558 | checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" 1559 | 1560 | [[package]] 1561 | name = "twoway" 1562 | version = "0.2.2" 1563 | source = "registry+https://github.com/rust-lang/crates.io-index" 1564 | checksum = "c57ffb460d7c24cd6eda43694110189030a3d1dfe418416d9468fd1c1d290b47" 1565 | dependencies = [ 1566 | "memchr", 1567 | "unchecked-index", 1568 | ] 1569 | 1570 | [[package]] 1571 | name = "ubyte" 1572 | version = "0.10.1" 1573 | source = "registry+https://github.com/rust-lang/crates.io-index" 1574 | checksum = "42756bb9e708855de2f8a98195643dff31a97f0485d90d8467b39dc24be9e8fe" 1575 | dependencies = [ 1576 | "serde", 1577 | ] 1578 | 1579 | [[package]] 1580 | name = "uncased" 1581 | version = "0.9.6" 1582 | source = "registry+https://github.com/rust-lang/crates.io-index" 1583 | checksum = "5baeed7327e25054889b9bd4f975f32e5f4c5d434042d59ab6cd4142c0a76ed0" 1584 | dependencies = [ 1585 | "serde", 1586 | "version_check", 1587 | ] 1588 | 1589 | [[package]] 1590 | name = "unchecked-index" 1591 | version = "0.2.2" 1592 | source = "registry+https://github.com/rust-lang/crates.io-index" 1593 | checksum = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c" 1594 | 1595 | [[package]] 1596 | name = "unicode-segmentation" 1597 | version = "1.8.0" 1598 | source = "registry+https://github.com/rust-lang/crates.io-index" 1599 | checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" 1600 | 1601 | [[package]] 1602 | name = "unicode-width" 1603 | version = "0.1.9" 1604 | source = "registry+https://github.com/rust-lang/crates.io-index" 1605 | checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" 1606 | 1607 | [[package]] 1608 | name = "unicode-xid" 1609 | version = "0.2.2" 1610 | source = "registry+https://github.com/rust-lang/crates.io-index" 1611 | checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" 1612 | 1613 | [[package]] 1614 | name = "vec_map" 1615 | version = "0.8.2" 1616 | source = "registry+https://github.com/rust-lang/crates.io-index" 1617 | checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" 1618 | 1619 | [[package]] 1620 | name = "version_check" 1621 | version = "0.9.3" 1622 | source = "registry+https://github.com/rust-lang/crates.io-index" 1623 | checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" 1624 | 1625 | [[package]] 1626 | name = "want" 1627 | version = "0.3.0" 1628 | source = "registry+https://github.com/rust-lang/crates.io-index" 1629 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" 1630 | dependencies = [ 1631 | "log", 1632 | "try-lock", 1633 | ] 1634 | 1635 | [[package]] 1636 | name = "wasi" 1637 | version = "0.10.2+wasi-snapshot-preview1" 1638 | source = "registry+https://github.com/rust-lang/crates.io-index" 1639 | checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" 1640 | 1641 | [[package]] 1642 | name = "wasm-bindgen" 1643 | version = "0.2.78" 1644 | source = "registry+https://github.com/rust-lang/crates.io-index" 1645 | checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" 1646 | dependencies = [ 1647 | "cfg-if", 1648 | "wasm-bindgen-macro", 1649 | ] 1650 | 1651 | [[package]] 1652 | name = "wasm-bindgen-backend" 1653 | version = "0.2.78" 1654 | source = "registry+https://github.com/rust-lang/crates.io-index" 1655 | checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" 1656 | dependencies = [ 1657 | "bumpalo", 1658 | "lazy_static", 1659 | "log", 1660 | "proc-macro2", 1661 | "quote", 1662 | "syn", 1663 | "wasm-bindgen-shared", 1664 | ] 1665 | 1666 | [[package]] 1667 | name = "wasm-bindgen-macro" 1668 | version = "0.2.78" 1669 | source = "registry+https://github.com/rust-lang/crates.io-index" 1670 | checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" 1671 | dependencies = [ 1672 | "quote", 1673 | "wasm-bindgen-macro-support", 1674 | ] 1675 | 1676 | [[package]] 1677 | name = "wasm-bindgen-macro-support" 1678 | version = "0.2.78" 1679 | source = "registry+https://github.com/rust-lang/crates.io-index" 1680 | checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" 1681 | dependencies = [ 1682 | "proc-macro2", 1683 | "quote", 1684 | "syn", 1685 | "wasm-bindgen-backend", 1686 | "wasm-bindgen-shared", 1687 | ] 1688 | 1689 | [[package]] 1690 | name = "wasm-bindgen-shared" 1691 | version = "0.2.78" 1692 | source = "registry+https://github.com/rust-lang/crates.io-index" 1693 | checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" 1694 | 1695 | [[package]] 1696 | name = "winapi" 1697 | version = "0.3.9" 1698 | source = "registry+https://github.com/rust-lang/crates.io-index" 1699 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1700 | dependencies = [ 1701 | "winapi-i686-pc-windows-gnu", 1702 | "winapi-x86_64-pc-windows-gnu", 1703 | ] 1704 | 1705 | [[package]] 1706 | name = "winapi-i686-pc-windows-gnu" 1707 | version = "0.4.0" 1708 | source = "registry+https://github.com/rust-lang/crates.io-index" 1709 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1710 | 1711 | [[package]] 1712 | name = "winapi-util" 1713 | version = "0.1.5" 1714 | source = "registry+https://github.com/rust-lang/crates.io-index" 1715 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 1716 | dependencies = [ 1717 | "winapi", 1718 | ] 1719 | 1720 | [[package]] 1721 | name = "winapi-x86_64-pc-windows-gnu" 1722 | version = "0.4.0" 1723 | source = "registry+https://github.com/rust-lang/crates.io-index" 1724 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1725 | 1726 | [[package]] 1727 | name = "yansi" 1728 | version = "0.5.0" 1729 | source = "registry+https://github.com/rust-lang/crates.io-index" 1730 | checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71" 1731 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "roogle", 4 | "roogle-engine", 5 | "roogle-util", 6 | ] 7 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:latest AS chef 2 | RUN cargo install cargo-chef 3 | WORKDIR /usr/src/roogle 4 | 5 | FROM chef AS planner 6 | COPY . . 7 | RUN cargo chef prepare --recipe-path recipe.json 8 | 9 | FROM chef AS builder 10 | COPY --from=planner /usr/src/roogle/recipe.json recipe.json 11 | RUN cargo chef cook --release --recipe-path recipe.json 12 | COPY . . 13 | RUN cargo build --release 14 | 15 | FROM debian:buster-slim AS runtime 16 | WORKDIR /usr/src/roogle 17 | COPY --from=builder /usr/src/roogle/target/release/roogle /usr/local/bin 18 | COPY --from=builder /usr/src/roogle/roogle-index roogle-index 19 | 20 | ARG ROCKET_ADDRESS=0.0.0.0 21 | ENV ROCKET_ADDRESS=${ROCKET_ADDRESS} 22 | 23 | CMD ["/usr/local/bin/roogle"] 24 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Hirochika Matsumoto 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Roogle 2 | Roogle is a Rust API search engine, which allows you to search functions by names and type signatures. 3 | 4 | ## Progress 5 | 6 | ### Available Queries 7 | - [x] Function queries 8 | - [x] Method queries 9 | 10 | ### Available Types to Query 11 | - [x] Primitive types 12 | - [ ] Generic types 13 | - [x] Without bounds and where predicates (e.g., ``) 14 | - [ ] With bounds (e.g., ``) 15 | - [ ] With where predicates 16 | - [x] Custom types 17 | - [x] Without generic args (e.g., `IpAddr`) 18 | - [x] With generic args (e.g., `Vec`, `Option`) 19 | - [ ] Other types 20 | 21 | ## Example 22 | ```sh 23 | $ cargo r --release 24 | # Then, on another shell session, run: 25 | $ curl -X GET \ 26 | -d "fn (Option>) -> Result, E>>" \ 27 | "localhost:8000/search?scope=set:libstd" 28 | ``` 29 | 30 | ## Example with Docker 31 | ```sh 32 | $ docker-compose up 33 | # Then, on another shell session, run: 34 | $ curl -X GET \ 35 | -d "fn (Option>) -> Result, E>>" \ 36 | "localhost:8000/search?scope=set:libstd" 37 | ``` 38 | 39 | ## Related Project 40 | - [cargo-roogle](https://github.com/roogle-rs/cargo-roogle) 41 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | roogle: 5 | build: . 6 | ports: 7 | - "8000:8000" 8 | -------------------------------------------------------------------------------- /roogle-engine/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "roogle-engine" 3 | version = "1.0.2" 4 | authors = ["Hirochika Matsumoto "] 5 | edition = "2021" 6 | description = "A Rust API search engine" 7 | documentation = "https://docs.rs/roogle-engine" 8 | readme = "../README.md" 9 | homepage = "https://roogle.hkmatsumoto.com" 10 | repository = "https://github.com/roogle-rs/roogle" 11 | license = "MIT OR Apache-2.0" 12 | 13 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 14 | 15 | [dependencies] 16 | levenshtein = "1.0" 17 | nom = "7.0" 18 | rustdoc-types = "0.5.0" 19 | serde = { version = "1.0", features = ["derive"] } 20 | serde_json = { version = "1.0", features = ["unbounded_depth"] } 21 | thiserror = "1.0" 22 | tracing = "0.1" 23 | -------------------------------------------------------------------------------- /roogle-engine/src/compare.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | cmp::{max, min}, 3 | collections::HashMap, 4 | }; 5 | 6 | use levenshtein::levenshtein; 7 | use rustdoc_types as types; 8 | use tracing::{instrument, trace}; 9 | 10 | use crate::query::*; 11 | 12 | #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] 13 | pub enum Similarity { 14 | /// Represents how digitally similar two objects are. 15 | Discrete(DiscreteSimilarity), 16 | 17 | /// Represents how analogly similar two objects are. 18 | Continuous(f32), 19 | } 20 | 21 | impl Similarity { 22 | pub fn score(&self) -> f32 { 23 | match self { 24 | Discrete(Equivalent) => 0.0, 25 | Discrete(Subequal) => 0.25, 26 | Discrete(Different) => 1.0, 27 | Continuous(s) => *s, 28 | } 29 | } 30 | } 31 | 32 | use Similarity::*; 33 | 34 | #[derive(Debug, Clone, PartialEq)] 35 | pub struct Similarities(pub Vec); 36 | 37 | impl Similarities { 38 | /// Calculate objective similarity for sorting. 39 | pub fn score(&self) -> f32 { 40 | let sum: f32 = self.0.iter().map(|sim| sim.score()).sum(); 41 | sum / self.0.len() as f32 42 | } 43 | } 44 | 45 | impl PartialOrd for Similarities { 46 | fn partial_cmp(&self, other: &Self) -> Option { 47 | (self.score()).partial_cmp(&other.score()) 48 | } 49 | } 50 | 51 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] 52 | pub enum DiscreteSimilarity { 53 | /// Indicates that two types are the same. 54 | /// 55 | /// For example: 56 | /// - `i32` and `i32` 57 | /// - `Result` and `Result` 58 | Equivalent, 59 | 60 | /// Indicates that two types are partially equal. 61 | /// 62 | /// For example: 63 | /// - an unbound generic type `T` and `i32` 64 | /// - an unbound generic type `T` and `Option` 65 | Subequal, 66 | 67 | /// Indicates that two types are not similar at all. 68 | /// 69 | /// For example: 70 | /// - `i32` and `Option` 71 | Different, 72 | } 73 | 74 | use DiscreteSimilarity::*; 75 | 76 | pub trait Compare { 77 | fn compare( 78 | &self, 79 | rhs: &Rhs, 80 | krate: &types::Crate, 81 | generics: &mut types::Generics, 82 | substs: &mut HashMap, 83 | ) -> Vec; 84 | } 85 | 86 | impl Compare for Query { 87 | #[instrument(skip(krate))] 88 | fn compare( 89 | &self, 90 | item: &types::Item, 91 | krate: &types::Crate, 92 | generics: &mut types::Generics, 93 | substs: &mut HashMap, 94 | ) -> Vec { 95 | let mut sims = vec![]; 96 | 97 | match (&self.name, &item.name) { 98 | (Some(q), Some(i)) => sims.append(&mut q.compare(i, krate, generics, substs)), 99 | (Some(_), None) => sims.push(Discrete(Different)), 100 | _ => {} 101 | } 102 | trace!(?sims); 103 | 104 | if let Some(ref kind) = self.kind { 105 | sims.append(&mut kind.compare(&item.inner, krate, generics, substs)) 106 | } 107 | trace!(?sims); 108 | 109 | sims 110 | } 111 | } 112 | 113 | impl Compare for Symbol { 114 | #[instrument] 115 | fn compare( 116 | &self, 117 | symbol: &String, 118 | _: &types::Crate, 119 | _: &mut types::Generics, 120 | _: &mut HashMap, 121 | ) -> Vec { 122 | use std::cmp::max; 123 | 124 | let symbol = symbol.split("::").last().unwrap(); // SAFETY: `symbol` is not empty. 125 | vec![Continuous( 126 | levenshtein(self, symbol) as f32 / max(self.len(), symbol.len()) as f32, 127 | )] 128 | } 129 | } 130 | 131 | impl Compare for QueryKind { 132 | #[instrument(skip(krate))] 133 | fn compare( 134 | &self, 135 | kind: &types::ItemEnum, 136 | krate: &types::Crate, 137 | generics: &mut types::Generics, 138 | substs: &mut HashMap, 139 | ) -> Vec { 140 | use types::ItemEnum::*; 141 | use QueryKind::*; 142 | 143 | match (self, kind) { 144 | (FunctionQuery(q), Function(i)) => q.compare(i, krate, generics, substs), 145 | (FunctionQuery(q), Method(i)) => q.compare(i, krate, generics, substs), 146 | (FunctionQuery(_), _) => vec![Discrete(Different)], 147 | } 148 | } 149 | } 150 | 151 | impl Compare for Function { 152 | #[instrument(skip(krate))] 153 | fn compare( 154 | &self, 155 | function: &types::Function, 156 | krate: &types::Crate, 157 | generics: &mut types::Generics, 158 | substs: &mut HashMap, 159 | ) -> Vec { 160 | generics 161 | .params 162 | .append(&mut function.generics.params.clone()); 163 | generics 164 | .where_predicates 165 | .append(&mut function.generics.where_predicates.clone()); 166 | self.decl.compare(&function.decl, krate, generics, substs) 167 | } 168 | } 169 | 170 | impl Compare for Function { 171 | #[instrument(skip(krate))] 172 | fn compare( 173 | &self, 174 | method: &types::Method, 175 | krate: &types::Crate, 176 | generics: &mut types::Generics, 177 | substs: &mut HashMap, 178 | ) -> Vec { 179 | generics.params.append(&mut method.generics.params.clone()); 180 | generics 181 | .where_predicates 182 | .append(&mut method.generics.where_predicates.clone()); 183 | self.decl.compare(&method.decl, krate, generics, substs) 184 | } 185 | } 186 | 187 | impl Compare for FnDecl { 188 | #[instrument(skip(krate))] 189 | fn compare( 190 | &self, 191 | decl: &types::FnDecl, 192 | krate: &types::Crate, 193 | generics: &mut types::Generics, 194 | substs: &mut HashMap, 195 | ) -> Vec { 196 | let mut sims = vec![]; 197 | 198 | if let Some(ref inputs) = self.inputs { 199 | inputs.iter().enumerate().for_each(|(idx, q)| { 200 | if let Some(i) = decl.inputs.get(idx) { 201 | sims.append(&mut q.compare(i, krate, generics, substs)) 202 | } 203 | }); 204 | 205 | if inputs.len() != decl.inputs.len() { 206 | // FIXME: Replace this line below with `usize::abs_diff` once it got stablized. 207 | let abs_diff = 208 | max(inputs.len(), decl.inputs.len()) - min(inputs.len(), decl.inputs.len()); 209 | sims.append(&mut vec![Discrete(Different); abs_diff]) 210 | } else if inputs.is_empty() && decl.inputs.is_empty() { 211 | sims.push(Discrete(Equivalent)); 212 | } 213 | } 214 | trace!(?sims); 215 | 216 | if let Some(ref output) = self.output { 217 | sims.append(&mut output.compare(&decl.output, krate, generics, substs)); 218 | } 219 | trace!(?sims); 220 | 221 | sims 222 | } 223 | } 224 | 225 | impl Compare<(String, types::Type)> for Argument { 226 | #[instrument(skip(krate))] 227 | fn compare( 228 | &self, 229 | arg: &(String, types::Type), 230 | krate: &types::Crate, 231 | generics: &mut types::Generics, 232 | substs: &mut HashMap, 233 | ) -> Vec { 234 | let mut sims = vec![]; 235 | 236 | if let Some(ref name) = self.name { 237 | sims.append(&mut name.compare(&arg.0, krate, generics, substs)); 238 | } 239 | trace!(?sims); 240 | 241 | if let Some(ref type_) = self.ty { 242 | sims.append(&mut type_.compare(&arg.1, krate, generics, substs)); 243 | } 244 | trace!(?sims); 245 | 246 | sims 247 | } 248 | } 249 | 250 | impl Compare> for FnRetTy { 251 | #[instrument(skip(krate))] 252 | fn compare( 253 | &self, 254 | ret_ty: &Option, 255 | krate: &types::Crate, 256 | generics: &mut types::Generics, 257 | substs: &mut HashMap, 258 | ) -> Vec { 259 | match (self, ret_ty) { 260 | (FnRetTy::Return(q), Some(i)) => q.compare(i, krate, generics, substs), 261 | (FnRetTy::DefaultReturn, None) => vec![Discrete(Equivalent)], 262 | _ => vec![Discrete(Different)], 263 | } 264 | } 265 | } 266 | 267 | fn compare_type( 268 | lhs: &Type, 269 | rhs: &types::Type, 270 | krate: &types::Crate, 271 | generics: &mut types::Generics, 272 | substs: &mut HashMap, 273 | allow_recursion: bool, 274 | ) -> Vec { 275 | use {crate::query::Type::*, types::Type}; 276 | 277 | match (lhs, rhs) { 278 | (q, Type::Generic(i)) if i == "Self" => { 279 | let mut i = None; 280 | for where_predicate in &generics.where_predicates { 281 | if let types::WherePredicate::EqPredicate { 282 | lhs: Type::Generic(lhs), 283 | rhs, 284 | } = where_predicate 285 | { 286 | if lhs == "Self" { 287 | i = Some(rhs).cloned(); 288 | break; 289 | } 290 | } 291 | } 292 | let i = &i.unwrap(); // SAFETY: `Self` only appears in definitions of associated items. 293 | q.compare(i, krate, generics, substs) 294 | } 295 | (q, Type::Generic(i)) => match substs.get(i) { 296 | Some(i) => { 297 | if q == i { 298 | vec![Discrete(Equivalent)] 299 | } else { 300 | vec![Discrete(Different)] 301 | } 302 | } 303 | None => { 304 | substs.insert(i.clone(), q.clone()); 305 | vec![Discrete(Subequal)] 306 | } 307 | }, 308 | (q, Type::ResolvedPath { id, .. }) 309 | if krate 310 | .index 311 | .get(id) 312 | .map(|i| matches!(i.inner, types::ItemEnum::Typedef(_))) 313 | .unwrap_or(false) 314 | && allow_recursion => 315 | { 316 | let sims_typedef = compare_type(lhs, rhs, krate, generics, substs, false); 317 | if let Some(types::Item { 318 | inner: types::ItemEnum::Typedef(types::Typedef { type_: ref i, .. }), 319 | .. 320 | }) = krate.index.get(id) 321 | { 322 | // TODO: Acknowledge `generics` of `types::Typedef` to get more accurate search results. 323 | let sims_adt = q.compare(i, krate, generics, substs); 324 | let sum = 325 | |sims: &Vec| -> f32 { sims.iter().map(Similarity::score).sum() }; 326 | if sum(&sims_adt) < sum(&sims_typedef) { 327 | return sims_adt; 328 | } 329 | } 330 | sims_typedef 331 | } 332 | (Tuple(q), Type::Tuple(i)) => { 333 | let mut sims = q 334 | .iter() 335 | .zip(i.iter()) 336 | .filter_map(|(q, i)| q.as_ref().map(|q| q.compare(i, krate, generics, substs))) 337 | .flatten() 338 | .collect::>(); 339 | 340 | // They are both tuples. 341 | sims.push(Discrete(Equivalent)); 342 | 343 | // FIXME: Replace this line below with `usize::abs_diff` once it got stablized. 344 | let abs_diff = max(q.len(), i.len()) - min(q.len(), i.len()); 345 | sims.append(&mut vec![Discrete(Different); abs_diff]); 346 | 347 | sims 348 | } 349 | (Slice(q), Type::Slice(i)) => { 350 | // They are both slices. 351 | let mut sims = vec![Discrete(Equivalent)]; 352 | 353 | if let Some(q) = q { 354 | sims.append(&mut q.compare(i, krate, generics, substs)); 355 | } 356 | 357 | sims 358 | } 359 | ( 360 | RawPointer { 361 | mutable: q_mut, 362 | type_: q, 363 | }, 364 | Type::RawPointer { 365 | mutable: i_mut, 366 | type_: i, 367 | }, 368 | ) 369 | | ( 370 | BorrowedRef { 371 | mutable: q_mut, 372 | type_: q, 373 | }, 374 | Type::BorrowedRef { 375 | mutable: i_mut, 376 | type_: i, 377 | .. 378 | }, 379 | ) => { 380 | if q_mut == i_mut { 381 | q.compare(i, krate, generics, substs) 382 | } else { 383 | let mut sims = q.compare(i, krate, generics, substs); 384 | sims.push(Discrete(Subequal)); 385 | sims 386 | } 387 | } 388 | (q, Type::RawPointer { type_: i, .. } | Type::BorrowedRef { type_: i, .. }) => { 389 | let mut sims = q.compare(i, krate, generics, substs); 390 | sims.push(Discrete(Subequal)); 391 | sims 392 | } 393 | (RawPointer { type_: q, .. } | BorrowedRef { type_: q, .. }, i) => { 394 | let mut sims = q.compare(i, krate, generics, substs); 395 | sims.push(Discrete(Subequal)); 396 | sims 397 | } 398 | ( 399 | UnresolvedPath { 400 | name: q, 401 | args: q_args, 402 | }, 403 | Type::ResolvedPath { 404 | name: i, 405 | args: i_args, 406 | .. 407 | }, 408 | ) => { 409 | let mut sims = q.compare(i, krate, generics, substs); 410 | 411 | match (q_args, i_args) { 412 | (Some(q), Some(i)) => match (&**q, &**i) { 413 | ( 414 | GenericArgs::AngleBracketed { args: ref q }, 415 | types::GenericArgs::AngleBracketed { args: ref i, .. }, 416 | ) => { 417 | let q = q.iter().map(|q| { 418 | q.as_ref().map(|q| match q { 419 | GenericArg::Type(q) => q, 420 | }) 421 | }); 422 | let i = i.iter().map(|i| match i { 423 | types::GenericArg::Type(t) => Some(t), 424 | _ => None, 425 | }); 426 | q.zip(i).for_each(|(q, i)| match (q, i) { 427 | (Some(q), Some(i)) => { 428 | sims.append(&mut q.compare(i, krate, generics, substs)) 429 | } 430 | (Some(_), None) => sims.push(Discrete(Different)), 431 | (None, _) => {} 432 | }); 433 | } 434 | // TODO: Support `GenericArgs::Parenthesized`. 435 | (_, _) => {} 436 | }, 437 | (Some(q), None) => { 438 | let GenericArgs::AngleBracketed { args: ref q } = **q; 439 | sims.append(&mut vec![Discrete(Different); q.len()]) 440 | } 441 | (None, _) => {} 442 | } 443 | 444 | sims 445 | } 446 | (Primitive(q), Type::Primitive(i)) => q.compare(i, krate, generics, substs), 447 | _ => vec![Discrete(Different)], 448 | } 449 | } 450 | 451 | impl Compare for Type { 452 | #[instrument(skip(krate))] 453 | fn compare( 454 | &self, 455 | type_: &types::Type, 456 | krate: &types::Crate, 457 | generics: &mut types::Generics, 458 | substs: &mut HashMap, 459 | ) -> Vec { 460 | compare_type(self, type_, krate, generics, substs, true) 461 | } 462 | } 463 | 464 | impl Compare for PrimitiveType { 465 | #[instrument] 466 | fn compare( 467 | &self, 468 | prim_ty: &String, 469 | _: &types::Crate, 470 | _: &mut types::Generics, 471 | _: &mut HashMap, 472 | ) -> Vec { 473 | if self.as_str() == prim_ty { 474 | vec![Discrete(Equivalent)] 475 | } else { 476 | vec![Discrete(Different)] 477 | } 478 | } 479 | } 480 | -------------------------------------------------------------------------------- /roogle-engine/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod compare; 2 | pub mod query; 3 | pub mod search; 4 | 5 | use std::collections::HashMap; 6 | 7 | use rustdoc_types::Crate; 8 | 9 | #[derive(Debug, Default)] 10 | pub struct Index { 11 | pub crates: HashMap, 12 | } 13 | -------------------------------------------------------------------------------- /roogle-engine/src/query/mod.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | pub mod parse; 4 | 5 | #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] 6 | pub struct Item { 7 | pub path: Vec, 8 | pub link: Vec, 9 | pub docs: Option, 10 | } 11 | 12 | #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] 13 | pub struct Query { 14 | pub name: Option, 15 | pub kind: Option, 16 | } 17 | 18 | impl Query { 19 | pub fn args(&self) -> Option> { 20 | self.kind 21 | .as_ref() 22 | .map(|kind| { 23 | let QueryKind::FunctionQuery(f) = kind; 24 | &f.decl 25 | }) 26 | .and_then(|decl| decl.inputs.clone()) 27 | } 28 | } 29 | 30 | #[non_exhaustive] 31 | #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] 32 | pub enum QueryKind { 33 | FunctionQuery(Function), 34 | } 35 | 36 | #[non_exhaustive] 37 | #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] 38 | pub struct Function { 39 | pub decl: FnDecl, 40 | // pub generics: Generics, 41 | } 42 | 43 | #[non_exhaustive] 44 | #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] 45 | pub enum GenericArgs { 46 | AngleBracketed { 47 | args: Vec>, /* bindings: Vec */ 48 | }, 49 | // Parenthesized { inputs: Vec, output: Option }, 50 | } 51 | 52 | #[non_exhaustive] 53 | #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] 54 | pub enum GenericArg { 55 | // Lifetime(String), 56 | Type(Type), 57 | // Const(Constant), 58 | } 59 | #[non_exhaustive] 60 | #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] 61 | pub struct FnDecl { 62 | pub inputs: Option>, 63 | pub output: Option, 64 | // pub c_variadic: bool, 65 | } 66 | 67 | #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] 68 | pub struct Argument { 69 | pub ty: Option, 70 | pub name: Option, 71 | } 72 | 73 | #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] 74 | pub enum FnRetTy { 75 | Return(Type), 76 | DefaultReturn, 77 | } 78 | 79 | pub type Symbol = String; 80 | 81 | #[non_exhaustive] 82 | #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] 83 | pub enum Type { 84 | // FIXME: Give `UnresolvedPath` a better name. 85 | UnresolvedPath { 86 | name: Symbol, 87 | args: Option>, 88 | }, 89 | Generic(String), 90 | Primitive(PrimitiveType), 91 | Tuple(Vec>), 92 | Slice(Option>), 93 | Never, 94 | RawPointer { 95 | mutable: bool, 96 | type_: Box, 97 | }, 98 | BorrowedRef { 99 | mutable: bool, 100 | type_: Box, 101 | }, 102 | } 103 | 104 | impl Type { 105 | pub fn inner_type(&self) -> &Self { 106 | match self { 107 | Type::RawPointer { type_, .. } => type_.inner_type(), 108 | Type::BorrowedRef { type_, .. } => type_.inner_type(), 109 | _ => self, 110 | } 111 | } 112 | } 113 | 114 | /// N.B. this has to be different from `hir::PrimTy` because it also includes types that aren't 115 | /// paths, like `Unit`. 116 | #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] 117 | pub enum PrimitiveType { 118 | Isize, 119 | I8, 120 | I16, 121 | I32, 122 | I64, 123 | I128, 124 | Usize, 125 | U8, 126 | U16, 127 | U32, 128 | U64, 129 | U128, 130 | F32, 131 | F64, 132 | Char, 133 | Bool, 134 | Str, 135 | Unit, 136 | Never, 137 | } 138 | 139 | impl PrimitiveType { 140 | pub fn as_str(&self) -> &str { 141 | use PrimitiveType::*; 142 | match self { 143 | Isize => "isize", 144 | I8 => "i8", 145 | I16 => "i16", 146 | I32 => "i32", 147 | I64 => "i64", 148 | I128 => "i128", 149 | Usize => "usize", 150 | U8 => "u8", 151 | U16 => "u16", 152 | U32 => "u32", 153 | U64 => "u64", 154 | U128 => "u128", 155 | F32 => "f32", 156 | F64 => "f64", 157 | Char => "char", 158 | Bool => "bool", 159 | Str => "str", 160 | Unit => "unit", 161 | Never => "never", 162 | } 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /roogle-engine/src/query/parse.rs: -------------------------------------------------------------------------------- 1 | use nom::{ 2 | branch::alt, 3 | bytes::complete::{tag, take_while1}, 4 | character::complete::char, 5 | character::complete::{alpha1, alphanumeric1, multispace0, multispace1}, 6 | combinator::{eof, fail, map, not, opt, recognize, value}, 7 | error::{ContextError, ParseError}, 8 | multi::{many0, separated_list0}, 9 | sequence::{delimited, pair, preceded}, 10 | IResult, 11 | }; 12 | 13 | use crate::query::*; 14 | 15 | type Symbol = String; 16 | 17 | pub fn parse_query(i: &str) -> IResult<&str, Query> { 18 | parse_function_query(i) 19 | } 20 | 21 | fn parse_symbol<'a, E>(i: &'a str) -> IResult<&'a str, Symbol, E> 22 | where 23 | E: ParseError<&'a str> + ContextError<&'a str>, 24 | { 25 | map( 26 | recognize(pair( 27 | alt((tag("_"), alpha1)), 28 | many0(alt((tag("_"), alphanumeric1))), 29 | )), 30 | |symbol: &str| symbol.to_string(), 31 | )(i) 32 | } 33 | 34 | fn parse_function_query<'a, E>(i: &'a str) -> IResult<&'a str, Query, E> 35 | where 36 | E: ParseError<&'a str> + ContextError<&'a str>, 37 | { 38 | let (i, f) = opt(tag("fn"))(i)?; 39 | let (i, _) = match f { 40 | Some(_) => multispace1(i)?, 41 | None => multispace0(i)?, 42 | }; 43 | let (i, name) = opt(parse_symbol)(i)?; 44 | let (i, decl) = opt(parse_function)(i)?; 45 | 46 | let query = Query { 47 | name, 48 | kind: decl.map(QueryKind::FunctionQuery), 49 | }; 50 | Ok((i, query)) 51 | } 52 | 53 | fn parse_function<'a, E>(i: &'a str) -> IResult<&'a str, Function, E> 54 | where 55 | E: ParseError<&'a str> + ContextError<&'a str>, 56 | { 57 | let (i, decl) = parse_function_decl(i)?; 58 | 59 | let function = Function { decl }; 60 | Ok((i, function)) 61 | } 62 | 63 | fn parse_function_decl<'a, E>(i: &'a str) -> IResult<&'a str, FnDecl, E> 64 | where 65 | E: ParseError<&'a str> + ContextError<&'a str>, 66 | { 67 | let (i, inputs) = delimited( 68 | char('('), 69 | alt(( 70 | value(None, tag("..")), 71 | opt(parse_arguments), 72 | value(Some(Vec::new()), not(eof)), 73 | )), 74 | char(')'), 75 | )(i)?; 76 | let (i, output) = opt(parse_output)(i)?; 77 | 78 | let decl = FnDecl { inputs, output }; 79 | Ok((i, decl)) 80 | } 81 | 82 | fn parse_arguments<'a, E>(i: &'a str) -> IResult<&'a str, Vec, E> 83 | where 84 | E: ParseError<&'a str> + ContextError<&'a str>, 85 | { 86 | separated_list0( 87 | char(','), 88 | preceded( 89 | multispace0, 90 | alt(( 91 | parse_argument, 92 | value( 93 | Argument { 94 | ty: None, 95 | name: None, 96 | }, 97 | char('_'), 98 | ), 99 | map(parse_type, |ty| Argument { 100 | ty: Some(ty), 101 | name: None, 102 | }), 103 | )), 104 | ), 105 | )(i) 106 | } 107 | 108 | fn parse_argument<'a, E>(i: &'a str) -> IResult<&'a str, Argument, E> 109 | where 110 | E: ParseError<&'a str> + ContextError<&'a str>, 111 | { 112 | let (i, name) = alt((value(None, char('_')), opt(parse_symbol)))(i)?; 113 | let (i, _) = char(':')(i)?; 114 | let (i, _) = multispace0(i)?; 115 | let (i, ty) = alt((value(None, char('_')), opt(parse_type)))(i)?; 116 | 117 | let arg = Argument { ty, name }; 118 | Ok((i, arg)) 119 | } 120 | 121 | fn parse_output<'a, E>(i: &'a str) -> IResult<&'a str, FnRetTy, E> 122 | where 123 | E: ParseError<&'a str> + ContextError<&'a str>, 124 | { 125 | preceded( 126 | multispace0, 127 | alt(( 128 | value( 129 | FnRetTy::DefaultReturn, 130 | preceded(preceded(tag("->"), multispace0), tag("()")), 131 | ), 132 | map(preceded(tag("->"), parse_type), FnRetTy::Return), 133 | value(FnRetTy::DefaultReturn, eof), 134 | )), 135 | )(i) 136 | } 137 | 138 | fn parse_type<'a, E>(i: &'a str) -> IResult<&'a str, Type, E> 139 | where 140 | E: ParseError<&'a str> + ContextError<&'a str>, 141 | { 142 | preceded( 143 | multispace0, 144 | alt(( 145 | map(parse_primitive_type, Type::Primitive), 146 | parse_generic_type, 147 | parse_unresolved_path, 148 | parse_tuple, 149 | parse_slice, 150 | value(Type::Never, char('!')), 151 | parse_raw_pointer, 152 | parse_borrowed_ref, 153 | )), 154 | )(i) 155 | } 156 | 157 | fn parse_tuple<'a, E>(i: &'a str) -> IResult<&'a str, Type, E> 158 | where 159 | E: ParseError<&'a str> + ContextError<&'a str>, 160 | { 161 | map( 162 | delimited( 163 | char('('), 164 | separated_list0( 165 | char(','), 166 | preceded( 167 | multispace0, 168 | alt((value(None, tag("_")), map(parse_type, Some))), 169 | ), 170 | ), 171 | char(')'), 172 | ), 173 | Type::Tuple, 174 | )(i) 175 | } 176 | 177 | fn parse_slice<'a, E>(i: &'a str) -> IResult<&'a str, Type, E> 178 | where 179 | E: ParseError<&'a str> + ContextError<&'a str>, 180 | { 181 | map( 182 | delimited( 183 | char('['), 184 | alt((value(None, tag("_")), map(parse_type, Some))), 185 | char(']'), 186 | ), 187 | |ty| Type::Slice(ty.map(Box::new)), 188 | )(i) 189 | } 190 | 191 | fn parse_raw_pointer<'a, E>(i: &'a str) -> IResult<&'a str, Type, E> 192 | where 193 | E: ParseError<&'a str> + ContextError<&'a str>, 194 | { 195 | let (i, mutable) = alt((value(true, tag("*mut")), value(false, tag("*const"))))(i)?; 196 | let (i, type_) = parse_type(i)?; 197 | 198 | Ok(( 199 | i, 200 | Type::RawPointer { 201 | mutable, 202 | type_: Box::new(type_), 203 | }, 204 | )) 205 | } 206 | 207 | fn parse_borrowed_ref<'a, E>(i: &'a str) -> IResult<&'a str, Type, E> 208 | where 209 | E: ParseError<&'a str> + ContextError<&'a str>, 210 | { 211 | let (i, mutable) = alt((value(true, tag("&mut")), value(false, tag("&"))))(i)?; 212 | let (i, type_) = parse_type(i)?; 213 | 214 | Ok(( 215 | i, 216 | Type::BorrowedRef { 217 | mutable, 218 | type_: Box::new(type_), 219 | }, 220 | )) 221 | } 222 | 223 | fn parse_unresolved_path<'a, E>(i: &'a str) -> IResult<&'a str, Type, E> 224 | where 225 | E: ParseError<&'a str> + ContextError<&'a str>, 226 | { 227 | let (i, name) = parse_symbol(i)?; 228 | let (i, args) = opt(parse_generic_args)(i)?; 229 | 230 | Ok(( 231 | i, 232 | Type::UnresolvedPath { 233 | name, 234 | args: args.map(Box::new), 235 | }, 236 | )) 237 | } 238 | 239 | fn parse_generic_args<'a, E>(i: &'a str) -> IResult<&'a str, GenericArgs, E> 240 | where 241 | E: ParseError<&'a str> + ContextError<&'a str>, 242 | { 243 | map( 244 | delimited( 245 | char('<'), 246 | separated_list0( 247 | char(','), 248 | preceded( 249 | multispace0, 250 | alt(( 251 | value(None, tag("_")), 252 | opt(map(parse_type, GenericArg::Type)), 253 | )), 254 | ), 255 | ), 256 | char('>'), 257 | ), 258 | |args| GenericArgs::AngleBracketed { args }, 259 | )(i) 260 | } 261 | 262 | fn parse_generic_type<'a, E>(i: &'a str) -> IResult<&'a str, Type, E> 263 | where 264 | E: ParseError<&'a str> + ContextError<&'a str>, 265 | { 266 | let (i, gen) = map(take_while1(|c: char| c.is_ascii_uppercase()), |s: &str| { 267 | Type::Generic(s.to_owned()) 268 | })(i)?; 269 | 270 | if i.chars().next().map_or(false, |c| c.is_ascii_lowercase()) { 271 | fail(i) 272 | } else { 273 | Ok((i, gen)) 274 | } 275 | } 276 | 277 | fn parse_primitive_type<'a, E>(i: &'a str) -> IResult<&'a str, PrimitiveType, E> 278 | where 279 | E: ParseError<&'a str> + ContextError<&'a str>, 280 | { 281 | use PrimitiveType::*; 282 | alt(( 283 | value(Isize, tag("isize")), 284 | value(I8, tag("i8")), 285 | value(I16, tag("i16")), 286 | value(I32, tag("i32")), 287 | value(I64, tag("i64")), 288 | value(I128, tag("i128")), 289 | value(Usize, tag("usize")), 290 | value(U8, tag("u8")), 291 | value(U16, tag("u16")), 292 | value(U32, tag("u32")), 293 | value(U64, tag("u64")), 294 | value(U128, tag("u128")), 295 | value(F32, tag("f32")), 296 | value(F64, tag("f64")), 297 | value(Char, tag("char")), 298 | value(Bool, tag("bool")), 299 | value(Str, tag("str")), 300 | ))(i) 301 | } 302 | -------------------------------------------------------------------------------- /roogle-engine/src/search.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use rustdoc_types as types; 4 | use serde::Serialize; 5 | use thiserror::Error; 6 | 7 | use crate::{ 8 | compare::{Compare, Similarities}, 9 | query::Query, 10 | Index, 11 | }; 12 | 13 | #[derive(Debug, Clone, PartialEq, Serialize)] 14 | pub struct Hit { 15 | pub name: String, 16 | pub path: Vec, 17 | pub link: Vec, 18 | pub docs: Option, 19 | #[serde(skip)] 20 | similarities: Similarities, 21 | } 22 | 23 | impl Hit { 24 | pub fn similarities(&self) -> &Similarities { 25 | &self.similarities 26 | } 27 | } 28 | 29 | impl PartialOrd for Hit { 30 | fn partial_cmp(&self, other: &Self) -> Option { 31 | self.similarities.partial_cmp(&other.similarities) 32 | } 33 | } 34 | 35 | #[derive(Error, Debug)] 36 | pub enum SearchError { 37 | #[error("crate `{0}` is not present in the index")] 38 | CrateNotFound(String), 39 | 40 | #[error("item with id `{0}` is not present in crate `{1}`")] 41 | ItemNotFound(String, String), 42 | } 43 | 44 | pub type Result = std::result::Result; 45 | 46 | /// Represents a scope to search in. 47 | #[derive(Debug, Clone, Serialize)] 48 | pub enum Scope { 49 | /// Represetns a single crate. 50 | Crate(String), 51 | 52 | /// Represents multiple crates. 53 | /// 54 | /// For example: 55 | /// - `rustc_ast`, `rustc_ast_lowering`, `rustc_passes` and `rustc_ast_pretty` 56 | /// - `std`, `core` and `alloc` 57 | Set(Vec), 58 | } 59 | 60 | impl Scope { 61 | pub fn flatten(self) -> Vec { 62 | match self { 63 | Scope::Crate(krate) => vec![krate], 64 | Scope::Set(krates) => krates, 65 | } 66 | } 67 | } 68 | 69 | impl Index { 70 | /// Perform search with given query and scope. 71 | /// 72 | /// Returns [`Hit`]s whose similarity score outperforms given `threshold`. 73 | pub fn search(&self, query: &Query, scope: Scope, threshold: f32) -> Result> { 74 | let mut hits = vec![]; 75 | 76 | let krates = scope.flatten(); 77 | for krate_name in krates { 78 | let krate = self 79 | .crates 80 | .get(&krate_name) 81 | .ok_or(SearchError::CrateNotFound(krate_name.clone()))?; 82 | for item in krate.index.values() { 83 | match item.inner { 84 | types::ItemEnum::Function(_) => { 85 | let (path, link) = Self::path_and_link(krate, &krate_name, item, None)?; 86 | let sims = self.compare(query, item, krate, None); 87 | 88 | if sims.score() < threshold { 89 | hits.push(Hit { 90 | name: item.name.clone().unwrap(), // SAFETY: all functions has its name. 91 | path, 92 | link, 93 | docs: item.docs.clone(), 94 | similarities: sims, 95 | }); 96 | } 97 | } 98 | types::ItemEnum::Impl(ref impl_) if impl_.trait_.is_none() => { 99 | let assoc_items = impl_ 100 | .items 101 | .iter() 102 | .map(|id| { 103 | krate.index.get(id).ok_or(SearchError::ItemNotFound( 104 | id.0.clone(), 105 | krate_name.clone(), 106 | )) 107 | }) 108 | .collect::>>()?; 109 | for assoc_item in assoc_items { 110 | if let types::ItemEnum::Method(_) = assoc_item.inner { 111 | let (path, link) = Self::path_and_link( 112 | krate, 113 | &krate_name, 114 | assoc_item, 115 | Some(impl_), 116 | )?; 117 | let sims = self.compare(query, assoc_item, krate, Some(impl_)); 118 | 119 | if sims.score() < threshold { 120 | hits.push(Hit { 121 | name: assoc_item.name.clone().unwrap(), // SAFETY: all methods has its name. 122 | path, 123 | link, 124 | docs: assoc_item.docs.clone(), 125 | similarities: sims, 126 | }) 127 | } 128 | } 129 | } 130 | } 131 | // TODO(hkmatsumoto): Acknowledge trait method as well. 132 | _ => {} 133 | } 134 | } 135 | } 136 | 137 | hits.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap()); 138 | Ok(hits) 139 | } 140 | 141 | #[tracing::instrument(skip(self, krate))] 142 | fn compare( 143 | &self, 144 | query: &Query, 145 | item: &types::Item, 146 | krate: &types::Crate, 147 | impl_: Option<&types::Impl>, 148 | ) -> Similarities { 149 | let mut generics; 150 | if let Some(impl_) = impl_ { 151 | generics = impl_.generics.clone(); 152 | generics 153 | .where_predicates 154 | .push(types::WherePredicate::EqPredicate { 155 | lhs: types::Type::Generic("Self".to_owned()), 156 | rhs: impl_.for_.clone(), 157 | }); 158 | } else { 159 | generics = types::Generics::default() 160 | } 161 | let mut substs = HashMap::default(); 162 | 163 | let sims = query.compare(item, krate, &mut generics, &mut substs); 164 | Similarities(sims) 165 | } 166 | 167 | /// Given `item` and optional `impl_`, compute its path and rustdoc link to `item`. 168 | /// 169 | /// `item` must be a function or a method, otherwise assertions will fail. 170 | fn path_and_link( 171 | krate: &types::Crate, 172 | krate_name: &str, 173 | item: &types::Item, 174 | impl_: Option<&types::Impl>, 175 | ) -> Result<(Vec, Vec)> { 176 | assert!(matches!( 177 | item.inner, 178 | types::ItemEnum::Function(_) | types::ItemEnum::Method(_) 179 | )); 180 | 181 | use types::Type; 182 | 183 | let get_path = |id: &types::Id| -> Result> { 184 | let path = krate 185 | .paths 186 | .get(id) 187 | .ok_or(SearchError::ItemNotFound( 188 | id.0.clone(), 189 | krate_name.to_owned(), 190 | ))? 191 | .path 192 | .clone(); 193 | 194 | Ok(path) 195 | }; 196 | 197 | // If `item` is a associated item, replace the last segment of the path for the link of the ADT 198 | // it is binded to. 199 | let mut path; 200 | let mut link; 201 | if let Some(impl_) = impl_ { 202 | let recv; 203 | match (&impl_.for_, &impl_.trait_) { 204 | (_, Some(ref t)) => { 205 | if let Type::ResolvedPath { name, id, .. } = t { 206 | path = get_path(id)?; 207 | recv = format!("trait.{}.html", name); 208 | } else { 209 | // SAFETY: All traits are represented by `ResolvedPath`. 210 | unreachable!() 211 | } 212 | } 213 | ( 214 | Type::ResolvedPath { 215 | ref name, ref id, .. 216 | }, 217 | _, 218 | ) => { 219 | path = get_path(id)?; 220 | let summary = krate.paths.get(id).ok_or(SearchError::ItemNotFound( 221 | id.0.clone(), 222 | krate_name.to_owned(), 223 | ))?; 224 | match summary.kind { 225 | types::ItemKind::Union => recv = format!("union.{}.html", name), 226 | types::ItemKind::Enum => recv = format!("enum.{}.html", name), 227 | types::ItemKind::Struct => recv = format!("struct.{}.html", name), 228 | // SAFETY: ADTs are either unions or enums or structs. 229 | _ => unreachable!(), 230 | } 231 | } 232 | (Type::Primitive(ref prim), _) => { 233 | path = vec![prim.clone()]; 234 | recv = format!("primitive.{}.html", prim); 235 | } 236 | (Type::Tuple(_), _) => { 237 | path = vec!["tuple".to_owned()]; 238 | recv = "primitive.tuple.html".to_owned(); 239 | } 240 | (Type::Slice(_), _) => { 241 | path = vec!["slice".to_owned()]; 242 | recv = "primitive.slice.html".to_owned(); 243 | } 244 | (Type::Array { .. }, _) => { 245 | path = vec!["array".to_owned()]; 246 | recv = "primitive.array.html".to_owned(); 247 | } 248 | (Type::RawPointer { .. }, _) => { 249 | path = vec!["pointer".to_owned()]; 250 | recv = "primitive.pointer.html".to_owned(); 251 | } 252 | (Type::BorrowedRef { .. }, _) => { 253 | path = vec!["reference".to_owned()]; 254 | recv = "primitive.reference.html".to_owned(); 255 | } 256 | _ => unreachable!(), 257 | } 258 | link = path.clone(); 259 | if let Some(l) = link.last_mut() { 260 | *l = recv; 261 | } 262 | } else { 263 | path = get_path(&item.id)?; 264 | link = path.clone(); 265 | } 266 | 267 | match item.inner { 268 | types::ItemEnum::Function(_) => { 269 | if let Some(l) = link.last_mut() { 270 | *l = format!("fn.{}.html", l); 271 | } 272 | Ok((path.clone(), link)) 273 | } 274 | types::ItemEnum::Method(_) => { 275 | let name = item.name.clone().unwrap(); // SAFETY: all methods has its name. 276 | if let Some(l) = link.last_mut() { 277 | *l = format!("{}#method.{}", l, &name); 278 | } 279 | path.push(name); 280 | 281 | Ok((path.clone(), link)) 282 | } 283 | // SAFETY: Already asserted at the beginning of this function. 284 | _ => unreachable!(), 285 | } 286 | } 287 | } 288 | 289 | #[cfg(test)] 290 | mod tests { 291 | use std::collections::HashSet; 292 | 293 | use super::*; 294 | use crate::compare::{DiscreteSimilarity::*, Similarity::*}; 295 | use crate::query::{FnDecl, FnRetTy, Function}; 296 | 297 | fn krate() -> types::Crate { 298 | types::Crate { 299 | root: types::Id("0:0".to_owned()), 300 | crate_version: Some("0.0.0".to_owned()), 301 | includes_private: false, 302 | index: Default::default(), 303 | paths: Default::default(), 304 | external_crates: Default::default(), 305 | format_version: 0, 306 | } 307 | } 308 | 309 | fn item(name: String, inner: types::ItemEnum) -> types::Item { 310 | types::Item { 311 | id: types::Id("test".to_owned()), 312 | crate_id: 0, 313 | name: Some(name), 314 | span: None, 315 | visibility: types::Visibility::Public, 316 | docs: None, 317 | links: HashMap::default(), 318 | attrs: vec![], 319 | deprecation: None, 320 | inner, 321 | } 322 | } 323 | 324 | /// Returns a function which will be expressed as `fn foo() -> ()`. 325 | fn foo() -> types::Function { 326 | types::Function { 327 | decl: types::FnDecl { 328 | inputs: vec![], 329 | output: None, 330 | c_variadic: false, 331 | }, 332 | generics: types::Generics { 333 | params: vec![], 334 | where_predicates: vec![], 335 | }, 336 | header: HashSet::default(), 337 | abi: "rust".to_owned(), 338 | } 339 | } 340 | 341 | #[test] 342 | fn compare_symbol() { 343 | let query = Query { 344 | name: Some("foo".to_owned()), 345 | kind: None, 346 | }; 347 | 348 | let function = foo(); 349 | let item = item("foo".to_owned(), types::ItemEnum::Function(function)); 350 | let krate = krate(); 351 | let mut generics = types::Generics::default(); 352 | let mut substs = HashMap::default(); 353 | 354 | assert_eq!( 355 | query.compare(&item, &krate, &mut generics, &mut substs), 356 | vec![Continuous(0.0)] 357 | ) 358 | } 359 | 360 | #[test] 361 | fn compare_function() { 362 | let q = Function { 363 | decl: FnDecl { 364 | inputs: Some(vec![]), 365 | output: Some(FnRetTy::DefaultReturn), 366 | }, 367 | }; 368 | 369 | let i = foo(); 370 | 371 | let krate = krate(); 372 | let mut generics = types::Generics::default(); 373 | let mut substs = HashMap::default(); 374 | 375 | assert_eq!( 376 | q.compare(&i, &krate, &mut generics, &mut substs), 377 | vec![Discrete(Equivalent), Discrete(Equivalent)] 378 | ) 379 | } 380 | } 381 | -------------------------------------------------------------------------------- /roogle-util/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "roogle-util" 3 | version = "0.1.0" 4 | authors = ["Hirochika Matsumoto "] 5 | edition = "2021" 6 | description = "Utilities for Roogle" 7 | documentation = "https://docs.rs/roogle-util" 8 | repository = "https://github.com/roogle-rs/roogle" 9 | license = "MIT OR Apache-2.0" 10 | 11 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 12 | 13 | [dependencies] 14 | rustdoc-types = "0.5.0" 15 | -------------------------------------------------------------------------------- /roogle-util/src/lib.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use rustdoc_types::{Crate, Id, Item, ItemSummary}; 4 | 5 | /// Perform a tree shaking to reduce the size of given `krate`. 6 | pub fn shake(krate: Crate) -> Crate { 7 | let Crate { 8 | root, 9 | crate_version, 10 | includes_private, 11 | index, 12 | paths, 13 | format_version, 14 | .. 15 | } = krate; 16 | 17 | let index = shake_index(index); 18 | let paths = shake_paths(paths); 19 | let external_crates = HashMap::default(); 20 | 21 | Crate { 22 | root, 23 | crate_version, 24 | includes_private, 25 | index, 26 | paths, 27 | external_crates, 28 | format_version, 29 | } 30 | } 31 | 32 | fn shake_index(index: HashMap) -> HashMap { 33 | use rustdoc_types::ItemEnum::*; 34 | 35 | index 36 | .into_iter() 37 | .filter(|(_, item)| { 38 | matches!( 39 | item.inner, 40 | Function(_) | Method(_) | Trait(_) | Impl(_) | Typedef(_) | AssocConst { .. } 41 | ) 42 | }) 43 | .collect() 44 | } 45 | 46 | fn shake_paths(paths: HashMap) -> HashMap { 47 | use rustdoc_types::ItemKind::*; 48 | 49 | paths 50 | .into_iter() 51 | .filter(|(_, item)| matches!(item.kind, Struct | Union | Enum | Function | Trait | Method)) 52 | .collect() 53 | } 54 | -------------------------------------------------------------------------------- /roogle/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "roogle" 3 | version = "1.0.0" 4 | authors = ["Hirochika Matsumoto "] 5 | edition = "2021" 6 | description = "A Rust API search engine" 7 | license = "MIT OR Apache-2.0" 8 | 9 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 10 | 11 | [dependencies] 12 | anyhow = "1.0" 13 | rocket = "0.5.0-rc.1" 14 | serde_json = "1.0.68" 15 | rustdoc-types = "0.5.0" 16 | tracing-subscriber = "0.2" 17 | tracing = "0.1" 18 | tracing-tree = "0.1" 19 | structopt = "0.3.25" 20 | serde = "1.0" 21 | 22 | [dependencies.roogle-engine] 23 | path = "../roogle-engine" 24 | version = "1.0.2" 25 | 26 | [dependencies.roogle-util] 27 | path = "../roogle-util" 28 | version = "0.1.0" 29 | -------------------------------------------------------------------------------- /roogle/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate rocket; 3 | 4 | use std::{collections::HashMap, path::PathBuf}; 5 | 6 | use anyhow::{anyhow, Context, Result}; 7 | use rocket::{ 8 | fairing::{Fairing, Info, Kind}, 9 | http::Header, 10 | response::content, 11 | State, 12 | }; 13 | use rustdoc_types::Crate; 14 | use serde::Deserialize; 15 | use structopt::StructOpt; 16 | use tracing::{debug, warn}; 17 | 18 | use roogle_engine::{query::parse::parse_query, search::Scope, Index}; 19 | use roogle_util::shake; 20 | 21 | #[get("/search?", data = "", rank = 2)] 22 | fn search_with_data( 23 | query: &str, 24 | scope: &str, 25 | index: &State, 26 | scopes: &State, 27 | ) -> Result, rocket::response::Debug> { 28 | search(query, scope, index, scopes) 29 | } 30 | 31 | #[get("/search?&")] 32 | fn search( 33 | query: &str, 34 | scope: &str, 35 | index: &State, 36 | scopes: &State, 37 | ) -> Result, rocket::response::Debug> { 38 | let scope = match scope.split(':').collect::>().as_slice() { 39 | ["set", set] => scopes 40 | .inner() 41 | .sets 42 | .get(*set) 43 | .context(format!("set `{}` not found", set))?, 44 | ["crate", krate] => scopes 45 | .inner() 46 | .krates 47 | .get(*krate) 48 | .context(format!("krate `{}` not found", krate))?, 49 | _ => Err(anyhow!("parsing scope `{}` failed", scope))?, 50 | }; 51 | debug!(?scope); 52 | 53 | let query = parse_query(query) 54 | .ok() 55 | .context(format!("parsing query `{}` failed", query))? 56 | .1; 57 | debug!(?query); 58 | 59 | let hits = index 60 | .search( 61 | &query, 62 | scope.clone(), 63 | 0.4, // NOTE(hkmatsumoto): Just a temporal value; maybe needs discussion in the future. 64 | ) 65 | .with_context(|| format!("search with query `{:?}` failed", query))?; 66 | let hits = hits 67 | .into_iter() 68 | .inspect(|hit| debug!(?hit.name, ?hit.link, similarities = ?hit.similarities(), score = ?hit.similarities().score())) 69 | .take(30) 70 | .collect::>(); 71 | 72 | Ok(content::Json( 73 | serde_json::to_string(&hits).context("serializing search result failed")?, 74 | )) 75 | } 76 | 77 | #[get("/scopes")] 78 | fn scopes( 79 | scopes: &State, 80 | ) -> Result, rocket::response::Debug> { 81 | let mut result = vec![]; 82 | for set in scopes.inner().sets.keys() { 83 | result.push(format!("set:{}", set)); 84 | } 85 | for krate in scopes.inner().krates.keys() { 86 | result.push(format!("crate:{}", krate)); 87 | } 88 | 89 | Ok(content::Json( 90 | serde_json::to_string(&result).context("serializing scopes failed")?, 91 | )) 92 | } 93 | 94 | #[derive(Debug, StructOpt)] 95 | struct Opt { 96 | #[structopt(short, long, name = "INDEX", default_value = "roogle-index")] 97 | index: PathBuf, 98 | } 99 | 100 | #[launch] 101 | fn rocket() -> _ { 102 | init_logger(); 103 | 104 | let opt = Opt::from_args(); 105 | 106 | let index = make_index(&opt).unwrap(); 107 | let scopes = make_scopes(&opt).unwrap(); 108 | rocket::build() 109 | .attach(Cors) 110 | .manage(index) 111 | .manage(scopes) 112 | .mount("/", routes![search, search_with_data, scopes]) 113 | } 114 | 115 | fn init_logger() { 116 | use tracing_subscriber::{filter::EnvFilter, layer::SubscriberExt, util::SubscriberInitExt}; 117 | 118 | let filter = match std::env::var("ROOGLE_LOG") { 119 | Ok(env) => EnvFilter::new(env), 120 | _ => return, 121 | }; 122 | let layer = tracing_tree::HierarchicalLayer::default() 123 | .with_indent_lines(true) 124 | .with_indent_amount(2) 125 | .with_ansi(true) 126 | .with_targets(true); 127 | tracing_subscriber::Registry::default() 128 | .with(filter) 129 | .with(layer) 130 | .init(); 131 | } 132 | 133 | fn make_index(opt: &Opt) -> Result { 134 | let crates = std::fs::read_dir(format!("{}/crate", opt.index.display())) 135 | .context("failed to read index files")? 136 | .map(|entry| { 137 | let entry = entry?; 138 | let json = std::fs::read_to_string(entry.path()) 139 | .with_context(|| format!("failed to read `{:?}`", entry.file_name()))?; 140 | let mut deserializer = serde_json::Deserializer::from_str(&json); 141 | deserializer.disable_recursion_limit(); 142 | let krate = Crate::deserialize(&mut deserializer) 143 | .with_context(|| format!("failed to deserialize `{:?}`", entry.file_name()))?; 144 | let file_name = entry 145 | .path() 146 | .with_extension("") 147 | .file_name() 148 | .with_context(|| format!("failed to get file name from `{:?}`", entry.path()))? 149 | .to_str() 150 | .context("failed to get `&str` from `&OsStr`")? 151 | .to_owned(); 152 | Ok((file_name, shake(krate))) 153 | }) 154 | .filter_map(|res: Result<_, anyhow::Error>| { 155 | if let Err(ref e) = res { 156 | warn!("parsing a JSON file skipped: {}", e); 157 | } 158 | res.ok() 159 | }) 160 | .collect::>(); 161 | Ok(Index { crates }) 162 | } 163 | 164 | struct Scopes { 165 | sets: HashMap, 166 | krates: HashMap, 167 | } 168 | 169 | fn make_scopes(opt: &Opt) -> Result { 170 | let krates: HashMap = 171 | std::fs::read_dir(format!("{}/crate", opt.index.display())) 172 | .context("failed to read crate files")? 173 | .map(|entry| { 174 | let entry = entry?; 175 | let path = entry.path(); 176 | let krate = path.file_stem().unwrap().to_str().unwrap(); // SAFETY: files in `roogle-index` has a name. 177 | 178 | Ok((krate.to_owned(), Scope::Crate(krate.to_owned()))) 179 | }) 180 | .filter_map(|res: Result<_, anyhow::Error>| { 181 | if let Err(ref e) = res { 182 | warn!("registering a scope skipped: {}", e) 183 | } 184 | res.ok() 185 | }) 186 | .collect(); 187 | let sets: HashMap = 188 | match std::fs::read_dir(format!("{}/set", opt.index.display())) { 189 | Err(e) => { 190 | warn!("registering sets skipped: {}", e); 191 | HashMap::default() 192 | } 193 | Ok(entry) => { 194 | entry 195 | .map(|entry| { 196 | let entry = entry?; 197 | let path = entry.path(); 198 | let json = std::fs::read_to_string(&path) 199 | .context(format!("failed to read `{:?}`", path))?; 200 | let set = path.file_stem().unwrap().to_str().unwrap().to_owned(); // SAFETY: files in `roogle-index` has a name. 201 | let krates = serde_json::from_str::>(&json) 202 | .context(format!("failed to deserialize set `{}`", &set))?; 203 | 204 | Ok((set, Scope::Set(krates))) 205 | }) 206 | .filter_map(|res: Result<_, anyhow::Error>| { 207 | if let Err(ref e) = res { 208 | warn!("registering a scope skipped: {}", e) 209 | } 210 | res.ok() 211 | }) 212 | .collect() 213 | } 214 | }; 215 | Ok(Scopes { sets, krates }) 216 | } 217 | 218 | struct Cors; 219 | 220 | #[rocket::async_trait] 221 | impl Fairing for Cors { 222 | fn info(&self) -> Info { 223 | Info { 224 | name: "CORS", 225 | kind: Kind::Response, 226 | } 227 | } 228 | 229 | async fn on_response<'r>(&self, _: &'r rocket::Request<'_>, res: &mut rocket::Response<'r>) { 230 | res.set_header(Header::new("Access-Control-Allow-Origin", "*")); 231 | res.set_header(Header::new("Access-Control-Allow-Methods", "GET")); 232 | res.set_header(Header::new("Access-Control-Allow-Headers", "Content-Type")); 233 | res.set_header(Header::new("Access-Control-Allow-Credentials", "true")); 234 | } 235 | } 236 | --------------------------------------------------------------------------------