diff --git a/.clippy.toml b/.clippy.toml deleted file mode 100644 index c5898979..00000000 --- a/.clippy.toml +++ /dev/null @@ -1,4 +0,0 @@ -avoid-breaking-exported-api = false -allowed-idents-below-min-chars = [ "x", "y", "z", "r", "g", "b", "c", "s" ] -absolute-paths-allowed-crates = [ "cstree" ] -allowed-wildcard-imports = [ "super", "Kind" ] diff --git a/.envrc b/.envrc deleted file mode 100644 index 23f9a4ef..00000000 --- a/.envrc +++ /dev/null @@ -1 +0,0 @@ -use flake . --substituters "https://cache.nixos.org" diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index de6ff5ef..00000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1 +0,0 @@ -* @NotAShelf diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 5ace4600..00000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,6 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml deleted file mode 100644 index a79a1c3e..00000000 --- a/.github/workflows/doc.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: Documentation - -on: - push: - branches: - - main - pull_request: - branches: - - main - -permissions: - contents: read - pages: write - id-token: write -concurrency: - group: deploy - cancel-in-progress: false - -jobs: - rustdoc: - name: Build API docs - runs-on: ubuntu-latest - env: - RUST_BACKTRACE: 1 - - steps: - - name: Checkout repository - uses: actions/checkout@v6 - - - name: Install Rust toolchain - uses: actions-rust-lang/setup-rust-toolchain@v1 - - - name: Configure cache - uses: Swatinem/rust-cache@v2 - - - name: Setup pages - id: pages - uses: actions/configure-pages@v6 - - - name: Build Documentation - run: | - cargo clean --doc ; cargo doc --no-deps --workspace --all-features - - - name: Add redirect - run: echo '' > target/doc/index.html - - - name: Remove lock file - run: rm target/doc/.lock - - - name: Upload artifact - uses: actions/upload-pages-artifact@v4 - with: - path: target/doc - - deploy: - name: Deploy Documentation - runs-on: ubuntu-latest - needs: rustdoc - - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v5 diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml deleted file mode 100644 index ef9de756..00000000 --- a/.github/workflows/rust.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Build with Cargo - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - -env: - CARGO_TERM_COLOR: always - -jobs: - cargo-build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - name: Build - run: cargo build --verbose - - - name: Test - run: cargo test --verbose diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 311d44ea..00000000 --- a/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -/target - -# Sensitive -certificate.pem -private_key.pem -identity.pfx - diff --git a/.lock b/.lock new file mode 100644 index 00000000..e69de29b diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/.rustfmt.toml b/.rustfmt.toml deleted file mode 100644 index 3663d8db..00000000 --- a/.rustfmt.toml +++ /dev/null @@ -1,5 +0,0 @@ -edition = "2024" # Keep in sync with Cargo.toml. -group_imports = "StdExternalCrate" -doc_comment_code_block_width = 100 -condense_wildcard_suffixes = true -imports_granularity = "Crate" diff --git a/.taplo.toml b/.taplo.toml deleted file mode 100644 index 5ff4e9f5..00000000 --- a/.taplo.toml +++ /dev/null @@ -1,14 +0,0 @@ -#:tombi schema.strict = false -[formatting] -align_entries = true -column_width = 110 -compact_arrays = false -reorder_inline_tables = false -reorder_keys = true - -[[rule]] -include = [ "**/Cargo.toml" ] -keys = [ "package" ] - -[rule.formatting] -reorder_keys = false diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 5d36c098..00000000 --- a/Cargo.lock +++ /dev/null @@ -1,1497 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "anstream" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" - -[[package]] -name = "anstyle-parse" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" -dependencies = [ - "anstyle", - "once_cell_polyfill", - "windows-sys", -] - -[[package]] -name = "anyhow" -version = "1.0.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" - -[[package]] -name = "bitflags" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" - -[[package]] -name = "bumpalo" -version = "3.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" - -[[package]] -name = "bytes" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" - -[[package]] -name = "cc" -version = "1.2.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" -dependencies = [ - "find-msvc-tools", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "clap" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_complete" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19c9f1dde76b736e3681f28cec9d5a61299cbaae0fce80a68e43724ad56031eb" -dependencies = [ - "clap", -] - -[[package]] -name = "clap_derive" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" - -[[package]] -name = "clipboard-win" -version = "5.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" -dependencies = [ - "error-code", -] - -[[package]] -name = "cobs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" -dependencies = [ - "thiserror", -] - -[[package]] -name = "colorchoice" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" - -[[package]] -name = "core-foundation" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "crossbeam-channel" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "dirs" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys", -] - -[[package]] -name = "embedded-io" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - -[[package]] -name = "endian-type" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "869b0adbda23651a9c5c0c3d270aac9fcb52e8622a8f2b17e57802d7791962f2" - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "error-code" -version = "3.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "find-msvc-tools" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" - -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "getrandom" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "getrandom" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" -dependencies = [ - "cfg-if", - "libc", - "r-efi 5.3.0", - "wasip2", -] - -[[package]] -name = "getrandom" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" -dependencies = [ - "cfg-if", - "libc", - "r-efi 6.0.0", - "wasip2", - "wasip3", -] - -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "foldhash", -] - -[[package]] -name = "hashbrown" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "home" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - -[[package]] -name = "indexmap" -version = "2.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" -dependencies = [ - "equivalent", - "hashbrown 0.16.1", - "serde", - "serde_core", -] - -[[package]] -name = "ipc-channel" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a441490012d80e9aea75fb27503df8e87e9557dcfc6fe4244dde86bfc12e94e3" -dependencies = [ - "crossbeam-channel", - "libc", - "mio", - "postcard", - "rand", - "rustc-hash", - "serde_core", - "tempfile", - "thiserror", - "uuid", - "windows", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" - -[[package]] -name = "itoa" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" - -[[package]] -name = "js-sys" -version = "0.3.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4c90f45aa2e6eacbe8645f77fdea542ac97a494bcd117a67df9ff4d611f995" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - -[[package]] -name = "libc" -version = "0.2.183" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" - -[[package]] -name = "libredox" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08" -dependencies = [ - "libc", -] - -[[package]] -name = "linux-raw-sys" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" - -[[package]] -name = "memchr" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" - -[[package]] -name = "mio" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" -dependencies = [ - "libc", - "wasi", - "windows-sys", -] - -[[package]] -name = "mpvrc" -version = "0.3.0" -dependencies = [ - "anstyle", - "anyhow", - "clap", - "clap_complete", - "clap_derive", - "dirs", - "ipc-channel", - "native-tls", - "rustyline", - "serde", - "serde_json", - "thiserror", - "tokio", - "tokio-native-tls", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "native-tls" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "nibble_vec" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" -dependencies = [ - "smallvec", -] - -[[package]] -name = "nix" -version = "0.31.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d0705320c1e6ba1d912b5e37cf18071b6c2e9b7fa8215a1e8a7651966f5d3" -dependencies = [ - "bitflags", - "cfg-if", - "cfg_aliases", - "libc", -] - -[[package]] -name = "nu-ansi-term" -version = "0.50.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "once_cell" -version = "1.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" - -[[package]] -name = "once_cell_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" - -[[package]] -name = "openssl" -version = "0.10.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "951c002c75e16ea2c65b8c7e4d3d51d5530d8dfa7d060b4776828c88cfb18ecf" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" - -[[package]] -name = "openssl-sys" -version = "0.9.112" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d55af3b3e226502be1526dfdba67ab0e9c96fc293004e79576b2b9edb0dbdb" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link 0.2.1", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" - -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "postcard" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" -dependencies = [ - "cobs", - "embedded-io 0.4.0", - "embedded-io 0.6.1", - "serde", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn", -] - -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "r-efi" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" - -[[package]] -name = "radix_trie" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b4431027dcd37fc2a73ef740b5f233aa805897935b8bce0195e41bbf9a3289a" -dependencies = [ - "endian-type", - "nibble_vec", -] - -[[package]] -name = "rand" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" -dependencies = [ - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" -dependencies = [ - "getrandom 0.3.4", -] - -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" -dependencies = [ - "getrandom 0.2.17", - "libredox", - "thiserror", -] - -[[package]] -name = "rustc-hash" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" - -[[package]] -name = "rustix" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "rustyline" -version = "18.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a990b25f351b25139ddc7f21ee3f6f56f86d6846b74ac8fad3a719a287cd4a0" -dependencies = [ - "bitflags", - "cfg-if", - "clipboard-win", - "home", - "libc", - "log", - "memchr", - "nix", - "radix_trie", - "unicode-segmentation", - "unicode-width", - "utf8parse", - "windows-sys", -] - -[[package]] -name = "schannel" -version = "0.1.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "security-framework" -version = "3.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "semver" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" -dependencies = [ - "itoa", - "memchr", - "serde", - "serde_core", - "zmij", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook-registry" -version = "1.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" -dependencies = [ - "errno", - "libc", -] - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "socket2" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tempfile" -version = "3.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" -dependencies = [ - "fastrand", - "getrandom 0.4.2", - "once_cell", - "rustix", - "windows-sys", -] - -[[package]] -name = "thiserror" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "tokio" -version = "1.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" -dependencies = [ - "bytes", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys", -] - -[[package]] -name = "tokio-macros" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tracing" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" -dependencies = [ - "nu-ansi-term", - "sharded-slab", - "smallvec", - "thread_local", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - -[[package]] -name = "unicode-segmentation" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" - -[[package]] -name = "unicode-width" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" - -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "uuid" -version = "1.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" -dependencies = [ - "getrandom 0.4.2", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasip2" -version = "1.0.2+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.115" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6523d69017b7633e396a89c5efab138161ed5aafcbc8d3e5c5a42ae38f50495a" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.115" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3a6c758eb2f701ed3d052ff5737f5bfe6614326ea7f3bbac7156192dc32e67" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.115" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "921de2737904886b52bcbb237301552d05969a6f9c40d261eb0533c8b055fedf" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.115" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a93e946af942b58934c604527337bad9ae33ba1d5c6900bbb41c2c07c2364a93" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags", - "hashbrown 0.15.5", - "indexmap", - "semver", -] - -[[package]] -name = "windows" -version = "0.61.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" -dependencies = [ - "windows-collections", - "windows-core", - "windows-future", - "windows-link 0.1.3", - "windows-numerics", -] - -[[package]] -name = "windows-collections" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" -dependencies = [ - "windows-core", -] - -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link 0.1.3", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-future" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" -dependencies = [ - "windows-core", - "windows-link 0.1.3", - "windows-threading", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-numerics" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" -dependencies = [ - "windows-core", - "windows-link 0.1.3", -] - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows-threading" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck", - "indexmap", - "prettyplease", - "syn", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap", - "log", - "semver", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] - -[[package]] -name = "zerocopy" -version = "0.8.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.48" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zmij" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index 292c6d93..00000000 --- a/Cargo.toml +++ /dev/null @@ -1,159 +0,0 @@ -[package] -categories = [ "command-line-utilities", "multimedia" ] -default-run = "cli" -description = "MPV Remote Control - CLI and server for controlling MPV via IPC" -edition = "2024" -keywords = [ "mpv", "media", "player", "control", "ipc" ] -license = "MPL-2.0" -name = "mpvrc" -readme = true -repository = "https://github.com/notashelf/mpvrc" -rust-version = "1.92.0" -version = "0.3.0" - -# CLI implementation for terminal usage -[[bin]] -name = "cli" -path = "src/cli.rs" - -# Server implementation for remote usage -[[bin]] -name = "server" -path = "src/server.rs" - -[dependencies] -anstyle = "1.0.14" -anyhow = "1.0.102" -clap = { version = "4.6.0", features = [ "derive", "cargo" ] } -clap_complete = "4.6.0" -clap_derive = "4.6.0" -dirs = "6.0.0" -ipc-channel = "0.21.0" -native-tls = "0.2.18" -rustyline = "18.0.0" -serde = { version = "1.0.228", features = [ "derive" ] } -serde_json = "1.0.149" -thiserror = "2.0.18" -tokio = { version = "1.50.0", features = [ "full" ] } -tokio-native-tls = "0.3.1" -tracing = "0.1.44" -tracing-subscriber = "0.3.23" - -[profile.dev] -opt-level = 1 - -[profile.release] -codegen-units = 1 -lto = "thin" -opt-level = "s" -panic = "abort" -strip = true - -[lints.clippy] -cargo = { level = "warn", priority = -1 } -complexity = { level = "warn", priority = -1 } -nursery = { level = "warn", priority = -1 } -pedantic = { level = "warn", priority = -1 } -perf = { level = "warn", priority = -1 } -style = { level = "warn", priority = -1 } - -# The lint groups above enable some less-than-desirable rules, we should manually -# enable those to keep our sanity. -absolute_paths = "allow" -alloc_instead_of_core = "allow" -allow_attributes_without_reason = "allow" -arbitrary_source_item_ordering = "allow" -arithmetic_side_effects = "allow" -as_conversions = "allow" -as_pointer_underscore = "allow" -as_underscore = "allow" -big_endian_bytes = "allow" -blanket_clippy_restriction_lints = "allow" -clone_on_ref_ptr = "allow" -dbg_macro = "allow" -disallowed_script_idents = "allow" -else_if_without_else = "allow" -empty_drop = "warn" -empty_structs_with_brackets = "warn" -error_impl_error = "allow" -exhaustive_enums = "allow" -exhaustive_structs = "allow" -exit = "warn" -expect_used = "allow" -field_scoped_visibility_modifiers = "allow" -filetype_is_file = "warn" -float_arithmetic = "allow" -get_unwrap = "warn" -host_endian_bytes = "allow" -impl_trait_in_params = "allow" -implicit_return = "allow" -indexing_slicing = "allow" -infinite_loop = "warn" -inline_asm_x86_intel_syntax = "allow" -integer_division = "allow" -integer_division_remainder_used = "allow" -large_include_file = "allow" -let_underscore_must_use = "allow" -let_underscore_untyped = "allow" -little_endian_bytes = "allow" -map_err_ignore = "allow" -map_with_unused_argument_over_ranges = "warn" -match_same_arms = "allow" -missing_assert_message = "allow" -missing_docs_in_private_items = "allow" -missing_errors_doc = "allow" -missing_inline_in_public_items = "allow" -missing_panics_doc = "allow" -missing_trait_methods = "allow" -mod_module_files = "allow" -multiple_crate_versions = "allow" # :( -multiple_inherent_impl = "allow" -mutex_atomic = "allow" -mutex_integer = "allow" -non_ascii_literal = "allow" -non_std_lazy_statics = "warn" -panic = "allow" -panic_in_result_fn = "allow" -partial_pub_fields = "allow" -pathbuf_init_then_push = "warn" -pattern_type_mismatch = "allow" -print_stderr = "allow" -print_stdout = "allow" -pub_use = "allow" -pub_with_shorthand = "allow" -pub_without_shorthand = "allow" -question_mark_used = "allow" -rc_buffer = "warn" -rc_mutex = "warn" -ref_patterns = "allow" -renamed_function_params = "allow" -rest_pat_in_fully_bound_structs = "warn" -same_name_method = "allow" -semicolon_outside_block = "allow" -separated_literal_suffix = "allow" -shadow_reuse = "allow" -shadow_same = "allow" -shadow_unrelated = "allow" -similar_names = "allow" -single_call_fn = "allow" -single_char_lifetime_names = "allow" -single_match_else = "allow" -std_instead_of_alloc = "allow" -std_instead_of_core = "allow" -string_add = "allow" -string_slice = "allow" -todo = "allow" -too_long_first_doc_paragraph = "allow" -too_many_lines = "allow" -try_err = "allow" -undocumented_unsafe_blocks = "warn" -unimplemented = "allow" -unnecessary_safety_comment = "allow" -unnecessary_safety_doc = "allow" -unreachable = "allow" -unused_result_ok = "warn" -unused_trait_names = "allow" -unwrap_in_result = "allow" -unwrap_used = "allow" -use_debug = "allow" -wildcard_enum_match_arm = "allow" diff --git a/LICENSE b/LICENSE deleted file mode 100644 index a612ad98..00000000 --- a/LICENSE +++ /dev/null @@ -1,373 +0,0 @@ -Mozilla Public License Version 2.0 -================================== - -1. Definitions --------------- - -1.1. "Contributor" - means each individual or legal entity that creates, contributes to - the creation of, or owns Covered Software. - -1.2. "Contributor Version" - means the combination of the Contributions of others (if any) used - by a Contributor and that particular Contributor's Contribution. - -1.3. "Contribution" - means Covered Software of a particular Contributor. - -1.4. "Covered Software" - means Source Code Form to which the initial Contributor has attached - the notice in Exhibit A, the Executable Form of such Source Code - Form, and Modifications of such Source Code Form, in each case - including portions thereof. - -1.5. "Incompatible With Secondary Licenses" - means - - (a) that the initial Contributor has attached the notice described - in Exhibit B to the Covered Software; or - - (b) that the Covered Software was made available under the terms of - version 1.1 or earlier of the License, but not also under the - terms of a Secondary License. - -1.6. "Executable Form" - means any form of the work other than Source Code Form. - -1.7. "Larger Work" - means a work that combines Covered Software with other material, in - a separate file or files, that is not Covered Software. - -1.8. "License" - means this document. - -1.9. "Licensable" - means having the right to grant, to the maximum extent possible, - whether at the time of the initial grant or subsequently, any and - all of the rights conveyed by this License. - -1.10. "Modifications" - means any of the following: - - (a) any file in Source Code Form that results from an addition to, - deletion from, or modification of the contents of Covered - Software; or - - (b) any new file in Source Code Form that contains any Covered - Software. - -1.11. "Patent Claims" of a Contributor - means any patent claim(s), including without limitation, method, - process, and apparatus claims, in any patent Licensable by such - Contributor that would be infringed, but for the grant of the - License, by the making, using, selling, offering for sale, having - made, import, or transfer of either its Contributions or its - Contributor Version. - -1.12. "Secondary License" - means either the GNU General Public License, Version 2.0, the GNU - Lesser General Public License, Version 2.1, the GNU Affero General - Public License, Version 3.0, or any later versions of those - licenses. - -1.13. "Source Code Form" - means the form of the work preferred for making modifications. - -1.14. "You" (or "Your") - means an individual or a legal entity exercising rights under this - License. For legal entities, "You" includes any entity that - controls, is controlled by, or is under common control with You. For - purposes of this definition, "control" means (a) the power, direct - or indirect, to cause the direction or management of such entity, - whether by contract or otherwise, or (b) ownership of more than - fifty percent (50%) of the outstanding shares or beneficial - ownership of such entity. - -2. License Grants and Conditions --------------------------------- - -2.1. Grants - -Each Contributor hereby grants You a world-wide, royalty-free, -non-exclusive license: - -(a) under intellectual property rights (other than patent or trademark) - Licensable by such Contributor to use, reproduce, make available, - modify, display, perform, distribute, and otherwise exploit its - Contributions, either on an unmodified basis, with Modifications, or - as part of a Larger Work; and - -(b) under Patent Claims of such Contributor to make, use, sell, offer - for sale, have made, import, and otherwise transfer either its - Contributions or its Contributor Version. - -2.2. Effective Date - -The licenses granted in Section 2.1 with respect to any Contribution -become effective for each Contribution on the date the Contributor first -distributes such Contribution. - -2.3. Limitations on Grant Scope - -The licenses granted in this Section 2 are the only rights granted under -this License. No additional rights or licenses will be implied from the -distribution or licensing of Covered Software under this License. -Notwithstanding Section 2.1(b) above, no patent license is granted by a -Contributor: - -(a) for any code that a Contributor has removed from Covered Software; - or - -(b) for infringements caused by: (i) Your and any other third party's - modifications of Covered Software, or (ii) the combination of its - Contributions with other software (except as part of its Contributor - Version); or - -(c) under Patent Claims infringed by Covered Software in the absence of - its Contributions. - -This License does not grant any rights in the trademarks, service marks, -or logos of any Contributor (except as may be necessary to comply with -the notice requirements in Section 3.4). - -2.4. Subsequent Licenses - -No Contributor makes additional grants as a result of Your choice to -distribute the Covered Software under a subsequent version of this -License (see Section 10.2) or under the terms of a Secondary License (if -permitted under the terms of Section 3.3). - -2.5. Representation - -Each Contributor represents that the Contributor believes its -Contributions are its original creation(s) or it has sufficient rights -to grant the rights to its Contributions conveyed by this License. - -2.6. Fair Use - -This License is not intended to limit any rights You have under -applicable copyright doctrines of fair use, fair dealing, or other -equivalents. - -2.7. Conditions - -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted -in Section 2.1. - -3. Responsibilities -------------------- - -3.1. Distribution of Source Form - -All distribution of Covered Software in Source Code Form, including any -Modifications that You create or to which You contribute, must be under -the terms of this License. You must inform recipients that the Source -Code Form of the Covered Software is governed by the terms of this -License, and how they can obtain a copy of this License. You may not -attempt to alter or restrict the recipients' rights in the Source Code -Form. - -3.2. Distribution of Executable Form - -If You distribute Covered Software in Executable Form then: - -(a) such Covered Software must also be made available in Source Code - Form, as described in Section 3.1, and You must inform recipients of - the Executable Form how they can obtain a copy of such Source Code - Form by reasonable means in a timely manner, at a charge no more - than the cost of distribution to the recipient; and - -(b) You may distribute such Executable Form under the terms of this - License, or sublicense it under different terms, provided that the - license for the Executable Form does not attempt to limit or alter - the recipients' rights in the Source Code Form under this License. - -3.3. Distribution of a Larger Work - -You may create and distribute a Larger Work under terms of Your choice, -provided that You also comply with the requirements of this License for -the Covered Software. If the Larger Work is a combination of Covered -Software with a work governed by one or more Secondary Licenses, and the -Covered Software is not Incompatible With Secondary Licenses, this -License permits You to additionally distribute such Covered Software -under the terms of such Secondary License(s), so that the recipient of -the Larger Work may, at their option, further distribute the Covered -Software under the terms of either this License or such Secondary -License(s). - -3.4. Notices - -You may not remove or alter the substance of any license notices -(including copyright notices, patent notices, disclaimers of warranty, -or limitations of liability) contained within the Source Code Form of -the Covered Software, except that You may alter any license notices to -the extent required to remedy known factual inaccuracies. - -3.5. Application of Additional Terms - -You may choose to offer, and to charge a fee for, warranty, support, -indemnity or liability obligations to one or more recipients of Covered -Software. However, You may do so only on Your own behalf, and not on -behalf of any Contributor. You must make it absolutely clear that any -such warranty, support, indemnity, or liability obligation is offered by -You alone, and You hereby agree to indemnify every Contributor for any -liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional -disclaimers of warranty and limitations of liability specific to any -jurisdiction. - -4. Inability to Comply Due to Statute or Regulation ---------------------------------------------------- - -If it is impossible for You to comply with any of the terms of this -License with respect to some or all of the Covered Software due to -statute, judicial order, or regulation then You must: (a) comply with -the terms of this License to the maximum extent possible; and (b) -describe the limitations and the code they affect. Such description must -be placed in a text file included with all distributions of the Covered -Software under this License. Except to the extent prohibited by statute -or regulation, such description must be sufficiently detailed for a -recipient of ordinary skill to be able to understand it. - -5. Termination --------------- - -5.1. The rights granted under this License will terminate automatically -if You fail to comply with any of its terms. However, if You become -compliant, then the rights granted under this License from a particular -Contributor are reinstated (a) provisionally, unless and until such -Contributor explicitly and finally terminates Your grants, and (b) on an -ongoing basis, if such Contributor fails to notify You of the -non-compliance by some reasonable means prior to 60 days after You have -come back into compliance. Moreover, Your grants from a particular -Contributor are reinstated on an ongoing basis if such Contributor -notifies You of the non-compliance by some reasonable means, this is the -first time You have received notice of non-compliance with this License -from such Contributor, and You become compliant prior to 30 days after -Your receipt of the notice. - -5.2. If You initiate litigation against any entity by asserting a patent -infringement claim (excluding declaratory judgment actions, -counter-claims, and cross-claims) alleging that a Contributor Version -directly or indirectly infringes any patent, then the rights granted to -You by any and all Contributors for the Covered Software under Section -2.1 of this License shall terminate. - -5.3. In the event of termination under Sections 5.1 or 5.2 above, all -end user license agreements (excluding distributors and resellers) which -have been validly granted by You or Your distributors under this License -prior to termination shall survive termination. - -************************************************************************ -* * -* 6. Disclaimer of Warranty * -* ------------------------- * -* * -* Covered Software is provided under this License on an "as is" * -* basis, without warranty of any kind, either expressed, implied, or * -* statutory, including, without limitation, warranties that the * -* Covered Software is free of defects, merchantable, fit for a * -* particular purpose or non-infringing. The entire risk as to the * -* quality and performance of the Covered Software is with You. * -* Should any Covered Software prove defective in any respect, You * -* (not any Contributor) assume the cost of any necessary servicing, * -* repair, or correction. This disclaimer of warranty constitutes an * -* essential part of this License. No use of any Covered Software is * -* authorized under this License except under this disclaimer. * -* * -************************************************************************ - -************************************************************************ -* * -* 7. Limitation of Liability * -* -------------------------- * -* * -* Under no circumstances and under no legal theory, whether tort * -* (including negligence), contract, or otherwise, shall any * -* Contributor, or anyone who distributes Covered Software as * -* permitted above, be liable to You for any direct, indirect, * -* special, incidental, or consequential damages of any character * -* including, without limitation, damages for lost profits, loss of * -* goodwill, work stoppage, computer failure or malfunction, or any * -* and all other commercial damages or losses, even if such party * -* shall have been informed of the possibility of such damages. This * -* limitation of liability shall not apply to liability for death or * -* personal injury resulting from such party's negligence to the * -* extent applicable law prohibits such limitation. Some * -* jurisdictions do not allow the exclusion or limitation of * -* incidental or consequential damages, so this exclusion and * -* limitation may not apply to You. * -* * -************************************************************************ - -8. Litigation -------------- - -Any litigation relating to this License may be brought only in the -courts of a jurisdiction where the defendant maintains its principal -place of business and such litigation shall be governed by laws of that -jurisdiction, without reference to its conflict-of-law provisions. -Nothing in this Section shall prevent a party's ability to bring -cross-claims or counter-claims. - -9. Miscellaneous ----------------- - -This License represents the complete agreement concerning the subject -matter hereof. If any provision of this License is held to be -unenforceable, such provision shall be reformed only to the extent -necessary to make it enforceable. Any law or regulation which provides -that the language of a contract shall be construed against the drafter -shall not be used to construe this License against a Contributor. - -10. Versions of the License ---------------------------- - -10.1. New Versions - -Mozilla Foundation is the license steward. Except as provided in Section -10.3, no one other than the license steward has the right to modify or -publish new versions of this License. Each version will be given a -distinguishing version number. - -10.2. Effect of New Versions - -You may distribute the Covered Software under the terms of the version -of the License under which You originally received the Covered Software, -or under the terms of any subsequent version published by the license -steward. - -10.3. Modified Versions - -If you create software not governed by this License, and you want to -create a new license for such software, you may create and use a -modified version of this License if you rename the license and remove -any references to the name of the license steward (except to note that -such modified license differs from this License). - -10.4. Distributing Source Code Form that is Incompatible With Secondary -Licenses - -If You choose to distribute Source Code Form that is Incompatible With -Secondary Licenses under the terms of this version of the License, the -notice described in Exhibit B of this License must be attached. - -Exhibit A - Source Code Form License Notice -------------------------------------------- - - This Source Code Form is subject to the terms of the Mozilla Public - License, v. 2.0. If a copy of the MPL was not distributed with this - file, You can obtain one at http://mozilla.org/MPL/2.0/. - -If it is not possible or desirable to put the notice in a particular -file, then You may include the notice in a location (such as a LICENSE -file in a relevant directory) where a recipient would be likely to look -for such a notice. - -You may add additional accurate notices of copyright ownership. - -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- - - This Source Code Form is "Incompatible With Secondary Licenses", as - defined by the Mozilla Public License, v. 2.0. diff --git a/README.md b/README.md deleted file mode 100644 index 6bf70ba2..00000000 --- a/README.md +++ /dev/null @@ -1,305 +0,0 @@ -# mpvrc - MPV Remote Control - -[![License: MPL 2.0](https://img.shields.io/badge/License-MPL%202.0-brightgreen.svg)](https://opensource.org/licenses/MPL-2.0) -[![crates.io](https://img.shields.io/crates/v/mpvrc.svg)](https://crates.io/crates/mpvrc) - -[mpv video player]: https://mpv.io/ - -mpvrc is an unofficial command-line tool and library for controlling the -[mpv video player] via its JSON IPC socket interface. Generally designed as a -scriptable playback controller and a real-time interactive REPL in addition to a -TLS-encrypted HTTP API for _remote_ control. mpvrc has you covered for anything -that is even vaguely related to controlling a MPV instance. - -## Features - -The project is equipped with various neat features such as, but not limited to: - -- **Full playback control**: play, pause, stop, seek, skip, and playlist - management -- **Interactive REPL**: vi-style editing, command history, and keyboard - shortcuts -- **HTTP server**: TLS-encrypted remote control with token authentication -- **Library API**: use MRC as a Rust crate in your own projects - -It's also async-first, for high-performance concurrency. - -## Prerequisites - -1. **MPV** with IPC support (any recent version) -2. **Rust** 1.92.0+ (or Nix for shell-based development) - -## Installation - -### From source - -```bash -# Clone and build using a recent cargo version -$ git clone https://github.com/notashelf/mpvrc.git -$ cd mpvrc - -# Build in release mode -$ cargo build --release -``` - -### With Nix - -The recommended way of building mpvrc is using Nix to acquire a developer shell. - -```bash -# Clone and build using cargo from the provided shell -$ git clone https://github.com/notashelf/mpvrc.git -$ cd mpvrc -$ nix develop -$ cargo build --release -``` - -### From crates.io - -You can also get mpvrc from . - -```bash -# Install to ~/.cargo/bin -$ cargo install mpvrc --locked -``` - -## Quick Start - -### 1. Start MPV with IPC - -Using mpvrc is quite simple. Start `mpv` with an IPC socket first: - -```bash -# `/tmp/mpvsocket` is the default socket path for mpvrc -$ mpv --idle --input-ipc-server=/tmp/mpvsocket -``` - -### 2. Control playback - -Then, once the socket is up, you may use `mpvrc` to control MPV. - -```bash -# Play/pause -$ mpvrc play -$ mpvrc pause - -# Navigation -$ mpvrc next -$ mpvrc prev - -# Seek 2 minutes forward -$ mpvrc seek 120 - -# Add files to playlist -$ mpvrc add ~/Videos/movie.mkv ~/Videos/episode1.mkv - -# View playlist -$ mpvrc list - -# Interactive mode -$ mpvrc interactive -``` - -## CLI Options - -```plaintext -Usage: mpvrc [OPTIONS] - -Options: - -s, --socket Path to MPV IPC socket [default: /tmp/mpvsocket] - -y, --yes Skip confirmation prompts for destructive commands - -d, --debug Enable debug logging - -h, --help Print help - -V, --version Print version -``` - -## Commands - - - -| Command | Description | Example | -| :------------------- | ------------------------------ | :----------------------------- | -| `play [index]` | Start/resume playback | `mpvrc play` or `mpvrc play 2` | -| `pause` | Pause playback | `mpvrc pause` | -| `stop` | Stop and quit MPV | `mpvrc stop` | -| `next` | Skip to next playlist item | `mpvrc next` | -| `prev` | Skip to previous item | `mpvrc prev` | -| `seek ` | Seek to position in seconds | `mpvrc seek 120` | -| `add ` | Add files to playlist | `mpvrc add a.mp3 b.mp3` | -| `remove [index]` | Remove item (default: current) | `mpvrc remove 0` | -| `move ` | Move playlist item | `mpvrc move 0 3` | -| `clear` | Clear playlist | `mpvrc clear` | -| `list` | Show playlist | `mpvrc list` | -| `prop ` | Get property values | `mpvrc prop volume` | -| `interactive` | Enter interactive REPL | `mpvrc interactive` | -| `completion ` | Generate shell completions | `mpvrc completion zsh` | - - - -### Shell Completions - -Generate completions for your shell: - -```bash -# Zsh -$ mpvrc completion zsh > ~/.zsh/completions/_mpvrc - -# Bash -$ mpvrc completion bash > /etc/bash_completion.d/mpvrc - -# Fish -$ mpvrc completion fish > ~/.config/fish/completions/mpvrc.fish -``` - -### Interactive Mode - -```bash -$ mpvrc interactive -Entering interactive mode. Type 'help' for commands or 'exit' to quit. -Socket: /tmp/mpvsocket - -mpv> play -mpv> seek 60 -mpv> list - 0 | Episode 1 | /path/to/episode1.mkv -> 1 | Episode 2 | /path/to/episode2.mkv - 2 | Episode 3 | /path/to/episode3.mkv -mpv> exit -``` - -Keyboard shortcuts in interactive mode: - -- `Ctrl+C` - Interrupt current command -- `Ctrl+L` - Clear screen -- `Ctrl+D` - Exit (EOF) - -## Server Mode - -Run MRC as a TLS-encrypted HTTP server for remote control: - -### 1. Generate TLS certificates - -```bash -openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -openssl pkcs12 -export -out identity.pfx -inkey key.pem -in cert.pem -``` - -### 2. Configure environment - -```bash -export TLS_PFX_PATH="./identity.pfx" -export TLS_PASSWORD="your_password" -export AUTH_TOKEN="your_secret_token" -``` - -### 3. Start server - -```bash -mpvrc server --bind 127.0.0.1:8080 --socket /tmp/mpvsocket -``` - -### 4. Send commands - -```bash -curl -k -H "Authorization: Bearer your_secret_token" \ - -d "play" https://127.0.0.1:8080/ -``` - -## Library Usage - -Add MRC to your `Cargo.toml`: - -```toml -[dependencies] -mpvrc = "0.2" -tokio = { version = "1", features = ["full"] } -serde_json = "1" -``` - -Control MPV from Rust: - -```rust -use mpvrc::{get_property, playlist_next, set_property}; -use serde_json::json; - -#[tokio::main] -async fn main() -> Result<(), Box> { - // Set volume - set_property("volume", &json!(75), None).await?; - - // Get current filename - if let Some(filename) = get_property("filename", None).await? { - println!("Now playing: {}", filename); - } - - // Skip to next track - playlist_next(None).await?; - - Ok(()) -} -``` - -## Configuration - -### Environment Variables - -| Variable | Description | Required | -| -------------- | ------------------------------- | -------- | -| `TLS_PFX_PATH` | Path to PKCS#12 certificate | Server | -| `TLS_PASSWORD` | Password for PKCS#12 file | Server | -| `AUTH_TOKEN` | Bearer token for authentication | Server | - -### Custom Socket Path - -Use `-s` or `--socket` to specify a different MPV socket: - -```bash -# As of 0.3.0, mvrc supports custom socket path -$ mpvrc -s /var/run/mpv/socket play -``` - -## Building & Development - -The recommended developer setup for working with mpvrc is using Nix. Use -`nix develop` or `direnv allow` to enter a reproducible devshell with the -expected tooling, then work with Rust sources as usual: - -```bash -# Build -$ cargo build - -# Release build -$ cargo build --release - -# Run tests -$ cargo test - -# Lint -$ cargo clippy --all-targets -``` - -## Troubleshooting - -### Socket not found - -```bash -# Verify MPV is running with IPC -ls -la /tmp/mpvsocket - -# Restart MPV with correct socket path -mpv --idle --input-ipc-server=/tmp/mpvsocket -``` - -### Debug output - -```bash -mpvrc -d interactive -# or -RUST_LOG=debug mpvrc interactive -``` - -## License - -This project is made available under Mozilla Public License (MPL) version 2.0. -See [LICENSE](LICENSE) for more details on the exact conditions. An online copy -is provided [here](https://www.mozilla.org/en-US/MPL/2.0/). diff --git a/cli/all.html b/cli/all.html new file mode 100644 index 00000000..641b449d --- /dev/null +++ b/cli/all.html @@ -0,0 +1 @@ +List of all items in this crate

List of all items

Structs

Enums

Functions

\ No newline at end of file diff --git a/cli/enum.CommandOptions.html b/cli/enum.CommandOptions.html new file mode 100644 index 00000000..9a69ea2f --- /dev/null +++ b/cli/enum.CommandOptions.html @@ -0,0 +1,81 @@ +CommandOptions in cli - Rust

Enum CommandOptions

Source
pub(crate) enum CommandOptions {
+
Show 14 variants Play { + index: Option<usize>, + }, + Pause, + Stop, + Next, + Prev, + Seek { + seconds: i32, + }, + Move { + index1: usize, + index2: usize, + }, + Remove { + index: Option<usize>, + }, + Clear, + List, + Add { + filenames: Vec<String>, + }, + Replace { + filenames: Vec<String>, + }, + Prop { + properties: Vec<String>, + }, + Interactive, +
}

Variants§

§

Play

Play media at the specified index in the playlist

+

Fields

§index: Option<usize>

The index of the media to play

+
§

Pause

Pause the currently playing media

+
§

Stop

Stop the playback and quit MPV

+
§

Next

Skip to the next item in the playlist

+
§

Prev

Skip to the previous item in the playlist

+
§

Seek

Seek to a specific position in the currently playing media

+

Fields

§seconds: i32

The number of seconds to seek to

+
§

Move

Move an item in the playlist from one index to another

+

Fields

§index1: usize

The index of the item to move

+
§index2: usize

The index to move the item to

+
§

Remove

Remove an item from the playlist

+

If invoked while playlist has no entries, or if the only entry +is the active video, then this will exit MPV.

+

Fields

§index: Option<usize>

The index of the item to remove (optional)

+
§

Clear

Clear the entire playlist

+
§

List

List all the items in the playlist

+
§

Add

Add files to the playlist

+

Needs at least one file to be passed.

+

Fields

§filenames: Vec<String>

The filenames of the files to add

+
§

Replace

Replace the current playlist with new files

+

Fields

§filenames: Vec<String>

The filenames of the files to replace the playlist with

+
§

Prop

Fetch properties of the current playback or playlist

+

Fields

§properties: Vec<String>

The properties to fetch

+
§

Interactive

Enter interactive mode to send commands to MPV IPC

+

Trait Implementations§

Source§

impl FromArgMatches for CommandOptions

Source§

fn from_arg_matches(__clap_arg_matches: &ArgMatches) -> Result<Self, Error>

Instantiate Self from [ArgMatches], parsing the arguments as needed. Read more
Source§

fn from_arg_matches_mut( + __clap_arg_matches: &mut ArgMatches, +) -> Result<Self, Error>

Instantiate Self from [ArgMatches], parsing the arguments as needed. Read more
Source§

fn update_from_arg_matches( + &mut self, + __clap_arg_matches: &ArgMatches, +) -> Result<(), Error>

Assign values from ArgMatches to self.
Source§

fn update_from_arg_matches_mut<'b>( + &mut self, + __clap_arg_matches: &mut ArgMatches, +) -> Result<(), Error>

Assign values from ArgMatches to self.
Source§

impl Subcommand for CommandOptions

Source§

fn augment_subcommands<'b>(__clap_app: Command) -> Command

Append to [Command] so it can instantiate Self via +[FromArgMatches::from_arg_matches_mut] Read more
Source§

fn augment_subcommands_for_update<'b>(__clap_app: Command) -> Command

Append to [Command] so it can instantiate self via +[FromArgMatches::update_from_arg_matches_mut] Read more
Source§

fn has_subcommand(__clap_name: &str) -> bool

Test whether Self can parse a specific subcommand

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where + T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where + T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an +Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an +Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where + U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where + S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a +[WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a +[WithDispatch] wrapper. Read more
\ No newline at end of file diff --git a/cli/fn.main.html b/cli/fn.main.html new file mode 100644 index 00000000..5a03a5f4 --- /dev/null +++ b/cli/fn.main.html @@ -0,0 +1 @@ +main in cli - Rust

Function main

Source
pub(crate) fn main() -> Result<()>
\ No newline at end of file diff --git a/cli/index.html b/cli/index.html new file mode 100644 index 00000000..1685b659 --- /dev/null +++ b/cli/index.html @@ -0,0 +1 @@ +cli - Rust

Crate cli

Source

Structs§

Cli 🔒

Enums§

CommandOptions 🔒

Functions§

main 🔒
\ No newline at end of file diff --git a/cli/sidebar-items.js b/cli/sidebar-items.js new file mode 100644 index 00000000..804681ff --- /dev/null +++ b/cli/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":["CommandOptions"],"fn":["main"],"struct":["Cli"]}; \ No newline at end of file diff --git a/cli/struct.Cli.html b/cli/struct.Cli.html new file mode 100644 index 00000000..0f1e9560 --- /dev/null +++ b/cli/struct.Cli.html @@ -0,0 +1,37 @@ +Cli in cli - Rust

Struct Cli

Source
pub(crate) struct Cli {
+    pub(crate) debug: bool,
+    pub(crate) command: CommandOptions,
+}

Fields§

§debug: bool§command: CommandOptions

Trait Implementations§

Source§

impl Args for Cli

Source§

fn group_id() -> Option<Id>

Report the [ArgGroup::id][crate::ArgGroup::id] for this set of arguments
Source§

fn augment_args<'b>(__clap_app: Command) -> Command

Append to [Command] so it can instantiate Self via +[FromArgMatches::from_arg_matches_mut] Read more
Source§

fn augment_args_for_update<'b>(__clap_app: Command) -> Command

Append to [Command] so it can instantiate self via +[FromArgMatches::update_from_arg_matches_mut] Read more
Source§

impl CommandFactory for Cli

Source§

fn command<'b>() -> Command

Build a [Command] that can instantiate Self. Read more
Source§

fn command_for_update<'b>() -> Command

Build a [Command] that can update self. Read more
Source§

impl FromArgMatches for Cli

Source§

fn from_arg_matches(__clap_arg_matches: &ArgMatches) -> Result<Self, Error>

Instantiate Self from [ArgMatches], parsing the arguments as needed. Read more
Source§

fn from_arg_matches_mut( + __clap_arg_matches: &mut ArgMatches, +) -> Result<Self, Error>

Instantiate Self from [ArgMatches], parsing the arguments as needed. Read more
Source§

fn update_from_arg_matches( + &mut self, + __clap_arg_matches: &ArgMatches, +) -> Result<(), Error>

Assign values from ArgMatches to self.
Source§

fn update_from_arg_matches_mut( + &mut self, + __clap_arg_matches: &mut ArgMatches, +) -> Result<(), Error>

Assign values from ArgMatches to self.
Source§

impl Parser for Cli

§

fn parse() -> Self

Parse from std::env::args_os(), [exit][Error::exit] on error.
§

fn try_parse() -> Result<Self, Error>

Parse from std::env::args_os(), return Err on error.
§

fn parse_from<I, T>(itr: I) -> Self
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Parse from iterator, [exit][Error::exit] on error.
§

fn try_parse_from<I, T>(itr: I) -> Result<Self, Error>
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Parse from iterator, return Err on error.
§

fn update_from<I, T>(&mut self, itr: I)
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Update from iterator, [exit][Error::exit] on error. Read more
§

fn try_update_from<I, T>(&mut self, itr: I) -> Result<(), Error>
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Update from iterator, return Err on error.

Auto Trait Implementations§

§

impl Freeze for Cli

§

impl RefUnwindSafe for Cli

§

impl Send for Cli

§

impl Sync for Cli

§

impl Unpin for Cli

§

impl UnwindSafe for Cli

Blanket Implementations§

Source§

impl<T> Any for T
where + T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where + T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an +Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an +Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where + U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where + S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a +[WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a +[WithDispatch] wrapper. Read more
\ No newline at end of file diff --git a/crates.js b/crates.js new file mode 100644 index 00000000..e7d7b430 --- /dev/null +++ b/crates.js @@ -0,0 +1,2 @@ +window.ALL_CRATES = ["cli","mrc","server"]; +//{"start":21,"fragment_lengths":[5,6,9]} \ No newline at end of file diff --git a/flake.lock b/flake.lock deleted file mode 100644 index d33b4d33..00000000 --- a/flake.lock +++ /dev/null @@ -1,27 +0,0 @@ -{ - "nodes": { - "nixpkgs": { - "locked": { - "lastModified": 1774386573, - "narHash": "sha256-4hAV26quOxdC6iyG7kYaZcM3VOskcPUrdCQd/nx8obc=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "46db2e09e1d3f113a13c0d7b81e2f221c63b8ce9", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "nixpkgs": "nixpkgs" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/flake.nix b/flake.nix deleted file mode 100644 index 67b64d53..00000000 --- a/flake.nix +++ /dev/null @@ -1,25 +0,0 @@ -{ - inputs.nixpkgs.url = "github:NixOS/nixpkgs?ref=nixos-unstable"; - - outputs = { - self, - nixpkgs, - ... - }: let - systems = ["x86_64-linux" "aarch64-linux"]; - forEachSystem = nixpkgs.lib.genAttrs systems; - - pkgsForEach = nixpkgs.legacyPackages; - in rec { - packages = forEachSystem (system: { - mpvrc = pkgsForEach.${system}.callPackage ./nix/package.nix {}; - default = self.packages.${system}.mpvrc; - }); - - devShells = forEachSystem (system: { - default = pkgsForEach.${system}.callPackage ./nix/shell.nix {}; - }); - - hydraJobs = packages; - }; -} diff --git a/help.html b/help.html new file mode 100644 index 00000000..21cb61e4 --- /dev/null +++ b/help.html @@ -0,0 +1 @@ +Help

Rustdoc help

Back
\ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..795116cd --- /dev/null +++ b/index.html @@ -0,0 +1 @@ + diff --git a/mrc/all.html b/mrc/all.html new file mode 100644 index 00000000..5ae872ef --- /dev/null +++ b/mrc/all.html @@ -0,0 +1 @@ +List of all items in this crate
\ No newline at end of file diff --git a/mrc/constant.SOCKET_PATH.html b/mrc/constant.SOCKET_PATH.html new file mode 100644 index 00000000..269190bf --- /dev/null +++ b/mrc/constant.SOCKET_PATH.html @@ -0,0 +1 @@ +SOCKET_PATH in mrc - Rust

Constant SOCKET_PATH

Source
pub const SOCKET_PATH: &str = "/tmp/mpvsocket";
\ No newline at end of file diff --git a/mrc/enum.MpvCommand.html b/mrc/enum.MpvCommand.html new file mode 100644 index 00000000..4862fd53 --- /dev/null +++ b/mrc/enum.MpvCommand.html @@ -0,0 +1,45 @@ +MpvCommand in mrc - Rust

Enum MpvCommand

Source
pub enum MpvCommand {
+    SetProperty,
+    PlaylistNext,
+    PlaylistPrev,
+    Seek,
+    Quit,
+    PlaylistMove,
+    PlaylistRemove,
+    PlaylistClear,
+    GetProperty,
+    LoadFile,
+}
Expand description

Represents common MPV commands.

+

This enum provides variants for frequently used MPV commands, which can be converted to their +string equivalents using the as_str method.

+

§Errors

+

Returns an error if the connection to the socket fails or the command execution encounters issues.

+

Variants§

§

SetProperty

Sets a property to a specified value in MPV.

+
§

PlaylistNext

Moves to the next item in the playlist.

+
§

PlaylistPrev

Moves to the previous item in the playlist.

+
§

Seek

Seeks to a specific time in the current media.

+
§

Quit

Quits the MPV application.

+
§

PlaylistMove

Moves an item in the playlist from one index to another.

+
§

PlaylistRemove

Removes an item from the playlist.

+
§

PlaylistClear

Clears all items from the playlist.

+
§

GetProperty

Retrieves the value of a property in MPV.

+
§

LoadFile

Loads a file into MPV.

+

Implementations§

Source§

impl MpvCommand

Source

pub const fn as_str(&self) -> &str

Converts MPV commands to their string equivalents.

+
§Returns
+

A string slice representing the command.

+

Trait Implementations§

Source§

impl Debug for MpvCommand

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where + T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where + T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an +Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an +Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where + U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where + S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a +[WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a +[WithDispatch] wrapper. Read more
\ No newline at end of file diff --git a/mrc/fn.get_property.html b/mrc/fn.get_property.html new file mode 100644 index 00000000..42bad364 --- /dev/null +++ b/mrc/fn.get_property.html @@ -0,0 +1,14 @@ +get_property in mrc - Rust

Function get_property

Source
pub async fn get_property(
+    property: &str,
+    socket_path: Option<&str>,
+) -> Result<Option<Value>>
Expand description

Sends the get_property command to retrieve a property value from MPV.

+

§Arguments

+
    +
  • property: The name of the property to retrieve.
  • +
  • socket_path: An optional custom socket path.
  • +
+

§Returns

+

A Result containing the response data.

+

§Errors

+

Returns an error if the connection to the socket fails or the command execution encounters issues.

+
\ No newline at end of file diff --git a/mrc/fn.loadfile.html b/mrc/fn.loadfile.html new file mode 100644 index 00000000..d183bba4 --- /dev/null +++ b/mrc/fn.loadfile.html @@ -0,0 +1,16 @@ +loadfile in mrc - Rust

Function loadfile

Source
pub async fn loadfile(
+    filename: &str,
+    append: bool,
+    socket_path: Option<&str>,
+) -> Result<Option<Value>>
Expand description

Sends the loadfile command to load a file into MPV.

+

§Arguments

+
    +
  • filename: The name of the file to load.
  • +
  • append: Whether to append the file to the playlist (true) or replace the current file (false).
  • +
  • socket_path: An optional custom socket path.
  • +
+

§Returns

+

A Result containing the response data.

+

§Errors

+

Returns an error if the connection to the socket fails or the command execution encounters issues.

+
\ No newline at end of file diff --git a/mrc/fn.playlist_clear.html b/mrc/fn.playlist_clear.html new file mode 100644 index 00000000..caa582b3 --- /dev/null +++ b/mrc/fn.playlist_clear.html @@ -0,0 +1,10 @@ +playlist_clear in mrc - Rust

Function playlist_clear

Source
pub async fn playlist_clear(socket_path: Option<&str>) -> Result<Option<Value>>
Expand description

Sends the playlist-clear command to clear the playlist.

+

§Arguments

+
    +
  • socket_path: An optional custom socket path.
  • +
+

§Returns

+

A Result containing the response data.

+

§Errors

+

Returns an error if the connection to the socket fails or the command execution encounters issues.

+
\ No newline at end of file diff --git a/mrc/fn.playlist_move.html b/mrc/fn.playlist_move.html new file mode 100644 index 00000000..36a27d5e --- /dev/null +++ b/mrc/fn.playlist_move.html @@ -0,0 +1,16 @@ +playlist_move in mrc - Rust

Function playlist_move

Source
pub async fn playlist_move(
+    from_index: usize,
+    to_index: usize,
+    socket_path: Option<&str>,
+) -> Result<Option<Value>>
Expand description

Sends the playlist-move command to move a playlist item from one index to another.

+

§Arguments

+
    +
  • from_index: The index of the item to move.
  • +
  • to_index: The index to move the item to.
  • +
  • socket_path: An optional custom socket path.
  • +
+

§Returns

+

A Result containing the response data.

+

§Errors

+

Returns an error if the connection to the socket fails or the command execution encounters issues.

+
\ No newline at end of file diff --git a/mrc/fn.playlist_next.html b/mrc/fn.playlist_next.html new file mode 100644 index 00000000..6e7e5267 --- /dev/null +++ b/mrc/fn.playlist_next.html @@ -0,0 +1,10 @@ +playlist_next in mrc - Rust

Function playlist_next

Source
pub async fn playlist_next(socket_path: Option<&str>) -> Result<Option<Value>>
Expand description

Sends the playlist-next command to move to the next playlist item.

+

§Arguments

+
    +
  • socket_path: An optional custom socket path.
  • +
+

§Returns

+

A Result containing the response data.

+

§Errors

+

Returns an error if the connection to the socket fails or the command execution encounters issues.

+
\ No newline at end of file diff --git a/mrc/fn.playlist_prev.html b/mrc/fn.playlist_prev.html new file mode 100644 index 00000000..3d9bc1d0 --- /dev/null +++ b/mrc/fn.playlist_prev.html @@ -0,0 +1,10 @@ +playlist_prev in mrc - Rust

Function playlist_prev

Source
pub async fn playlist_prev(socket_path: Option<&str>) -> Result<Option<Value>>
Expand description

Sends the playlist-prev command to move to the previous playlist item.

+

§Arguments

+
    +
  • socket_path: An optional custom socket path.
  • +
+

§Returns

+

A Result containing the response data.

+

§Errors

+

Returns an error if the connection to the socket fails or the command execution encounters issues.

+
\ No newline at end of file diff --git a/mrc/fn.playlist_remove.html b/mrc/fn.playlist_remove.html new file mode 100644 index 00000000..cb5bd50f --- /dev/null +++ b/mrc/fn.playlist_remove.html @@ -0,0 +1,14 @@ +playlist_remove in mrc - Rust

Function playlist_remove

Source
pub async fn playlist_remove(
+    index: Option<usize>,
+    socket_path: Option<&str>,
+) -> Result<Option<Value>>
Expand description

Sends the playlist-remove command to remove an item from the playlist.

+

§Arguments

+
    +
  • index: The index of the item to remove, or None to remove the current item.
  • +
  • socket_path: An optional custom socket path.
  • +
+

§Returns

+

A Result containing the response data.

+

§Errors

+

Returns an error if the connection to the socket fails or the command execution encounters issues.

+
\ No newline at end of file diff --git a/mrc/fn.quit.html b/mrc/fn.quit.html new file mode 100644 index 00000000..4970850f --- /dev/null +++ b/mrc/fn.quit.html @@ -0,0 +1,10 @@ +quit in mrc - Rust

Function quit

Source
pub async fn quit(socket_path: Option<&str>) -> Result<Option<Value>>
Expand description

Sends the quit command to terminate MPV.

+

§Arguments

+
    +
  • socket_path: An optional custom socket path.
  • +
+

§Returns

+

A Result containing the response data.

+

§Errors

+

Returns an error if the connection to the socket fails or the command execution encounters issues.

+
\ No newline at end of file diff --git a/mrc/fn.seek.html b/mrc/fn.seek.html new file mode 100644 index 00000000..217ebe13 --- /dev/null +++ b/mrc/fn.seek.html @@ -0,0 +1,14 @@ +seek in mrc - Rust

Function seek

Source
pub async fn seek(
+    seconds: f64,
+    socket_path: Option<&str>,
+) -> Result<Option<Value>>
Expand description

Sends the seek command to seek the media playback by a given number of seconds.

+

§Arguments

+
    +
  • seconds: The number of seconds to seek.
  • +
  • socket_path: An optional custom socket path.
  • +
+

§Returns

+

A Result containing the response data.

+

§Errors

+

Returns an error if the connection to the socket fails or the command execution encounters issues.

+
\ No newline at end of file diff --git a/mrc/fn.send_ipc_command.html b/mrc/fn.send_ipc_command.html new file mode 100644 index 00000000..160c39b0 --- /dev/null +++ b/mrc/fn.send_ipc_command.html @@ -0,0 +1,16 @@ +send_ipc_command in mrc - Rust

Function send_ipc_command

Source
pub async fn send_ipc_command(
+    command: &str,
+    args: &[Value],
+    socket_path: Option<&str>,
+) -> Result<Option<Value>>
Expand description

Sends a generic IPC command to the specified socket and returns the parsed response data.

+

§Arguments

+
    +
  • command: The name of the command to send to MPV.
  • +
  • args: A slice of Value arguments to include in the command.
  • +
  • socket_path: An optional custom path to the MPV IPC socket. If None, the default path is used.
  • +
+

§Returns

+

A Result containing an Option<Value> with the parsed response data if successful.

+

§Errors

+

Returns an error if the connection to the socket fails or if the response cannot be parsed.

+
\ No newline at end of file diff --git a/mrc/fn.set_property.html b/mrc/fn.set_property.html new file mode 100644 index 00000000..d70d4963 --- /dev/null +++ b/mrc/fn.set_property.html @@ -0,0 +1,16 @@ +set_property in mrc - Rust

Function set_property

Source
pub async fn set_property(
+    property: &str,
+    value: &Value,
+    socket_path: Option<&str>,
+) -> Result<Option<Value>>
Expand description

Sends the set_property command to MPV to change a property value.

+

§Arguments

+
    +
  • property: The name of the property to set.
  • +
  • value: The new value to assign to the property.
  • +
  • socket_path: An optional custom socket path.
  • +
+

§Returns

+

A Result containing the response data.

+

§Errors

+

Returns an error if the connection to the socket fails or the command execution encounters issues.

+
\ No newline at end of file diff --git a/mrc/index.html b/mrc/index.html new file mode 100644 index 00000000..518b3e54 --- /dev/null +++ b/mrc/index.html @@ -0,0 +1,33 @@ +mrc - Rust

Crate mrc

Source
Expand description

MRC +A library for interacting with the MPV media player using its JSON IPC (Inter-Process Communication) protocol.

+

This crate provides a set of utilities to communicate with MPV’s IPC socket, enabling you to send commands +and retrieve responses in a structured format.

+

§Features

+
    +
  • Send commands to MPV’s IPC socket
  • +
  • Retrieve responses in JSON format
  • +
  • Supports common MPV commands like set_property, seek, and playlist-next
  • +
  • Flexible socket path configuration
  • +
+

§Example Usage

+
use serde_json::json;
+use tokio;
+use mrc::{send_ipc_command, playlist_next, set_property};
+
+#[tokio::main]
+async fn main() {
+    let result = playlist_next(None).await;
+    match result {
+        Ok(response) => println!("Playlist moved to next: {:?}", response),
+        Err(err) => eprintln!("Error: {:?}", err),
+    }
+
+    let property_result = set_property("volume", &json!(50), None).await;
+    match property_result {
+        Ok(response) => println!("Volume set: {:?}", response),
+        Err(err) => eprintln!("Error: {:?}", err),
+    }
+}
+

§Constants

§SOCKET_PATH

+

Default path for the MPV IPC socket: /tmp/mpvsocket

+

§Functions

Enums§

MpvCommand
Represents common MPV commands.

Constants§

SOCKET_PATH

Functions§

get_property
Sends the get_property command to retrieve a property value from MPV.
loadfile
Sends the loadfile command to load a file into MPV.
playlist_clear
Sends the playlist-clear command to clear the playlist.
playlist_move
Sends the playlist-move command to move a playlist item from one index to another.
playlist_next
Sends the playlist-next command to move to the next playlist item.
playlist_prev
Sends the playlist-prev command to move to the previous playlist item.
playlist_remove
Sends the playlist-remove command to remove an item from the playlist.
quit
Sends the quit command to terminate MPV.
seek
Sends the seek command to seek the media playback by a given number of seconds.
send_ipc_command
Sends a generic IPC command to the specified socket and returns the parsed response data.
set_property
Sends the set_property command to MPV to change a property value.
\ No newline at end of file diff --git a/mrc/sidebar-items.js b/mrc/sidebar-items.js new file mode 100644 index 00000000..65c57faf --- /dev/null +++ b/mrc/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":["SOCKET_PATH"],"enum":["MpvCommand"],"fn":["get_property","loadfile","playlist_clear","playlist_move","playlist_next","playlist_prev","playlist_remove","quit","seek","send_ipc_command","set_property"]}; \ No newline at end of file diff --git a/nix/package.nix b/nix/package.nix deleted file mode 100644 index 07150283..00000000 --- a/nix/package.nix +++ /dev/null @@ -1,43 +0,0 @@ -{ - lib, - rustPlatform, - pkg-config, - openssl, -}: let - fs = lib.fileset; - s = ../.; -in - rustPlatform.buildRustPackage (finalAttrs: { - pname = "mpvrc"; - version = (lib.importTOML (s + /Cargo.toml)).package.version; - - src = fs.toSource { - root = s; - fileset = fs.unions [ - (fs.fileFilter (file: builtins.any file.hasExt ["rs"]) (s + /src)) - (s + /Cargo.lock) - (s + /Cargo.toml) - ]; - }; - - strictDeps = true; - enableParallelBuilding = true; - - nativeBuildInputs = [ - pkg-config - ]; - - buildInputs = [ - openssl - ]; - - cargoLock.lockFile = "${finalAttrs.src}/Cargo.lock"; - - meta = { - description = "IPC wrapper & command-line controller for MPV, the video player"; - homePage = "https://github.com/notashelf/mpvrc"; - mainProgram = "mpvrc"; - license = lib.licenses.mpl20; - maintainers = [lib.maintainers.NotAShelf]; - }; - }) diff --git a/nix/shell.nix b/nix/shell.nix deleted file mode 100644 index bc24eff0..00000000 --- a/nix/shell.nix +++ /dev/null @@ -1,27 +0,0 @@ -{ - mkShell, - rust-analyzer, - rustfmt, - clippy, - cargo, - taplo, - openssl, - pkg-config, - rustc, -}: -mkShell { - name = "mpvrc"; - packages = [ - cargo - rustc - - rust-analyzer - clippy - (rustfmt.override {asNightly = true;}) - taplo - - # For TLS and friends - openssl - pkg-config - ]; -} diff --git a/search-index.js b/search-index.js new file mode 100644 index 00000000..e063a97f --- /dev/null +++ b/search-index.js @@ -0,0 +1,4 @@ +var searchIndex = new Map(JSON.parse('[["cli",{"t":"PPFGPPPPPPPPPPPPNNNNNNNNNONONNNNNNNNNNHNNNNNNNNNNOOOOOOOO","n":["Add","Clear","Cli","CommandOptions","Interactive","List","Move","Next","Pause","Play","Prev","Prop","Remove","Replace","Seek","Stop","augment_args","augment_args_for_update","augment_subcommands","augment_subcommands_for_update","borrow","","borrow_mut","","command","","command_for_update","debug","from","","from_arg_matches","","from_arg_matches_mut","","group_id","has_subcommand","into","","main","try_from","","try_into","","type_id","","update_from_arg_matches","","update_from_arg_matches_mut","","filenames","","index","","index1","index2","properties","seconds"],"q":[[0,"cli"],[49,"cli::CommandOptions"],[57,"clap_builder::builder::command"],[58,"clap_builder::parser::matches::arg_matches"],[59,"clap_builder"],[60,"core::result"],[61,"clap_builder::util::id"],[62,"core::option"],[63,"std::io::error"],[64,"core::any"],[65,"alloc::vec"]],"i":"j0``000000000000h011010100000101010101`0101010101B`BdBfBhBj0BnC`","f":"````````````````{bb}000{d{{d{c}}}{}}0{{{d{f}}}{{d{fc}}}{}}0{{}b}{hj}1{hl}{cc{}}0{{{d{n}}}{{Ab{hA`}}}}{{{d{n}}}{{Ab{jA`}}}}{{{d{fn}}}{{Ab{hA`}}}}{{{d{fn}}}{{Ab{jA`}}}}{{}{{Af{Ad}}}}{{{d{Ah}}}l}{{}c{}}0{{}{{Al{Aj}}}}{c{{Ab{e}}}{}{}}0{{}{{Ab{c}}}{}}0{dAn}0{{{d{fh}}{d{n}}}{{Ab{AjA`}}}}{{{d{fj}}{d{n}}}{{Ab{AjA`}}}}{{{d{fh}}{d{fn}}}{{Ab{AjA`}}}}{{{d{fj}}{d{fn}}}{{Ab{AjA`}}}}{B`Bb}{BdBb}{BfAf}{BhAf}{BjBl}0{BnBb}{C`Cb}","D":"Cd","p":[[5,"Command",57],[1,"reference",null,null,1],[0,"mut"],[5,"Cli",0],[6,"CommandOptions",0],[1,"bool"],[5,"ArgMatches",58],[8,"Error",59],[6,"Result",60,null,1],[5,"Id",61],[6,"Option",62,null,1],[1,"str"],[1,"unit"],[8,"Result",63],[5,"TypeId",64],[15,"Add",49],[5,"Vec",65],[15,"Replace",49],[15,"Play",49],[15,"Remove",49],[15,"Move",49],[1,"usize"],[15,"Prop",49],[15,"Seek",49],[1,"i32"]],"r":[],"b":[],"c":"OjAAAAAAAAA=","e":"OzAAAAEAAB8ABQAAAAAAAwABABEACwAfAAUAJwAKAA==","P":[[20,"T"],[24,""],[28,"T"],[30,""],[36,"U"],[38,""],[39,"U,T"],[41,"U"],[43,""]]}],["mrc",{"t":"PPGPPPPPPSPPNNNNNHNHHHHHHHHHHNNN","n":["GetProperty","LoadFile","MpvCommand","PlaylistClear","PlaylistMove","PlaylistNext","PlaylistPrev","PlaylistRemove","Quit","SOCKET_PATH","Seek","SetProperty","as_str","borrow","borrow_mut","fmt","from","get_property","into","loadfile","playlist_clear","playlist_move","playlist_next","playlist_prev","playlist_remove","quit","seek","send_ipc_command","set_property","try_from","try_into","type_id"],"q":[[0,"mrc"],[32,"core::fmt"],[33,"core::option"],[34,"serde_json::value"],[35,"std::io::error"],[36,"core::result"],[37,"core::any"]],"i":"d0`000000`0000000`0``````````000","f":"`````````{{}b}``{{{b{d}}}{{b{f}}}}{b{{b{c}}}{}}{{{b{h}}}{{b{hc}}}{}}{{{b{d}}{b{hj}}}l}{cc{}}{{{b{f}}{n{{b{f}}}}}{{Ab{{n{A`}}}}}}{{}c{}}{{{b{f}}Ad{n{{b{f}}}}}{{Ab{{n{A`}}}}}}{{{n{{b{f}}}}}{{Ab{{n{A`}}}}}}{{AfAf{n{{b{f}}}}}{{Ab{{n{A`}}}}}}11{{{n{Af}}{n{{b{f}}}}}{{Ab{{n{A`}}}}}}2{{Ah{n{{b{f}}}}}{{Ab{{n{A`}}}}}}{{{b{f}}{b{{Aj{A`}}}}{n{{b{f}}}}}{{Ab{{n{A`}}}}}}{{{b{f}}{b{A`}}{n{{b{f}}}}}{{Ab{{n{A`}}}}}}{c{{Al{e}}}{}{}}{{}{{Al{c}}}{}}{bAn}","D":"Cd","p":[[1,"reference",null,null,1],[6,"MpvCommand",0],[1,"str"],[0,"mut"],[5,"Formatter",32],[8,"Result",32],[6,"Option",33,null,1],[6,"Value",34],[8,"Result",35],[1,"bool"],[1,"usize"],[1,"f64"],[1,"slice"],[6,"Result",36,null,1],[5,"TypeId",37]],"r":[],"b":[],"c":"OjAAAAAAAAA=","e":"OzAAAAEAAAYAAwAKAAAADgACAB4AAgA=","P":[[13,"T"],[15,""],[16,"T"],[17,""],[18,"U"],[19,""],[29,"U,T"],[30,"U"],[31,""]]}],["server",{"t":"FNNONNNNHNNNNHNHHONNNNN","n":["Config","augment_args","augment_args_for_update","bind","borrow","borrow_mut","command","command_for_update","create_tls_acceptor","from","from_arg_matches","from_arg_matches_mut","group_id","handle_connection","into","main","process_command","socket","try_from","try_into","type_id","update_from_arg_matches","update_from_arg_matches_mut"],"q":[[0,"server"],[23,"clap_builder::builder::command"],[24,"alloc::string"],[25,"tokio_native_tls"],[26,"core::error"],[27,"alloc::boxed"],[28,"core::result"],[29,"clap_builder::parser::matches::arg_matches"],[30,"clap_builder"],[31,"clap_builder::util::id"],[32,"core::option"],[33,"tokio::net::tcp::stream"],[34,"alloc::sync"],[35,"core::any"]],"i":"`d000000`0000`0``000000","f":"`{bb}0{df}{h{{h{c}}}{}}{{{h{j}}}{{h{jc}}}{}}{{}b}0{{}{{Ab{l{A`{n}}}}}}{cc{}}{{{h{Ad}}}{{Ab{dAf}}}}{{{h{jAd}}}{{Ab{dAf}}}}{{}{{Aj{Ah}}}}{{Al{An{l}}}{{Ab{B`{A`{n}}}}}}{{}c{}}{{}{{Ab{B`{A`{n}}}}}}{{{h{Bb}}}{{Ab{ff}}}}<{c{{Ab{e}}}{}{}}{{}{{Ab{c}}}{}}{hBd}{{{h{jd}}{h{Ad}}}{{Ab{B`Af}}}}{{{h{jd}}{h{jAd}}}{{Ab{B`Af}}}}","D":"h","p":[[5,"Command",23],[5,"Config",0],[5,"String",24],[1,"reference",null,null,1],[0,"mut"],[5,"TlsAcceptor",25],[10,"Error",26],[5,"Box",27,null,1],[6,"Result",28,null,1],[5,"ArgMatches",29],[8,"Error",30],[5,"Id",31],[6,"Option",32,null,1],[5,"TcpStream",33],[5,"Arc",34,null,1],[1,"unit"],[1,"str"],[5,"TypeId",35]],"r":[],"b":[],"c":"OjAAAAAAAAA=","e":"OzAAAAEAABMABQAAAAMABQAEAAsAAwAQAAEAEwAEAA==","P":[[4,"T"],[6,""],[9,"T"],[10,""],[14,"U"],[15,""],[18,"U,T"],[19,"U"],[20,""]]}]]')); +if (typeof exports !== 'undefined') exports.searchIndex = searchIndex; +else if (window.initSearch) window.initSearch(searchIndex); +//{"start":39,"fragment_lengths":[1997,1485,1579]} \ No newline at end of file diff --git a/search.desc/cli/cli-desc-0-.js b/search.desc/cli/cli-desc-0-.js new file mode 100644 index 00000000..8bac10d8 --- /dev/null +++ b/search.desc/cli/cli-desc-0-.js @@ -0,0 +1 @@ +searchState.loadedDescShard("cli", 0, "Add files to the playlist\nClear the entire playlist\nEnter interactive mode to send commands to MPV IPC\nList all the items in the playlist\nMove an item in the playlist from one index to another\nSkip to the next item in the playlist\nPause the currently playing media\nPlay media at the specified index in the playlist\nSkip to the previous item in the playlist\nFetch properties of the current playback or playlist\nRemove an item from the playlist\nReplace the current playlist with new files\nSeek to a specific position in the currently playing media\nStop the playback and quit MPV\nReturns the argument unchanged.\nReturns the argument unchanged.\nCalls U::from(self).\nCalls U::from(self).\nThe filenames of the files to add\nThe filenames of the files to replace the playlist with\nThe index of the media to play\nThe index of the item to remove (optional)\nThe index of the item to move\nThe index to move the item to\nThe properties to fetch\nThe number of seconds to seek to") \ No newline at end of file diff --git a/search.desc/mrc/mrc-desc-0-.js b/search.desc/mrc/mrc-desc-0-.js new file mode 100644 index 00000000..aebd50c2 --- /dev/null +++ b/search.desc/mrc/mrc-desc-0-.js @@ -0,0 +1 @@ +searchState.loadedDescShard("mrc", 0, "MRC A library for interacting with the MPV media player …\nRetrieves the value of a property in MPV.\nLoads a file into MPV.\nRepresents common MPV commands.\nClears all items from the playlist.\nMoves an item in the playlist from one index to another.\nMoves to the next item in the playlist.\nMoves to the previous item in the playlist.\nRemoves an item from the playlist.\nQuits the MPV application.\nSeeks to a specific time in the current media.\nSets a property to a specified value in MPV.\nConverts MPV commands to their string equivalents.\nReturns the argument unchanged.\nSends the get_property command to retrieve a property …\nCalls U::from(self).\nSends the loadfile command to load a file into MPV.\nSends the playlist-clear command to clear the playlist.\nSends the playlist-move command to move a playlist item …\nSends the playlist-next command to move to the next …\nSends the playlist-prev command to move to the previous …\nSends the playlist-remove command to remove an item from …\nSends the quit command to terminate MPV.\nSends the seek command to seek the media playback by a …\nSends a generic IPC command to the specified socket and …\nSends the set_property command to MPV to change a property …") \ No newline at end of file diff --git a/search.desc/server/server-desc-0-.js b/search.desc/server/server-desc-0-.js new file mode 100644 index 00000000..c4a2bfb8 --- /dev/null +++ b/search.desc/server/server-desc-0-.js @@ -0,0 +1 @@ +searchState.loadedDescShard("server", 0, "The IP address and port to bind the server to\nReturns the argument unchanged.\nCalls U::from(self).\nPath to MPV IPC socket") \ No newline at end of file diff --git a/server/all.html b/server/all.html new file mode 100644 index 00000000..aff4217d --- /dev/null +++ b/server/all.html @@ -0,0 +1 @@ +List of all items in this crate
\ No newline at end of file diff --git a/server/fn.create_tls_acceptor.html b/server/fn.create_tls_acceptor.html new file mode 100644 index 00000000..8dc3cbc9 --- /dev/null +++ b/server/fn.create_tls_acceptor.html @@ -0,0 +1 @@ +create_tls_acceptor in server - Rust

Function create_tls_acceptor

Source
pub(crate) fn create_tls_acceptor() -> Result<TlsAcceptor, Box<dyn Error + Send + Sync>>
\ No newline at end of file diff --git a/server/fn.handle_connection.html b/server/fn.handle_connection.html new file mode 100644 index 00000000..2110d6bd --- /dev/null +++ b/server/fn.handle_connection.html @@ -0,0 +1,4 @@ +handle_connection in server - Rust

Function handle_connection

Source
pub(crate) async fn handle_connection(
+    stream: TcpStream,
+    acceptor: Arc<TlsAcceptor>,
+) -> Result<(), Box<dyn Error + Send + Sync>>
\ No newline at end of file diff --git a/server/fn.main.html b/server/fn.main.html new file mode 100644 index 00000000..7d18a01e --- /dev/null +++ b/server/fn.main.html @@ -0,0 +1 @@ +main in server - Rust

Function main

Source
pub(crate) fn main() -> Result<(), Box<dyn Error + Send + Sync>>
\ No newline at end of file diff --git a/server/fn.process_command.html b/server/fn.process_command.html new file mode 100644 index 00000000..a99b1025 --- /dev/null +++ b/server/fn.process_command.html @@ -0,0 +1 @@ +process_command in server - Rust

Function process_command

Source
pub(crate) async fn process_command(command: &str) -> Result<String, String>
\ No newline at end of file diff --git a/server/index.html b/server/index.html new file mode 100644 index 00000000..756e878b --- /dev/null +++ b/server/index.html @@ -0,0 +1 @@ +server - Rust

Crate server

Source

Structs§

Config 🔒

Functions§

create_tls_acceptor 🔒
handle_connection 🔒
main 🔒
process_command 🔒
\ No newline at end of file diff --git a/server/sidebar-items.js b/server/sidebar-items.js new file mode 100644 index 00000000..4c1c274c --- /dev/null +++ b/server/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":["create_tls_acceptor","handle_connection","main","process_command"],"struct":["Config"]}; \ No newline at end of file diff --git a/server/struct.Config.html b/server/struct.Config.html new file mode 100644 index 00000000..669932ab --- /dev/null +++ b/server/struct.Config.html @@ -0,0 +1,39 @@ +Config in server - Rust

Struct Config

Source
pub(crate) struct Config {
+    pub(crate) bind: String,
+    pub(crate) socket: String,
+}

Fields§

§bind: String

The IP address and port to bind the server to

+
§socket: String

Path to MPV IPC socket

+

Trait Implementations§

Source§

impl Args for Config

Source§

fn group_id() -> Option<Id>

Report the [ArgGroup::id][crate::ArgGroup::id] for this set of arguments
Source§

fn augment_args<'b>(__clap_app: Command) -> Command

Append to [Command] so it can instantiate Self via +[FromArgMatches::from_arg_matches_mut] Read more
Source§

fn augment_args_for_update<'b>(__clap_app: Command) -> Command

Append to [Command] so it can instantiate self via +[FromArgMatches::update_from_arg_matches_mut] Read more
Source§

impl CommandFactory for Config

Source§

fn command<'b>() -> Command

Build a [Command] that can instantiate Self. Read more
Source§

fn command_for_update<'b>() -> Command

Build a [Command] that can update self. Read more
Source§

impl FromArgMatches for Config

Source§

fn from_arg_matches(__clap_arg_matches: &ArgMatches) -> Result<Self, Error>

Instantiate Self from [ArgMatches], parsing the arguments as needed. Read more
Source§

fn from_arg_matches_mut( + __clap_arg_matches: &mut ArgMatches, +) -> Result<Self, Error>

Instantiate Self from [ArgMatches], parsing the arguments as needed. Read more
Source§

fn update_from_arg_matches( + &mut self, + __clap_arg_matches: &ArgMatches, +) -> Result<(), Error>

Assign values from ArgMatches to self.
Source§

fn update_from_arg_matches_mut( + &mut self, + __clap_arg_matches: &mut ArgMatches, +) -> Result<(), Error>

Assign values from ArgMatches to self.
Source§

impl Parser for Config

§

fn parse() -> Self

Parse from std::env::args_os(), [exit][Error::exit] on error.
§

fn try_parse() -> Result<Self, Error>

Parse from std::env::args_os(), return Err on error.
§

fn parse_from<I, T>(itr: I) -> Self
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Parse from iterator, [exit][Error::exit] on error.
§

fn try_parse_from<I, T>(itr: I) -> Result<Self, Error>
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Parse from iterator, return Err on error.
§

fn update_from<I, T>(&mut self, itr: I)
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Update from iterator, [exit][Error::exit] on error. Read more
§

fn try_update_from<I, T>(&mut self, itr: I) -> Result<(), Error>
where + I: IntoIterator<Item = T>, + T: Into<OsString> + Clone,

Update from iterator, return Err on error.

Auto Trait Implementations§

§

impl Freeze for Config

§

impl RefUnwindSafe for Config

§

impl Send for Config

§

impl Sync for Config

§

impl Unpin for Config

§

impl UnwindSafe for Config

Blanket Implementations§

Source§

impl<T> Any for T
where + T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where + T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where + T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

+
§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an +Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an +Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where + U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Source§

impl<T, U> TryFrom<U> for T
where + U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where + U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where + S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a +[WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a +[WithDispatch] wrapper. Read more
\ No newline at end of file diff --git a/settings.html b/settings.html new file mode 100644 index 00000000..e95da019 --- /dev/null +++ b/settings.html @@ -0,0 +1 @@ +Settings

Rustdoc settings

Back
\ No newline at end of file diff --git a/src-files.js b/src-files.js new file mode 100644 index 00000000..6b882830 --- /dev/null +++ b/src-files.js @@ -0,0 +1,3 @@ +var srcIndex = new Map(JSON.parse('[["cli",["",[],["cli.rs"]]],["mrc",["",[],["lib.rs"]]],["server",["",[],["server.rs"]]]]')); +createSrcSidebar(); +//{"start":36,"fragment_lengths":[26,27,33]} \ No newline at end of file diff --git a/src/cli.rs b/src/cli.rs deleted file mode 100644 index f6eb35e5..00000000 --- a/src/cli.rs +++ /dev/null @@ -1,280 +0,0 @@ -use std::{ - io::{self, Write}, - path::PathBuf, -}; - -use clap::{CommandFactory, Parser, Subcommand, ValueEnum}; -use mpvrc::{MrcError, Result, SOCKET_PATH, commands::Commands, interactive::InteractiveMode}; -use tracing::{debug, error}; - -#[derive(Parser)] -#[command(author, version, about)] -struct Cli { - #[arg(short, long, global = true, help = "Path to MPV socket")] - socket: Option, - - #[arg(short, long, global = true, help = "Skip confirmation prompts")] - yes: bool, - - #[arg(short, long, global = true, help = "Enable debug output")] - debug: bool, - - #[command(subcommand)] - command: CommandOptions, -} - -#[derive(Subcommand)] -enum CommandOptions { - /// Play media at the specified index in the playlist - Play { - /// The index of the media to play - index: Option, - }, - - /// Pause the currently playing media - Pause, - - /// Stop the playback and quit MPV - Stop, - - /// Skip to the next item in the playlist - Next, - - /// Skip to the previous item in the playlist - Prev, - - /// Seek to a specific position in the currently playing media - Seek { - /// The number of seconds to seek to - seconds: i32, - }, - - /// Move an item in the playlist from one index to another - Move { - /// The index of the item to move - index1: usize, - - /// The index to move the item to - index2: usize, - }, - - /// Remove an item from the playlist - /// - /// If invoked while playlist has no entries, or if the only entry - /// is the active video, then this will exit MPV. - Remove { - /// The index of the item to remove (optional) - index: Option, - }, - - /// Clear the entire playlist - Clear, - - /// List all the items in the playlist - List, - - /// Add files to the playlist - /// - /// Needs at least one file to be passed. - Add { - /// The filenames of the files to add - filenames: Vec, - }, - - /// Replace the current playlist with new files - Replace { - /// The filenames of the files to replace the playlist with - filenames: Vec, - }, - - /// Fetch properties of the current playback or playlist - Prop { - /// The properties to fetch - properties: Vec, - }, - - /// Enter interactive mode to send commands to MPV IPC - Interactive, - - /// Generate shell completions - Completion { - #[arg(value_enum, default_value_t = Shell::Bash)] - shell: Shell, - }, -} - -#[expect(clippy::enum_variant_names)] -#[derive(Clone, ValueEnum)] -pub enum Shell { - Bash, - Elvish, - Fish, - PowerShell, - Zsh, -} - -impl Shell { - pub fn generate(&self, app: &mut clap::Command) { - match self { - Self::Bash => { - clap_complete::generate( - clap_complete::Shell::Bash, - app, - "mpvrc", - &mut io::stdout(), - ); - } - - Self::Elvish => { - clap_complete::generate( - clap_complete::Shell::Elvish, - app, - "mpvrc", - &mut io::stdout(), - ); - } - - Self::Fish => { - clap_complete::generate( - clap_complete::Shell::Fish, - app, - "mpvrc", - &mut io::stdout(), - ); - } - - Self::PowerShell => clap_complete::generate( - clap_complete::Shell::PowerShell, - app, - "mpvrc", - &mut io::stdout(), - ), - - Self::Zsh => { - clap_complete::generate(clap_complete::Shell::Zsh, app, "mpvrc", &mut io::stdout()); - } - } - } -} - -fn get_socket_path(cli: &Cli) -> String { - cli.socket - .clone() - .unwrap_or_else(|| SOCKET_PATH.to_string()) -} - -fn confirm(prompt: &str, yes: bool) -> bool { - if yes { - return true; - } - print!("{prompt} [y/N] "); - io::stdout().flush().unwrap(); - let mut input = String::new(); - io::stdin().read_line(&mut input).unwrap(); - input.trim().eq_ignore_ascii_case("y") -} - -#[tokio::main] -async fn main() -> Result<()> { - tracing_subscriber::fmt::init(); - let cli = Cli::parse(); - - if matches!(cli.command, CommandOptions::Completion { .. }) { - let mut app = Cli::command(); - if let CommandOptions::Completion { shell } = &cli.command { - shell.generate(&mut app); - } - return Ok(()); - } - - let socket_path = get_socket_path(&cli); - - if !PathBuf::from(&socket_path).exists() { - debug!(socket_path); - error!( - "Error: MPV socket not found at {}. Is MPV running?", - socket_path - ); - return Err(MrcError::ConnectionError(std::io::Error::new( - std::io::ErrorKind::NotFound, - "MPV socket not found", - ))); - } - - match cli.command { - CommandOptions::Play { index } => { - Commands::play(index, Some(&socket_path)).await?; - } - - CommandOptions::Pause => { - Commands::pause(Some(&socket_path)).await?; - } - - CommandOptions::Stop => { - if confirm("This will stop playback and quit MPV. Continue?", cli.yes) { - Commands::stop(Some(&socket_path)).await?; - } else { - println!("Cancelled."); - } - } - - CommandOptions::Next => { - Commands::next(Some(&socket_path)).await?; - } - - CommandOptions::Prev => { - Commands::prev(Some(&socket_path)).await?; - } - - CommandOptions::Seek { seconds } => { - Commands::seek_to(seconds.into(), Some(&socket_path)).await?; - } - - CommandOptions::Move { index1, index2 } => { - Commands::move_item(index1, index2, Some(&socket_path)).await?; - } - - CommandOptions::Remove { index } => { - if confirm( - &format!("This will remove item at index {index:?}. Continue?"), - cli.yes, - ) { - Commands::remove_item(index, Some(&socket_path)).await?; - } else { - println!("Cancelled."); - } - } - - CommandOptions::Clear => { - if confirm("This will clear the entire playlist. Continue?", cli.yes) { - Commands::clear_playlist(Some(&socket_path)).await?; - } else { - println!("Cancelled."); - } - } - - CommandOptions::List => { - Commands::list_playlist(Some(&socket_path)).await?; - } - - CommandOptions::Add { filenames } => { - Commands::add_files(&filenames, Some(&socket_path)).await?; - } - - CommandOptions::Replace { filenames } => { - Commands::replace_playlist(&filenames, Some(&socket_path)).await?; - } - - CommandOptions::Prop { properties } => { - Commands::get_properties(&properties, Some(&socket_path)).await?; - } - - CommandOptions::Interactive => { - InteractiveMode::run(Some(&socket_path)).await?; - } - - CommandOptions::Completion { .. } => unreachable!(), - } - - Ok(()) -} diff --git a/src/cli/cli.rs.html b/src/cli/cli.rs.html new file mode 100644 index 00000000..be122e06 --- /dev/null +++ b/src/cli/cli.rs.html @@ -0,0 +1,342 @@ +cli.rs - source

cli/
cli.rs

1use clap::{Parser, Subcommand};
+2use mrc::set_property;
+3use mrc::SOCKET_PATH;
+4use mrc::{
+5    get_property, loadfile, playlist_clear, playlist_move, playlist_next, playlist_prev,
+6    playlist_remove, quit, seek,
+7};
+8use serde_json::json;
+9use std::io::{self, Write};
+10use std::path::PathBuf;
+11use tracing::{debug, error, info};
+12
+13#[derive(Parser)]
+14#[command(author, version, about)]
+15struct Cli {
+16    #[arg(short, long, global = true)]
+17    debug: bool,
+18
+19    #[command(subcommand)]
+20    command: CommandOptions,
+21}
+22
+23#[derive(Subcommand)]
+24enum CommandOptions {
+25    /// Play media at the specified index in the playlist
+26    Play {
+27        /// The index of the media to play
+28        index: Option<usize>,
+29    },
+30
+31    /// Pause the currently playing media
+32    Pause,
+33
+34    /// Stop the playback and quit MPV
+35    Stop,
+36
+37    /// Skip to the next item in the playlist
+38    Next,
+39
+40    /// Skip to the previous item in the playlist
+41    Prev,
+42
+43    /// Seek to a specific position in the currently playing media
+44    Seek {
+45        /// The number of seconds to seek to
+46        seconds: i32,
+47    },
+48
+49    /// Move an item in the playlist from one index to another
+50    Move {
+51        /// The index of the item to move
+52        index1: usize,
+53
+54        /// The index to move the item to
+55        index2: usize,
+56    },
+57
+58    /// Remove an item from the playlist
+59    ///
+60    /// If invoked while playlist has no entries, or if the only entry
+61    /// is the active video, then this will exit MPV.
+62    Remove {
+63        /// The index of the item to remove (optional)
+64        index: Option<usize>,
+65    },
+66
+67    /// Clear the entire playlist
+68    Clear,
+69
+70    /// List all the items in the playlist
+71    List,
+72
+73    /// Add files to the playlist
+74    ///
+75    /// Needs at least one file to be passed.
+76    Add {
+77        /// The filenames of the files to add
+78        filenames: Vec<String>,
+79    },
+80
+81    /// Replace the current playlist with new files
+82    Replace {
+83        /// The filenames of the files to replace the playlist with
+84        filenames: Vec<String>,
+85    },
+86
+87    /// Fetch properties of the current playback or playlist
+88    Prop {
+89        /// The properties to fetch
+90        properties: Vec<String>,
+91    },
+92
+93    /// Enter interactive mode to send commands to MPV IPC
+94    Interactive,
+95}
+96
+97#[tokio::main]
+98async fn main() -> io::Result<()> {
+99    tracing_subscriber::fmt::init();
+100    let cli = Cli::parse();
+101
+102    if !PathBuf::from(SOCKET_PATH).exists() {
+103        debug!(SOCKET_PATH);
+104        error!("Error: MPV socket not found. Is MPV running?");
+105        return Ok(());
+106    }
+107
+108    match cli.command {
+109        CommandOptions::Play { index } => {
+110            if let Some(idx) = index {
+111                info!("Playing media at index: {}", idx);
+112                set_property("playlist-pos", &json!(idx), None).await?;
+113            }
+114            info!("Unpausing playback");
+115            set_property("pause", &json!(false), None).await?;
+116        }
+117
+118        CommandOptions::Pause => {
+119            info!("Pausing playback");
+120            set_property("pause", &json!(true), None).await?;
+121        }
+122
+123        CommandOptions::Stop => {
+124            info!("Stopping playback and quitting MPV");
+125            quit(None).await?;
+126        }
+127
+128        CommandOptions::Next => {
+129            info!("Skipping to next item in the playlist");
+130            playlist_next(None).await?;
+131        }
+132
+133        CommandOptions::Prev => {
+134            info!("Skipping to previous item in the playlist");
+135            playlist_prev(None).await?;
+136        }
+137
+138        CommandOptions::Seek { seconds } => {
+139            info!("Seeking to {} seconds", seconds);
+140            seek(seconds.into(), None).await?;
+141        }
+142
+143        CommandOptions::Move { index1, index2 } => {
+144            info!("Moving item from index {} to {}", index1, index2);
+145            playlist_move(index1, index2, None).await?;
+146        }
+147
+148        CommandOptions::Remove { index } => {
+149            if let Some(idx) = index {
+150                info!("Removing item at index {}", idx);
+151                playlist_remove(Some(idx), None).await?;
+152            } else {
+153                info!("Removing current item from playlist");
+154                playlist_remove(None, None).await?;
+155            }
+156        }
+157
+158        CommandOptions::Clear => {
+159            info!("Clearing the playlist");
+160            playlist_clear(None).await?;
+161        }
+162
+163        CommandOptions::List => {
+164            info!("Listing playlist items");
+165            if let Some(data) = get_property("playlist", None).await? {
+166                println!("{}", serde_json::to_string_pretty(&data)?);
+167            }
+168        }
+169
+170        CommandOptions::Add { filenames } => {
+171            if filenames.is_empty() {
+172                let e = "No files provided to add to the playlist";
+173                error!("{}", e);
+174                return Err(io::Error::new(io::ErrorKind::InvalidInput, e));
+175            }
+176
+177            info!("Adding {} files to the playlist", filenames.len());
+178            for filename in filenames {
+179                loadfile(&filename, true, None).await?;
+180            }
+181        }
+182
+183        CommandOptions::Replace { filenames } => {
+184            info!("Replacing current playlist with {} files", filenames.len());
+185            if let Some(first_file) = filenames.first() {
+186                loadfile(first_file, false, None).await?;
+187                for filename in &filenames[1..] {
+188                    loadfile(filename, true, None).await?;
+189                }
+190            }
+191        }
+192
+193        CommandOptions::Prop { properties } => {
+194            info!("Fetching properties: {:?}", properties);
+195            for property in properties {
+196                if let Some(data) = get_property(&property, None).await? {
+197                    println!("{property}: {data}");
+198                }
+199            }
+200        }
+201
+202        CommandOptions::Interactive => {
+203            println!("Entering interactive mode. Type 'exit' to quit.");
+204            let stdin = io::stdin();
+205            let mut stdout = io::stdout();
+206
+207            loop {
+208                print!("mpv> ");
+209                stdout.flush()?;
+210                let mut input = String::new();
+211                stdin.read_line(&mut input)?;
+212                let trimmed = input.trim();
+213
+214                if trimmed.eq_ignore_ascii_case("exit") {
+215                    println!("Exiting interactive mode.");
+216                    break;
+217                }
+218
+219                // I don't like this either, but it looks cleaner than a multi-line
+220                // print macro just cramped in here.
+221                let commands = vec![
+222                    (
+223                        "play [index]",
+224                        "Play or unpause playback, optionally at the specified index",
+225                    ),
+226                    ("pause", "Pause playback"),
+227                    ("stop", "Stop playback and quit MPV"),
+228                    ("next", "Skip to the next item in the playlist"),
+229                    ("prev", "Skip to the previous item in the playlist"),
+230                    ("seek <seconds>", "Seek to the specified position"),
+231                    ("clear", "Clear the playlist"),
+232                    ("list", "List all items in the playlist"),
+233                    ("add <files>", "Add files to the playlist"),
+234                    ("get <property>", "Get the specified property"),
+235                    (
+236                        "set <property> <value>",
+237                        "Set the specified property to a value",
+238                    ),
+239                    ("exit", "Quit interactive mode"),
+240                ];
+241
+242                if trimmed.eq_ignore_ascii_case("help") {
+243                    println!("Valid commands:");
+244                    for (command, description) in commands {
+245                        println!("  {} - {}", command, description);
+246                    }
+247                    continue;
+248                }
+249
+250                let parts: Vec<&str> = trimmed.split_whitespace().collect();
+251                match parts.as_slice() {
+252                    ["play"] => {
+253                        info!("Unpausing playback");
+254                        set_property("pause", &json!(false), None).await?;
+255                    }
+256
+257                    ["play", index] => {
+258                        if let Ok(idx) = index.parse::<usize>() {
+259                            info!("Playing media at index: {}", idx);
+260                            set_property("playlist-pos", &json!(idx), None).await?;
+261                            set_property("pause", &json!(false), None).await?;
+262                        } else {
+263                            println!("Invalid index: {}", index);
+264                        }
+265                    }
+266
+267                    ["pause"] => {
+268                        info!("Pausing playback");
+269                        set_property("pause", &json!(true), None).await?;
+270                    }
+271
+272                    ["stop"] => {
+273                        info!("Pausing playback");
+274                        quit(None).await?;
+275                    }
+276
+277                    ["next"] => {
+278                        info!("Skipping to next item in the playlist");
+279                        playlist_next(None).await?;
+280                    }
+281
+282                    ["prev"] => {
+283                        info!("Skipping to previous item in the playlist");
+284                        playlist_prev(None).await?;
+285                    }
+286
+287                    ["seek", seconds] => {
+288                        if let Ok(sec) = seconds.parse::<i32>() {
+289                            info!("Seeking to {} seconds", sec);
+290                            seek(sec.into(), None).await?;
+291                        } else {
+292                            println!("Invalid seconds: {}", seconds);
+293                        }
+294                    }
+295
+296                    ["clear"] => {
+297                        info!("Clearing the playlist");
+298                        playlist_clear(None).await?;
+299                    }
+300
+301                    ["list"] => {
+302                        info!("Listing playlist items");
+303                        if let Some(data) = get_property("playlist", None).await? {
+304                            println!("{}", serde_json::to_string_pretty(&data)?);
+305                        }
+306                    }
+307
+308                    ["add", files @ ..] => {
+309                        if files.is_empty() {
+310                            println!("No files provided to add to the playlist");
+311                        } else {
+312                            info!("Adding {} files to the playlist", files.len());
+313                            for file in files {
+314                                loadfile(file, true, None).await?;
+315                            }
+316                        }
+317                    }
+318
+319                    ["get", property] => {
+320                        if let Some(data) = get_property(property, None).await? {
+321                            println!("{property}: {data}");
+322                        }
+323                    }
+324
+325                    ["set", property, value] => {
+326                        let json_value = serde_json::from_str::<serde_json::Value>(value)
+327                            .unwrap_or_else(|_| json!(value));
+328                        set_property(property, &json_value, None).await?;
+329                        println!("Set {property} to {value}");
+330                    }
+331
+332                    _ => {
+333                        println!("Unknown command: {}", trimmed);
+334                        println!("Valid commands: play <index>, pause, stop, next, prev, seek <seconds>, clear, list, add <files>, get <property>, set <property> <value>, exit");
+335                    }
+336                }
+337            }
+338        }
+339    }
+340
+341    Ok(())
+342}
\ No newline at end of file diff --git a/src/commands.rs b/src/commands.rs deleted file mode 100644 index ccd23e7c..00000000 --- a/src/commands.rs +++ /dev/null @@ -1,337 +0,0 @@ -//! Command processing module for MRC. -//! -//! # Examples -//! -//! ```rust -//! use mpvrc::commands::Commands; -//! -//! # async fn example() -> mpvrc::Result<()> { -//! // Play media at a specific playlist index -//! Commands::play(Some(0), None).await; -//! -//! // Pause playback -//! Commands::pause(None).await; -//! -//! // Add files to playlist -//! let files = vec!["movie1.mp4".to_string(), "movie2.mp4".to_string()]; -//! Commands::add_files(&files, None).await; -//! # Ok(()) -//! # } -//! ``` - -use serde_json::json; -use tracing::info; - -use crate::{ - MrcError, Result, get_property, loadfile, playlist_clear, playlist_move, playlist_next, - playlist_prev, playlist_remove, quit, seek, set_property, -}; - -/// Centralized command processing for MPV operations. -pub struct Commands; - -impl Commands { - /// Plays media, optionally at a specific playlist index. - /// - /// If an index is provided, seeks to that position in the playlist first. - /// Always unpauses playback regardless of whether an index is specified. - /// - /// # Arguments - /// - /// * `index` - Optional playlist index to play from - /// - /// # Errors - /// - /// Returns an error if the socket communication fails. - pub async fn play(index: Option, socket_path: Option<&str>) -> Result<()> { - if let Some(idx) = index { - info!("Playing media at index: {}", idx); - set_property("playlist-pos", &json!(idx), socket_path).await?; - } - info!("Unpausing playback"); - set_property("pause", &json!(false), socket_path).await?; - Ok(()) - } - - /// Pauses the currently playing media. - /// - /// # Errors - /// - /// Returns an error if the socket communication fails. - pub async fn pause(socket_path: Option<&str>) -> Result<()> { - info!("Pausing playback"); - set_property("pause", &json!(true), socket_path).await?; - Ok(()) - } - - /// Stops playback and quits MPV. - /// - /// This is a destructive operation that will terminate the MPV process. - /// - /// # Errors - /// - /// Returns an error if the socket communication fails. - pub async fn stop(socket_path: Option<&str>) -> Result<()> { - info!("Stopping playback and quitting MPV"); - quit(socket_path).await?; - Ok(()) - } - - /// Advances to the next item in the playlist. - /// - /// # Errors - /// - /// Returns an error if the socket communication fails. - pub async fn next(socket_path: Option<&str>) -> Result<()> { - info!("Skipping to next item in the playlist"); - playlist_next(socket_path).await?; - Ok(()) - } - - /// Goes back to the previous item in the playlist. - /// - /// # Errors - /// - /// Returns an error if the socket communication fails. - pub async fn prev(socket_path: Option<&str>) -> Result<()> { - info!("Skipping to previous item in the playlist"); - playlist_prev(socket_path).await?; - Ok(()) - } - - /// Seeks to a specific position in the currently playing media. - /// - /// # Arguments - /// - /// * `seconds` - The position in seconds to seek to - /// - /// # Errors - /// - /// Returns an error if the socket communication fails. - pub async fn seek_to(seconds: f64, socket_path: Option<&str>) -> Result<()> { - info!("Seeking to {} seconds", seconds); - seek(seconds, socket_path).await?; - Ok(()) - } - - /// Moves an item in the playlist from one index to another. - /// - /// # Arguments - /// - /// * `from_index` - The current index of the item - /// * `to_index` - The desired new index for the item - /// - /// # Errors - /// - /// Returns an error if the socket communication fails. - pub async fn move_item( - from_index: usize, - to_index: usize, - socket_path: Option<&str>, - ) -> Result<()> { - info!("Moving item from index {} to {}", from_index, to_index); - playlist_move(from_index, to_index, socket_path).await?; - Ok(()) - } - - /// Removes an item from the playlist. - /// - /// If no index is provided, removes the currently playing item. - /// - /// # Arguments - /// - /// * `index` - Optional specific index to remove - /// - /// # Errors - /// - /// Returns an error if the socket communication fails. - pub async fn remove_item(index: Option, socket_path: Option<&str>) -> Result<()> { - if let Some(idx) = index { - info!("Removing item at index {}", idx); - playlist_remove(Some(idx), socket_path).await?; - } else { - info!("Removing current item from playlist"); - playlist_remove(None, socket_path).await?; - } - Ok(()) - } - - /// Clears the entire playlist. - /// - /// # Errors - /// - /// Returns an error if the socket communication fails. - pub async fn clear_playlist(socket_path: Option<&str>) -> Result<()> { - info!("Clearing the playlist"); - playlist_clear(socket_path).await?; - Ok(()) - } - - /// Lists all items in the playlist. - /// - /// # Errors - /// - /// Returns an error if the socket communication fails. - pub async fn list_playlist(socket_path: Option<&str>) -> Result<()> { - info!("Listing playlist items"); - if let Some(data) = get_property("playlist", socket_path).await? { - print_playlist(&data); - } - Ok(()) - } - - /// Adds files to the playlist. - /// - /// # Arguments - /// - /// * `filenames` - List of file paths to add - /// - /// # Errors - /// - /// Returns an error if no files are provided or socket communication fails. - pub async fn add_files(filenames: &[String], socket_path: Option<&str>) -> Result<()> { - if filenames.is_empty() { - let e = "No files provided to add to the playlist"; - return Err(MrcError::InvalidInput(e.to_string())); - } - - info!("Adding {} files to the playlist", filenames.len()); - for filename in filenames { - loadfile(filename, true, socket_path).await?; - } - Ok(()) - } - - /// Replaces the current playlist with new files. - /// - /// # Arguments - /// - /// * `filenames` - List of file paths to replace the playlist with - /// - /// # Errors - /// - /// Returns an error if the socket communication fails. - pub async fn replace_playlist(filenames: &[String], socket_path: Option<&str>) -> Result<()> { - info!("Replacing current playlist with {} files", filenames.len()); - if let Some(first_file) = filenames.first() { - loadfile(first_file, false, socket_path).await?; - for filename in &filenames[1..] { - loadfile(filename, true, socket_path).await?; - } - } - Ok(()) - } - - /// Fetches multiple properties and prints them. - /// - /// # Arguments - /// - /// * `properties` - List of property names to fetch - /// - /// # Errors - /// - /// Returns an error if the socket communication fails. - pub async fn get_properties(properties: &[String], socket_path: Option<&str>) -> Result<()> { - info!("Fetching properties: {:?}", properties); - for property in properties { - if let Some(data) = get_property(property, socket_path).await? { - println!("{property}: {data}"); - } - } - Ok(()) - } - - /// Fetches a single property and prints it. - /// - /// # Arguments - /// - /// * `property` - The property name to fetch - /// - /// # Errors - /// - /// Returns an error if the socket communication fails. - pub async fn get_single_property(property: &str, socket_path: Option<&str>) -> Result<()> { - if let Some(data) = get_property(property, socket_path).await? { - println!("{property}: {data}"); - } - Ok(()) - } - - /// Sets a property and prints a confirmation. - /// - /// # Arguments - /// - /// * `property` - The property name to set - /// * `value` - The JSON value to set - /// - /// # Errors - /// - /// Returns an error if the socket communication fails. - pub async fn set_single_property( - property: &str, - value: &serde_json::Value, - socket_path: Option<&str>, - ) -> Result<()> { - set_property(property, value, socket_path).await?; - println!("Set {property} to {value}"); - Ok(()) - } -} - -fn print_playlist(data: &serde_json::Value) { - if let Some(items) = data.as_array() { - if items.is_empty() { - println!("Playlist is empty."); - return; - } - - for (i, item) in items.iter().enumerate() { - let title = item - .get("title") - .and_then(|v| v.as_str()) - .unwrap_or("unknown"); - let filename = item - .get("filename") - .and_then(|v| v.as_str()) - .unwrap_or("unknown"); - let current = item - .get("current") - .and_then(serde_json::Value::as_bool) - .unwrap_or(false); - - let marker = if current { ">" } else { " " }; - println!("{marker} {i:3} | {title} | {filename}"); - } - } else { - let pretty_json = serde_json::to_string_pretty(data).unwrap_or_else(|_| data.to_string()); - println!("{pretty_json}"); - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[tokio::test] - async fn test_add_files_empty_list() { - let result = Commands::add_files(&[], None).await; - assert!(result.is_err()); - if let Err(MrcError::InvalidInput(msg)) = result { - assert_eq!(msg, "No files provided to add to the playlist"); - } else { - panic!("Expected InvalidInput error"); - } - } - - #[tokio::test] - async fn test_replace_playlist_empty() { - let result = Commands::replace_playlist(&[], None).await; - assert!(result.is_ok()); - } - - #[tokio::test] - async fn test_get_properties_empty() { - let result = Commands::get_properties(&[], None).await; - assert!(result.is_ok()); - } -} diff --git a/src/interactive.rs b/src/interactive.rs deleted file mode 100644 index 4341e4ed..00000000 --- a/src/interactive.rs +++ /dev/null @@ -1,187 +0,0 @@ -use std::{io::Error, path::PathBuf}; - -use rustyline::{Cmd, Config, Editor, KeyEvent, config::EditMode}; -use serde_json::json; - -use crate::{MrcError, Result, commands::Commands}; - -pub struct InteractiveMode; - -impl InteractiveMode { - /// Runs the interactive mode REPL. - /// - /// # Errors - /// - /// Returns an error if the socket communication fails or the REPL encounters an error. - pub async fn run(socket_path: Option<&str>) -> Result<()> { - let hist_path = dirs::data_local_dir().map_or_else( - || PathBuf::from("history.txt"), - |p| p.join("mpvrc").join("history.txt"), - ); - - let config = Config::builder().edit_mode(EditMode::Vi).build(); - - let mut rl: Editor<(), _> = Editor::with_config(config) - .map_err(|e| MrcError::ConnectionError(Error::other(e.to_string())))?; - - rl.bind_sequence(KeyEvent::ctrl('c'), Cmd::Interrupt); - rl.bind_sequence(KeyEvent::ctrl('l'), Cmd::ClearScreen); - - let _ = rl.load_history(&hist_path); - - println!("Entering interactive mode. Type 'help' for commands or 'exit' to quit."); - println!("Socket: {}", socket_path.unwrap_or("/tmp/mpvsocket")); - - loop { - let readline = rl.readline("mpv> "); - match readline { - Ok(input) => { - let trimmed = input.trim(); - if trimmed.is_empty() { - continue; - } - rl.add_history_entry(trimmed).ok(); - - if trimmed.eq_ignore_ascii_case("exit") { - println!("Exiting interactive mode."); - break; - } - - if trimmed.eq_ignore_ascii_case("help") { - Self::show_help(); - continue; - } - - if let Err(e) = Self::process_command(trimmed, socket_path).await { - eprintln!("Error: {e}"); - } - } - Err(rustyline::error::ReadlineError::Interrupted) => { - println!("(interrupted)"); - } - Err(rustyline::error::ReadlineError::Eof) => { - println!("Exiting interactive mode."); - break; - } - Err(err) => { - eprintln!("Error: {err:?}"); - break; - } - } - } - - rl.save_history(&hist_path).ok(); - Ok(()) - } - - fn show_help() { - println!("Available commands:"); - let commands = [ - ( - "play [index]", - "Play or unpause playback, optionally at the specified index", - ), - ("pause", "Pause playback"), - ("stop", "Stop playback and quit MPV"), - ("next", "Skip to the next item in the playlist"), - ("prev", "Skip to the previous item in the playlist"), - ("seek ", "Seek to the specified position"), - ("clear", "Clear the playlist"), - ("list", "List all items in the playlist"), - ("add ", "Add files to the playlist"), - ("get ", "Get the specified property"), - ( - "set ", - "Set the specified property to a value", - ), - ("help", "Show this help message"), - ("exit", "Quit interactive mode"), - ]; - - for (command, description) in commands { - println!(" {command:<22} - {description}"); - } - - println!("\nKeyboard shortcuts:"); - println!(" Ctrl+C - Interrupt current command"); - println!(" Ctrl+L - Clear screen"); - println!(" Ctrl+D - Exit"); - } - - async fn process_command(input: &str, socket_path: Option<&str>) -> Result<()> { - let parts: Vec<&str> = input.split_whitespace().collect(); - - match parts.as_slice() { - ["play"] => { - Commands::play(None, socket_path).await?; - } - - ["play", index] => { - if let Ok(idx) = index.parse::() { - Commands::play(Some(idx), socket_path).await?; - } else { - println!("Invalid index: {index}"); - } - } - - ["pause"] => { - Commands::pause(socket_path).await?; - } - - ["stop"] => { - Commands::stop(socket_path).await?; - } - - ["next"] => { - Commands::next(socket_path).await?; - } - - ["prev"] => { - Commands::prev(socket_path).await?; - } - - ["seek", seconds] => { - if let Ok(sec) = seconds.parse::() { - Commands::seek_to(sec.into(), socket_path).await?; - } else { - println!("Invalid seconds: {seconds}"); - } - } - - ["clear"] => { - Commands::clear_playlist(socket_path).await?; - } - - ["list"] => { - Commands::list_playlist(socket_path).await?; - } - - ["add", files @ ..] => { - let file_strings: Vec = - files.iter().map(std::string::ToString::to_string).collect(); - if file_strings.is_empty() { - println!("No files provided to add to the playlist"); - } else { - Commands::add_files(&file_strings, socket_path).await?; - } - } - - ["get", property] => { - Commands::get_single_property(property, socket_path).await?; - } - - ["set", property, value] => { - let json_value = serde_json::from_str::(value) - .unwrap_or_else(|_| json!(value)); - Commands::set_single_property(property, &json_value, socket_path).await?; - } - - _ => { - println!("Unknown command: {input}"); - println!("Type 'help' for a list of available commands."); - } - } - - Ok(()) - } -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index f22b4bed..00000000 --- a/src/lib.rs +++ /dev/null @@ -1,660 +0,0 @@ -//! MRC -//! A library for interacting with the MPV media player using its JSON IPC (Inter-Process Communication) protocol. -//! -//! This crate provides a set of utilities to communicate with MPV's IPC socket, enabling you to send commands -//! and retrieve responses in a structured format. -//! -//! ## Features -//! -//! - Send commands to MPV's IPC socket -//! - Retrieve responses in JSON format -//! - Supports common MPV commands like `set_property`, `seek`, and `playlist-next` -//! - Flexible socket path configuration -//! -//! ## Example Usage -//! ```rust -//! use serde_json::json; -//! use tokio; -//! use mpvrc::{send_ipc_command, playlist_next, set_property}; -//! -//! #[tokio::main] -//! async fn main() { -//! let result = playlist_next(None).await; -//! match result { -//! Ok(response) => println!("Playlist moved to next: {:?}", response), -//! Err(err) => eprintln!("Error: {:?}", err), -//! } -//! -//! let property_result = set_property("volume", &json!(50), None).await; -//! match property_result { -//! Ok(response) => println!("Volume set: {:?}", response), -//! Err(err) => eprintln!("Error: {:?}", err), -//! } -//! } -//! ``` -//! -//! ## Constants -//! -//! ### `SOCKET_PATH` -//! Default path for the MPV IPC socket: `/tmp/mpvsocket` -//! - -pub mod commands; -pub mod interactive; - -use std::io; - -use serde_json::{Value, json}; -use thiserror::Error; -use tokio::{ - io::{AsyncReadExt, AsyncWriteExt}, - net::UnixStream, -}; -use tracing::debug; - -pub const SOCKET_PATH: &str = "/tmp/mpvsocket"; -const SOCKET_TIMEOUT_SECS: u64 = 5; - -/// Errors that can occur when interacting with the MPV IPC interface. -#[derive(Error, Debug)] -pub enum MrcError { - /// Connection to the MPV socket could not be established. - #[error("failed to connect to MPV socket: {0}")] - ConnectionError(#[from] io::Error), - - /// Error when parsing a JSON response from MPV. - #[error("failed to parse JSON response: {0}")] - ParseError(#[from] serde_json::Error), - - /// Error when a socket operation times out. - #[error("socket operation timed out after {0} seconds")] - SocketTimeout(u64), - - /// Error when MPV returns an error response. - #[error("MPV error: {0}")] - MpvError(String), - - /// Error when trying to use a property that doesn't exist. - #[error("property '{0}' not found")] - PropertyNotFound(String), - - /// Error when the socket response is not valid UTF-8. - #[error("invalid UTF-8 in socket response: {0}")] - InvalidUtf8(#[from] std::string::FromUtf8Error), - - /// Error when a network operation fails. - #[error("network error: {0}")] - NetworkError(String), - - /// Error when the server connection is lost or broken. - #[error("server connection lost: {0}")] - ConnectionLost(String), - - /// Error when a communication protocol is violated. - #[error("protocol error: {0}")] - ProtocolError(String), - - /// Error when invalid input is provided. - #[error("invalid input: {0}")] - InvalidInput(String), - - /// Error related to TLS operations. - #[error("TLS error: {0}")] - TlsError(String), -} - -/// A specialized Result type for MRC operations. -pub type Result = std::result::Result; - -/// Connects to the MPV IPC socket with timeout. -async fn connect_to_socket(socket_path: &str) -> Result { - debug!("Connecting to socket at {}", socket_path); - - tokio::time::timeout( - std::time::Duration::from_secs(SOCKET_TIMEOUT_SECS), - UnixStream::connect(socket_path), - ) - .await - .map_err(|_| MrcError::SocketTimeout(SOCKET_TIMEOUT_SECS))? - .map_err(MrcError::ConnectionError) -} - -/// Sends a command message to the socket with timeout. -async fn send_message(socket: &mut UnixStream, command: &str, args: &[Value]) -> Result<()> { - let mut command_array = vec![json!(command)]; - command_array.extend_from_slice(args); - let message = json!({ "command": command_array }); - let message_str = format!("{}\n", serde_json::to_string(&message)?); - - debug!("Serialized message to send with newline: {}", message_str); - - // Write with timeout - tokio::time::timeout( - std::time::Duration::from_secs(SOCKET_TIMEOUT_SECS), - socket.write_all(message_str.as_bytes()), - ) - .await - .map_err(|_| MrcError::SocketTimeout(SOCKET_TIMEOUT_SECS))??; - - // Flush with timeout - tokio::time::timeout( - std::time::Duration::from_secs(SOCKET_TIMEOUT_SECS), - socket.flush(), - ) - .await - .map_err(|_| MrcError::SocketTimeout(SOCKET_TIMEOUT_SECS))??; - - debug!("Message sent and flushed"); - Ok(()) -} - -/// Reads and parses the response from the socket. -async fn read_response(socket: &mut UnixStream) -> Result { - let mut response = vec![0; 1024]; - - // Read with timeout - let n = tokio::time::timeout( - std::time::Duration::from_secs(SOCKET_TIMEOUT_SECS), - socket.read(&mut response), - ) - .await - .map_err(|_| MrcError::SocketTimeout(SOCKET_TIMEOUT_SECS))??; - - if n == 0 { - return Err(MrcError::ConnectionLost( - "Socket closed unexpectedly".into(), - )); - } - - let response_str = String::from_utf8(response[..n].to_vec())?; - debug!("Raw response: {}", response_str); - - let json_response = - serde_json::from_str::(&response_str).map_err(MrcError::ParseError)?; - - debug!("Parsed IPC response: {:?}", json_response); - - // Check if MPV returned an error - if let Some(error) = json_response.get("error").and_then(|e| e.as_str()) - && !error.is_empty() - { - return Err(MrcError::MpvError(error.to_string())); - } - - Ok(json_response) -} - -/// Sends a generic IPC command to the specified socket and returns the parsed response data. -/// -/// # Arguments -/// - `command`: The name of the command to send to MPV. -/// - `args`: A slice of `Value` arguments to include in the command. -/// - `socket_path`: An optional custom path to the MPV IPC socket. If `None`, the default path is used. -/// -/// # Returns -/// A `Result` containing an `Option` with the parsed response data if successful. -/// -/// # Errors -/// Returns a `MrcError` if the connection to the socket fails or if the response cannot be parsed. -pub async fn send_ipc_command( - command: &str, - args: &[Value], - socket_path: Option<&str>, -) -> Result> { - let socket_path = socket_path.unwrap_or(SOCKET_PATH); - debug!( - "Sending IPC command: {} with arguments: {:?}", - command, args - ); - - let mut socket = connect_to_socket(socket_path).await?; - send_message(&mut socket, command, args).await?; - let json_response = read_response(&mut socket).await?; - - Ok(json_response.get("data").cloned()) -} - -/// Represents common MPV commands. -/// -/// This enum provides variants for frequently used MPV commands, which can be converted to their -/// string equivalents using the `as_str` method. -/// -/// # Errors -/// Returns an error if the connection to the socket fails or the command execution encounters issues. -#[derive(Debug)] -pub enum MpvCommand { - /// Sets a property to a specified value in MPV. - SetProperty, - /// Moves to the next item in the playlist. - PlaylistNext, - /// Moves to the previous item in the playlist. - PlaylistPrev, - /// Seeks to a specific time in the current media. - Seek, - /// Quits the MPV application. - Quit, - /// Moves an item in the playlist from one index to another. - PlaylistMove, - /// Removes an item from the playlist. - PlaylistRemove, - /// Clears all items from the playlist. - PlaylistClear, - /// Retrieves the value of a property in MPV. - GetProperty, - /// Loads a file into MPV. - LoadFile, -} - -impl MpvCommand { - /// Converts MPV commands to their string equivalents. - /// - /// # Returns - /// A string slice representing the command. - #[must_use] - pub const fn as_str(&self) -> &str { - match self { - Self::SetProperty => "set_property", - Self::PlaylistNext => "playlist-next", - Self::PlaylistPrev => "playlist-prev", - Self::Seek => "seek", - Self::Quit => "quit", - Self::PlaylistMove => "playlist-move", - Self::PlaylistRemove => "playlist-remove", - Self::PlaylistClear => "playlist-clear", - Self::GetProperty => "get_property", - Self::LoadFile => "loadfile", - } - } -} - -/// Sends the `set_property` command to MPV to change a property value. -/// -/// # Arguments -/// - `property`: The name of the property to set. -/// - `value`: The new value to assign to the property. -/// - `socket_path`: An optional custom socket path. -/// -/// # Returns -/// A `Result` containing the response data. -/// -/// # Errors -/// Returns an error if the connection to the socket fails or the command execution encounters issues. -pub async fn set_property( - property: &str, - value: &Value, - socket_path: Option<&str>, -) -> Result> { - send_ipc_command( - MpvCommand::SetProperty.as_str(), - &[json!(property), value.clone()], - socket_path, - ) - .await -} - -/// Sends the `playlist-next` command to move to the next playlist item. -/// -/// # Arguments -/// - `socket_path`: An optional custom socket path. -/// -/// # Returns -/// A `Result` containing the response data. -/// -/// # Errors -/// Returns an error if the connection to the socket fails or the command execution encounters issues. -pub async fn playlist_next(socket_path: Option<&str>) -> Result> { - send_ipc_command(MpvCommand::PlaylistNext.as_str(), &[], socket_path).await -} - -/// Sends the `playlist-prev` command to move to the previous playlist item. -/// -/// # Arguments -/// - `socket_path`: An optional custom socket path. -/// -/// # Returns -/// A `Result` containing the response data. -/// -/// # Errors -/// Returns an error if the connection to the socket fails or the command execution encounters issues. -pub async fn playlist_prev(socket_path: Option<&str>) -> Result> { - send_ipc_command(MpvCommand::PlaylistPrev.as_str(), &[], socket_path).await -} - -/// Sends the `seek` command to seek the media playback by a given number of seconds. -/// -/// # Arguments -/// - `seconds`: The number of seconds to seek. -/// - `socket_path`: An optional custom socket path. -/// -/// # Returns -/// A `Result` containing the response data. -/// -/// # Errors -/// Returns an error if the connection to the socket fails or the command execution encounters issues. -pub async fn seek(seconds: f64, socket_path: Option<&str>) -> Result> { - send_ipc_command(MpvCommand::Seek.as_str(), &[json!(seconds)], socket_path).await -} - -/// Sends the `quit` command to terminate MPV. -/// -/// # Arguments -/// - `socket_path`: An optional custom socket path. -/// -/// # Returns -/// A `Result` containing the response data. -/// -/// # Errors -/// Returns an error if the connection to the socket fails or the command execution encounters issues. -pub async fn quit(socket_path: Option<&str>) -> Result> { - send_ipc_command(MpvCommand::Quit.as_str(), &[], socket_path).await -} - -/// Sends the `playlist-move` command to move a playlist item from one index to another. -/// -/// # Arguments -/// - `from_index`: The index of the item to move. -/// - `to_index`: The index to move the item to. -/// - `socket_path`: An optional custom socket path. -/// -/// # Returns -/// A `Result` containing the response data. -/// -/// # Errors -/// Returns an error if the connection to the socket fails or the command execution encounters issues. -pub async fn playlist_move( - from_index: usize, - to_index: usize, - socket_path: Option<&str>, -) -> Result> { - send_ipc_command( - MpvCommand::PlaylistMove.as_str(), - &[json!(from_index), json!(to_index)], - socket_path, - ) - .await -} - -/// Sends the `playlist-remove` command to remove an item from the playlist. -/// -/// # Arguments -/// - `index`: The index of the item to remove, or `None` to remove the current item. -/// - `socket_path`: An optional custom socket path. -/// -/// # Returns -/// A `Result` containing the response data. -/// -/// # Errors -/// Returns an error if the connection to the socket fails or the command execution encounters issues. -pub async fn playlist_remove( - index: Option, - socket_path: Option<&str>, -) -> Result> { - let args = index.map_or_else(|| vec![json!("current")], |idx| vec![json!(idx)]); - send_ipc_command(MpvCommand::PlaylistRemove.as_str(), &args, socket_path).await -} - -/// Sends the `playlist-clear` command to clear the playlist. -/// -/// # Arguments -/// - `socket_path`: An optional custom socket path. -/// -/// # Returns -/// A `Result` containing the response data. -/// -/// # Errors -/// Returns an error if the connection to the socket fails or the command execution encounters issues. -pub async fn playlist_clear(socket_path: Option<&str>) -> Result> { - send_ipc_command(MpvCommand::PlaylistClear.as_str(), &[], socket_path).await -} - -/// Sends the `get_property` command to retrieve a property value from MPV. -/// -/// # Arguments -/// - `property`: The name of the property to retrieve. -/// - `socket_path`: An optional custom socket path. -/// -/// # Returns -/// A `Result` containing the response data. -/// -/// # Errors -/// Returns an error if the connection to the socket fails or the command execution encounters issues. -pub async fn get_property(property: &str, socket_path: Option<&str>) -> Result> { - send_ipc_command( - MpvCommand::GetProperty.as_str(), - &[json!(property)], - socket_path, - ) - .await -} - -/// Sends the `loadfile` command to load a file into MPV. -/// -/// # Arguments -/// - `filename`: The name of the file to load. -/// - `append`: Whether to append the file to the playlist (`true`) or replace the current file (`false`). -/// - `socket_path`: An optional custom socket path. -/// -/// # Returns -/// A `Result` containing the response data. -/// -/// # Errors -/// Returns an error if the connection to the socket fails or the command execution encounters issues. -pub async fn loadfile( - filename: &str, - append: bool, - socket_path: Option<&str>, -) -> Result> { - let append_flag = if append { - json!("append-play") - } else { - json!("replace") - }; - send_ipc_command( - MpvCommand::LoadFile.as_str(), - &[json!(filename), append_flag], - socket_path, - ) - .await -} - -#[cfg(test)] -mod tests { - use std::error::Error; - - use serde_json::json; - - use super::*; - - #[test] - fn test_mpvrc_error_display() { - let error = MrcError::InvalidInput("test message".to_string()); - assert_eq!(error.to_string(), "invalid input: test message"); - } - - #[test] - fn test_mpvrc_error_from_io_error() { - let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found"); - let mrc_error = MrcError::from(io_error); - assert!(matches!(mrc_error, MrcError::ConnectionError(_))); - } - - #[test] - fn test_mpvrc_error_from_json_error() { - let json_error = serde_json::from_str::("invalid json").unwrap_err(); - let mrc_error = MrcError::from(json_error); - assert!(matches!(mrc_error, MrcError::ParseError(_))); - } - - #[test] - fn test_socket_timeout_error() { - let error = MrcError::SocketTimeout(5); - assert_eq!( - error.to_string(), - "socket operation timed out after 5 seconds" - ); - } - - #[test] - fn test_mpv_error() { - let error = MrcError::MpvError("playback failed".to_string()); - assert_eq!(error.to_string(), "MPV error: playback failed"); - } - - #[test] - fn test_property_not_found_error() { - let error = MrcError::PropertyNotFound("volume".to_string()); - assert_eq!(error.to_string(), "property 'volume' not found"); - } - - #[test] - fn test_connection_lost_error() { - let error = MrcError::ConnectionLost("socket closed".to_string()); - assert_eq!(error.to_string(), "server connection lost: socket closed"); - } - - #[test] - fn test_tls_error() { - let error = MrcError::TlsError("certificate invalid".to_string()); - assert_eq!(error.to_string(), "TLS error: certificate invalid"); - } - - #[test] - fn test_error_trait_implementation() { - let error = MrcError::InvalidInput("test".to_string()); - assert!(error.source().is_none()); - - let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "test"); - let connection_error = MrcError::ConnectionError(io_error); - assert!(connection_error.source().is_some()); - } - - #[test] - fn test_mpv_command_as_str() { - assert_eq!(MpvCommand::SetProperty.as_str(), "set_property"); - assert_eq!(MpvCommand::PlaylistNext.as_str(), "playlist-next"); - assert_eq!(MpvCommand::PlaylistPrev.as_str(), "playlist-prev"); - assert_eq!(MpvCommand::Seek.as_str(), "seek"); - assert_eq!(MpvCommand::Quit.as_str(), "quit"); - assert_eq!(MpvCommand::PlaylistMove.as_str(), "playlist-move"); - assert_eq!(MpvCommand::PlaylistRemove.as_str(), "playlist-remove"); - assert_eq!(MpvCommand::PlaylistClear.as_str(), "playlist-clear"); - assert_eq!(MpvCommand::GetProperty.as_str(), "get_property"); - assert_eq!(MpvCommand::LoadFile.as_str(), "loadfile"); - } - - #[test] - fn test_mpv_command_debug() { - let cmd = MpvCommand::SetProperty; - let debug_str = format!("{cmd:?}"); - assert_eq!(debug_str, "SetProperty"); - } - - #[test] - fn test_result_type_alias() { - #[allow(clippy::unnecessary_wraps)] - fn test_function() -> Result { - Ok("test".to_string()) - } - - let result = test_function(); - assert!(result.is_ok()); - assert_eq!(result.unwrap(), "test"); - } - - #[test] - fn test_error_variants_exhaustive() { - // Test that all error variants are properly handled - let errors = vec![ - MrcError::ConnectionError(std::io::Error::other("test")), - MrcError::ParseError(serde_json::from_str::("").unwrap_err()), - MrcError::SocketTimeout(10), - MrcError::MpvError("test".to_string()), - MrcError::PropertyNotFound("test".to_string()), - MrcError::InvalidUtf8(String::from_utf8(vec![0, 159, 146, 150]).unwrap_err()), - MrcError::NetworkError("test".to_string()), - MrcError::ConnectionLost("test".to_string()), - MrcError::ProtocolError("test".to_string()), - MrcError::InvalidInput("test".to_string()), - MrcError::TlsError("test".to_string()), - ]; - - for error in errors { - // Ensure all errors implement Display - let _ = error.to_string(); - // Ensure all errors implement Debug - let _ = format!("{error:?}"); - } - } - - // Mock tests for functions that would require MPV socket - #[tokio::test] - async fn test_loadfile_append_flag_true() { - // Test that loadfile creates correct append flag for true - // This would fail with socket connection, but tests the parameter handling - let result = loadfile("test.mp4", true, Some("/nonexistent/socket")).await; - assert!(result.is_err()); - assert!(matches!(result.unwrap_err(), MrcError::ConnectionError(_))); - } - - #[tokio::test] - async fn test_loadfile_append_flag_false() { - // Test that loadfile creates correct append flag for false - let result = loadfile("test.mp4", false, Some("/nonexistent/socket")).await; - assert!(result.is_err()); - assert!(matches!(result.unwrap_err(), MrcError::ConnectionError(_))); - } - - #[tokio::test] - async fn test_seek_parameter_handling() { - let result = seek(42.5, Some("/nonexistent/socket")).await; - assert!(result.is_err()); - assert!(matches!(result.unwrap_err(), MrcError::ConnectionError(_))); - } - - #[tokio::test] - async fn test_playlist_move_parameter_handling() { - let result = playlist_move(0, 1, Some("/nonexistent/socket")).await; - assert!(result.is_err()); - assert!(matches!(result.unwrap_err(), MrcError::ConnectionError(_))); - } - - #[tokio::test] - async fn test_set_property_parameter_handling() { - let result = set_property("volume", &json!(50), Some("/nonexistent/socket")).await; - assert!(result.is_err()); - assert!(matches!(result.unwrap_err(), MrcError::ConnectionError(_))); - } - - #[tokio::test] - async fn test_get_property_parameter_handling() { - let result = get_property("volume", Some("/nonexistent/socket")).await; - assert!(result.is_err()); - assert!(matches!(result.unwrap_err(), MrcError::ConnectionError(_))); - } - - #[tokio::test] - async fn test_playlist_operations_error_handling() { - // Test that all playlist operations handle connection errors properly - let socket_path = Some("/nonexistent/socket"); - - let results = vec![ - playlist_next(socket_path).await, - playlist_prev(socket_path).await, - playlist_clear(socket_path).await, - playlist_remove(Some(0), socket_path).await, - playlist_remove(None, socket_path).await, - ]; - - for result in results { - assert!(result.is_err()); - assert!(matches!(result.unwrap_err(), MrcError::ConnectionError(_))); - } - } - - #[tokio::test] - async fn test_quit_command() { - let result = quit(Some("/nonexistent/socket")).await; - assert!(result.is_err()); - assert!(matches!(result.unwrap_err(), MrcError::ConnectionError(_))); - } -} diff --git a/src/mrc/lib.rs.html b/src/mrc/lib.rs.html new file mode 100644 index 00000000..930baf51 --- /dev/null +++ b/src/mrc/lib.rs.html @@ -0,0 +1,357 @@ +lib.rs - source

mrc/
lib.rs

1//! MRC
+2//! A library for interacting with the MPV media player using its JSON IPC (Inter-Process Communication) protocol.
+3//!
+4//! This crate provides a set of utilities to communicate with MPV's IPC socket, enabling you to send commands
+5//! and retrieve responses in a structured format.
+6//!
+7//! ## Features
+8//!
+9//! - Send commands to MPV's IPC socket
+10//! - Retrieve responses in JSON format
+11//! - Supports common MPV commands like `set_property`, `seek`, and `playlist-next`
+12//! - Flexible socket path configuration
+13//!
+14//! ## Example Usage
+15//! ```rust
+16//! use serde_json::json;
+17//! use tokio;
+18//! use mrc::{send_ipc_command, playlist_next, set_property};
+19//!
+20//! #[tokio::main]
+21//! async fn main() {
+22//!     let result = playlist_next(None).await;
+23//!     match result {
+24//!         Ok(response) => println!("Playlist moved to next: {:?}", response),
+25//!         Err(err) => eprintln!("Error: {:?}", err),
+26//!     }
+27//!
+28//!     let property_result = set_property("volume", &json!(50), None).await;
+29//!     match property_result {
+30//!         Ok(response) => println!("Volume set: {:?}", response),
+31//!         Err(err) => eprintln!("Error: {:?}", err),
+32//!     }
+33//! }
+34//! ```
+35//!
+36//! ## Constants
+37//!
+38//! ### `SOCKET_PATH`
+39//! Default path for the MPV IPC socket: `/tmp/mpvsocket`
+40//!
+41//! ## Functions
+42
+43use serde_json::{json, Value};
+44use std::io::{self};
+45use tokio::io::{AsyncReadExt, AsyncWriteExt};
+46use tokio::net::UnixStream;
+47use tracing::{debug, error};
+48
+49pub const SOCKET_PATH: &str = "/tmp/mpvsocket";
+50
+51/// Sends a generic IPC command to the specified socket and returns the parsed response data.
+52///
+53/// # Arguments
+54/// - `command`: The name of the command to send to MPV.
+55/// - `args`: A slice of `Value` arguments to include in the command.
+56/// - `socket_path`: An optional custom path to the MPV IPC socket. If `None`, the default path is used.
+57///
+58/// # Returns
+59/// A `Result` containing an `Option<Value>` with the parsed response data if successful.
+60///
+61/// # Errors
+62/// Returns an error if the connection to the socket fails or if the response cannot be parsed.
+63pub async fn send_ipc_command(
+64    command: &str,
+65    args: &[Value],
+66    socket_path: Option<&str>,
+67) -> io::Result<Option<Value>> {
+68    let socket_path = socket_path.unwrap_or(SOCKET_PATH);
+69    debug!(
+70        "Sending IPC command: {} with arguments: {:?}",
+71        command, args
+72    );
+73
+74    match UnixStream::connect(socket_path).await {
+75        Ok(mut socket) => {
+76            debug!("Connected to socket at {}", socket_path);
+77
+78            let mut command_array = vec![json!(command)];
+79            command_array.extend_from_slice(args);
+80            let message = json!({ "command": command_array });
+81            let message_str = format!("{}\n", serde_json::to_string(&message)?);
+82            debug!("Serialized message to send with newline: {}", message_str);
+83
+84            socket.write_all(message_str.as_bytes()).await?;
+85            socket.flush().await?;
+86            debug!("Message sent and flushed");
+87
+88            let mut response = vec![0; 1024];
+89            let n = socket.read(&mut response).await?;
+90            let response_str = String::from_utf8_lossy(&response[..n]);
+91            debug!("Raw response: {}", response_str);
+92
+93            match serde_json::from_str::<Value>(&response_str) {
+94                Ok(json_response) => {
+95                    debug!("Parsed IPC response: {:?}", json_response);
+96                    Ok(json_response.get("data").cloned())
+97                }
+98
+99                Err(e) => {
+100                    error!("Failed to parse response: {}", e);
+101                    Ok(None)
+102                }
+103            }
+104        }
+105
+106        Err(e) => {
+107            error!("Failed to connect to MPV socket: {}", e);
+108            Err(e)
+109        }
+110    }
+111}
+112
+113/// Represents common MPV commands.
+114///
+115/// This enum provides variants for frequently used MPV commands, which can be converted to their
+116/// string equivalents using the `as_str` method.
+117///
+118/// # Errors
+119/// Returns an error if the connection to the socket fails or the command execution encounters issues.
+120#[derive(Debug)]
+121pub enum MpvCommand {
+122    /// Sets a property to a specified value in MPV.
+123    SetProperty,
+124    /// Moves to the next item in the playlist.
+125    PlaylistNext,
+126    /// Moves to the previous item in the playlist.
+127    PlaylistPrev,
+128    /// Seeks to a specific time in the current media.
+129    Seek,
+130    /// Quits the MPV application.
+131    Quit,
+132    /// Moves an item in the playlist from one index to another.
+133    PlaylistMove,
+134    /// Removes an item from the playlist.
+135    PlaylistRemove,
+136    /// Clears all items from the playlist.
+137    PlaylistClear,
+138    /// Retrieves the value of a property in MPV.
+139    GetProperty,
+140    /// Loads a file into MPV.
+141    LoadFile,
+142}
+143
+144impl MpvCommand {
+145    /// Converts MPV commands to their string equivalents.
+146    ///
+147    /// # Returns
+148    /// A string slice representing the command.
+149    #[must_use]
+150    pub const fn as_str(&self) -> &str {
+151        match self {
+152            Self::SetProperty => "set_property",
+153            Self::PlaylistNext => "playlist-next",
+154            Self::PlaylistPrev => "playlist-prev",
+155            Self::Seek => "seek",
+156            Self::Quit => "quit",
+157            Self::PlaylistMove => "playlist-move",
+158            Self::PlaylistRemove => "playlist-remove",
+159            Self::PlaylistClear => "playlist-clear",
+160            Self::GetProperty => "get_property",
+161            Self::LoadFile => "loadfile",
+162        }
+163    }
+164}
+165
+166/// Sends the `set_property` command to MPV to change a property value.
+167///
+168/// # Arguments
+169/// - `property`: The name of the property to set.
+170/// - `value`: The new value to assign to the property.
+171/// - `socket_path`: An optional custom socket path.
+172///
+173/// # Returns
+174/// A `Result` containing the response data.
+175///
+176/// # Errors
+177/// Returns an error if the connection to the socket fails or the command execution encounters issues.
+178pub async fn set_property(
+179    property: &str,
+180    value: &Value,
+181    socket_path: Option<&str>,
+182) -> io::Result<Option<Value>> {
+183    send_ipc_command(
+184        MpvCommand::SetProperty.as_str(),
+185        &[json!(property), value.clone()],
+186        socket_path,
+187    )
+188    .await
+189}
+190
+191/// Sends the `playlist-next` command to move to the next playlist item.
+192///
+193/// # Arguments
+194/// - `socket_path`: An optional custom socket path.
+195///
+196/// # Returns
+197/// A `Result` containing the response data.
+198///
+199/// # Errors
+200/// Returns an error if the connection to the socket fails or the command execution encounters issues.
+201pub async fn playlist_next(socket_path: Option<&str>) -> io::Result<Option<Value>> {
+202    send_ipc_command(MpvCommand::PlaylistNext.as_str(), &[], socket_path).await
+203}
+204
+205/// Sends the `playlist-prev` command to move to the previous playlist item.
+206///
+207/// # Arguments
+208/// - `socket_path`: An optional custom socket path.
+209///
+210/// # Returns
+211/// A `Result` containing the response data.
+212///
+213/// # Errors
+214/// Returns an error if the connection to the socket fails or the command execution encounters issues.
+215pub async fn playlist_prev(socket_path: Option<&str>) -> io::Result<Option<Value>> {
+216    send_ipc_command(MpvCommand::PlaylistPrev.as_str(), &[], socket_path).await
+217}
+218
+219/// Sends the `seek` command to seek the media playback by a given number of seconds.
+220///
+221/// # Arguments
+222/// - `seconds`: The number of seconds to seek.
+223/// - `socket_path`: An optional custom socket path.
+224///
+225/// # Returns
+226/// A `Result` containing the response data.
+227///
+228/// # Errors
+229/// Returns an error if the connection to the socket fails or the command execution encounters issues.
+230pub async fn seek(seconds: f64, socket_path: Option<&str>) -> io::Result<Option<Value>> {
+231    send_ipc_command(MpvCommand::Seek.as_str(), &[json!(seconds)], socket_path).await
+232}
+233
+234/// Sends the `quit` command to terminate MPV.
+235///
+236/// # Arguments
+237/// - `socket_path`: An optional custom socket path.
+238///
+239/// # Returns
+240/// A `Result` containing the response data.
+241///
+242/// # Errors
+243/// Returns an error if the connection to the socket fails or the command execution encounters issues.
+244pub async fn quit(socket_path: Option<&str>) -> io::Result<Option<Value>> {
+245    send_ipc_command(MpvCommand::Quit.as_str(), &[], socket_path).await
+246}
+247
+248/// Sends the `playlist-move` command to move a playlist item from one index to another.
+249///
+250/// # Arguments
+251/// - `from_index`: The index of the item to move.
+252/// - `to_index`: The index to move the item to.
+253/// - `socket_path`: An optional custom socket path.
+254///
+255/// # Returns
+256/// A `Result` containing the response data.
+257///
+258/// # Errors
+259/// Returns an error if the connection to the socket fails or the command execution encounters issues.
+260pub async fn playlist_move(
+261    from_index: usize,
+262    to_index: usize,
+263    socket_path: Option<&str>,
+264) -> io::Result<Option<Value>> {
+265    send_ipc_command(
+266        MpvCommand::PlaylistMove.as_str(),
+267        &[json!(from_index), json!(to_index)],
+268        socket_path,
+269    )
+270    .await
+271}
+272
+273/// Sends the `playlist-remove` command to remove an item from the playlist.
+274///
+275/// # Arguments
+276/// - `index`: The index of the item to remove, or `None` to remove the current item.
+277/// - `socket_path`: An optional custom socket path.
+278///
+279/// # Returns
+280/// A `Result` containing the response data.
+281///
+282/// # Errors
+283/// Returns an error if the connection to the socket fails or the command execution encounters issues.
+284pub async fn playlist_remove(
+285    index: Option<usize>,
+286    socket_path: Option<&str>,
+287) -> io::Result<Option<Value>> {
+288    let args = match index {
+289        Some(idx) => vec![json!(idx)],
+290        None => vec![json!("current")],
+291    };
+292    send_ipc_command(MpvCommand::PlaylistRemove.as_str(), &args, socket_path).await
+293}
+294
+295/// Sends the `playlist-clear` command to clear the playlist.
+296///
+297/// # Arguments
+298/// - `socket_path`: An optional custom socket path.
+299///
+300/// # Returns
+301/// A `Result` containing the response data.
+302///
+303/// # Errors
+304/// Returns an error if the connection to the socket fails or the command execution encounters issues.
+305pub async fn playlist_clear(socket_path: Option<&str>) -> io::Result<Option<Value>> {
+306    send_ipc_command(MpvCommand::PlaylistClear.as_str(), &[], socket_path).await
+307}
+308
+309/// Sends the `get_property` command to retrieve a property value from MPV.
+310///
+311/// # Arguments
+312/// - `property`: The name of the property to retrieve.
+313/// - `socket_path`: An optional custom socket path.
+314///
+315/// # Returns
+316/// A `Result` containing the response data.
+317///
+318/// # Errors
+319/// Returns an error if the connection to the socket fails or the command execution encounters issues.
+320pub async fn get_property(property: &str, socket_path: Option<&str>) -> io::Result<Option<Value>> {
+321    send_ipc_command(
+322        MpvCommand::GetProperty.as_str(),
+323        &[json!(property)],
+324        socket_path,
+325    )
+326    .await
+327}
+328
+329/// Sends the `loadfile` command to load a file into MPV.
+330///
+331/// # Arguments
+332/// - `filename`: The name of the file to load.
+333/// - `append`: Whether to append the file to the playlist (`true`) or replace the current file (`false`).
+334/// - `socket_path`: An optional custom socket path.
+335///
+336/// # Returns
+337/// A `Result` containing the response data.
+338///
+339/// # Errors
+340/// Returns an error if the connection to the socket fails or the command execution encounters issues.
+341pub async fn loadfile(
+342    filename: &str,
+343    append: bool,
+344    socket_path: Option<&str>,
+345) -> io::Result<Option<Value>> {
+346    let append_flag = if append {
+347        json!("append-play")
+348    } else {
+349        json!("replace")
+350    };
+351    send_ipc_command(
+352        MpvCommand::LoadFile.as_str(),
+353        &[json!(filename), append_flag],
+354        socket_path,
+355    )
+356    .await
+357}
\ No newline at end of file diff --git a/src/server.rs b/src/server.rs deleted file mode 100644 index 5f0125e5..00000000 --- a/src/server.rs +++ /dev/null @@ -1,240 +0,0 @@ -use std::{env, io::Read, sync::Arc}; - -use clap::Parser; -use mpvrc::{MrcError, Result as MrcResult, SOCKET_PATH, commands::Commands}; -use native_tls::{Identity, TlsAcceptor as NativeTlsAcceptor}; -use tokio::io::{AsyncReadExt, AsyncWriteExt}; -use tokio_native_tls::TlsAcceptor; -use tracing::{debug, error, info, warn}; - -#[derive(Parser)] -#[command(author, version, about)] -struct Config { - /// The IP address and port to bind the server to - #[arg(short, long, default_value = "127.0.0.1:8080")] - bind: String, - - /// Path to MPV IPC socket - #[arg(short, long)] - socket: Option, -} - -impl Config { - fn socket_path(&self) -> String { - self.socket - .clone() - .unwrap_or_else(|| SOCKET_PATH.to_string()) - } -} - -async fn handle_connection( - stream: tokio::net::TcpStream, - acceptor: Arc, - socket_path: String, -) -> MrcResult<()> { - let mut stream = acceptor - .accept(stream) - .await - .map_err(|e| MrcError::TlsError(e.to_string()))?; - let mut buffer = vec![0; 2048]; - - let n = stream - .read(&mut buffer) - .await - .map_err(MrcError::ConnectionError)?; - let request = String::from_utf8_lossy(&buffer[..n]); - - debug!("Received request:\n{}", request); - - let headers = request.split("\r\n").collect::>(); - let token_line = headers - .iter() - .find(|&&line| line.starts_with("Authorization:")); - let token = token_line.map_or("", |line| line.split(' ').nth(1).unwrap_or_default()); - - let Ok(auth_token) = env::var("AUTH_TOKEN") else { - warn!("AUTH_TOKEN environment variable not set. Authentication disabled."); - let response = - "HTTP/1.1 401 Unauthorized\r\nContent-Length: 29\r\n\r\nAuthentication token not set\n"; - stream.write_all(response.as_bytes()).await?; - return Ok(()); - }; - - if token.is_empty() || token != auth_token { - warn!( - "Authentication failed for token: {}", - if token.is_empty() { - "" - } else { - "" - } - ); - let response = - "HTTP/1.1 401 Unauthorized\r\nContent-Length: 21\r\n\r\nAuthentication failed\n"; - stream.write_all(response.as_bytes()).await?; - return Ok(()); - } - - info!("Client authenticated successfully"); - - let command = request.split("\r\n\r\n").last().unwrap_or("").trim(); - - if command.is_empty() { - warn!("Received empty command"); - let response = - "HTTP/1.1 400 Bad Request\r\nContent-Length: 20\r\n\r\nNo command provided\n"; - stream.write_all(response.as_bytes()).await?; - return Ok(()); - } - - info!("Processing command: {}", command); - - let (status_code, response_body) = match process_command(command, &socket_path).await { - Ok(response) => ("200 OK", response), - Err(e) => { - error!("Error processing command '{}': {}", command, e); - ("400 Bad Request", format!("Error: {e}\n")) - } - }; - - let http_response = format!( - "HTTP/1.1 {}\r\nContent-Length: {}\r\nContent-Type: text/plain\r\n\r\n{}", - status_code, - response_body.len(), - response_body - ); - - stream.write_all(http_response.as_bytes()).await?; - - Ok(()) -} - -async fn process_command(command: &str, socket_path: &str) -> MrcResult { - let parts: Vec<&str> = command.split_whitespace().collect(); - - match parts.as_slice() { - ["pause"] => { - Commands::pause(Some(socket_path)).await?; - Ok("Paused playback\n".to_string()) - } - - ["play"] => { - Commands::play(None, Some(socket_path)).await?; - Ok("Resumed playback\n".to_string()) - } - - ["play", index] => { - if let Ok(idx) = index.parse::() { - Commands::play(Some(idx), Some(socket_path)).await?; - Ok(format!("Playing from index {idx}\n")) - } else { - Err(MrcError::InvalidInput(format!("Invalid index: {index}"))) - } - } - - ["stop"] => { - Commands::stop(Some(socket_path)).await?; - Ok("Stopped playback\n".to_string()) - } - - ["next"] => { - Commands::next(Some(socket_path)).await?; - Ok("Skipped to next item\n".to_string()) - } - - ["prev"] => { - Commands::prev(Some(socket_path)).await?; - Ok("Skipped to previous item\n".to_string()) - } - - ["seek", seconds] => { - if let Ok(sec) = seconds.parse::() { - Commands::seek_to(sec, Some(socket_path)).await?; - Ok(format!("Seeking to {sec} seconds\n")) - } else { - Err(MrcError::InvalidInput(format!( - "Invalid seconds: {seconds}" - ))) - } - } - - ["clear"] => { - Commands::clear_playlist(Some(socket_path)).await?; - Ok("Cleared playlist\n".to_string()) - } - - ["list"] => match mpvrc::get_property("playlist", Some(socket_path)).await? { - Some(data) => { - let pretty_json = - serde_json::to_string_pretty(&data).map_err(MrcError::ParseError)?; - Ok(format!("Playlist: {pretty_json}\n")) - } - None => Ok("Playlist is empty\n".to_string()), - }, - - _ => Err(MrcError::InvalidInput(format!( - "Unknown command: {}. Available commands: pause, play [index], stop, next, prev, seek , clear, list", - command.trim() - ))), - } -} - -fn create_tls_acceptor() -> MrcResult { - let pfx_path = env::var("TLS_PFX_PATH") - .map_err(|_| MrcError::InvalidInput("TLS_PFX_PATH not set".to_string()))?; - let password = env::var("TLS_PASSWORD") - .map_err(|_| MrcError::InvalidInput("TLS_PASSWORD not set".to_string()))?; - - let mut file = std::fs::File::open(&pfx_path).map_err(MrcError::ConnectionError)?; - let mut identity = vec![]; - file.read_to_end(&mut identity) - .map_err(MrcError::ConnectionError)?; - - let identity = Identity::from_pkcs12(&identity, &password) - .map_err(|e| MrcError::TlsError(e.to_string()))?; - let native_acceptor = - NativeTlsAcceptor::new(identity).map_err(|e| MrcError::TlsError(e.to_string()))?; - Ok(TlsAcceptor::from(native_acceptor)) -} - -#[tokio::main] -async fn main() -> MrcResult<()> { - tracing_subscriber::fmt::init(); - let config = Config::parse(); - let socket_path = config.socket_path(); - - if !std::path::Path::new(&socket_path).exists() { - error!( - "Error: MPV socket not found at '{}'. Is MPV running?", - socket_path - ); - return Err(MrcError::ConnectionError(std::io::Error::new( - std::io::ErrorKind::NotFound, - format!("MPV socket not found at '{socket_path}'"), - ))); - } - - info!("Server is starting..."); - match create_tls_acceptor() { - Ok(acceptor) => { - let acceptor = Arc::new(acceptor); - let listener = tokio::net::TcpListener::bind(&config.bind) - .await - .map_err(MrcError::ConnectionError)?; - info!("Server is listening on {}", config.bind); - - loop { - let (stream, _) = listener.accept().await.map_err(MrcError::ConnectionError)?; - info!("New connection accepted."); - - let acceptor = Arc::clone(&acceptor); - tokio::spawn(handle_connection(stream, acceptor, socket_path.clone())); - } - } - - Err(e) => { - error!("Failed to initialize TLS: {}", e); - return Err(e); - } - } -} diff --git a/src/server/server.rs.html b/src/server/server.rs.html new file mode 100644 index 00000000..81d3f5c9 --- /dev/null +++ b/src/server/server.rs.html @@ -0,0 +1,217 @@ +server.rs - source

server/
server.rs

1use std::env;
+2use std::io::Read;
+3use std::sync::Arc;
+4
+5use clap::Parser;
+6use native_tls::{Identity, TlsAcceptor as NativeTlsAcceptor};
+7use serde_json::json;
+8use tokio::io::{AsyncReadExt, AsyncWriteExt};
+9use tokio_native_tls::TlsAcceptor;
+10use tracing::{debug, error, info};
+11
+12use mrc::{get_property, playlist_clear, playlist_next, playlist_prev, quit, seek, set_property};
+13
+14#[derive(Parser)]
+15#[command(author, version, about)]
+16struct Config {
+17    /// The IP address and port to bind the server to
+18    #[arg(short, long, default_value = "127.0.0.1:8080")]
+19    bind: String,
+20
+21    /// Path to MPV IPC socket
+22    #[arg(short, long, default_value = "/tmp/mpvsocket")]
+23    socket: String,
+24}
+25
+26async fn handle_connection(
+27    stream: tokio::net::TcpStream,
+28    acceptor: Arc<TlsAcceptor>,
+29) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
+30    let mut stream = acceptor.accept(stream).await?;
+31    let mut buffer = vec![0; 2048];
+32
+33    let n = stream.read(&mut buffer).await?;
+34    let request = String::from_utf8_lossy(&buffer[..n]);
+35
+36    debug!("Received request:\n{}", request);
+37
+38    let headers = request.split("\r\n").collect::<Vec<&str>>();
+39    let token_line = headers
+40        .iter()
+41        .find(|&&line| line.starts_with("Authorization:"));
+42    let token = match token_line {
+43        Some(line) => line.split(" ").nth(1).unwrap_or_default(),
+44        None => "",
+45    };
+46
+47    let auth_token = match env::var("AUTH_TOKEN") {
+48        Ok(token) => token,
+49        Err(_) => {
+50            error!("Authentication token is not set. Connection cannot be accepted.");
+51            stream.write_all(b"Authentication token not set\n").await?;
+52
+53            // You know what? I do not care to panic when the authentication token is
+54            // missing in the environment. Start the goddamned server and hell, even
+55            // accept incoming connections. Authenticated requests will be refused
+56            // when the token is incorrect or not set, so we can simply continue here.
+57            return Ok(());
+58        }
+59    };
+60
+61    if token != auth_token {
+62        stream.write_all(b"Authentication failed\n").await?;
+63        return Ok(());
+64    }
+65
+66    info!("Client authenticated");
+67    stream.write_all(b"Authenticated\n").await?;
+68
+69    let command = request.split("\r\n\r\n").last().unwrap_or("");
+70    info!("Received command: {}", command);
+71
+72    let response = match process_command(command.trim()).await {
+73        Ok(response) => response,
+74        Err(e) => {
+75            error!("Error processing command: {}", e);
+76            format!("Error: {:?}", e)
+77        }
+78    };
+79
+80    let http_response = format!(
+81        "HTTP/1.1 200 OK\r\nContent-Length: {}\r\n\r\n{}",
+82        response.len(),
+83        response
+84    );
+85    stream.write_all(http_response.as_bytes()).await?;
+86
+87    Ok(())
+88}
+89
+90async fn process_command(command: &str) -> Result<String, String> {
+91    match command {
+92        "pause" => {
+93            info!("Pausing playback");
+94            set_property("pause", &json!(true), None)
+95                .await
+96                .map_err(|e| format!("Failed to pause: {:?}", e))?;
+97            Ok("Paused playback\n".to_string())
+98        }
+99
+100        "play" => {
+101            info!("Unpausing playback");
+102            set_property("pause", &json!(false), None)
+103                .await
+104                .map_err(|e| format!("Failed to play: {:?}", e))?;
+105            Ok("Resumed playback\n".to_string())
+106        }
+107
+108        "stop" => {
+109            info!("Stopping playback and quitting MPV");
+110            quit(None)
+111                .await
+112                .map_err(|e| format!("Failed to stop: {:?}", e))?;
+113            Ok("Stopped playback\n".to_string())
+114        }
+115
+116        "next" => {
+117            info!("Skipping to next item in the playlist");
+118            playlist_next(None)
+119                .await
+120                .map_err(|e| format!("Failed to skip to next: {:?}", e))?;
+121            Ok("Skipped to next item\n".to_string())
+122        }
+123
+124        "prev" => {
+125            info!("Skipping to previous item in the playlist");
+126            playlist_prev(None)
+127                .await
+128                .map_err(|e| format!("Failed to skip to previous: {:?}", e))?;
+129            Ok("Skipped to previous item\n".to_string())
+130        }
+131
+132        "seek" => {
+133            let parts: Vec<&str> = command.split_whitespace().collect();
+134            if let Some(seconds) = parts.get(1) {
+135                if let Ok(sec) = seconds.parse::<i32>() {
+136                    info!("Seeking to {} seconds", sec);
+137                    seek(sec.into(), None)
+138                        .await
+139                        .map_err(|e| format!("Failed to seek: {:?}", e))?;
+140                    return Ok(format!("Seeking to {} seconds\n", sec));
+141                }
+142            }
+143            Err("Invalid seek command".to_string())
+144        }
+145
+146        "clear" => {
+147            info!("Clearing the playlist");
+148            playlist_clear(None)
+149                .await
+150                .map_err(|e| format!("Failed to clear playlist: {:?}", e))?;
+151            Ok("Cleared playlist\n".to_string())
+152        }
+153
+154        "list" => {
+155            info!("Listing playlist items");
+156            match get_property("playlist", None).await {
+157                Ok(Some(data)) => Ok(format!(
+158                    "Playlist: {}",
+159                    serde_json::to_string_pretty(&data).unwrap()
+160                )),
+161                Ok(None) => Err("No playlist data available".to_string()),
+162                Err(e) => Err(format!("Failed to fetch playlist: {:?}", e)),
+163            }
+164        }
+165        _ => Err("Unknown command".to_string()),
+166    }
+167}
+168
+169fn create_tls_acceptor() -> Result<TlsAcceptor, Box<dyn std::error::Error + Send + Sync>> {
+170    let pfx_path = env::var("TLS_PFX_PATH")
+171        .map_err(|_| std::io::Error::new(std::io::ErrorKind::NotFound, "TLS_PFX_PATH not set"))?;
+172    let password = env::var("TLS_PASSWORD")
+173        .map_err(|_| std::io::Error::new(std::io::ErrorKind::NotFound, "TLS_PASSWORD not set"))?;
+174
+175    let mut file = std::fs::File::open(&pfx_path)?;
+176    let mut identity = vec![];
+177    file.read_to_end(&mut identity)?;
+178
+179    let identity = Identity::from_pkcs12(&identity, &password)?;
+180    let native_acceptor = NativeTlsAcceptor::new(identity)?;
+181    Ok(TlsAcceptor::from(native_acceptor))
+182}
+183
+184#[tokio::main]
+185async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
+186    tracing_subscriber::fmt::init();
+187    let config = Config::parse();
+188
+189    if !std::path::Path::new(&config.socket).exists() {
+190        error!(
+191            "Error: MPV socket not found at '{}'. Is MPV running?",
+192            config.socket
+193        );
+194    }
+195
+196    info!("Server is starting...");
+197    match create_tls_acceptor() {
+198        Ok(acceptor) => {
+199            let acceptor = Arc::new(acceptor);
+200            let listener = tokio::net::TcpListener::bind(&config.bind).await?;
+201            info!("Server is listening on {}", config.bind);
+202
+203            loop {
+204                let (stream, _) = listener.accept().await?;
+205                info!("New connection accepted.");
+206
+207                let acceptor = Arc::clone(&acceptor);
+208                tokio::spawn(handle_connection(stream, acceptor));
+209            }
+210        }
+211
+212        Err(e) => {
+213            error!("Failed to initialize TLS: {}", e);
+214            return Err(e);
+215        }
+216    }
+217}
\ No newline at end of file diff --git a/static.files/COPYRIGHT-7fb11f4e.txt b/static.files/COPYRIGHT-7fb11f4e.txt new file mode 100644 index 00000000..752dab0a --- /dev/null +++ b/static.files/COPYRIGHT-7fb11f4e.txt @@ -0,0 +1,71 @@ +# REUSE-IgnoreStart + +These documentation pages include resources by third parties. This copyright +file applies only to those resources. The following third party resources are +included, and carry their own copyright notices and license terms: + +* Fira Sans (FiraSans-Regular.woff2, FiraSans-Medium.woff2): + + Copyright (c) 2014, Mozilla Foundation https://mozilla.org/ + with Reserved Font Name Fira Sans. + + Copyright (c) 2014, Telefonica S.A. + + Licensed under the SIL Open Font License, Version 1.1. + See FiraSans-LICENSE.txt. + +* rustdoc.css, main.js, and playpen.js: + + Copyright 2015 The Rust Developers. + Licensed under the Apache License, Version 2.0 (see LICENSE-APACHE.txt) or + the MIT license (LICENSE-MIT.txt) at your option. + +* normalize.css: + + Copyright (c) Nicolas Gallagher and Jonathan Neal. + Licensed under the MIT license (see LICENSE-MIT.txt). + +* Source Code Pro (SourceCodePro-Regular.ttf.woff2, + SourceCodePro-Semibold.ttf.woff2, SourceCodePro-It.ttf.woff2): + + Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), + with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark + of Adobe Systems Incorporated in the United States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceCodePro-LICENSE.txt. + +* Source Serif 4 (SourceSerif4-Regular.ttf.woff2, SourceSerif4-Bold.ttf.woff2, + SourceSerif4-It.ttf.woff2, SourceSerif4-Semibold.ttf.woff2): + + Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name + 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United + States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceSerif4-LICENSE.md. + +* Nanum Barun Gothic Font (NanumBarunGothic.woff2) + + Copyright 2010, NAVER Corporation (http://www.nhncorp.com) + with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic, + NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen, + Naver NanumPen, Naver NanumGothicEco, NanumGothicEco, + Naver NanumMyeongjoEco, NanumMyeongjoEco, Naver NanumGothicLight, + NanumGothicLight, NanumBarunGothic, Naver NanumBarunGothic. + + https://hangeul.naver.com/2017/nanum + https://github.com/hiun/NanumBarunGothic + + Licensed under the SIL Open Font License, Version 1.1. + See NanumBarunGothic-LICENSE.txt. + +* Rust logos (rust-logo.svg, favicon.svg, favicon-32x32.png) + + Copyright 2025 Rust Foundation. + Licensed under the Creative Commons Attribution license (CC-BY). + https://rustfoundation.org/policy/rust-trademark-policy/ + +This copyright file is intended to be distributed with rustdoc output. + +# REUSE-IgnoreEnd diff --git a/static.files/FiraMono-Medium-86f75c8c.woff2 b/static.files/FiraMono-Medium-86f75c8c.woff2 new file mode 100644 index 00000000..610e9b20 Binary files /dev/null and b/static.files/FiraMono-Medium-86f75c8c.woff2 differ diff --git a/static.files/FiraMono-Regular-87c26294.woff2 b/static.files/FiraMono-Regular-87c26294.woff2 new file mode 100644 index 00000000..9fa44b7c Binary files /dev/null and b/static.files/FiraMono-Regular-87c26294.woff2 differ diff --git a/static.files/FiraSans-Italic-81dc35de.woff2 b/static.files/FiraSans-Italic-81dc35de.woff2 new file mode 100644 index 00000000..3f63664f Binary files /dev/null and b/static.files/FiraSans-Italic-81dc35de.woff2 differ diff --git a/static.files/FiraSans-LICENSE-05ab6dbd.txt b/static.files/FiraSans-LICENSE-05ab6dbd.txt new file mode 100644 index 00000000..d7e9c149 --- /dev/null +++ b/static.files/FiraSans-LICENSE-05ab6dbd.txt @@ -0,0 +1,98 @@ +// REUSE-IgnoreStart + +Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A. +with Reserved Font Name < Fira >, + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +// REUSE-IgnoreEnd diff --git a/static.files/FiraSans-Medium-e1aa3f0a.woff2 b/static.files/FiraSans-Medium-e1aa3f0a.woff2 new file mode 100644 index 00000000..7a1e5fc5 Binary files /dev/null and b/static.files/FiraSans-Medium-e1aa3f0a.woff2 differ diff --git a/static.files/FiraSans-MediumItalic-ccf7e434.woff2 b/static.files/FiraSans-MediumItalic-ccf7e434.woff2 new file mode 100644 index 00000000..2d08f9f7 Binary files /dev/null and b/static.files/FiraSans-MediumItalic-ccf7e434.woff2 differ diff --git a/static.files/FiraSans-Regular-0fe48ade.woff2 b/static.files/FiraSans-Regular-0fe48ade.woff2 new file mode 100644 index 00000000..e766e06c Binary files /dev/null and b/static.files/FiraSans-Regular-0fe48ade.woff2 differ diff --git a/static.files/LICENSE-APACHE-a60eea81.txt b/static.files/LICENSE-APACHE-a60eea81.txt new file mode 100644 index 00000000..16fe87b0 --- /dev/null +++ b/static.files/LICENSE-APACHE-a60eea81.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/static.files/LICENSE-MIT-23f18e03.txt b/static.files/LICENSE-MIT-23f18e03.txt new file mode 100644 index 00000000..31aa7938 --- /dev/null +++ b/static.files/LICENSE-MIT-23f18e03.txt @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/static.files/NanumBarunGothic-13b3dcba.ttf.woff2 b/static.files/NanumBarunGothic-13b3dcba.ttf.woff2 new file mode 100644 index 00000000..1866ad4b Binary files /dev/null and b/static.files/NanumBarunGothic-13b3dcba.ttf.woff2 differ diff --git a/static.files/NanumBarunGothic-LICENSE-a37d393b.txt b/static.files/NanumBarunGothic-LICENSE-a37d393b.txt new file mode 100644 index 00000000..4b3edc29 --- /dev/null +++ b/static.files/NanumBarunGothic-LICENSE-a37d393b.txt @@ -0,0 +1,103 @@ +// REUSE-IgnoreStart + +Copyright (c) 2010, NAVER Corporation (https://www.navercorp.com/), + +with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic, +NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen, +Naver NanumPen, Naver NanumGothicEco, NanumGothicEco, Naver NanumMyeongjoEco, +NanumMyeongjoEco, Naver NanumGothicLight, NanumGothicLight, NanumBarunGothic, +Naver NanumBarunGothic, NanumSquareRound, NanumBarunPen, MaruBuri + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +// REUSE-IgnoreEnd diff --git a/static.files/SourceCodePro-It-fc8b9304.ttf.woff2 b/static.files/SourceCodePro-It-fc8b9304.ttf.woff2 new file mode 100644 index 00000000..462c34ef Binary files /dev/null and b/static.files/SourceCodePro-It-fc8b9304.ttf.woff2 differ diff --git a/static.files/SourceCodePro-LICENSE-67f54ca7.txt b/static.files/SourceCodePro-LICENSE-67f54ca7.txt new file mode 100644 index 00000000..0d2941e1 --- /dev/null +++ b/static.files/SourceCodePro-LICENSE-67f54ca7.txt @@ -0,0 +1,97 @@ +// REUSE-IgnoreStart + +Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +// REUSE-IgnoreEnd diff --git a/static.files/SourceCodePro-Regular-8badfe75.ttf.woff2 b/static.files/SourceCodePro-Regular-8badfe75.ttf.woff2 new file mode 100644 index 00000000..10b558e0 Binary files /dev/null and b/static.files/SourceCodePro-Regular-8badfe75.ttf.woff2 differ diff --git a/static.files/SourceCodePro-Semibold-aa29a496.ttf.woff2 b/static.files/SourceCodePro-Semibold-aa29a496.ttf.woff2 new file mode 100644 index 00000000..5ec64eef Binary files /dev/null and b/static.files/SourceCodePro-Semibold-aa29a496.ttf.woff2 differ diff --git a/static.files/SourceSerif4-Bold-6d4fd4c0.ttf.woff2 b/static.files/SourceSerif4-Bold-6d4fd4c0.ttf.woff2 new file mode 100644 index 00000000..181a07f6 Binary files /dev/null and b/static.files/SourceSerif4-Bold-6d4fd4c0.ttf.woff2 differ diff --git a/static.files/SourceSerif4-It-ca3b17ed.ttf.woff2 b/static.files/SourceSerif4-It-ca3b17ed.ttf.woff2 new file mode 100644 index 00000000..2ae08a7b Binary files /dev/null and b/static.files/SourceSerif4-It-ca3b17ed.ttf.woff2 differ diff --git a/static.files/SourceSerif4-LICENSE-a2cfd9d5.md b/static.files/SourceSerif4-LICENSE-a2cfd9d5.md new file mode 100644 index 00000000..175fa4f4 --- /dev/null +++ b/static.files/SourceSerif4-LICENSE-a2cfd9d5.md @@ -0,0 +1,98 @@ + + +Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. +Copyright 2014 - 2023 Adobe (http://www.adobe.com/), with Reserved Font Name ‘Source’. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + + diff --git a/static.files/SourceSerif4-Regular-6b053e98.ttf.woff2 b/static.files/SourceSerif4-Regular-6b053e98.ttf.woff2 new file mode 100644 index 00000000..0263fc30 Binary files /dev/null and b/static.files/SourceSerif4-Regular-6b053e98.ttf.woff2 differ diff --git a/static.files/SourceSerif4-Semibold-457a13ac.ttf.woff2 b/static.files/SourceSerif4-Semibold-457a13ac.ttf.woff2 new file mode 100644 index 00000000..dd55f4e9 Binary files /dev/null and b/static.files/SourceSerif4-Semibold-457a13ac.ttf.woff2 differ diff --git a/static.files/favicon-044be391.svg b/static.files/favicon-044be391.svg new file mode 100644 index 00000000..8b34b511 --- /dev/null +++ b/static.files/favicon-044be391.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/static.files/favicon-32x32-6580c154.png b/static.files/favicon-32x32-6580c154.png new file mode 100644 index 00000000..69b8613c Binary files /dev/null and b/static.files/favicon-32x32-6580c154.png differ diff --git a/static.files/main-fb8c74a8.js b/static.files/main-fb8c74a8.js new file mode 100644 index 00000000..c36a7edf --- /dev/null +++ b/static.files/main-fb8c74a8.js @@ -0,0 +1,11 @@ +"use strict";window.RUSTDOC_TOOLTIP_HOVER_MS=300;window.RUSTDOC_TOOLTIP_HOVER_EXIT_MS=450;function resourcePath(basename,extension){return getVar("root-path")+basename+getVar("resource-suffix")+extension}function hideMain(){addClass(document.getElementById(MAIN_ID),"hidden");const toggle=document.getElementById("toggle-all-docs");if(toggle){toggle.setAttribute("disabled","disabled")}}function showMain(){const main=document.getElementById(MAIN_ID);if(!main){return}removeClass(main,"hidden");const mainHeading=main.querySelector(".main-heading");if(mainHeading&&window.searchState.rustdocToolbar){if(window.searchState.rustdocToolbar.parentElement){window.searchState.rustdocToolbar.parentElement.removeChild(window.searchState.rustdocToolbar,)}mainHeading.appendChild(window.searchState.rustdocToolbar)}const toggle=document.getElementById("toggle-all-docs");if(toggle){toggle.removeAttribute("disabled")}}window.rootPath=getVar("root-path");window.currentCrate=getVar("current-crate");function setMobileTopbar(){const mobileTopbar=document.querySelector(".mobile-topbar");const locationTitle=document.querySelector(".sidebar h2.location");if(mobileTopbar){const mobileTitle=document.createElement("h2");mobileTitle.className="location";if(hasClass(document.querySelector(".rustdoc"),"crate")){mobileTitle.innerHTML=`Crate ${window.currentCrate}`}else if(locationTitle){mobileTitle.innerHTML=locationTitle.innerHTML}mobileTopbar.appendChild(mobileTitle)}}function getVirtualKey(ev){if("key"in ev&&typeof ev.key!=="undefined"){return ev.key}const c=ev.charCode||ev.keyCode;if(c===27){return"Escape"}return String.fromCharCode(c)}const MAIN_ID="main-content";const SETTINGS_BUTTON_ID="settings-menu";const ALTERNATIVE_DISPLAY_ID="alternative-display";const NOT_DISPLAYED_ID="not-displayed";const HELP_BUTTON_ID="help-button";function getSettingsButton(){return document.getElementById(SETTINGS_BUTTON_ID)}function getHelpButton(){return document.getElementById(HELP_BUTTON_ID)}function getNakedUrl(){return window.location.href.split("?")[0].split("#")[0]}function insertAfter(newNode,referenceNode){referenceNode.parentNode.insertBefore(newNode,referenceNode.nextSibling)}function getOrCreateSection(id,classes){let el=document.getElementById(id);if(!el){el=document.createElement("section");el.id=id;el.className=classes;insertAfter(el,document.getElementById(MAIN_ID))}return el}function getAlternativeDisplayElem(){return getOrCreateSection(ALTERNATIVE_DISPLAY_ID,"content hidden")}function getNotDisplayedElem(){return getOrCreateSection(NOT_DISPLAYED_ID,"hidden")}function switchDisplayedElement(elemToDisplay){const el=getAlternativeDisplayElem();if(el.children.length>0){getNotDisplayedElem().appendChild(el.firstElementChild)}if(elemToDisplay===null){addClass(el,"hidden");showMain();return}el.appendChild(elemToDisplay);hideMain();removeClass(el,"hidden");const mainHeading=elemToDisplay.querySelector(".main-heading");if(mainHeading&&window.searchState.rustdocToolbar){if(window.searchState.rustdocToolbar.parentElement){window.searchState.rustdocToolbar.parentElement.removeChild(window.searchState.rustdocToolbar,)}mainHeading.appendChild(window.searchState.rustdocToolbar)}}function browserSupportsHistoryApi(){return window.history&&typeof window.history.pushState==="function"}function preLoadCss(cssUrl){const link=document.createElement("link");link.href=cssUrl;link.rel="preload";link.as="style";document.getElementsByTagName("head")[0].appendChild(link)}(function(){const isHelpPage=window.location.pathname.endsWith("/help.html");function loadScript(url,errorCallback){const script=document.createElement("script");script.src=url;if(errorCallback!==undefined){script.onerror=errorCallback}document.head.append(script)}const settingsButton=getSettingsButton();if(settingsButton){settingsButton.onclick=event=>{if(event.ctrlKey||event.altKey||event.metaKey){return}window.hideAllModals(false);addClass(getSettingsButton(),"rotate");event.preventDefault();loadScript(getVar("static-root-path")+getVar("settings-js"));setTimeout(()=>{const themes=getVar("themes").split(",");for(const theme of themes){if(theme!==""){preLoadCss(getVar("root-path")+theme+".css")}}},0)}}window.searchState={rustdocToolbar:document.querySelector("rustdoc-toolbar"),loadingText:"Loading search results...",input:document.getElementsByClassName("search-input")[0],outputElement:()=>{let el=document.getElementById("search");if(!el){el=document.createElement("section");el.id="search";getNotDisplayedElem().appendChild(el)}return el},title:document.title,titleBeforeSearch:document.title,timeout:null,currentTab:0,focusedByTab:[null,null,null],clearInputTimeout:()=>{if(window.searchState.timeout!==null){clearTimeout(window.searchState.timeout);window.searchState.timeout=null}},isDisplayed:()=>{const outputElement=window.searchState.outputElement();return!!outputElement&&!!outputElement.parentElement&&outputElement.parentElement.id===ALTERNATIVE_DISPLAY_ID},focus:()=>{window.searchState.input&&window.searchState.input.focus()},defocus:()=>{window.searchState.input&&window.searchState.input.blur()},showResults:search=>{if(search===null||typeof search==="undefined"){search=window.searchState.outputElement()}switchDisplayedElement(search);document.title=window.searchState.title},removeQueryParameters:()=>{document.title=window.searchState.titleBeforeSearch;if(browserSupportsHistoryApi()){history.replaceState(null,"",getNakedUrl()+window.location.hash)}},hideResults:()=>{switchDisplayedElement(null);window.searchState.removeQueryParameters()},getQueryStringParams:()=>{const params={};window.location.search.substring(1).split("&").map(s=>{const pair=s.split("=").map(x=>x.replace(/\+/g," "));params[decodeURIComponent(pair[0])]=typeof pair[1]==="undefined"?null:decodeURIComponent(pair[1])});return params},setup:()=>{const search_input=window.searchState.input;if(!search_input){return}let searchLoaded=false;function sendSearchForm(){document.getElementsByClassName("search-form")[0].submit()}function loadSearch(){if(!searchLoaded){searchLoaded=true;loadScript(getVar("static-root-path")+getVar("search-js"),sendSearchForm);loadScript(resourcePath("search-index",".js"),sendSearchForm)}}search_input.addEventListener("focus",()=>{window.searchState.origPlaceholder=search_input.placeholder;search_input.placeholder="Type your search here.";loadSearch()});if(search_input.value!==""){loadSearch()}const params=window.searchState.getQueryStringParams();if(params.search!==undefined){window.searchState.setLoadingSearch();loadSearch()}},setLoadingSearch:()=>{const search=window.searchState.outputElement();if(!search){return}search.innerHTML="

"+window.searchState.loadingText+"

";window.searchState.showResults(search)},descShards:new Map(),loadDesc:async function({descShard,descIndex}){if(descShard.promise===null){descShard.promise=new Promise((resolve,reject)=>{descShard.resolve=resolve;const ds=descShard;const fname=`${ds.crate}-desc-${ds.shard}-`;const url=resourcePath(`search.desc/${descShard.crate}/${fname}`,".js",);loadScript(url,reject)})}const list=await descShard.promise;return list[descIndex]},loadedDescShard:function(crate,shard,data){this.descShards.get(crate)[shard].resolve(data.split("\n"))},};const toggleAllDocsId="toggle-all-docs";let savedHash="";function handleHashes(ev){if(ev!==null&&window.searchState.isDisplayed()&&ev.newURL){switchDisplayedElement(null);const hash=ev.newURL.slice(ev.newURL.indexOf("#")+1);if(browserSupportsHistoryApi()){history.replaceState(null,"",getNakedUrl()+window.location.search+"#"+hash)}const elem=document.getElementById(hash);if(elem){elem.scrollIntoView()}}const pageId=window.location.hash.replace(/^#/,"");if(savedHash!==pageId){savedHash=pageId;if(pageId!==""){expandSection(pageId)}}if(savedHash.startsWith("impl-")){const splitAt=savedHash.indexOf("/");if(splitAt!==-1){const implId=savedHash.slice(0,splitAt);const assocId=savedHash.slice(splitAt+1);const implElems=document.querySelectorAll(`details > summary > section[id^="${implId}"]`,);onEachLazy(implElems,implElem=>{const numbered=/^(.+?)-([0-9]+)$/.exec(implElem.id);if(implElem.id!==implId&&(!numbered||numbered[1]!==implId)){return false}return onEachLazy(implElem.parentElement.parentElement.querySelectorAll(`[id^="${assocId}"]`),item=>{const numbered=/^(.+?)-([0-9]+)$/.exec(item.id);if(item.id===assocId||(numbered&&numbered[1]===assocId)){openParentDetails(item);item.scrollIntoView();setTimeout(()=>{window.location.replace("#"+item.id)},0);return true}},)})}}}function onHashChange(ev){hideSidebar();handleHashes(ev)}function openParentDetails(elem){while(elem){if(elem.tagName==="DETAILS"){elem.open=true}elem=elem.parentElement}}function expandSection(id){openParentDetails(document.getElementById(id))}function handleEscape(ev){window.searchState.clearInputTimeout();window.searchState.hideResults();ev.preventDefault();window.searchState.defocus();window.hideAllModals(true)}function handleShortcut(ev){const disableShortcuts=getSettingValue("disable-shortcuts")==="true";if(ev.ctrlKey||ev.altKey||ev.metaKey||disableShortcuts){return}if(document.activeElement&&document.activeElement.tagName==="INPUT"&&document.activeElement.type!=="checkbox"&&document.activeElement.type!=="radio"){switch(getVirtualKey(ev)){case"Escape":handleEscape(ev);break}}else{switch(getVirtualKey(ev)){case"Escape":handleEscape(ev);break;case"s":case"S":case"/":ev.preventDefault();window.searchState.focus();break;case"+":ev.preventDefault();expandAllDocs();break;case"-":ev.preventDefault();collapseAllDocs();break;case"?":showHelp();break;default:break}}}document.addEventListener("keypress",handleShortcut);document.addEventListener("keydown",handleShortcut);function addSidebarItems(){if(!window.SIDEBAR_ITEMS){return}const sidebar=document.getElementById("rustdoc-modnav");function block(shortty,id,longty){const filtered=window.SIDEBAR_ITEMS[shortty];if(!filtered){return}const modpath=hasClass(document.querySelector(".rustdoc"),"mod")?"../":"";const h3=document.createElement("h3");h3.innerHTML=`${longty}`;const ul=document.createElement("ul");ul.className="block "+shortty;for(const name of filtered){let path;if(shortty==="mod"){path=`${modpath}${name}/index.html`}else{path=`${modpath}${shortty}.${name}.html`}let current_page=document.location.href.toString();if(current_page.endsWith("/")){current_page+="index.html"}const link=document.createElement("a");link.href=path;link.textContent=name;const li=document.createElement("li");if(link.href===current_page){li.classList.add("current")}li.appendChild(link);ul.appendChild(li)}sidebar.appendChild(h3);sidebar.appendChild(ul)}if(sidebar){block("primitive","primitives","Primitive Types");block("mod","modules","Modules");block("macro","macros","Macros");block("struct","structs","Structs");block("enum","enums","Enums");block("constant","constants","Constants");block("static","static","Statics");block("trait","traits","Traits");block("fn","functions","Functions");block("type","types","Type Aliases");block("union","unions","Unions");block("foreigntype","foreign-types","Foreign Types");block("keyword","keywords","Keywords");block("attr","attributes","Attribute Macros");block("derive","derives","Derive Macros");block("traitalias","trait-aliases","Trait Aliases")}}window.register_implementors=imp=>{const implementors=document.getElementById("implementors-list");const synthetic_implementors=document.getElementById("synthetic-implementors-list");const inlined_types=new Set();const TEXT_IDX=0;const SYNTHETIC_IDX=1;const TYPES_IDX=2;if(synthetic_implementors){onEachLazy(synthetic_implementors.getElementsByClassName("impl"),el=>{const aliases=el.getAttribute("data-aliases");if(!aliases){return}aliases.split(",").forEach(alias=>{inlined_types.add(alias)})})}let currentNbImpls=implementors.getElementsByClassName("impl").length;const traitName=document.querySelector(".main-heading h1 > .trait").textContent;const baseIdName="impl-"+traitName+"-";const libs=Object.getOwnPropertyNames(imp);const script=document.querySelector("script[data-ignore-extern-crates]");const ignoreExternCrates=new Set((script?script.getAttribute("data-ignore-extern-crates"):"").split(","),);for(const lib of libs){if(lib===window.currentCrate||ignoreExternCrates.has(lib)){continue}const structs=imp[lib];struct_loop:for(const struct of structs){const list=struct[SYNTHETIC_IDX]?synthetic_implementors:implementors;if(struct[SYNTHETIC_IDX]){for(const struct_type of struct[TYPES_IDX]){if(inlined_types.has(struct_type)){continue struct_loop}inlined_types.add(struct_type)}}const code=document.createElement("h3");code.innerHTML=struct[TEXT_IDX];addClass(code,"code-header");onEachLazy(code.getElementsByTagName("a"),elem=>{const href=elem.getAttribute("href");if(href&&!href.startsWith("#")&&!/^(?:[a-z+]+:)?\/\//.test(href)){elem.setAttribute("href",window.rootPath+href)}});const currentId=baseIdName+currentNbImpls;const anchor=document.createElement("a");anchor.href="#"+currentId;addClass(anchor,"anchor");const display=document.createElement("div");display.id=currentId;addClass(display,"impl");display.appendChild(anchor);display.appendChild(code);list.appendChild(display);currentNbImpls+=1}}};if(window.pending_implementors){window.register_implementors(window.pending_implementors)}window.register_type_impls=imp=>{if(!imp||!imp[window.currentCrate]){return}window.pending_type_impls=undefined;const idMap=new Map();let implementations=document.getElementById("implementations-list");let trait_implementations=document.getElementById("trait-implementations-list");let trait_implementations_header=document.getElementById("trait-implementations");const script=document.querySelector("script[data-self-path]");const selfPath=script?script.getAttribute("data-self-path"):null;const mainContent=document.querySelector("#main-content");const sidebarSection=document.querySelector(".sidebar section");let methods=document.querySelector(".sidebar .block.method");let associatedTypes=document.querySelector(".sidebar .block.associatedtype");let associatedConstants=document.querySelector(".sidebar .block.associatedconstant");let sidebarTraitList=document.querySelector(".sidebar .block.trait-implementation");for(const impList of imp[window.currentCrate]){const types=impList.slice(2);const text=impList[0];const isTrait=impList[1]!==0;const traitName=impList[1];if(types.indexOf(selfPath)===-1){continue}let outputList=isTrait?trait_implementations:implementations;if(outputList===null){const outputListName=isTrait?"Trait Implementations":"Implementations";const outputListId=isTrait?"trait-implementations-list":"implementations-list";const outputListHeaderId=isTrait?"trait-implementations":"implementations";const outputListHeader=document.createElement("h2");outputListHeader.id=outputListHeaderId;outputListHeader.innerText=outputListName;outputList=document.createElement("div");outputList.id=outputListId;if(isTrait){const link=document.createElement("a");link.href=`#${outputListHeaderId}`;link.innerText="Trait Implementations";const h=document.createElement("h3");h.appendChild(link);trait_implementations=outputList;trait_implementations_header=outputListHeader;sidebarSection.appendChild(h);sidebarTraitList=document.createElement("ul");sidebarTraitList.className="block trait-implementation";sidebarSection.appendChild(sidebarTraitList);mainContent.appendChild(outputListHeader);mainContent.appendChild(outputList)}else{implementations=outputList;if(trait_implementations){mainContent.insertBefore(outputListHeader,trait_implementations_header);mainContent.insertBefore(outputList,trait_implementations_header)}else{const mainContent=document.querySelector("#main-content");mainContent.appendChild(outputListHeader);mainContent.appendChild(outputList)}}}const template=document.createElement("template");template.innerHTML=text;onEachLazy(template.content.querySelectorAll("a"),elem=>{const href=elem.getAttribute("href");if(href&&!href.startsWith("#")&&!/^(?:[a-z+]+:)?\/\//.test(href)){elem.setAttribute("href",window.rootPath+href)}});onEachLazy(template.content.querySelectorAll("[id]"),el=>{let i=0;if(idMap.has(el.id)){i=idMap.get(el.id)}else if(document.getElementById(el.id)){i=1;while(document.getElementById(`${el.id}-${2 * i}`)){i=2*i}while(document.getElementById(`${el.id}-${i}`)){i+=1}}if(i!==0){const oldHref=`#${el.id}`;const newHref=`#${el.id}-${i}`;el.id=`${el.id}-${i}`;onEachLazy(template.content.querySelectorAll("a[href]"),link=>{if(link.getAttribute("href")===oldHref){link.href=newHref}})}idMap.set(el.id,i+1)});const templateAssocItems=template.content.querySelectorAll("section.tymethod, "+"section.method, section.associatedtype, section.associatedconstant");if(isTrait){const li=document.createElement("li");const a=document.createElement("a");a.href=`#${template.content.querySelector(".impl").id}`;a.textContent=traitName;li.appendChild(a);sidebarTraitList.append(li)}else{onEachLazy(templateAssocItems,item=>{let block=hasClass(item,"associatedtype")?associatedTypes:(hasClass(item,"associatedconstant")?associatedConstants:(methods));if(!block){const blockTitle=hasClass(item,"associatedtype")?"Associated Types":(hasClass(item,"associatedconstant")?"Associated Constants":("Methods"));const blockClass=hasClass(item,"associatedtype")?"associatedtype":(hasClass(item,"associatedconstant")?"associatedconstant":("method"));const blockHeader=document.createElement("h3");const blockLink=document.createElement("a");blockLink.href="#implementations";blockLink.innerText=blockTitle;blockHeader.appendChild(blockLink);block=document.createElement("ul");block.className=`block ${blockClass}`;const insertionReference=methods||sidebarTraitList;if(insertionReference){const insertionReferenceH=insertionReference.previousElementSibling;sidebarSection.insertBefore(blockHeader,insertionReferenceH);sidebarSection.insertBefore(block,insertionReferenceH)}else{sidebarSection.appendChild(blockHeader);sidebarSection.appendChild(block)}if(hasClass(item,"associatedtype")){associatedTypes=block}else if(hasClass(item,"associatedconstant")){associatedConstants=block}else{methods=block}}const li=document.createElement("li");const a=document.createElement("a");a.innerText=item.id.split("-")[0].split(".")[1];a.href=`#${item.id}`;li.appendChild(a);block.appendChild(li)})}outputList.appendChild(template.content)}for(const list of[methods,associatedTypes,associatedConstants,sidebarTraitList]){if(!list){continue}const newChildren=Array.prototype.slice.call(list.children);newChildren.sort((a,b)=>{const aI=a.innerText;const bI=b.innerText;return aIbI?1:0});list.replaceChildren(...newChildren)}};if(window.pending_type_impls){window.register_type_impls(window.pending_type_impls)}function addSidebarCrates(){if(!window.ALL_CRATES){return}const sidebarElems=document.getElementById("rustdoc-modnav");if(!sidebarElems){return}const h3=document.createElement("h3");h3.innerHTML="Crates";const ul=document.createElement("ul");ul.className="block crate";for(const crate of window.ALL_CRATES){const link=document.createElement("a");link.href=window.rootPath+crate+"/index.html";link.textContent=crate;const li=document.createElement("li");if(window.rootPath!=="./"&&crate===window.currentCrate){li.className="current"}li.appendChild(link);ul.appendChild(li)}sidebarElems.appendChild(h3);sidebarElems.appendChild(ul)}function expandAllDocs(){const innerToggle=document.getElementById(toggleAllDocsId);removeClass(innerToggle,"will-expand");onEachLazy(document.getElementsByClassName("toggle"),e=>{if(!hasClass(e,"type-contents-toggle")&&!hasClass(e,"more-examples-toggle")){e.open=true}});innerToggle.children[0].innerText="Summary"}function collapseAllDocs(){const innerToggle=document.getElementById(toggleAllDocsId);addClass(innerToggle,"will-expand");onEachLazy(document.getElementsByClassName("toggle"),e=>{if(e.parentNode.id!=="implementations-list"||(!hasClass(e,"implementors-toggle")&&!hasClass(e,"type-contents-toggle"))){e.open=false}});innerToggle.children[0].innerText="Show all"}function toggleAllDocs(){const innerToggle=document.getElementById(toggleAllDocsId);if(!innerToggle){return}if(hasClass(innerToggle,"will-expand")){expandAllDocs()}else{collapseAllDocs()}}(function(){const toggles=document.getElementById(toggleAllDocsId);if(toggles){toggles.onclick=toggleAllDocs}const hideMethodDocs=getSettingValue("auto-hide-method-docs")==="true";const hideImplementations=getSettingValue("auto-hide-trait-implementations")==="true";const hideLargeItemContents=getSettingValue("auto-hide-large-items")!=="false";function setImplementorsTogglesOpen(id,open){const list=document.getElementById(id);if(list!==null){onEachLazy(list.getElementsByClassName("implementors-toggle"),e=>{e.open=open})}}if(hideImplementations){setImplementorsTogglesOpen("trait-implementations-list",false);setImplementorsTogglesOpen("blanket-implementations-list",false)}onEachLazy(document.getElementsByClassName("toggle"),e=>{if(!hideLargeItemContents&&hasClass(e,"type-contents-toggle")){e.open=true}if(hideMethodDocs&&hasClass(e,"method-toggle")){e.open=false}})}());window.rustdoc_add_line_numbers_to_examples=()=>{function generateLine(nb){return`${nb}`}onEachLazy(document.querySelectorAll(".rustdoc:not(.src) :not(.scraped-example) > .example-wrap > pre > code",),code=>{if(hasClass(code.parentElement.parentElement,"hide-lines")){removeClass(code.parentElement.parentElement,"hide-lines");return}const lines=code.innerHTML.split("\n");const digits=(lines.length+"").length;code.innerHTML=lines.map((line,index)=>generateLine(index+1)+line).join("\n");addClass(code.parentElement.parentElement,`digits-${digits}`)})};window.rustdoc_remove_line_numbers_from_examples=()=>{onEachLazy(document.querySelectorAll(".rustdoc:not(.src) :not(.scraped-example) > .example-wrap"),x=>addClass(x,"hide-lines"),)};if(getSettingValue("line-numbers")==="true"){window.rustdoc_add_line_numbers_to_examples()}function showSidebar(){window.hideAllModals(false);const sidebar=document.getElementsByClassName("sidebar")[0];addClass(sidebar,"shown")}function hideSidebar(){const sidebar=document.getElementsByClassName("sidebar")[0];removeClass(sidebar,"shown")}window.addEventListener("resize",()=>{if(window.CURRENT_TOOLTIP_ELEMENT){const base=window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE;const force_visible=base.TOOLTIP_FORCE_VISIBLE;hideTooltip(false);if(force_visible){showTooltip(base);base.TOOLTIP_FORCE_VISIBLE=true}}});const mainElem=document.getElementById(MAIN_ID);if(mainElem){mainElem.addEventListener("click",hideSidebar)}onEachLazy(document.querySelectorAll("a[href^='#']"),el=>{el.addEventListener("click",()=>{expandSection(el.hash.slice(1));hideSidebar()})});onEachLazy(document.querySelectorAll(".toggle > summary:not(.hideme)"),el=>{el.addEventListener("click",e=>{if(e.target.tagName!=="SUMMARY"&&e.target.tagName!=="A"){e.preventDefault()}})});function showTooltip(e){const notable_ty=e.getAttribute("data-notable-ty");if(!window.NOTABLE_TRAITS&¬able_ty){const data=document.getElementById("notable-traits-data");if(data){window.NOTABLE_TRAITS=JSON.parse(data.innerText)}else{throw new Error("showTooltip() called with notable without any notable traits!")}}if(window.CURRENT_TOOLTIP_ELEMENT&&window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE===e){clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);return}window.hideAllModals(false);const wrapper=document.createElement("div");if(notable_ty){wrapper.innerHTML="
"+window.NOTABLE_TRAITS[notable_ty]+"
"}else{const ttl=e.getAttribute("title");if(ttl!==null){e.setAttribute("data-title",ttl);e.removeAttribute("title")}const dttl=e.getAttribute("data-title");if(dttl!==null){const titleContent=document.createElement("div");titleContent.className="content";titleContent.appendChild(document.createTextNode(dttl));wrapper.appendChild(titleContent)}}wrapper.className="tooltip popover";const focusCatcher=document.createElement("div");focusCatcher.setAttribute("tabindex","0");focusCatcher.onfocus=hideTooltip;wrapper.appendChild(focusCatcher);const pos=e.getBoundingClientRect();wrapper.style.top=(pos.top+window.scrollY+pos.height)+"px";wrapper.style.left=0;wrapper.style.right="auto";wrapper.style.visibility="hidden";document.body.appendChild(wrapper);const wrapperPos=wrapper.getBoundingClientRect();const finalPos=pos.left+window.scrollX-wrapperPos.width+24;if(finalPos>0){wrapper.style.left=finalPos+"px"}else{wrapper.style.setProperty("--popover-arrow-offset",(wrapperPos.right-pos.right+4)+"px",)}wrapper.style.visibility="";window.CURRENT_TOOLTIP_ELEMENT=wrapper;window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE=e;clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);wrapper.onpointerenter=ev=>{if(ev.pointerType!=="mouse"){return}clearTooltipHoverTimeout(e)};wrapper.onpointerleave=ev=>{if(ev.pointerType!=="mouse"||!(ev.relatedTarget instanceof HTMLElement)){return}if(!e.TOOLTIP_FORCE_VISIBLE&&!e.contains(ev.relatedTarget)){setTooltipHoverTimeout(e,false);addClass(wrapper,"fade-out")}}}function setTooltipHoverTimeout(element,show){clearTooltipHoverTimeout(element);if(!show&&!window.CURRENT_TOOLTIP_ELEMENT){return}if(show&&window.CURRENT_TOOLTIP_ELEMENT){return}if(window.CURRENT_TOOLTIP_ELEMENT&&window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE!==element){return}element.TOOLTIP_HOVER_TIMEOUT=setTimeout(()=>{if(show){showTooltip(element)}else if(!element.TOOLTIP_FORCE_VISIBLE){hideTooltip(false)}},show?window.RUSTDOC_TOOLTIP_HOVER_MS:window.RUSTDOC_TOOLTIP_HOVER_EXIT_MS)}function clearTooltipHoverTimeout(element){if(element.TOOLTIP_HOVER_TIMEOUT!==undefined){removeClass(window.CURRENT_TOOLTIP_ELEMENT,"fade-out");clearTimeout(element.TOOLTIP_HOVER_TIMEOUT);delete element.TOOLTIP_HOVER_TIMEOUT}}function tooltipBlurHandler(event){if(window.CURRENT_TOOLTIP_ELEMENT&&!window.CURRENT_TOOLTIP_ELEMENT.contains(document.activeElement)&&!window.CURRENT_TOOLTIP_ELEMENT.contains(event.relatedTarget)&&!window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(document.activeElement)&&!window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(event.relatedTarget)){setTimeout(()=>hideTooltip(false),0)}}function hideTooltip(focus){if(window.CURRENT_TOOLTIP_ELEMENT){if(window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE){if(focus){window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.focus()}window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE=false}document.body.removeChild(window.CURRENT_TOOLTIP_ELEMENT);clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);window.CURRENT_TOOLTIP_ELEMENT=null}}onEachLazy(document.getElementsByClassName("tooltip"),e=>{e.onclick=()=>{e.TOOLTIP_FORCE_VISIBLE=e.TOOLTIP_FORCE_VISIBLE?false:true;if(window.CURRENT_TOOLTIP_ELEMENT&&!e.TOOLTIP_FORCE_VISIBLE){hideTooltip(true)}else{showTooltip(e);window.CURRENT_TOOLTIP_ELEMENT.setAttribute("tabindex","0");window.CURRENT_TOOLTIP_ELEMENT.focus();window.CURRENT_TOOLTIP_ELEMENT.onblur=tooltipBlurHandler}return false};e.onpointerenter=ev=>{if(ev.pointerType!=="mouse"){return}setTooltipHoverTimeout(e,true)};e.onpointermove=ev=>{if(ev.pointerType!=="mouse"){return}setTooltipHoverTimeout(e,true)};e.onpointerleave=ev=>{if(ev.pointerType!=="mouse"){return}if(!e.TOOLTIP_FORCE_VISIBLE&&window.CURRENT_TOOLTIP_ELEMENT&&!window.CURRENT_TOOLTIP_ELEMENT.contains(ev.relatedTarget)){setTooltipHoverTimeout(e,false);addClass(window.CURRENT_TOOLTIP_ELEMENT,"fade-out")}}});const sidebar_menu_toggle=document.getElementsByClassName("sidebar-menu-toggle")[0];if(sidebar_menu_toggle){sidebar_menu_toggle.addEventListener("click",()=>{const sidebar=document.getElementsByClassName("sidebar")[0];if(!hasClass(sidebar,"shown")){showSidebar()}else{hideSidebar()}})}function helpBlurHandler(event){if(!getHelpButton().contains(document.activeElement)&&!getHelpButton().contains(event.relatedTarget)&&!getSettingsButton().contains(document.activeElement)&&!getSettingsButton().contains(event.relatedTarget)){window.hidePopoverMenus()}}function buildHelpMenu(){const book_info=document.createElement("span");const drloChannel=`https://doc.rust-lang.org/${getVar("channel")}`;book_info.className="top";book_info.innerHTML=`You can find more information in \ +the rustdoc book.`;const shortcuts=[["?","Show this help dialog"],["S / /","Focus the search field"],["↑","Move up in search results"],["↓","Move down in search results"],["← / →","Switch result tab (when results focused)"],["⏎","Go to active search result"],["+","Expand all sections"],["-","Collapse all sections"],].map(x=>"
"+x[0].split(" ").map((y,index)=>((index&1)===0?""+y+"":" "+y+" ")).join("")+"
"+x[1]+"
").join("");const div_shortcuts=document.createElement("div");addClass(div_shortcuts,"shortcuts");div_shortcuts.innerHTML="

Keyboard Shortcuts

"+shortcuts+"
";const infos=[`For a full list of all search features, take a look \ + here.`,"Prefix searches with a type followed by a colon (e.g., fn:) to \ + restrict the search to a given item kind.","Accepted kinds are: fn, mod, struct, \ + enum, trait, type, macro, \ + and const.","Search functions by type signature (e.g., vec -> usize or \ + -> vec or String, enum:Cow -> bool)","You can look for items with an exact name by putting double quotes around \ + your request: \"string\"",`Look for functions that accept or return \ + slices and \ + arrays by writing square \ + brackets (e.g., -> [u8] or [] -> Option)`,"Look for items inside another one by searching for a path: vec::Vec",].map(x=>"

"+x+"

").join("");const div_infos=document.createElement("div");addClass(div_infos,"infos");div_infos.innerHTML="

Search Tricks

"+infos;const rustdoc_version=document.createElement("span");rustdoc_version.className="bottom";const rustdoc_version_code=document.createElement("code");rustdoc_version_code.innerText="rustdoc "+getVar("rustdoc-version");rustdoc_version.appendChild(rustdoc_version_code);const container=document.createElement("div");if(!isHelpPage){container.className="popover"}container.id="help";container.style.display="none";const side_by_side=document.createElement("div");side_by_side.className="side-by-side";side_by_side.appendChild(div_shortcuts);side_by_side.appendChild(div_infos);container.appendChild(book_info);container.appendChild(side_by_side);container.appendChild(rustdoc_version);if(isHelpPage){const help_section=document.createElement("section");help_section.appendChild(container);document.getElementById("main-content").appendChild(help_section);container.style.display="block"}else{const help_button=getHelpButton();help_button.appendChild(container);container.onblur=helpBlurHandler;help_button.onblur=helpBlurHandler;help_button.children[0].onblur=helpBlurHandler}return container}window.hideAllModals=switchFocus=>{hideSidebar();window.hidePopoverMenus();hideTooltip(switchFocus)};window.hidePopoverMenus=()=>{onEachLazy(document.querySelectorAll("rustdoc-toolbar .popover"),elem=>{elem.style.display="none"});const button=getHelpButton();if(button){removeClass(button,"help-open")}};function getHelpMenu(buildNeeded){let menu=getHelpButton().querySelector(".popover");if(!menu&&buildNeeded){menu=buildHelpMenu()}return menu}function showHelp(){const button=getHelpButton();addClass(button,"help-open");button.querySelector("a").focus();const menu=getHelpMenu(true);if(menu.style.display==="none"){window.hideAllModals();menu.style.display=""}}const helpLink=document.querySelector(`#${HELP_BUTTON_ID} > a`);if(isHelpPage){buildHelpMenu()}else if(helpLink){helpLink.addEventListener("click",event=>{if(!helpLink.contains(helpLink)||event.ctrlKey||event.altKey||event.metaKey){return}event.preventDefault();const menu=getHelpMenu(true);const shouldShowHelp=menu.style.display==="none";if(shouldShowHelp){showHelp()}else{window.hidePopoverMenus()}})}setMobileTopbar();addSidebarItems();addSidebarCrates();onHashChange(null);window.addEventListener("hashchange",onHashChange);window.searchState.setup()}());(function(){const SIDEBAR_MIN=100;const SIDEBAR_MAX=500;const RUSTDOC_MOBILE_BREAKPOINT=700;const BODY_MIN=400;const SIDEBAR_VANISH_THRESHOLD=SIDEBAR_MIN/2;const sidebarButton=document.getElementById("sidebar-button");if(sidebarButton){sidebarButton.addEventListener("click",e=>{removeClass(document.documentElement,"hide-sidebar");updateLocalStorage("hide-sidebar","false");if(document.querySelector(".rustdoc.src")){window.rustdocToggleSrcSidebar()}e.preventDefault()})}let currentPointerId=null;let desiredSidebarSize=null;let pendingSidebarResizingFrame=false;const resizer=document.querySelector(".sidebar-resizer");const sidebar=document.querySelector(".sidebar");if(!resizer||!sidebar){return}const isSrcPage=hasClass(document.body,"src");const hideSidebar=function(){if(isSrcPage){window.rustdocCloseSourceSidebar();updateLocalStorage("src-sidebar-width",null);document.documentElement.style.removeProperty("--src-sidebar-width");sidebar.style.removeProperty("--src-sidebar-width");resizer.style.removeProperty("--src-sidebar-width")}else{addClass(document.documentElement,"hide-sidebar");updateLocalStorage("hide-sidebar","true");updateLocalStorage("desktop-sidebar-width",null);document.documentElement.style.removeProperty("--desktop-sidebar-width");sidebar.style.removeProperty("--desktop-sidebar-width");resizer.style.removeProperty("--desktop-sidebar-width")}};const showSidebar=function(){if(isSrcPage){window.rustdocShowSourceSidebar()}else{removeClass(document.documentElement,"hide-sidebar");updateLocalStorage("hide-sidebar","false")}};const changeSidebarSize=function(size){if(isSrcPage){updateLocalStorage("src-sidebar-width",size.toString());sidebar.style.setProperty("--src-sidebar-width",size+"px");resizer.style.setProperty("--src-sidebar-width",size+"px")}else{updateLocalStorage("desktop-sidebar-width",size.toString());sidebar.style.setProperty("--desktop-sidebar-width",size+"px");resizer.style.setProperty("--desktop-sidebar-width",size+"px")}};const isSidebarHidden=function(){return isSrcPage?!hasClass(document.documentElement,"src-sidebar-expanded"):hasClass(document.documentElement,"hide-sidebar")};const resize=function(e){if(currentPointerId===null||currentPointerId!==e.pointerId){return}e.preventDefault();const pos=e.clientX-3;if(pos=SIDEBAR_MIN){if(isSidebarHidden()){showSidebar()}const constrainedPos=Math.min(pos,window.innerWidth-BODY_MIN,SIDEBAR_MAX);changeSidebarSize(constrainedPos);desiredSidebarSize=constrainedPos;if(pendingSidebarResizingFrame!==false){clearTimeout(pendingSidebarResizingFrame)}pendingSidebarResizingFrame=setTimeout(()=>{if(currentPointerId===null||pendingSidebarResizingFrame===false){return}pendingSidebarResizingFrame=false;document.documentElement.style.setProperty("--resizing-sidebar-width",desiredSidebarSize+"px",)},100)}};window.addEventListener("resize",()=>{if(window.innerWidth=(window.innerWidth-BODY_MIN)){changeSidebarSize(window.innerWidth-BODY_MIN)}else if(desiredSidebarSize!==null&&desiredSidebarSize>SIDEBAR_MIN){changeSidebarSize(desiredSidebarSize)}});const stopResize=function(e){if(currentPointerId===null){return}if(e){e.preventDefault()}desiredSidebarSize=sidebar.getBoundingClientRect().width;removeClass(resizer,"active");window.removeEventListener("pointermove",resize,false);window.removeEventListener("pointerup",stopResize,false);removeClass(document.documentElement,"sidebar-resizing");document.documentElement.style.removeProperty("--resizing-sidebar-width");if(resizer.releasePointerCapture){resizer.releasePointerCapture(currentPointerId);currentPointerId=null}};const initResize=function(e){if(currentPointerId!==null||e.altKey||e.ctrlKey||e.metaKey||e.button!==0){return}if(resizer.setPointerCapture){resizer.setPointerCapture(e.pointerId);if(!resizer.hasPointerCapture(e.pointerId)){resizer.releasePointerCapture(e.pointerId);return}currentPointerId=e.pointerId}window.hideAllModals(false);e.preventDefault();window.addEventListener("pointermove",resize,false);window.addEventListener("pointercancel",stopResize,false);window.addEventListener("pointerup",stopResize,false);addClass(resizer,"active");addClass(document.documentElement,"sidebar-resizing");const pos=e.clientX-sidebar.offsetLeft-3;document.documentElement.style.setProperty("--resizing-sidebar-width",pos+"px");desiredSidebarSize=null};resizer.addEventListener("pointerdown",initResize,false)}());(function(){function copyContentToClipboard(content){if(content===null){return}const el=document.createElement("textarea");el.value=content;el.setAttribute("readonly","");el.style.position="absolute";el.style.left="-9999px";document.body.appendChild(el);el.select();document.execCommand("copy");document.body.removeChild(el)}function copyButtonAnimation(button){button.classList.add("clicked");if(button.reset_button_timeout!==undefined){clearTimeout(button.reset_button_timeout)}button.reset_button_timeout=setTimeout(()=>{button.reset_button_timeout=undefined;button.classList.remove("clicked")},1000)}const but=document.getElementById("copy-path");if(!but){return}but.onclick=()=>{const titleElement=document.querySelector("title");const title=titleElement&&titleElement.textContent?titleElement.textContent.replace(" - Rust",""):"";const[item,module]=title.split(" in ");const path=[item];if(module!==undefined){path.unshift(module)}copyContentToClipboard(path.join("::"));copyButtonAnimation(but)};function copyCode(codeElem){if(!codeElem){return}copyContentToClipboard(codeElem.textContent)}function getExampleWrap(event){const target=event.target;if(target instanceof HTMLElement){let elem=target;while(elem!==null&&!hasClass(elem,"example-wrap")){if(elem===document.body||elem.tagName==="A"||elem.tagName==="BUTTON"||hasClass(elem,"docblock")){return null}elem=elem.parentElement}return elem}else{return null}}function addCopyButton(event){const elem=getExampleWrap(event);if(elem===null){return}elem.removeEventListener("mouseover",addCopyButton);const parent=document.createElement("div");parent.className="button-holder";const runButton=elem.querySelector(".test-arrow");if(runButton!==null){parent.appendChild(runButton)}elem.appendChild(parent);const copyButton=document.createElement("button");copyButton.className="copy-button";copyButton.title="Copy code to clipboard";copyButton.addEventListener("click",()=>{copyCode(elem.querySelector("pre > code"));copyButtonAnimation(copyButton)});parent.appendChild(copyButton);if(!elem.parentElement||!elem.parentElement.classList.contains("scraped-example")||!window.updateScrapedExample){return}const scrapedWrapped=elem.parentElement;window.updateScrapedExample(scrapedWrapped,parent)}function showHideCodeExampleButtons(event){const elem=getExampleWrap(event);if(elem===null){return}let buttons=elem.querySelector(".button-holder");if(buttons===null){addCopyButton(event);buttons=elem.querySelector(".button-holder");if(buttons===null){return}}buttons.classList.toggle("keep-visible")}onEachLazy(document.querySelectorAll(".docblock .example-wrap"),elem=>{elem.addEventListener("mouseover",addCopyButton);elem.addEventListener("click",showHideCodeExampleButtons)})}()) \ No newline at end of file diff --git a/static.files/normalize-9960930a.css b/static.files/normalize-9960930a.css new file mode 100644 index 00000000..469959f1 --- /dev/null +++ b/static.files/normalize-9960930a.css @@ -0,0 +1,2 @@ + /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ +html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:0.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type="button"],[type="reset"],[type="submit"],button{-webkit-appearance:button}[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:0.35em 0.75em 0.625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{-webkit-appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none} \ No newline at end of file diff --git a/static.files/noscript-893ab5e7.css b/static.files/noscript-893ab5e7.css new file mode 100644 index 00000000..a6c18eca --- /dev/null +++ b/static.files/noscript-893ab5e7.css @@ -0,0 +1 @@ + #main-content .attributes{margin-left:0 !important;}#copy-path,#sidebar-button,.sidebar-resizer{display:none !important;}nav.sub{display:none;}.src .sidebar{display:none;}.notable-traits{display:none;}:root,:root:not([data-theme]){--main-background-color:white;--main-color:black;--settings-input-color:#2196f3;--settings-input-border-color:#717171;--settings-button-color:#000;--settings-button-border-focus:#717171;--sidebar-background-color:#f5f5f5;--sidebar-background-color-hover:#e0e0e0;--code-block-background-color:#f5f5f5;--scrollbar-track-background-color:#dcdcdc;--scrollbar-thumb-background-color:rgba(36,37,39,0.6);--scrollbar-color:rgba(36,37,39,0.6) #d9d9d9;--headings-border-bottom-color:#ddd;--border-color:#e0e0e0;--button-background-color:#fff;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:none;--mobile-sidebar-menu-filter:none;--search-input-focused-border-color:#66afe9;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(35%);--code-example-button-color:#7f7f7f;--code-example-button-hover-color:#595959;--settings-menu-filter:invert(50%);--settings-menu-hover-filter:invert(35%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#ad378a;--trait-link-color:#6e4fc9;--assoc-item-link-color:#3873ad;--function-link-color:#ad7c37;--macro-link-color:#068000;--keyword-link-color:#3873ad;--mod-link-color:#3873ad;--link-color:#3873ad;--sidebar-link-color:#356da4;--sidebar-current-link-background-color:#fff;--search-result-link-focus-background-color:#ccc;--search-result-border-color:#aaa3;--search-color:#000;--search-error-code-background-color:#d0cccc;--search-results-alias-color:#000;--search-results-grey-color:#999;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#e6e6e6;--search-tab-button-not-selected-background:#e6e6e6;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#fff;--stab-background-color:#fff5d6;--stab-code-color:#000;--code-highlight-kw-color:#8959a8;--code-highlight-kw-2-color:#4271ae;--code-highlight-lifetime-color:#b76514;--code-highlight-prelude-color:#4271ae;--code-highlight-prelude-val-color:#c82829;--code-highlight-number-color:#718c00;--code-highlight-string-color:#718c00;--code-highlight-literal-color:#c82829;--code-highlight-attribute-color:#c82829;--code-highlight-self-color:#c82829;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8e908c;--code-highlight-doc-comment-color:#4d4d4c;--src-line-numbers-span-color:#c67e2d;--src-line-number-highlighted-background-color:#fdffd3;--target-background-color:#fdffd3;--target-border-color:#ad7c37;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:initial;--crate-search-div-filter:invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%);--crate-search-div-hover-filter:invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);--crate-search-hover-border:#717171;--src-sidebar-background-selected:#fff;--src-sidebar-background-hover:#e0e0e0;--table-alt-row-background-color:#f5f5f5;--codeblock-link-background:#eee;--scrape-example-toggle-line-background:#ccc;--scrape-example-toggle-line-hover-background:#999;--scrape-example-code-line-highlight:#fcffd6;--scrape-example-code-line-highlight-focus:#f6fdb0;--scrape-example-help-border-color:#555;--scrape-example-help-color:#333;--scrape-example-help-hover-border-color:#000;--scrape-example-help-hover-color:#000;--scrape-example-code-wrapper-background-start:rgba(255,255,255,1);--scrape-example-code-wrapper-background-end:rgba(255,255,255,0);--sidebar-resizer-hover:hsl(207,90%,66%);--sidebar-resizer-active:hsl(207,90%,54%);}@media (prefers-color-scheme:dark){:root,:root:not([data-theme]){--main-background-color:#353535;--main-color:#ddd;--settings-input-color:#2196f3;--settings-input-border-color:#999;--settings-button-color:#000;--settings-button-border-focus:#ffb900;--sidebar-background-color:#505050;--sidebar-background-color-hover:#676767;--code-block-background-color:#2A2A2A;--scrollbar-track-background-color:#717171;--scrollbar-thumb-background-color:rgba(32,34,37,.6);--scrollbar-color:rgba(32,34,37,.6) #5a5a5a;--headings-border-bottom-color:#d2d2d2;--border-color:#e0e0e0;--button-background-color:#f0f0f0;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:invert(100%);--mobile-sidebar-menu-filter:invert(100%);--search-input-focused-border-color:#008dfd;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(65%);--code-example-button-color:#7f7f7f;--code-example-button-hover-color:#a5a5a5;--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#2dbfb8;--trait-link-color:#b78cf2;--assoc-item-link-color:#d2991d;--function-link-color:#2bab63;--macro-link-color:#09bd00;--keyword-link-color:#d2991d;--mod-link-color:#d2991d;--link-color:#d2991d;--sidebar-link-color:#fdbf35;--sidebar-current-link-background-color:#444;--search-result-link-focus-background-color:#616161;--search-result-border-color:#aaa3;--search-color:#111;--search-error-code-background-color:#484848;--search-results-alias-color:#fff;--search-results-grey-color:#ccc;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#252525;--search-tab-button-not-selected-background:#252525;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#353535;--settings-menu-filter:invert(50%);--settings-menu-hover-filter:invert(65%);--stab-background-color:#314559;--stab-code-color:#e6e1cf;--code-highlight-kw-color:#ab8ac1;--code-highlight-kw-2-color:#769acb;--code-highlight-lifetime-color:#d97f26;--code-highlight-prelude-color:#769acb;--code-highlight-prelude-val-color:#ee6868;--code-highlight-number-color:#83a300;--code-highlight-string-color:#83a300;--code-highlight-literal-color:#ee6868;--code-highlight-attribute-color:#ee6868;--code-highlight-self-color:#ee6868;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8d8d8b;--code-highlight-doc-comment-color:#8ca375;--src-line-numbers-span-color:#3b91e2;--src-line-number-highlighted-background-color:#0a042f;--target-background-color:#494a3d;--target-border-color:#bb7410;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff);--crate-search-div-filter:invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) brightness(90%) contrast(90%);--crate-search-div-hover-filter:invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);--crate-search-hover-border:#2196f3;--src-sidebar-background-selected:#333;--src-sidebar-background-hover:#444;--table-alt-row-background-color:#2a2a2a;--codeblock-link-background:#333;--scrape-example-toggle-line-background:#999;--scrape-example-toggle-line-hover-background:#c5c5c5;--scrape-example-code-line-highlight:#5b3b01;--scrape-example-code-line-highlight-focus:#7c4b0f;--scrape-example-help-border-color:#aaa;--scrape-example-help-color:#eee;--scrape-example-help-hover-border-color:#fff;--scrape-example-help-hover-color:#fff;--scrape-example-code-wrapper-background-start:rgba(53,53,53,1);--scrape-example-code-wrapper-background-end:rgba(53,53,53,0);--sidebar-resizer-hover:hsl(207,30%,54%);--sidebar-resizer-active:hsl(207,90%,54%);}} \ No newline at end of file diff --git a/static.files/rust-logo-9a9549ea.svg b/static.files/rust-logo-9a9549ea.svg new file mode 100644 index 00000000..62424d8f --- /dev/null +++ b/static.files/rust-logo-9a9549ea.svg @@ -0,0 +1,61 @@ + + + diff --git a/static.files/rustdoc-916cea96.css b/static.files/rustdoc-916cea96.css new file mode 100644 index 00000000..3bcdd2e6 --- /dev/null +++ b/static.files/rustdoc-916cea96.css @@ -0,0 +1,63 @@ + :root{--nav-sub-mobile-padding:8px;--search-typename-width:6.75rem;--desktop-sidebar-width:200px;--src-sidebar-width:300px;--desktop-sidebar-z-index:100;--sidebar-elems-left-padding:24px;--clipboard-image:url('data:image/svg+xml,\ +\ +\ +');--copy-path-height:34px;--copy-path-width:33px;--checkmark-image:url('data:image/svg+xml,\ +\ +');--button-left-margin:4px;--button-border-radius:2px;--toolbar-button-border-radius:6px;--code-block-border-radius:6px;--impl-items-indent:0.3em;--docblock-indent:24px;--font-family:"Source Serif 4",NanumBarunGothic,serif;--font-family-code:"Source Code Pro",monospace;--line-number-padding:4px;--line-number-right-margin:20px;--prev-arrow-image:url('data:image/svg+xml,');--next-arrow-image:url('data:image/svg+xml,');--expand-arrow-image:url('data:image/svg+xml,');--collapse-arrow-image:url('data:image/svg+xml,');}:root.sans-serif{--font-family:"Fira Sans",sans-serif;--font-family-code:"Fira Mono",monospace;}@font-face {font-family:'Fira Sans';font-style:normal;font-weight:400;src:local('Fira Sans'),url("FiraSans-Regular-0fe48ade.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Fira Sans';font-style:italic;font-weight:400;src:local('Fira Sans Italic'),url("FiraSans-Italic-81dc35de.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Fira Sans';font-style:normal;font-weight:500;src:local('Fira Sans Medium'),url("FiraSans-Medium-e1aa3f0a.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Fira Sans';font-style:italic;font-weight:500;src:local('Fira Sans Medium Italic'),url("FiraSans-MediumItalic-ccf7e434.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Fira Mono';font-style:normal;font-weight:400;src:local('Fira Mono'),url("FiraMono-Regular-87c26294.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Fira Mono';font-style:normal;font-weight:500;src:local('Fira Mono Medium'),url("FiraMono-Medium-86f75c8c.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:normal;font-weight:400;src:local('Source Serif 4'),url("SourceSerif4-Regular-6b053e98.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:italic;font-weight:400;src:local('Source Serif 4 Italic'),url("SourceSerif4-It-ca3b17ed.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:normal;font-weight:500;src:local('Source Serif 4 Semibold'),url("SourceSerif4-Semibold-457a13ac.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:normal;font-weight:700;src:local('Source Serif 4 Bold'),url("SourceSerif4-Bold-6d4fd4c0.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:normal;font-weight:400;src:url("SourceCodePro-Regular-8badfe75.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:italic;font-weight:400;src:url("SourceCodePro-It-fc8b9304.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:normal;font-weight:600;src:url("SourceCodePro-Semibold-aa29a496.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'NanumBarunGothic';src:url("NanumBarunGothic-13b3dcba.ttf.woff2") format("woff2");font-display:swap;unicode-range:U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF;}*{box-sizing:border-box;}body{font:1rem/1.5 var(--font-family);margin:0;position:relative;overflow-wrap:break-word;overflow-wrap:anywhere;font-feature-settings:"kern","liga";background-color:var(--main-background-color);color:var(--main-color);}h1{font-size:1.5rem;}h2{font-size:1.375rem;}h3{font-size:1.25rem;}h1,h2,h3,h4,h5,h6{font-weight:500;}h1,h2,h3,h4{margin:25px 0 15px 0;padding-bottom:6px;}.docblock h3,.docblock h4,h5,h6{margin:15px 0 5px 0;}.docblock>h2:first-child,.docblock>h3:first-child,.docblock>h4:first-child,.docblock>h5:first-child,.docblock>h6:first-child{margin-top:0;}.main-heading h1{margin:0;padding:0;grid-area:main-heading-h1;overflow-wrap:break-word;overflow-wrap:anywhere;}.main-heading{position:relative;display:grid;grid-template-areas:"main-heading-breadcrumbs main-heading-breadcrumbs" "main-heading-h1 main-heading-toolbar" "main-heading-sub-heading main-heading-toolbar";grid-template-columns:minmax(105px,1fr) minmax(0,max-content);grid-template-rows:minmax(25px,min-content) min-content min-content;padding-bottom:6px;margin-bottom:15px;}.rustdoc-breadcrumbs{grid-area:main-heading-breadcrumbs;line-height:1.25;padding-top:5px;position:relative;z-index:1;}.rustdoc-breadcrumbs a{padding:5px 0 7px;}.content h2,.top-doc .docblock>h3,.top-doc .docblock>h4{border-bottom:1px solid var(--headings-border-bottom-color);}h1,h2{line-height:1.25;padding-top:3px;padding-bottom:9px;}h3.code-header{font-size:1.125rem;}h4.code-header{font-size:1rem;}.code-header{font-weight:600;margin:0;padding:0;white-space:pre-wrap;}.structfield,.sub-variant-field{margin:0.6em 0;}#crate-search,h1,h2,h3,h4,h5,h6,.sidebar,.mobile-topbar,.search-input,.search-results .result-name,.item-table dt>a,.out-of-band,.sub-heading,span.since,a.src,rustdoc-toolbar,summary.hideme,.scraped-example-list,.rustdoc-breadcrumbs,ul.all-items{font-family:"Fira Sans",Arial,NanumBarunGothic,sans-serif;}#toggle-all-docs,a.anchor,.section-header a,#src-sidebar a,.rust a,.sidebar h2 a,.sidebar h3 a,.mobile-topbar h2 a,h1 a,.search-results a,.search-results li,.stab,.result-name i{color:var(--main-color);}span.enum,a.enum,span.struct,a.struct,span.union,a.union,span.primitive,a.primitive,span.type,a.type,span.foreigntype,a.foreigntype{color:var(--type-link-color);}span.trait,a.trait,span.traitalias,a.traitalias{color:var(--trait-link-color);}span.associatedtype,a.associatedtype,span.constant,a.constant,span.static,a.static{color:var(--assoc-item-link-color);}span.fn,a.fn,span.method,a.method,span.tymethod,a.tymethod{color:var(--function-link-color);}span.attr,a.attr,span.derive,a.derive,span.macro,a.macro{color:var(--macro-link-color);}span.mod,a.mod{color:var(--mod-link-color);}span.keyword,a.keyword{color:var(--keyword-link-color);}a{color:var(--link-color);text-decoration:none;}ol,ul{padding-left:24px;}ul ul,ol ul,ul ol,ol ol{margin-bottom:.625em;}p,.docblock>.warning{margin:0 0 .75em 0;}p:last-child,.docblock>.warning:last-child{margin:0;}button{padding:1px 6px;cursor:pointer;}button#toggle-all-docs{padding:0;background:none;border:none;-webkit-appearance:none;opacity:1;}.rustdoc{display:flex;flex-direction:row;flex-wrap:nowrap;}main{position:relative;flex-grow:1;padding:10px 15px 40px 45px;min-width:0;}.src main{padding:15px;}.width-limiter{max-width:960px;margin-right:auto;}details:not(.toggle) summary{margin-bottom:.6em;}code,pre,.code-header,.type-signature{font-family:var(--font-family-code);}.docblock code,.item-table dd code{border-radius:3px;padding:0 0.125em;}.docblock pre code,.item-table dd pre code{padding:0;}pre{padding:14px;line-height:1.5;}pre.item-decl{overflow-x:auto;}.item-decl .type-contents-toggle{contain:initial;}.src .content pre{padding:20px;padding-left:16px;}img{max-width:100%;}.logo-container{line-height:0;display:block;}.rust-logo{filter:var(--rust-logo-filter);}.sidebar{font-size:0.875rem;flex:0 0 var(--desktop-sidebar-width);width:var(--desktop-sidebar-width);overflow-y:scroll;overscroll-behavior:contain;position:sticky;height:100vh;top:0;left:0;z-index:var(--desktop-sidebar-z-index);}.rustdoc.src .sidebar{flex-basis:50px;width:50px;border-right:1px solid;overflow-x:hidden;overflow-y:hidden;}.hide-sidebar .sidebar,.hide-sidebar .sidebar-resizer{display:none;}.sidebar-resizer{touch-action:none;width:9px;cursor:col-resize;z-index:calc(var(--desktop-sidebar-z-index) + 1);position:fixed;height:100%;left:calc(var(--desktop-sidebar-width) + 1px);}.rustdoc.src .sidebar-resizer{left:49px;}.src-sidebar-expanded .src .sidebar-resizer{left:var(--src-sidebar-width);}.sidebar-resizing{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;}.sidebar-resizing *{cursor:col-resize !important;}.sidebar-resizing .sidebar{position:fixed;}.sidebar-resizing>body{padding-left:var(--resizing-sidebar-width);}.sidebar-resizer:hover,.sidebar-resizer:active,.sidebar-resizer:focus,.sidebar-resizer.active{width:10px;margin:0;left:var(--desktop-sidebar-width);border-left:solid 1px var(--sidebar-resizer-hover);}.src-sidebar-expanded .rustdoc.src .sidebar-resizer:hover,.src-sidebar-expanded .rustdoc.src .sidebar-resizer:active,.src-sidebar-expanded .rustdoc.src .sidebar-resizer:focus,.src-sidebar-expanded .rustdoc.src .sidebar-resizer.active{left:calc(var(--src-sidebar-width) - 1px);}@media (pointer:coarse){.sidebar-resizer{display:none !important;}}.sidebar-resizer.active{padding:0 140px;width:2px;margin-left:-140px;border-left:none;}.sidebar-resizer.active:before{border-left:solid 2px var(--sidebar-resizer-active);display:block;height:100%;content:"";}.sidebar,.mobile-topbar,.sidebar-menu-toggle,#src-sidebar{background-color:var(--sidebar-background-color);}.src .sidebar>*{visibility:hidden;}.src-sidebar-expanded .src .sidebar{overflow-y:auto;flex-basis:var(--src-sidebar-width);width:var(--src-sidebar-width);}.src-sidebar-expanded .src .sidebar>*{visibility:visible;}#all-types{margin-top:1em;}*{scrollbar-width:initial;scrollbar-color:var(--scrollbar-color);}.sidebar{scrollbar-width:thin;scrollbar-color:var(--scrollbar-color);}::-webkit-scrollbar{width:12px;}.sidebar::-webkit-scrollbar{width:8px;}::-webkit-scrollbar-track{-webkit-box-shadow:inset 0;background-color:var(--scrollbar-track-background-color);}.sidebar::-webkit-scrollbar-track{background-color:var(--scrollbar-track-background-color);}::-webkit-scrollbar-thumb,.sidebar::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb-background-color);}.hidden{display:none !important;}.logo-container>img{height:48px;width:48px;}ul.block,.block li,.block ul{padding:0;margin:0;list-style:none;}.block ul a{padding-left:1rem;}.sidebar-elems a,.sidebar>h2 a{display:block;padding:0.25rem;margin-right:0.25rem;border-left:solid var(--sidebar-elems-left-padding) transparent;margin-left:calc(-0.25rem - var(--sidebar-elems-left-padding));background-clip:border-box;}.hide-toc #rustdoc-toc,.hide-toc .in-crate{display:none;}.hide-modnav #rustdoc-modnav{display:none;}.sidebar h2{text-wrap:balance;overflow-wrap:anywhere;padding:0;margin:0.7rem 0;}.sidebar h3{text-wrap:balance;overflow-wrap:anywhere;font-size:1.125rem;padding:0;margin:0;}.sidebar-elems,.sidebar>.version,.sidebar>h2{padding-left:var(--sidebar-elems-left-padding);}.sidebar a{color:var(--sidebar-link-color);}.sidebar .current,.sidebar .current a,.sidebar-crate a.logo-container:hover+h2 a,.sidebar a:hover:not(.logo-container){background-color:var(--sidebar-current-link-background-color);}.sidebar-elems .block{margin-bottom:2em;}.sidebar-elems .block li a{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;}.sidebar-crate{display:flex;align-items:center;justify-content:center;margin:14px 32px 1rem;row-gap:10px;column-gap:32px;flex-wrap:wrap;}.sidebar-crate h2{flex-grow:1;margin:0 -8px;align-self:start;}.sidebar-crate .logo-container{margin:0 calc(-16px - var(--sidebar-elems-left-padding));padding:0 var(--sidebar-elems-left-padding);text-align:center;}.sidebar-crate .logo-container img{margin-top:-16px;border-top:solid 16px transparent;box-sizing:content-box;position:relative;background-clip:border-box;z-index:1;}.sidebar-crate h2 a{display:block;border-left:solid var(--sidebar-elems-left-padding) transparent;background-clip:border-box;margin:0 calc(-24px + 0.25rem) 0 calc(-0.2rem - var(--sidebar-elems-left-padding));padding:calc((16px - 0.57rem ) / 2 ) 0.25rem;padding-left:0.2rem;}.sidebar-crate h2 .version{display:block;font-weight:normal;font-size:1rem;overflow-wrap:break-word;}.sidebar-crate+.version{margin-top:-1rem;margin-bottom:1rem;}.mobile-topbar{display:none;}.rustdoc .example-wrap{display:flex;position:relative;margin-bottom:10px;}.rustdoc .example-wrap>pre,.rustdoc .scraped-example .src-line-numbers,.rustdoc .scraped-example .src-line-numbers>pre{border-radius:6px;}.rustdoc .scraped-example{position:relative;}.rustdoc .example-wrap:last-child{margin-bottom:0px;}.rustdoc .example-wrap pre{margin:0;flex-grow:1;}.scraped-example:not(.expanded) .example-wrap{max-height:calc(1.5em * 5 + 10px);}.more-scraped-examples .scraped-example:not(.expanded) .example-wrap{max-height:calc(1.5em * 10 + 10px);}.rustdoc:not(.src) .scraped-example:not(.expanded) .src-line-numbers,.rustdoc:not(.src) .scraped-example:not(.expanded) .src-line-numbers>pre,.rustdoc:not(.src) .scraped-example:not(.expanded) pre.rust{padding-bottom:0;overflow:auto hidden;}.rustdoc:not(.src) .scraped-example .src-line-numbers{padding-top:0;}.rustdoc:not(.src) .scraped-example.expanded .src-line-numbers{padding-bottom:0;}.rustdoc:not(.src) .example-wrap pre{overflow:auto;}.example-wrap.digits-1:not(.hide-lines) [data-nosnippet]{width:calc(1ch + var(--line-number-padding) * 2);}.example-wrap.digits-2:not(.hide-lines) [data-nosnippet]{width:calc(2ch + var(--line-number-padding) * 2);}.example-wrap.digits-3:not(.hide-lines) [data-nosnippet]{width:calc(3ch + var(--line-number-padding) * 2);}.example-wrap.digits-4:not(.hide-lines) [data-nosnippet]{width:calc(4ch + var(--line-number-padding) * 2);}.example-wrap.digits-5:not(.hide-lines) [data-nosnippet]{width:calc(5ch + var(--line-number-padding) * 2);}.example-wrap.digits-6:not(.hide-lines) [data-nosnippet]{width:calc(6ch + var(--line-number-padding) * 2);}.example-wrap.digits-7:not(.hide-lines) [data-nosnippet]{width:calc(7ch + var(--line-number-padding) * 2);}.example-wrap.digits-8:not(.hide-lines) [data-nosnippet]{width:calc(8ch + var(--line-number-padding) * 2);}.example-wrap.digits-9:not(.hide-lines) [data-nosnippet]{width:calc(9ch + var(--line-number-padding) * 2);}.example-wrap [data-nosnippet]{color:var(--src-line-numbers-span-color);text-align:right;display:inline-block;margin-right:var(--line-number-right-margin);-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none;user-select:none;padding:0 var(--line-number-padding);}.example-wrap [data-nosnippet]:target{border-right:none;}.example-wrap .line-highlighted[data-nosnippet]{background-color:var(--src-line-number-highlighted-background-color);}:root.word-wrap-source-code .example-wrap [data-nosnippet]{position:absolute;left:0;}.word-wrap-source-code .example-wrap pre>code{position:relative;word-break:break-all;}:root.word-wrap-source-code .example-wrap pre>code{display:block;white-space:pre-wrap;}:root.word-wrap-source-code .example-wrap pre>code *{word-break:break-all;}:root.word-wrap-source-code .example-wrap.digits-1 pre>code{padding-left:calc(1ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));}:root.word-wrap-source-code .example-wrap.digits-2 pre>code{padding-left:calc(2ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));}:root.word-wrap-source-code .example-wrap.digits-3 pre>code{padding-left:calc(3ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));}:root.word-wrap-source-code .example-wrap.digits-4 pre>code{padding-left:calc(4ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));}:root.word-wrap-source-code .example-wrap.digits-5 pre>code{padding-left:calc(5ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));}:root.word-wrap-source-code .example-wrap.digits-6 pre>code{padding-left:calc(6ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));}:root.word-wrap-source-code .example-wrap.digits-7 pre>code{padding-left:calc(7ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));}:root.word-wrap-source-code .example-wrap.digits-8 pre>code{padding-left:calc(8ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));}:root.word-wrap-source-code .example-wrap.digits-9 pre>code{padding-left:calc(9ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));}.example-wrap.hide-lines [data-nosnippet]{display:none;}.search-loading{text-align:center;}.item-table dd{overflow-wrap:break-word;overflow-wrap:anywhere;}.docblock :not(pre)>code,.item-table dd code{white-space:pre-wrap;}.top-doc .docblock h2{font-size:1.375rem;}.top-doc .docblock h3{font-size:1.25rem;}.top-doc .docblock h4,.top-doc .docblock h5{font-size:1.125rem;}.top-doc .docblock h6{font-size:1rem;}.docblock h5{font-size:1rem;}.docblock h6{font-size:0.875rem;}.docblock{margin-left:var(--docblock-indent);position:relative;}.docblock>:not(.more-examples-toggle):not(.example-wrap){max-width:100%;overflow-x:auto;}.sub-heading{font-size:1rem;flex-grow:0;grid-area:main-heading-sub-heading;line-height:1.25;padding-bottom:4px;}.main-heading rustdoc-toolbar,.main-heading .out-of-band{grid-area:main-heading-toolbar;}rustdoc-toolbar{display:flex;flex-direction:row;flex-wrap:nowrap;min-height:60px;}.docblock code,.item-table dd code,pre,.rustdoc.src .example-wrap,.example-wrap .src-line-numbers{background-color:var(--code-block-background-color);border-radius:var(--code-block-border-radius);text-decoration:inherit;}#main-content{position:relative;}.docblock table{margin:.5em 0;border-collapse:collapse;}.docblock table td,.docblock table th{padding:.5em;border:1px solid var(--border-color);}.docblock table tbody tr:nth-child(2n){background:var(--table-alt-row-background-color);}.docblock .stab,.item-table dd .stab,.docblock p code{display:inline-block;}.docblock li{margin-bottom:.4em;}.docblock li p:not(:last-child){margin-bottom:.3em;}div.where{white-space:pre-wrap;font-size:0.875rem;}.item-info{display:block;margin-left:var(--docblock-indent);}.impl-items>.item-info{margin-left:calc(var(--docblock-indent) + var(--impl-items-indent));}.item-info code{font-size:0.875rem;}#main-content>.item-info{margin-left:0;}nav.sub{flex-grow:1;flex-flow:row nowrap;margin:4px 0 0 0;display:flex;align-items:center;}.search-form{position:relative;display:flex;height:34px;flex-grow:1;margin-bottom:4px;}.src nav.sub{margin:0 0 -10px 0;}.section-header{display:block;position:relative;}.section-header:hover>.anchor,.impl:hover>.anchor,.trait-impl:hover>.anchor,.variant:hover>.anchor{display:initial;}.anchor{display:none;position:absolute;left:-0.5em;background:none !important;}.anchor.field{left:-5px;}.section-header>.anchor{left:-15px;padding-right:8px;}h2.section-header>.anchor{padding-right:6px;}a.doc-anchor{color:var(--main-color);display:none;position:absolute;left:-17px;padding-right:10px;padding-left:3px;}*:hover>.doc-anchor{display:block;}.top-doc>.docblock>*:first-child>.doc-anchor{display:none !important;}.main-heading a:hover,.example-wrap .rust a:hover:not([data-nosnippet]),.all-items a:hover,.docblock a:not(.scrape-help):not(.tooltip):hover:not(.doc-anchor),.item-table dd a:not(.scrape-help):not(.tooltip):hover,.item-info a{text-decoration:underline;}.crate.block li.current a{font-weight:500;}table,.item-table{overflow-wrap:break-word;}.item-table{padding:0;margin:0;width:100%;}.item-table>dt{padding-right:1.25rem;}.item-table>dd{margin-inline-start:0;margin-left:0;}.search-results-title{margin-top:0;white-space:nowrap;display:flex;align-items:baseline;}.search-results-title+.sub-heading{color:var(--main-color);display:flex;align-items:baseline;white-space:nowrap;}#crate-search-div{position:relative;min-width:0;}#crate-search{padding:0 23px 0 4px;max-width:100%;text-overflow:ellipsis;border:1px solid var(--border-color);border-radius:4px;outline:none;cursor:pointer;-moz-appearance:none;-webkit-appearance:none;text-indent:0.01px;background-color:var(--main-background-color);color:inherit;line-height:1.5;font-weight:500;}#crate-search:hover,#crate-search:focus{border-color:var(--crate-search-hover-border);}#crate-search-div::after{pointer-events:none;width:100%;height:100%;position:absolute;top:0;left:0;content:"";background-repeat:no-repeat;background-size:20px;background-position:calc(100% - 2px) 56%;background-image:url('data:image/svg+xml, \ + ');filter:var(--crate-search-div-filter);}#crate-search-div:hover::after,#crate-search-div:focus-within::after{filter:var(--crate-search-div-hover-filter);}#crate-search>option{font-size:1rem;}.search-input{-webkit-appearance:none;outline:none;border:1px solid var(--border-color);border-radius:2px;padding:8px;font-size:1rem;flex-grow:1;background-color:var(--button-background-color);color:var(--search-color);}.search-input:focus{border-color:var(--search-input-focused-border-color);}.search-results{display:none;}.search-results.active{display:block;margin:0;padding:0;}.search-results>a{display:grid;grid-template-areas:"search-result-name search-result-desc" "search-result-type-signature search-result-type-signature";grid-template-columns:.6fr .4fr;margin-left:2px;margin-right:2px;border-bottom:1px solid var(--search-result-border-color);column-gap:1em;}.search-results>a>div.desc{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;grid-area:search-result-desc;}.search-results a:hover,.search-results a:focus{background-color:var(--search-result-link-focus-background-color);}.search-results .result-name{display:flex;align-items:center;justify-content:start;grid-area:search-result-name;}.search-results .result-name .alias{color:var(--search-results-alias-color);}.search-results .result-name .grey{color:var(--search-results-grey-color);}.search-results .result-name .typename{color:var(--search-results-grey-color);font-size:0.875rem;width:var(--search-typename-width);}.search-results .result-name .path{word-break:break-all;max-width:calc(100% - var(--search-typename-width));display:inline-block;}.search-results .result-name .path>*{display:inline;}.search-results .type-signature{grid-area:search-result-type-signature;white-space:pre-wrap;}.popover{position:absolute;top:100%;right:0;z-index:calc(var(--desktop-sidebar-z-index) + 1);margin-top:7px;border-radius:3px;border:1px solid var(--border-color);background-color:var(--main-background-color);color:var(--main-color);--popover-arrow-offset:11px;}.popover::before{content:'';position:absolute;right:var(--popover-arrow-offset);border:solid var(--border-color);border-width:1px 1px 0 0;background-color:var(--main-background-color);padding:4px;transform:rotate(-45deg);top:-5px;}.setting-line{margin:1.2em 0.6em;}.setting-radio input,.setting-check input{margin-right:0.3em;height:1.2rem;width:1.2rem;border:2px solid var(--settings-input-border-color);outline:none;-webkit-appearance:none;cursor:pointer;}.setting-radio input{border-radius:50%;}.setting-radio span,.setting-check span{padding-bottom:1px;}.setting-radio{margin-top:0.1em;margin-bottom:0.1em;min-width:3.8em;padding:0.3em;display:inline-flex;align-items:center;cursor:pointer;}.setting-radio+.setting-radio{margin-left:0.5em;}.setting-check{margin-right:20px;display:flex;align-items:center;cursor:pointer;}.setting-radio input:checked{box-shadow:inset 0 0 0 3px var(--main-background-color);background-color:var(--settings-input-color);}.setting-check input:checked{background-color:var(--settings-input-color);border-width:1px;content:url('data:image/svg+xml,\ + \ + ');}.setting-radio input:focus,.setting-check input:focus{box-shadow:0 0 1px 1px var(--settings-input-color);}.setting-radio input:checked:focus{box-shadow:inset 0 0 0 3px var(--main-background-color),0 0 2px 2px var(--settings-input-color);}.setting-radio input:hover,.setting-check input:hover{border-color:var(--settings-input-color) !important;}#settings.popover{--popover-arrow-offset:202px;top:calc(100% - 16px);}#help.popover{max-width:600px;--popover-arrow-offset:118px;top:calc(100% - 16px);}#help dt{float:left;clear:left;margin-right:0.5rem;}#help dd{margin-bottom:0.5rem;}#help span.top,#help span.bottom{text-align:center;display:block;font-size:1.125rem;padding:0 0.5rem;text-wrap-style:balance;}#help span.top{margin:10px 0;border-bottom:1px solid var(--border-color);padding-bottom:4px;margin-bottom:6px;}#help span.bottom{clear:both;border-top:1px solid var(--border-color);}.side-by-side{display:flex;margin-bottom:20px;}.side-by-side>div{width:50%;padding:0 20px 0 17px;}.item-info .stab{display:block;padding:3px;margin-bottom:5px;}.item-table dt .stab{margin-left:0.3125em;}.stab{padding:0 2px;font-size:0.875rem;font-weight:normal;color:var(--main-color);background-color:var(--stab-background-color);width:fit-content;white-space:pre-wrap;border-radius:3px;display:inline;vertical-align:baseline;}.stab.portability>code{background:none;color:var(--stab-code-color);}.stab .emoji,.item-info .stab::before{font-size:1.25rem;}.stab .emoji{margin-right:0.3rem;}.item-info .stab::before{content:"\0";width:0;display:inline-block;color:transparent;}.emoji{text-shadow:1px 0 0 black,-1px 0 0 black,0 1px 0 black,0 -1px 0 black;}.since{font-weight:normal;font-size:initial;}.rightside{padding-left:12px;float:right;}.rightside:not(a),.out-of-band,.sub-heading,rustdoc-toolbar{color:var(--right-side-color);}pre.rust{tab-size:4;-moz-tab-size:4;}pre.rust .kw{color:var(--code-highlight-kw-color);}pre.rust .kw-2{color:var(--code-highlight-kw-2-color);}pre.rust .lifetime{color:var(--code-highlight-lifetime-color);}pre.rust .prelude-ty{color:var(--code-highlight-prelude-color);}pre.rust .prelude-val{color:var(--code-highlight-prelude-val-color);}pre.rust .string{color:var(--code-highlight-string-color);}pre.rust .number{color:var(--code-highlight-number-color);}pre.rust .bool-val{color:var(--code-highlight-literal-color);}pre.rust .self{color:var(--code-highlight-self-color);}pre.rust .attr{color:var(--code-highlight-attribute-color);}pre.rust .macro,pre.rust .macro-nonterminal{color:var(--code-highlight-macro-color);}pre.rust .question-mark{font-weight:bold;color:var(--code-highlight-question-mark-color);}pre.rust .comment{color:var(--code-highlight-comment-color);}pre.rust .doccomment{color:var(--code-highlight-doc-comment-color);}.rustdoc.src .example-wrap pre.rust a:not([data-nosnippet]){background:var(--codeblock-link-background);}.example-wrap.compile_fail,.example-wrap.should_panic{border-left:2px solid var(--codeblock-error-color);}.ignore.example-wrap{border-left:2px solid var(--codeblock-ignore-color);}.example-wrap.compile_fail:hover,.example-wrap.should_panic:hover{border-left:2px solid var(--codeblock-error-hover-color);}.example-wrap.ignore:hover{border-left:2px solid var(--codeblock-ignore-hover-color);}.example-wrap.compile_fail .tooltip,.example-wrap.should_panic .tooltip{color:var(--codeblock-error-color);}.example-wrap.ignore .tooltip{color:var(--codeblock-ignore-color);}.example-wrap.compile_fail:hover .tooltip,.example-wrap.should_panic:hover .tooltip{color:var(--codeblock-error-hover-color);}.example-wrap.ignore:hover .tooltip{color:var(--codeblock-ignore-hover-color);}.example-wrap .tooltip{position:absolute;display:block;left:-25px;top:5px;margin:0;line-height:1;}.example-wrap.compile_fail .tooltip,.example-wrap.should_panic .tooltip,.example-wrap.ignore .tooltip{font-weight:bold;font-size:1.25rem;}.content .docblock .warning{border-left:2px solid var(--warning-border-color);padding:14px;position:relative;overflow-x:visible !important;}.content .docblock .warning::before{color:var(--warning-border-color);content:"ⓘ";position:absolute;left:-25px;top:5px;font-weight:bold;font-size:1.25rem;}.top-doc>.docblock>.warning:first-child::before{top:20px;}.example-wrap>a.test-arrow,.example-wrap .button-holder{visibility:hidden;position:absolute;top:4px;right:4px;z-index:1;}a.test-arrow{height:var(--copy-path-height);padding:6px 4px 0 11px;}a.test-arrow::before{content:url('data:image/svg+xml,');}.example-wrap .button-holder{display:flex;}@media not (pointer:coarse){.example-wrap:hover>a.test-arrow,.example-wrap:hover>.button-holder{visibility:visible;}}.example-wrap .button-holder.keep-visible{visibility:visible;}.example-wrap .button-holder>*{background:var(--main-background-color);cursor:pointer;border-radius:var(--button-border-radius);height:var(--copy-path-height);width:var(--copy-path-width);border:0;color:var(--code-example-button-color);}.example-wrap .button-holder>*:hover{color:var(--code-example-button-hover-color);}.example-wrap .button-holder>*:not(:first-child){margin-left:var(--button-left-margin);}.example-wrap .button-holder .copy-button{padding:2px 0 0 4px;}.example-wrap .button-holder .copy-button::before,.example-wrap .test-arrow::before,.example-wrap .button-holder .prev::before,.example-wrap .button-holder .next::before,.example-wrap .button-holder .expand::before{filter:var(--copy-path-img-filter);}.example-wrap .button-holder .copy-button::before{content:var(--clipboard-image);}.example-wrap .button-holder .copy-button:hover::before,.example-wrap .test-arrow:hover::before{filter:var(--copy-path-img-hover-filter);}.example-wrap .button-holder .copy-button.clicked::before{content:var(--checkmark-image);padding-right:5px;}.example-wrap .button-holder .prev,.example-wrap .button-holder .next,.example-wrap .button-holder .expand{line-height:0px;}.example-wrap .button-holder .prev::before{content:var(--prev-arrow-image);}.example-wrap .button-holder .next::before{content:var(--next-arrow-image);}.example-wrap .button-holder .expand::before{content:var(--expand-arrow-image);}.example-wrap .button-holder .expand.collapse::before{content:var(--collapse-arrow-image);}.code-attribute{font-weight:300;color:var(--code-attribute-color);}.item-spacer{width:100%;height:12px;display:block;}.main-heading span.since::before{content:"Since ";}.sub-variant h4{font-size:1rem;font-weight:400;margin-top:0;margin-bottom:0;}.sub-variant{margin-left:24px;margin-bottom:40px;}.sub-variant>.sub-variant-field{margin-left:24px;}@keyframes targetfadein{from{background-color:var(--main-background-color);}10%{background-color:var(--target-border-color);}to{background-color:var(--target-background-color);}}:target:not([data-nosnippet]){background-color:var(--target-background-color);border-right:3px solid var(--target-border-color);}.code-header a.tooltip{color:inherit;margin-right:15px;position:relative;}.code-header a.tooltip:hover{color:var(--link-color);}a.tooltip:hover::after{position:absolute;top:calc(100% - 10px);left:-15px;right:-15px;height:20px;content:"\00a0";}@media not (prefers-reduced-motion){:target{animation:0.65s cubic-bezier(0,0,0.1,1.0) 0.1s targetfadein;}.fade-out{opacity:0;transition:opacity 0.45s cubic-bezier(0,0,0.1,1.0);}}.popover.tooltip .content{margin:0.25em 0.5em;}.popover.tooltip .content pre,.popover.tooltip .content code{background:transparent;margin:0;padding:0;font-size:1.25rem;white-space:pre-wrap;}.popover.tooltip .content>h3:first-child{margin:0 0 5px 0;}.search-failed{text-align:center;margin-top:20px;display:none;}.search-failed.active{display:block;}.search-failed>ul{text-align:left;max-width:570px;margin-left:auto;margin-right:auto;}#search-tabs{margin-top:0.25rem;display:flex;flex-direction:row;gap:1px;margin-bottom:4px;}#search-tabs button{text-align:center;font-size:1.125rem;border:0;border-top:2px solid;flex:1;line-height:1.5;color:inherit;}#search-tabs button:not(.selected){background-color:var(--search-tab-button-not-selected-background);border-top-color:var(--search-tab-button-not-selected-border-top-color);}#search-tabs button:hover,#search-tabs button.selected{background-color:var(--search-tab-button-selected-background);border-top-color:var(--search-tab-button-selected-border-top-color);}#search-tabs .count{font-size:1rem;font-variant-numeric:tabular-nums;color:var(--search-tab-title-count-color);}#search .error code{border-radius:3px;background-color:var(--search-error-code-background-color);}.search-corrections{font-weight:normal;}#src-sidebar{width:100%;overflow:auto;}#src-sidebar div.files>a:hover,details.dir-entry summary:hover,#src-sidebar div.files>a:focus,details.dir-entry summary:focus{background-color:var(--src-sidebar-background-hover);}#src-sidebar div.files>a.selected{background-color:var(--src-sidebar-background-selected);}.src-sidebar-title{position:sticky;top:0;display:flex;padding:8px 8px 0 48px;margin-bottom:7px;background:var(--sidebar-background-color);border-bottom:1px solid var(--border-color);}#settings-menu,#help-button,button#toggle-all-docs{margin-left:var(--button-left-margin);display:flex;line-height:1.25;min-width:14px;}#sidebar-button{display:none;line-height:0;}.hide-sidebar #sidebar-button,.src #sidebar-button{display:flex;margin-right:4px;position:fixed;left:6px;height:34px;width:34px;background-color:var(--main-background-color);z-index:1;}.src #sidebar-button{left:8px;z-index:calc(var(--desktop-sidebar-z-index) + 1);}.hide-sidebar .src #sidebar-button{position:static;}#settings-menu>a,#help-button>a,#sidebar-button>a,button#toggle-all-docs{display:flex;align-items:center;justify-content:center;flex-direction:column;border:1px solid transparent;border-radius:var(--button-border-radius);color:var(--main-color);}#settings-menu>a,#help-button>a,button#toggle-all-docs{width:80px;border-radius:var(--toolbar-button-border-radius);}#settings-menu>a,#help-button>a{min-width:0;}#sidebar-button>a{background-color:var(--button-background-color);border-color:var(--border-color);width:33px;}#settings-menu>a:hover,#settings-menu>a:focus-visible,#help-button>a:hover,#help-button>a:focus-visible,#sidebar-button>a:hover,#sidebar-button>a:focus-visible,button#toggle-all-docs:hover,button#toggle-all-docs:focus-visible{border-color:var(--settings-button-border-focus);text-decoration:none;}#settings-menu>a:before{content:url('data:image/svg+xml,\ + ');width:18px;height:18px;filter:var(--settings-menu-filter);}button#toggle-all-docs:before{content:url('data:image/svg+xml,\ + ');width:18px;height:18px;filter:var(--settings-menu-filter);}button#toggle-all-docs.will-expand:before{content:url('data:image/svg+xml,\ + ');}#help-button>a:before{content:url('data:image/svg+xml,\ + \ + ?');width:18px;height:18px;filter:var(--settings-menu-filter);}button#toggle-all-docs:before,#help-button>a:before,#settings-menu>a:before{filter:var(--settings-menu-filter);margin:8px;}@media not (pointer:coarse){button#toggle-all-docs:hover:before,#help-button>a:hover:before,#settings-menu>a:hover:before{filter:var(--settings-menu-hover-filter);}}button[disabled]#toggle-all-docs{opacity:0.25;border:solid 1px var(--main-background-color);background-size:cover;}button[disabled]#toggle-all-docs:hover{border:solid 1px var(--main-background-color);cursor:not-allowed;}rustdoc-toolbar span.label{font-size:1rem;flex-grow:1;padding-bottom:4px;}#sidebar-button>a:before{content:url('data:image/svg+xml,\ + \ + \ + ');width:22px;height:22px;}#copy-path{color:var(--copy-path-button-color);background:var(--main-background-color);height:var(--copy-path-height);width:var(--copy-path-width);margin-left:10px;padding:0;padding-left:2px;border:0;font-size:0;}#copy-path::before{filter:var(--copy-path-img-filter);content:var(--clipboard-image);}#copy-path:hover::before{filter:var(--copy-path-img-hover-filter);}#copy-path.clicked::before{content:var(--checkmark-image);}@keyframes rotating{from{transform:rotate(0deg);}to{transform:rotate(360deg);}}#settings-menu.rotate>a img{animation:rotating 2s linear infinite;}kbd{display:inline-block;padding:3px 5px;font:15px monospace;line-height:10px;vertical-align:middle;border:solid 1px var(--border-color);border-radius:3px;color:var(--kbd-color);background-color:var(--kbd-background);box-shadow:inset 0 -1px 0 var(--kbd-box-shadow-color);}ul.all-items>li{list-style:none;}details.dir-entry{padding-left:4px;}details.dir-entry>summary{margin:0 0 0 -4px;padding:0 0 0 4px;cursor:pointer;}details.dir-entry div.folders,details.dir-entry div.files{padding-left:23px;}details.dir-entry a{display:block;}details.toggle{contain:layout;position:relative;}details.big-toggle{contain:inline-size;}details.toggle>summary.hideme{cursor:pointer;font-size:1rem;}details.toggle>summary{list-style:none;outline:none;}details.toggle>summary::-webkit-details-marker,details.toggle>summary::marker{display:none;}details.toggle>summary.hideme>span{margin-left:9px;}details.toggle>summary::before{background:url('data:image/svg+xml,\ + ');content:"";cursor:pointer;width:16px;height:16px;display:inline-block;vertical-align:middle;opacity:.5;filter:var(--toggle-filter);}details.toggle>summary.hideme>span,.more-examples-toggle summary,.more-examples-toggle .hide-more{color:var(--toggles-color);}details.toggle>summary::after{content:"Expand";overflow:hidden;width:0;height:0;position:absolute;}details.toggle>summary.hideme::after{content:"";}details.toggle>summary:focus::before,details.toggle>summary:hover::before{opacity:1;}details.toggle>summary:focus-visible::before{outline:1px dotted #000;outline-offset:1px;}details.non-exhaustive{margin-bottom:8px;}details.toggle>summary.hideme::before{position:relative;}details.toggle>summary:not(.hideme)::before{position:absolute;left:-24px;top:4px;}.impl-items>details.toggle>summary:not(.hideme)::before,#main-content>.methods>details.toggle>summary:not(.hideme)::before{position:absolute;left:-24px;}.impl-items>*:not(.item-info),.implementors-toggle>.docblock,#main-content>.methods>:not(.item-info){margin-left:var(--impl-items-indent);}details.big-toggle>summary:not(.hideme)::before{left:-34px;top:9px;}details.toggle[open] >summary.hideme{position:absolute;}details.toggle[open] >summary.hideme>span{display:none;}details.toggle[open] >summary::before{background:url('data:image/svg+xml,\ + ');}details.toggle[open] >summary::after{content:"Collapse";}details.toggle:not([open])>summary .docblock{max-height:calc(1.5em + 0.75em);overflow-y:hidden;}details.toggle:not([open])>summary .docblock>:first-child{max-width:100%;overflow:hidden;width:fit-content;white-space:nowrap;position:relative;padding-right:1em;}details.toggle:not([open])>summary .docblock>:first-child::after{content:"…";position:absolute;right:0;top:0;bottom:0;z-index:1;background-color:var(--main-background-color);font:1rem/1.5 "Source Serif 4",NanumBarunGothic,serif;padding-left:0.2em;}details.toggle:not([open])>summary .docblock>div:first-child::after{padding-top:calc(1.5em + 0.75em - 1.2rem);}details.toggle>summary .docblock{margin-top:0.75em;}.docblock summary>*{display:inline-block;}.docblock>.example-wrap:first-child .tooltip{margin-top:16px;}.src #sidebar-button>a:before,.sidebar-menu-toggle:before{content:url('data:image/svg+xml,\ + ');opacity:0.75;}.sidebar-menu-toggle:hover:before,.sidebar-menu-toggle:active:before,.sidebar-menu-toggle:focus:before{opacity:1;}.src #sidebar-button>a:before{content:url('data:image/svg+xml,\ + \ + \ + ');opacity:0.75;}@media (max-width:850px){#search-tabs .count{display:block;}.side-by-side{flex-direction:column-reverse;}.side-by-side>div{width:auto;}}@media (max-width:700px){:root{--impl-items-indent:0.7em;}*[id]{scroll-margin-top:45px;}#copy-path{width:0;visibility:hidden;}rustdoc-toolbar span.label{display:none;}#settings-menu>a,#help-button>a,button#toggle-all-docs{width:33px;}#settings.popover{--popover-arrow-offset:86px;}#help.popover{--popover-arrow-offset:48px;}.rustdoc{display:block;}main{padding-left:15px;padding-top:0px;}.sidebar .logo-container,.sidebar .location,.sidebar-resizer{display:none;}.sidebar{position:fixed;top:45px;left:-1000px;z-index:11;height:calc(100vh - 45px);width:200px;}.src main,.rustdoc.src .sidebar{top:0;padding:0;height:100vh;border:0;}.src .search-form{margin-left:40px;}.src .main-heading{margin-left:8px;}.hide-sidebar .search-form{margin-left:32px;}.hide-sidebar .src .search-form{margin-left:0;}.sidebar.shown,.src-sidebar-expanded .src .sidebar,.rustdoc:not(.src) .sidebar:focus-within{left:0;}.mobile-topbar h2{padding-bottom:0;margin:auto 0.5em auto auto;overflow:hidden;font-size:24px;white-space:nowrap;text-overflow:ellipsis;}.mobile-topbar .logo-container>img{max-width:35px;max-height:35px;margin:5px 0 5px 20px;}.mobile-topbar{display:flex;flex-direction:row;position:sticky;z-index:10;font-size:2rem;height:45px;width:100%;left:0;top:0;}.hide-sidebar .mobile-topbar{display:none;}.sidebar-menu-toggle{width:45px;border:none;line-height:0;}.hide-sidebar .sidebar-menu-toggle{display:none;}.sidebar-elems{margin-top:1em;}.anchor{display:none !important;}#main-content>details.toggle>summary::before,#main-content>div>details.toggle>summary::before{left:-11px;}#sidebar-button>a:before{content:url('data:image/svg+xml,\ + \ + \ + ');width:22px;height:22px;}.sidebar-menu-toggle:before{filter:var(--mobile-sidebar-menu-filter);}.sidebar-menu-toggle:hover{background:var(--main-background-color);}.search-results>a,.search-results>a>div{display:block;}.search-results>a{padding:5px 0px;}.search-results>a>div.desc,.item-table dd{padding-left:2em;}.search-results .result-name{display:block;}.search-results .result-name .typename{width:initial;margin-right:0;}.search-results .result-name .typename,.search-results .result-name .path{display:inline;}.src-sidebar-expanded .src .sidebar{position:fixed;max-width:100vw;width:100vw;}.src .src-sidebar-title{padding-top:0;}details.implementors-toggle:not(.top-doc)>summary{margin-left:10px;}.impl-items>details.toggle>summary:not(.hideme)::before,#main-content>.methods>details.toggle>summary:not(.hideme)::before{left:-20px;}summary>.item-info{margin-left:10px;}.impl-items>.item-info{margin-left:calc(var(--impl-items-indent) + 10px);}.src nav.sub{margin:0 0 -25px 0;padding:var(--nav-sub-mobile-padding);}}@media (min-width:701px){.scraped-example-title{position:absolute;z-index:10;background:var(--main-background-color);bottom:8px;right:5px;padding:2px 4px;box-shadow:0 0 4px var(--main-background-color);}.item-table:not(.reexports){display:grid;grid-template-columns:33% 67%;}.item-table>dt,.item-table>dd{overflow-wrap:anywhere;}.item-table>dt{grid-column-start:1;}.item-table>dd{grid-column-start:2;}}@media print{:root{--docblock-indent:0;}nav.sidebar,nav.sub,.out-of-band,a.src,#copy-path,details.toggle[open] >summary::before,details.toggle>summary::before,details.toggle.top-doc>summary{display:none;}main{padding:10px;}}@media (max-width:464px){:root{--docblock-indent:12px;}.docblock code{overflow-wrap:break-word;overflow-wrap:anywhere;}nav.sub{flex-direction:column;}.search-form{align-self:stretch;}}.variant,.implementors-toggle>summary,.impl,#implementors-list>.docblock,.impl-items>section,.impl-items>.toggle>summary,.methods>section,.methods>.toggle>summary{margin-bottom:0.75em;}.variants>.docblock,.implementors-toggle>.docblock,.impl-items>.toggle[open]:not(:last-child),.methods>.toggle[open]:not(:last-child),.implementors-toggle[open]:not(:last-child){margin-bottom:2em;}#trait-implementations-list .impl-items>.toggle:not(:last-child),#synthetic-implementations-list .impl-items>.toggle:not(:last-child),#blanket-implementations-list .impl-items>.toggle:not(:last-child){margin-bottom:1em;}.scraped-example-list .scrape-help{margin-left:10px;padding:0 4px;font-weight:normal;font-size:12px;position:relative;bottom:1px;border:1px solid var(--scrape-example-help-border-color);border-radius:50px;color:var(--scrape-example-help-color);}.scraped-example-list .scrape-help:hover{border-color:var(--scrape-example-help-hover-border-color);color:var(--scrape-example-help-hover-color);}.scraped-example:not(.expanded) .example-wrap::before,.scraped-example:not(.expanded) .example-wrap::after{content:" ";width:100%;height:5px;position:absolute;z-index:1;}.scraped-example:not(.expanded) .example-wrap::before{top:0;background:linear-gradient(to bottom,var(--scrape-example-code-wrapper-background-start),var(--scrape-example-code-wrapper-background-end));}.scraped-example:not(.expanded) .example-wrap::after{bottom:0;background:linear-gradient(to top,var(--scrape-example-code-wrapper-background-start),var(--scrape-example-code-wrapper-background-end));}.scraped-example:not(.expanded){width:100%;overflow-y:hidden;margin-bottom:0;}.scraped-example:not(.expanded){overflow-x:hidden;}.scraped-example .rust span.highlight{background:var(--scrape-example-code-line-highlight);}.scraped-example .rust span.highlight.focus{background:var(--scrape-example-code-line-highlight-focus);}.more-examples-toggle{max-width:calc(100% + 25px);margin-top:10px;margin-left:-25px;}.more-examples-toggle .hide-more{margin-left:25px;cursor:pointer;}.more-scraped-examples{margin-left:25px;position:relative;}.toggle-line{position:absolute;top:5px;bottom:0;right:calc(100% + 10px);padding:0 4px;cursor:pointer;}.toggle-line-inner{min-width:2px;height:100%;background:var(--scrape-example-toggle-line-background);}.toggle-line:hover .toggle-line-inner{background:var(--scrape-example-toggle-line-hover-background);}.more-scraped-examples .scraped-example,.example-links{margin-top:20px;}.more-scraped-examples .scraped-example:first-child{margin-top:5px;}.example-links ul{margin-bottom:0;}:root[data-theme="light"],:root:not([data-theme]){--main-background-color:white;--main-color:black;--settings-input-color:#2196f3;--settings-input-border-color:#717171;--settings-button-color:#000;--settings-button-border-focus:#717171;--sidebar-background-color:#f5f5f5;--sidebar-background-color-hover:#e0e0e0;--code-block-background-color:#f5f5f5;--scrollbar-track-background-color:#dcdcdc;--scrollbar-thumb-background-color:rgba(36,37,39,0.6);--scrollbar-color:rgba(36,37,39,0.6) #d9d9d9;--headings-border-bottom-color:#ddd;--border-color:#e0e0e0;--button-background-color:#fff;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:none;--mobile-sidebar-menu-filter:none;--search-input-focused-border-color:#66afe9;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(35%);--code-example-button-color:#7f7f7f;--code-example-button-hover-color:#595959;--settings-menu-filter:invert(50%);--settings-menu-hover-filter:invert(35%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#ad378a;--trait-link-color:#6e4fc9;--assoc-item-link-color:#3873ad;--function-link-color:#ad7c37;--macro-link-color:#068000;--keyword-link-color:#3873ad;--mod-link-color:#3873ad;--link-color:#3873ad;--sidebar-link-color:#356da4;--sidebar-current-link-background-color:#fff;--search-result-link-focus-background-color:#ccc;--search-result-border-color:#aaa3;--search-color:#000;--search-error-code-background-color:#d0cccc;--search-results-alias-color:#000;--search-results-grey-color:#999;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#e6e6e6;--search-tab-button-not-selected-background:#e6e6e6;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#fff;--stab-background-color:#fff5d6;--stab-code-color:#000;--code-highlight-kw-color:#8959a8;--code-highlight-kw-2-color:#4271ae;--code-highlight-lifetime-color:#b76514;--code-highlight-prelude-color:#4271ae;--code-highlight-prelude-val-color:#c82829;--code-highlight-number-color:#718c00;--code-highlight-string-color:#718c00;--code-highlight-literal-color:#c82829;--code-highlight-attribute-color:#c82829;--code-highlight-self-color:#c82829;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8e908c;--code-highlight-doc-comment-color:#4d4d4c;--src-line-numbers-span-color:#c67e2d;--src-line-number-highlighted-background-color:#fdffd3;--target-background-color:#fdffd3;--target-border-color:#ad7c37;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:initial;--crate-search-div-filter:invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%);--crate-search-div-hover-filter:invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);--crate-search-hover-border:#717171;--src-sidebar-background-selected:#fff;--src-sidebar-background-hover:#e0e0e0;--table-alt-row-background-color:#f5f5f5;--codeblock-link-background:#eee;--scrape-example-toggle-line-background:#ccc;--scrape-example-toggle-line-hover-background:#999;--scrape-example-code-line-highlight:#fcffd6;--scrape-example-code-line-highlight-focus:#f6fdb0;--scrape-example-help-border-color:#555;--scrape-example-help-color:#333;--scrape-example-help-hover-border-color:#000;--scrape-example-help-hover-color:#000;--scrape-example-code-wrapper-background-start:rgba(255,255,255,1);--scrape-example-code-wrapper-background-end:rgba(255,255,255,0);--sidebar-resizer-hover:hsl(207,90%,66%);--sidebar-resizer-active:hsl(207,90%,54%);}:root[data-theme="dark"]{--main-background-color:#353535;--main-color:#ddd;--settings-input-color:#2196f3;--settings-input-border-color:#999;--settings-button-color:#000;--settings-button-border-focus:#ffb900;--sidebar-background-color:#505050;--sidebar-background-color-hover:#676767;--code-block-background-color:#2A2A2A;--scrollbar-track-background-color:#717171;--scrollbar-thumb-background-color:rgba(32,34,37,.6);--scrollbar-color:rgba(32,34,37,.6) #5a5a5a;--headings-border-bottom-color:#d2d2d2;--border-color:#e0e0e0;--button-background-color:#f0f0f0;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:invert(100%);--mobile-sidebar-menu-filter:invert(100%);--search-input-focused-border-color:#008dfd;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(65%);--code-example-button-color:#7f7f7f;--code-example-button-hover-color:#a5a5a5;--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#2dbfb8;--trait-link-color:#b78cf2;--assoc-item-link-color:#d2991d;--function-link-color:#2bab63;--macro-link-color:#09bd00;--keyword-link-color:#d2991d;--mod-link-color:#d2991d;--link-color:#d2991d;--sidebar-link-color:#fdbf35;--sidebar-current-link-background-color:#444;--search-result-link-focus-background-color:#616161;--search-result-border-color:#aaa3;--search-color:#111;--search-error-code-background-color:#484848;--search-results-alias-color:#fff;--search-results-grey-color:#ccc;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:#252525;--search-tab-button-not-selected-background:#252525;--search-tab-button-selected-border-top-color:#0089ff;--search-tab-button-selected-background:#353535;--settings-menu-filter:invert(50%);--settings-menu-hover-filter:invert(65%);--stab-background-color:#314559;--stab-code-color:#e6e1cf;--code-highlight-kw-color:#ab8ac1;--code-highlight-kw-2-color:#769acb;--code-highlight-lifetime-color:#d97f26;--code-highlight-prelude-color:#769acb;--code-highlight-prelude-val-color:#ee6868;--code-highlight-number-color:#83a300;--code-highlight-string-color:#83a300;--code-highlight-literal-color:#ee6868;--code-highlight-attribute-color:#ee6868;--code-highlight-self-color:#ee6868;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8d8d8b;--code-highlight-doc-comment-color:#8ca375;--src-line-numbers-span-color:#3b91e2;--src-line-number-highlighted-background-color:#0a042f;--target-background-color:#494a3d;--target-border-color:#bb7410;--kbd-color:#000;--kbd-background:#fafbfc;--kbd-box-shadow-color:#c6cbd1;--rust-logo-filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff);--crate-search-div-filter:invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) brightness(90%) contrast(90%);--crate-search-div-hover-filter:invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);--crate-search-hover-border:#2196f3;--src-sidebar-background-selected:#333;--src-sidebar-background-hover:#444;--table-alt-row-background-color:#2a2a2a;--codeblock-link-background:#333;--scrape-example-toggle-line-background:#999;--scrape-example-toggle-line-hover-background:#c5c5c5;--scrape-example-code-line-highlight:#5b3b01;--scrape-example-code-line-highlight-focus:#7c4b0f;--scrape-example-help-border-color:#aaa;--scrape-example-help-color:#eee;--scrape-example-help-hover-border-color:#fff;--scrape-example-help-hover-color:#fff;--scrape-example-code-wrapper-background-start:rgba(53,53,53,1);--scrape-example-code-wrapper-background-end:rgba(53,53,53,0);--sidebar-resizer-hover:hsl(207,30%,54%);--sidebar-resizer-active:hsl(207,90%,54%);}:root[data-theme="ayu"]{--main-background-color:#0f1419;--main-color:#c5c5c5;--settings-input-color:#ffb454;--settings-input-border-color:#999;--settings-button-color:#fff;--settings-button-border-focus:#e0e0e0;--sidebar-background-color:#14191f;--sidebar-background-color-hover:rgba(70,70,70,0.33);--code-block-background-color:#191f26;--scrollbar-track-background-color:transparent;--scrollbar-thumb-background-color:#5c6773;--scrollbar-color:#5c6773 #24292f;--headings-border-bottom-color:#5c6773;--border-color:#5c6773;--button-background-color:#141920;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--toggle-filter:invert(100%);--mobile-sidebar-menu-filter:invert(100%);--search-input-focused-border-color:#5c6773;--copy-path-button-color:#fff;--copy-path-img-filter:invert(70%);--copy-path-img-hover-filter:invert(100%);--code-example-button-color:#b2b2b2;--code-example-button-hover-color:#fff;--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--warning-border-color:#ff8e00;--type-link-color:#ffa0a5;--trait-link-color:#39afd7;--assoc-item-link-color:#39afd7;--function-link-color:#fdd687;--macro-link-color:#a37acc;--keyword-link-color:#39afd7;--mod-link-color:#39afd7;--link-color:#39afd7;--sidebar-link-color:#53b1db;--sidebar-current-link-background-color:transparent;--search-result-link-focus-background-color:#3c3c3c;--search-result-border-color:#aaa3;--search-color:#fff;--search-error-code-background-color:#4f4c4c;--search-results-alias-color:#c5c5c5;--search-results-grey-color:#999;--search-tab-title-count-color:#888;--search-tab-button-not-selected-border-top-color:none;--search-tab-button-not-selected-background:transparent !important;--search-tab-button-selected-border-top-color:none;--search-tab-button-selected-background:#141920 !important;--settings-menu-filter:invert(70%);--settings-menu-hover-filter:invert(100%);--stab-background-color:#314559;--stab-code-color:#e6e1cf;--code-highlight-kw-color:#ff7733;--code-highlight-kw-2-color:#ff7733;--code-highlight-lifetime-color:#ff7733;--code-highlight-prelude-color:#69f2df;--code-highlight-prelude-val-color:#ff7733;--code-highlight-number-color:#b8cc52;--code-highlight-string-color:#b8cc52;--code-highlight-literal-color:#ff7733;--code-highlight-attribute-color:#e6e1cf;--code-highlight-self-color:#36a3d9;--code-highlight-macro-color:#a37acc;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#788797;--code-highlight-doc-comment-color:#a1ac88;--src-line-numbers-span-color:#5c6773;--src-line-number-highlighted-background-color:rgba(255,236,164,0.06);--target-background-color:rgba(255,236,164,0.06);--target-border-color:rgba(255,180,76,0.85);--kbd-color:#c5c5c5;--kbd-background:#314559;--kbd-box-shadow-color:#5c6773;--rust-logo-filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff);--crate-search-div-filter:invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg) brightness(94%) contrast(94%);--crate-search-div-hover-filter:invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg) brightness(113%) contrast(76%);--crate-search-hover-border:#e0e0e0;--src-sidebar-background-selected:#14191f;--src-sidebar-background-hover:#14191f;--table-alt-row-background-color:#191f26;--codeblock-link-background:#333;--scrape-example-toggle-line-background:#999;--scrape-example-toggle-line-hover-background:#c5c5c5;--scrape-example-code-line-highlight:#5b3b01;--scrape-example-code-line-highlight-focus:#7c4b0f;--scrape-example-help-border-color:#aaa;--scrape-example-help-color:#eee;--scrape-example-help-hover-border-color:#fff;--scrape-example-help-hover-color:#fff;--scrape-example-code-wrapper-background-start:rgba(15,20,25,1);--scrape-example-code-wrapper-background-end:rgba(15,20,25,0);--sidebar-resizer-hover:hsl(34,50%,33%);--sidebar-resizer-active:hsl(34,100%,66%);}:root[data-theme="ayu"] h1,:root[data-theme="ayu"] h2,:root[data-theme="ayu"] h3,:root[data-theme="ayu"] h4,:where(:root[data-theme="ayu"]) h1 a,:root[data-theme="ayu"] .sidebar h2 a,:root[data-theme="ayu"] .sidebar h3 a{color:#fff;}:root[data-theme="ayu"] .docblock code{color:#ffb454;}:root[data-theme="ayu"] .docblock a>code{color:#39AFD7 !important;}:root[data-theme="ayu"] .code-header,:root[data-theme="ayu"] .docblock pre>code,:root[data-theme="ayu"] pre,:root[data-theme="ayu"] pre>code,:root[data-theme="ayu"] .item-info code,:root[data-theme="ayu"] .rustdoc.source .example-wrap{color:#e6e1cf;}:root[data-theme="ayu"] .sidebar .current,:root[data-theme="ayu"] .sidebar .current a,:root[data-theme="ayu"] .sidebar a:hover,:root[data-theme="ayu"] #src-sidebar div.files>a:hover,:root[data-theme="ayu"] details.dir-entry summary:hover,:root[data-theme="ayu"] #src-sidebar div.files>a:focus,:root[data-theme="ayu"] details.dir-entry summary:focus,:root[data-theme="ayu"] #src-sidebar div.files>a.selected{color:#ffb44c;}:root[data-theme="ayu"] .sidebar-elems .location{color:#ff7733;}:root[data-theme="ayu"] a[data-nosnippet].line-highlighted{color:#708090;padding-right:7px;border-right:1px solid #ffb44c;}:root[data-theme="ayu"] .search-results a:hover,:root[data-theme="ayu"] .search-results a:focus{color:#fff !important;background-color:#3c3c3c;}:root[data-theme="ayu"] .search-results a{color:#0096cf;}:root[data-theme="ayu"] .search-results a div.desc{color:#c5c5c5;}:root[data-theme="ayu"] .result-name .primitive>i,:root[data-theme="ayu"] .result-name .keyword>i{color:#788797;}:root[data-theme="ayu"] #search-tabs>button.selected{border-bottom:1px solid #ffb44c !important;border-top:none;}:root[data-theme="ayu"] #search-tabs>button:not(.selected){border:none;background-color:transparent !important;}:root[data-theme="ayu"] #search-tabs>button:hover{border-bottom:1px solid rgba(242,151,24,0.3);}:root[data-theme="ayu"] #settings-menu>a img,:root[data-theme="ayu"] #sidebar-button>a:before{filter:invert(100);} \ No newline at end of file diff --git a/static.files/scrape-examples-5e967b76.js b/static.files/scrape-examples-5e967b76.js new file mode 100644 index 00000000..d34361fe --- /dev/null +++ b/static.files/scrape-examples-5e967b76.js @@ -0,0 +1 @@ +"use strict";(function(){const DEFAULT_MAX_LINES=5;const HIDDEN_MAX_LINES=10;function scrollToLoc(elt,loc,isHidden){const lines=elt.querySelectorAll("[data-nosnippet]");let scrollOffset;const maxLines=isHidden?HIDDEN_MAX_LINES:DEFAULT_MAX_LINES;if(loc[1]-loc[0]>maxLines){const line=Math.max(0,loc[0]-1);scrollOffset=lines[line].offsetTop}else{const halfHeight=elt.offsetHeight/2;const offsetTop=lines[loc[0]].offsetTop;const lastLine=lines[loc[1]];const offsetBot=lastLine.offsetTop+lastLine.offsetHeight;const offsetMid=(offsetTop+offsetBot)/2;scrollOffset=offsetMid-halfHeight}lines[0].parentElement.scrollTo(0,scrollOffset);elt.querySelector(".rust").scrollTo(0,scrollOffset)}function createScrapeButton(parent,className,content){const button=document.createElement("button");button.className=className;button.title=content;parent.insertBefore(button,parent.firstChild);return button}window.updateScrapedExample=(example,buttonHolder)=>{let locIndex=0;const highlights=Array.prototype.slice.call(example.querySelectorAll(".highlight"));const link=example.querySelector(".scraped-example-title a");let expandButton=null;if(!example.classList.contains("expanded")){expandButton=createScrapeButton(buttonHolder,"expand","Show all")}const isHidden=example.parentElement.classList.contains("more-scraped-examples");const locs=example.locs;if(locs.length>1){const next=createScrapeButton(buttonHolder,"next","Next usage");const prev=createScrapeButton(buttonHolder,"prev","Previous usage");const onChangeLoc=changeIndex=>{removeClass(highlights[locIndex],"focus");changeIndex();scrollToLoc(example,locs[locIndex][0],isHidden);addClass(highlights[locIndex],"focus");const url=locs[locIndex][1];const title=locs[locIndex][2];link.href=url;link.innerHTML=title};prev.addEventListener("click",()=>{onChangeLoc(()=>{locIndex=(locIndex-1+locs.length)%locs.length})});next.addEventListener("click",()=>{onChangeLoc(()=>{locIndex=(locIndex+1)%locs.length})})}if(expandButton){expandButton.addEventListener("click",()=>{if(hasClass(example,"expanded")){removeClass(example,"expanded");removeClass(expandButton,"collapse");expandButton.title="Show all";scrollToLoc(example,locs[0][0],isHidden)}else{addClass(example,"expanded");addClass(expandButton,"collapse");expandButton.title="Show single example"}})}};function setupLoc(example,isHidden){example.locs=JSON.parse(example.attributes.getNamedItem("data-locs").textContent);scrollToLoc(example,example.locs[0][0],isHidden)}const firstExamples=document.querySelectorAll(".scraped-example-list > .scraped-example");onEachLazy(firstExamples,el=>setupLoc(el,false));onEachLazy(document.querySelectorAll(".more-examples-toggle"),toggle=>{onEachLazy(toggle.querySelectorAll(".toggle-line, .hide-more"),button=>{button.addEventListener("click",()=>{toggle.open=false})});const moreExamples=toggle.querySelectorAll(".scraped-example");toggle.querySelector("summary").addEventListener("click",()=>{setTimeout(()=>{onEachLazy(moreExamples,el=>setupLoc(el,true))})},{once:true})})})() \ No newline at end of file diff --git a/static.files/search-e7298875.js b/static.files/search-e7298875.js new file mode 100644 index 00000000..55e832d0 --- /dev/null +++ b/static.files/search-e7298875.js @@ -0,0 +1,6 @@ +"use strict";if(!Array.prototype.toSpliced){Array.prototype.toSpliced=function(){const me=this.slice();Array.prototype.splice.apply(me,arguments);return me}}function onEachBtwn(arr,func,funcBtwn){let skipped=true;for(const value of arr){if(!skipped){funcBtwn(value)}skipped=func(value)}}const itemTypes=["keyword","primitive","mod","externcrate","import","struct","enum","fn","type","static","trait","impl","tymethod","method","structfield","variant","macro","associatedtype","constant","associatedconstant","union","foreigntype","existential","attr","derive","traitalias","generic",];const TY_PRIMITIVE=itemTypes.indexOf("primitive");const TY_GENERIC=itemTypes.indexOf("generic");const TY_IMPORT=itemTypes.indexOf("import");const TY_TRAIT=itemTypes.indexOf("trait");const TY_FN=itemTypes.indexOf("fn");const TY_METHOD=itemTypes.indexOf("method");const TY_TYMETHOD=itemTypes.indexOf("tymethod");const ROOT_PATH=typeof window!=="undefined"?window.rootPath:"../";const UNBOXING_LIMIT=5;const REGEX_IDENT=/\p{ID_Start}\p{ID_Continue}*|_\p{ID_Continue}+/uy;const REGEX_INVALID_TYPE_FILTER=/[^a-z]/ui;const MAX_RESULTS=200;const NO_TYPE_FILTER=-1;const editDistanceState={current:[],prev:[],prevPrev:[],calculate:function calculate(a,b,limit){if(a.lengthlimit){return limit+1}while(b.length>0&&b[0]===a[0]){a=a.substring(1);b=b.substring(1)}while(b.length>0&&b[b.length-1]===a[a.length-1]){a=a.substring(0,a.length-1);b=b.substring(0,b.length-1)}if(b.length===0){return minDist}const aLength=a.length;const bLength=b.length;for(let i=0;i<=bLength;++i){this.current[i]=0;this.prev[i]=i;this.prevPrev[i]=Number.MAX_VALUE}for(let i=1;i<=aLength;++i){this.current[0]=i;const aIdx=i-1;for(let j=1;j<=bLength;++j){const bIdx=j-1;const substitutionCost=a[aIdx]===b[bIdx]?0:1;this.current[j]=Math.min(this.prev[j]+1,this.current[j-1]+1,this.prev[j-1]+substitutionCost,);if((i>1)&&(j>1)&&(a[aIdx]===b[bIdx-1])&&(a[aIdx-1]===b[bIdx])){this.current[j]=Math.min(this.current[j],this.prevPrev[j-2]+1,)}}const prevPrevTmp=this.prevPrev;this.prevPrev=this.prev;this.prev=this.current;this.current=prevPrevTmp}const distance=this.prev[bLength];return distance<=limit?distance:(limit+1)},};function editDistance(a,b,limit){return editDistanceState.calculate(a,b,limit)}function isEndCharacter(c){return"=,>-])".indexOf(c)!==-1}function isFnLikeTy(ty){return ty===TY_FN||ty===TY_METHOD||ty===TY_TYMETHOD}function isSeparatorCharacter(c){return c===","||c==="="}function isReturnArrow(parserState){return parserState.userQuery.slice(parserState.pos,parserState.pos+2)==="->"}function skipWhitespace(parserState){while(parserState.pos0){const c=parserState.userQuery[pos-1];if(c===lookingFor){return true}else if(c!==" "){break}pos-=1}return false}function isLastElemGeneric(elems,parserState){return(elems.length>0&&elems[elems.length-1].generics.length>0)||prevIs(parserState,">")}function getFilteredNextElem(query,parserState,elems,isInGenerics){const start=parserState.pos;if(parserState.userQuery[parserState.pos]===":"&&!isPathStart(parserState)){throw["Expected type filter before ",":"]}getNextElem(query,parserState,elems,isInGenerics);if(parserState.userQuery[parserState.pos]===":"&&!isPathStart(parserState)){if(parserState.typeFilter!==null){throw["Unexpected ",":"," (expected path after type filter ",parserState.typeFilter+":",")",]}if(elems.length===0){throw["Expected type filter before ",":"]}else if(query.literalSearch){throw["Cannot use quotes on type filter"]}const typeFilterElem=elems.pop();checkExtraTypeFilterCharacters(start,parserState);parserState.typeFilter=typeFilterElem.normalizedPathLast;parserState.pos+=1;parserState.totalElems-=1;query.literalSearch=false;getNextElem(query,parserState,elems,isInGenerics)}}function getItemsBefore(query,parserState,elems,endChar){let foundStopChar=true;let foundSeparator=false;const oldTypeFilter=parserState.typeFilter;parserState.typeFilter=null;const oldIsInBinding=parserState.isInBinding;parserState.isInBinding=null;let hofParameters=null;let extra="";if(endChar===">"){extra="<"}else if(endChar==="]"){extra="["}else if(endChar===")"){extra="("}else if(endChar===""){extra="->"}else{extra=endChar}while(parserState.pos"," after ","="]}hofParameters=[...elems];elems.length=0;parserState.pos+=2;foundStopChar=true;foundSeparator=false;continue}else if(c===" "){parserState.pos+=1;continue}else if(isSeparatorCharacter(c)){parserState.pos+=1;foundStopChar=true;foundSeparator=true;continue}else if(c===":"&&isPathStart(parserState)){throw["Unexpected ","::",": paths cannot start with ","::"]}else if(isEndCharacter(c)){throw["Unexpected ",c," after ",extra]}if(!foundStopChar){let extra=[];if(isLastElemGeneric(query.elems,parserState)){extra=[" after ",">"]}else if(prevIs(parserState,"\"")){throw["Cannot have more than one element if you use quotes"]}if(endChar!==""){throw["Expected ",",",", ","=",", or ",endChar,...extra,", found ",c,]}throw["Expected ",","," or ","=",...extra,", found ",c,]}const posBefore=parserState.pos;getFilteredNextElem(query,parserState,elems,endChar!=="");if(endChar!==""&&parserState.pos>=parserState.length){throw["Unclosed ",extra]}if(posBefore===parserState.pos){parserState.pos+=1}foundStopChar=false}if(parserState.pos>=parserState.length&&endChar!==""){throw["Unclosed ",extra]}parserState.pos+=1;if(hofParameters){foundSeparator=false;if([...elems,...hofParameters].some(x=>x.bindingName)||parserState.isInBinding){throw["Unexpected ","="," within ","->"]}const hofElem=makePrimitiveElement("->",{generics:hofParameters,bindings:new Map([["output",[...elems]]]),typeFilter:null,});elems.length=0;elems[0]=hofElem}parserState.typeFilter=oldTypeFilter;parserState.isInBinding=oldIsInBinding;return{foundSeparator}}function getNextElem(query,parserState,elems,isInGenerics){const generics=[];skipWhitespace(parserState);let start=parserState.pos;let end;if("[(".indexOf(parserState.userQuery[parserState.pos])!==-1){let endChar=")";let name="()";let friendlyName="tuple";if(parserState.userQuery[parserState.pos]==="["){endChar="]";name="[]";friendlyName="slice"}parserState.pos+=1;const{foundSeparator}=getItemsBefore(query,parserState,generics,endChar);const typeFilter=parserState.typeFilter;const bindingName=parserState.isInBinding;parserState.typeFilter=null;parserState.isInBinding=null;for(const gen of generics){if(gen.bindingName!==null){throw["Type parameter ","=",` cannot be within ${friendlyName} `,name]}}if(name==="()"&&!foundSeparator&&generics.length===1&&typeFilter===null){elems.push(generics[0])}else if(name==="()"&&generics.length===1&&generics[0].name==="->"){generics[0].typeFilter=typeFilter;elems.push(generics[0])}else{if(typeFilter!==null&&typeFilter!=="primitive"){throw["Invalid search type: primitive ",name," and ",typeFilter," both specified",]}parserState.totalElems+=1;if(isInGenerics){parserState.genericsElems+=1}elems.push(makePrimitiveElement(name,{bindingName,generics}))}}else if(parserState.userQuery[parserState.pos]==="&"){if(parserState.typeFilter!==null&&parserState.typeFilter!=="primitive"){throw["Invalid search type: primitive ","&"," and ",parserState.typeFilter," both specified",]}parserState.typeFilter=null;parserState.pos+=1;let c=parserState.userQuery[parserState.pos];while(c===" "&&parserState.pos=end){throw["Found generics without a path"]}parserState.pos+=1;getItemsBefore(query,parserState,generics,">")}else if(parserState.pos=end){throw["Found generics without a path"]}if(parserState.isInBinding){throw["Unexpected ","("," after ","="]}parserState.pos+=1;const typeFilter=parserState.typeFilter;parserState.typeFilter=null;getItemsBefore(query,parserState,generics,")");skipWhitespace(parserState);if(isReturnArrow(parserState)){parserState.pos+=2;skipWhitespace(parserState);getFilteredNextElem(query,parserState,generics,isInGenerics);generics[generics.length-1].bindingName=makePrimitiveElement("output")}else{generics.push(makePrimitiveElement(null,{bindingName:makePrimitiveElement("output"),typeFilter:null,}))}parserState.typeFilter=typeFilter}if(isStringElem){skipWhitespace(parserState)}if(start>=end&&generics.length===0){return}if(parserState.userQuery[parserState.pos]==="="){if(parserState.isInBinding){throw["Cannot write ","="," twice in a binding"]}if(!isInGenerics){throw["Type parameter ","="," must be within generics list"]}const name=parserState.userQuery.slice(start,end).trim();if(name==="!"){throw["Type parameter ","="," key cannot be ","!"," never type"]}if(name.includes("!")){throw["Type parameter ","="," key cannot be ","!"," macro"]}if(name.includes("::")){throw["Type parameter ","="," key cannot contain ","::"," path"]}if(name.includes(":")){throw["Type parameter ","="," key cannot contain ",":"," type"]}parserState.isInBinding={name,generics}}else{elems.push(createQueryElement(query,parserState,parserState.userQuery.slice(start,end),generics,isInGenerics,),)}}}function checkExtraTypeFilterCharacters(start,parserState){const query=parserState.userQuery.slice(start,parserState.pos).trim();const match=query.match(REGEX_INVALID_TYPE_FILTER);if(match){throw["Unexpected ",match[0]," in type filter (before ",":",")",]}}function createQueryElement(query,parserState,name,generics,isInGenerics){const path=name.trim();if(path.length===0&&generics.length===0){throw["Unexpected ",parserState.userQuery[parserState.pos]]}if(query.literalSearch&&parserState.totalElems-parserState.genericsElems>0){throw["Cannot have more than one element if you use quotes"]}const typeFilter=parserState.typeFilter;parserState.typeFilter=null;if(name.trim()==="!"){if(typeFilter!==null&&typeFilter!=="primitive"){throw["Invalid search type: primitive never type ","!"," and ",typeFilter," both specified",]}if(generics.length!==0){throw["Never type ","!"," does not accept generic parameters",]}const bindingName=parserState.isInBinding;parserState.isInBinding=null;return makePrimitiveElement("never",{bindingName})}const quadcolon=/::\s*::/.exec(path);if(path.startsWith("::")){throw["Paths cannot start with ","::"]}else if(quadcolon!==null){throw["Unexpected ",quadcolon[0]]}const pathSegments=path.split(/(?:::\s*)|(?:\s+(?:::\s*)?)/).map(x=>x.toLowerCase());if(pathSegments.length===0||(pathSegments.length===1&&pathSegments[0]==="")){if(generics.length>0||prevIs(parserState,">")){throw["Found generics without a path"]}else{throw["Unexpected ",parserState.userQuery[parserState.pos]]}}for(const[i,pathSegment]of pathSegments.entries()){if(pathSegment==="!"){if(i!==0){throw["Never type ","!"," is not associated item"]}pathSegments[i]="never"}}parserState.totalElems+=1;if(isInGenerics){parserState.genericsElems+=1}const bindingName=parserState.isInBinding;parserState.isInBinding=null;const bindings=new Map();const pathLast=pathSegments[pathSegments.length-1];return{name:name.trim(),id:null,fullPath:pathSegments,pathWithoutLast:pathSegments.slice(0,pathSegments.length-1),pathLast,normalizedPathLast:pathLast.replace(/_/g,""),generics:generics.filter(gen=>{if(gen.bindingName!==null&&gen.bindingName.name!==null){if(gen.name!==null){gen.bindingName.generics.unshift(gen)}bindings.set(gen.bindingName.name.toLowerCase().replace(/_/g,""),gen.bindingName.generics,);return false}return true}),bindings,typeFilter,bindingName,}}function makePrimitiveElement(name,extra){return Object.assign({name:name,id:null,fullPath:[name],pathWithoutLast:[],pathLast:name,normalizedPathLast:name,generics:[],bindings:new Map(),typeFilter:"primitive",bindingName:null,},extra)}function getStringElem(query,parserState,isInGenerics){if(isInGenerics){throw["Unexpected ","\""," in generics"]}else if(query.literalSearch){throw["Cannot have more than one literal search element"]}else if(parserState.totalElems-parserState.genericsElems>0){throw["Cannot use literal search when there is more than one element"]}parserState.pos+=1;const start=parserState.pos;const end=getIdentEndPosition(parserState);if(parserState.pos>=parserState.length){throw["Unclosed ","\""]}else if(parserState.userQuery[end]!=="\""){throw["Unexpected ",parserState.userQuery[end]," in a string element"]}else if(start===end){throw["Cannot have empty string element"]}parserState.pos+=1;query.literalSearch=true}function getIdentEndPosition(parserState){let afterIdent=consumeIdent(parserState);let end=parserState.pos;let macroExclamation=-1;while(parserState.pos0){throw["Unexpected ",c," after ",parserState.userQuery[parserState.pos-1]," (not a valid identifier)"]}else{throw["Unexpected ",c," (not a valid identifier)"]}parserState.pos+=1;afterIdent=consumeIdent(parserState);end=parserState.pos}if(macroExclamation!==-1){if(parserState.typeFilter===null){parserState.typeFilter="macro"}else if(parserState.typeFilter!=="macro"){throw["Invalid search type: macro ","!"," and ",parserState.typeFilter," both specified",]}end=macroExclamation}return end}function isSpecialStartCharacter(c){return"<\"".indexOf(c)!==-1}function isPathStart(parserState){return parserState.userQuery.slice(parserState.pos,parserState.pos+2)==="::"}function consumeIdent(parserState){REGEX_IDENT.lastIndex=parserState.pos;const match=parserState.userQuery.match(REGEX_IDENT);if(match){parserState.pos+=match[0].length;return true}return false}function isPathSeparator(c){return c===":"||c===" "}class VlqHexDecoder{constructor(string,cons){this.string=string;this.cons=cons;this.offset=0;this.backrefQueue=[]}decodeList(){let c=this.string.charCodeAt(this.offset);const ret=[];while(c!==125){ret.push(this.decode());c=this.string.charCodeAt(this.offset)}this.offset+=1;return ret}decode(){let n=0;let c=this.string.charCodeAt(this.offset);if(c===123){this.offset+=1;return this.decodeList()}while(c<96){n=(n<<4)|(c&0xF);this.offset+=1;c=this.string.charCodeAt(this.offset)}n=(n<<4)|(c&0xF);const[sign,value]=[n&1,n>>1];this.offset+=1;return sign?-value:value}next(){const c=this.string.charCodeAt(this.offset);if(c>=48&&c<64){this.offset+=1;return this.backrefQueue[c-48]}if(c===96){this.offset+=1;return this.cons(0)}const result=this.cons(this.decode());this.backrefQueue.unshift(result);if(this.backrefQueue.length>16){this.backrefQueue.pop()}return result}}class RoaringBitmap{constructor(str){const strdecoded=atob(str);const u8array=new Uint8Array(strdecoded.length);for(let j=0;j=4){offsets=[];for(let j=0;j>3]&(1<<(j&0x7))){const runcount=(u8array[i]|(u8array[i+1]<<8));i+=2;this.containers.push(new RoaringBitmapRun(runcount,u8array.slice(i,i+(runcount*4)),));i+=runcount*4}else if(this.cardinalities[j]>=4096){this.containers.push(new RoaringBitmapBits(u8array.slice(i,i+8192)));i+=8192}else{const end=this.cardinalities[j]*2;this.containers.push(new RoaringBitmapArray(this.cardinalities[j],u8array.slice(i,i+end),));i+=end}}}contains(keyvalue){const key=keyvalue>>16;const value=keyvalue&0xFFFF;let left=0;let right=this.keys.length-1;while(left<=right){const mid=Math.floor((left+right)/2);const x=this.keys[mid];if(xkey){right=mid-1}else{return this.containers[mid].contains(value)}}return false}}class RoaringBitmapRun{constructor(runcount,array){this.runcount=runcount;this.array=array}contains(value){let left=0;let right=this.runcount-1;while(left<=right){const mid=Math.floor((left+right)/2);const i=mid*4;const start=this.array[i]|(this.array[i+1]<<8);const lenm1=this.array[i+2]|(this.array[i+3]<<8);if((start+lenm1)value){right=mid-1}else{return true}}return false}}class RoaringBitmapArray{constructor(cardinality,array){this.cardinality=cardinality;this.array=array}contains(value){let left=0;let right=this.cardinality-1;while(left<=right){const mid=Math.floor((left+right)/2);const i=mid*2;const x=this.array[i]|(this.array[i+1]<<8);if(xvalue){right=mid-1}else{return true}}return false}}class RoaringBitmapBits{constructor(array){this.array=array}contains(value){return!!(this.array[value>>3]&(1<<(value&7)))}}class NameTrie{constructor(){this.children=[];this.matches=[]}insert(name,id,tailTable){this.insertSubstring(name,0,id,tailTable)}insertSubstring(name,substart,id,tailTable){const l=name.length;if(substart===l){this.matches.push(id)}else{const sb=name.charCodeAt(substart);let child;if(this.children[sb]!==undefined){child=this.children[sb]}else{child=new NameTrie();this.children[sb]=child;let sste;if(substart>=2){const tail=name.substring(substart-2,substart+1);if(tailTable.has(tail)){sste=tailTable.get(tail)}else{sste=[];tailTable.set(tail,sste)}sste.push(child)}}child.insertSubstring(name,substart+1,id,tailTable)}}search(name,tailTable){const results=new Set();this.searchSubstringPrefix(name,0,results);if(results.size=3){const levParams=name.length>=6?new Lev2TParametricDescription(name.length):new Lev1TParametricDescription(name.length);this.searchLev(name,0,levParams,results);const tail=name.substring(0,3);if(tailTable.has(tail)){for(const entry of tailTable.get(tail)){entry.searchSubstringPrefix(name,3,results)}}}return[...results]}searchSubstringPrefix(name,substart,results){const l=name.length;if(substart===l){for(const match of this.matches){results.add(match)}let unprocessedChildren=[];for(const child of this.children){if(child){unprocessedChildren.push(child)}}let nextSet=[];while(unprocessedChildren.length!==0){const next=unprocessedChildren.pop();for(const child of next.children){if(child){nextSet.push(child)}}for(const match of next.matches){results.add(match)}if(unprocessedChildren.length===0){const tmp=unprocessedChildren;unprocessedChildren=nextSet;nextSet=tmp}}}else{const sb=name.charCodeAt(substart);if(this.children[sb]!==undefined){this.children[sb].searchSubstringPrefix(name,substart+1,results)}}}searchLev(name,substart,levParams,results){const stack=[[this,0]];const n=levParams.n;while(stack.length!==0){const[trie,levState]=stack.pop();for(const[charCode,child]of trie.children.entries()){if(!child){continue}const levPos=levParams.getPosition(levState);const vector=levParams.getVector(name,charCode,levPos,Math.min(name.length,levPos+(2*n)+1),);const newLevState=levParams.transition(levState,levPos,vector,);if(newLevState>=0){stack.push([child,newLevState]);if(levParams.isAccept(newLevState)){for(const match of child.matches){results.add(match)}}}}}}}class DocSearch{constructor(rawSearchIndex,rootPath,searchState){this.searchIndexDeprecated=new Map();this.searchIndexEmptyDesc=new Map();this.functionTypeFingerprint=new Uint32Array(0);this.typeNameIdMap=new Map();this.assocTypeIdNameMap=new Map();this.ALIASES=new Map();this.rootPath=rootPath;this.searchState=searchState;this.typeNameIdOfArray=this.buildTypeMapIndex("array");this.typeNameIdOfSlice=this.buildTypeMapIndex("slice");this.typeNameIdOfArrayOrSlice=this.buildTypeMapIndex("[]");this.typeNameIdOfTuple=this.buildTypeMapIndex("tuple");this.typeNameIdOfUnit=this.buildTypeMapIndex("unit");this.typeNameIdOfTupleOrUnit=this.buildTypeMapIndex("()");this.typeNameIdOfFn=this.buildTypeMapIndex("fn");this.typeNameIdOfFnMut=this.buildTypeMapIndex("fnmut");this.typeNameIdOfFnOnce=this.buildTypeMapIndex("fnonce");this.typeNameIdOfHof=this.buildTypeMapIndex("->");this.typeNameIdOfOutput=this.buildTypeMapIndex("output",true);this.typeNameIdOfReference=this.buildTypeMapIndex("reference");this.EMPTY_BINDINGS_MAP=new Map();this.EMPTY_GENERICS_ARRAY=[];this.TYPES_POOL=new Map();this.nameTrie=new NameTrie();this.tailTable=new Map();this.searchIndex=this.buildIndex(rawSearchIndex)}buildTypeMapIndex(name,isAssocType){if(name===""||name===null){return null}if(this.typeNameIdMap.has(name)){const obj=this.typeNameIdMap.get(name);obj.assocOnly=!!(isAssocType&&obj.assocOnly);return obj.id}else{const id=this.typeNameIdMap.size;this.typeNameIdMap.set(name,{id,assocOnly:!!isAssocType});return id}}buildItemSearchTypeAll(types,paths,lowercasePaths){return types&&types.length>0?types.map(type=>this.buildItemSearchType(type,paths,lowercasePaths)):this.EMPTY_GENERICS_ARRAY}buildItemSearchType(type,paths,lowercasePaths,isAssocType){const PATH_INDEX_DATA=0;const GENERICS_DATA=1;const BINDINGS_DATA=2;let pathIndex,generics,bindings;if(typeof type==="number"){pathIndex=type;generics=this.EMPTY_GENERICS_ARRAY;bindings=this.EMPTY_BINDINGS_MAP}else{pathIndex=type[PATH_INDEX_DATA];generics=this.buildItemSearchTypeAll(type[GENERICS_DATA],paths,lowercasePaths,);if(type.length>BINDINGS_DATA&&type[BINDINGS_DATA].length>0){bindings=new Map(type[BINDINGS_DATA].map(binding=>{const[assocType,constraints]=binding;return[this.buildItemSearchType(assocType,paths,lowercasePaths,true).id,this.buildItemSearchTypeAll(constraints,paths,lowercasePaths),]}))}else{bindings=this.EMPTY_BINDINGS_MAP}}let result;if(pathIndex<0){result={id:pathIndex,name:"",ty:TY_GENERIC,path:null,exactPath:null,generics,bindings,unboxFlag:true,}}else if(pathIndex===0){result={id:null,name:"",ty:null,path:null,exactPath:null,generics,bindings,unboxFlag:true,}}else{const item=lowercasePaths[pathIndex-1];const id=this.buildTypeMapIndex(item.name,isAssocType);if(isAssocType&&id!==null){this.assocTypeIdNameMap.set(id,paths[pathIndex-1].name)}result={id,name:paths[pathIndex-1].name,ty:item.ty,path:item.path,exactPath:item.exactPath,generics,bindings,unboxFlag:item.unboxFlag,}}const cr=this.TYPES_POOL.get(result.id);if(cr){if(cr.generics.length===result.generics.length&&cr.generics!==result.generics&&cr.generics.every((x,i)=>result.generics[i]===x)){result.generics=cr.generics}if(cr.bindings.size===result.bindings.size&&cr.bindings!==result.bindings){let ok=true;for(const[k,v]of cr.bindings.entries()){const v2=result.bindings.get(v);if(!v2){ok=false;break}if(v!==v2&&v.length===v2.length&&v.every((x,i)=>v2[i]===x)){result.bindings.set(k,v)}else if(v!==v2){ok=false;break}}if(ok){result.bindings=cr.bindings}}if(cr.ty===result.ty&&cr.path===result.path&&cr.bindings===result.bindings&&cr.generics===result.generics&&cr.ty===result.ty&&cr.name===result.name&&cr.unboxFlag===result.unboxFlag){return cr}}this.TYPES_POOL.set(result.id,result);return result}buildFunctionTypeFingerprint(type,output){let input=type.id;if(input===this.typeNameIdOfArray||input===this.typeNameIdOfSlice){input=this.typeNameIdOfArrayOrSlice}if(input===this.typeNameIdOfTuple||input===this.typeNameIdOfUnit){input=this.typeNameIdOfTupleOrUnit}if(input===this.typeNameIdOfFn||input===this.typeNameIdOfFnMut||input===this.typeNameIdOfFnOnce){input=this.typeNameIdOfHof}const hashint1=k=>{k=(~~k+0x7ed55d16)+(k<<12);k=(k ^ 0xc761c23c)^(k>>>19);k=(~~k+0x165667b1)+(k<<5);k=(~~k+0xd3a2646c)^(k<<9);k=(~~k+0xfd7046c5)+(k<<3);return(k ^ 0xb55a4f09)^(k>>>16)};const hashint2=k=>{k=~k+(k<<15);k ^=k>>>12;k+=k<<2;k ^=k>>>4;k=Math.imul(k,2057);return k ^(k>>16)};if(input!==null){const h0a=hashint1(input);const h0b=hashint2(input);const h1a=~~(h0a+Math.imul(h0b,2));const h1b=~~(h0a+Math.imul(h0b,3));const h2a=~~(h0a+Math.imul(h0b,4));const h2b=~~(h0a+Math.imul(h0b,5));output[0]|=(1<<(h0a%32))|(1<<(h1b%32));output[1]|=(1<<(h1a%32))|(1<<(h2b%32));output[2]|=(1<<(h2a%32))|(1<<(h0b%32));output[3]+=1}for(const g of type.generics){this.buildFunctionTypeFingerprint(g,output)}const fb={id:null,ty:0,generics:this.EMPTY_GENERICS_ARRAY,bindings:this.EMPTY_BINDINGS_MAP,};for(const[k,v]of type.bindings.entries()){fb.id=k;fb.generics=v;this.buildFunctionTypeFingerprint(fb,output)}}buildIndex(rawSearchIndex){const buildFunctionSearchTypeCallback=(paths,lowercasePaths)=>{const cb=functionSearchType=>{if(functionSearchType===0){return null}const INPUTS_DATA=0;const OUTPUT_DATA=1;let inputs;let output;if(typeof functionSearchType[INPUTS_DATA]==="number"){inputs=[this.buildItemSearchType(functionSearchType[INPUTS_DATA],paths,lowercasePaths,),]}else{inputs=this.buildItemSearchTypeAll(functionSearchType[INPUTS_DATA],paths,lowercasePaths,)}if(functionSearchType.length>1){if(typeof functionSearchType[OUTPUT_DATA]==="number"){output=[this.buildItemSearchType(functionSearchType[OUTPUT_DATA],paths,lowercasePaths,),]}else{output=this.buildItemSearchTypeAll(functionSearchType[OUTPUT_DATA],paths,lowercasePaths,)}}else{output=[]}const where_clause=[];const l=functionSearchType.length;for(let i=2;i{const n=noop;return n});let descShard={crate,shard:0,start:0,len:itemDescShardDecoder.next(),promise:null,resolve:null,};const descShardList=[descShard];this.searchIndexDeprecated.set(crate,new RoaringBitmap(crateCorpus.c));this.searchIndexEmptyDesc.set(crate,new RoaringBitmap(crateCorpus.e));let descIndex=0;let lastParamNames=[];let normalizedName=crate.indexOf("_")===-1?crate:crate.replace(/_/g,"");const crateRow={crate,ty:3,name:crate,path:"",descShard,descIndex,exactPath:"",desc:crateCorpus.doc,parent:undefined,type:null,paramNames:lastParamNames,id,word:crate,normalizedName,bitIndex:0,implDisambiguator:null,};this.nameTrie.insert(normalizedName,id,this.tailTable);id+=1;searchIndex.push(crateRow);currentIndex+=1;if(!this.searchIndexEmptyDesc.get(crate).contains(0)){descIndex+=1}const itemTypes=crateCorpus.t;const itemNames=crateCorpus.n;const itemPaths=new Map(crateCorpus.q);const itemReexports=new Map(crateCorpus.r);const itemParentIdxDecoder=new VlqHexDecoder(crateCorpus.i,noop=>noop);const implDisambiguator=new Map(crateCorpus.b);const rawPaths=crateCorpus.p;const aliases=crateCorpus.a;const itemParamNames=new Map(crateCorpus.P);const lowercasePaths=[];const paths=[];const itemFunctionDecoder=new VlqHexDecoder(crateCorpus.f,buildFunctionSearchTypeCallback(paths,lowercasePaths),);let len=rawPaths.length;let lastPath=itemPaths.get(0);for(let i=0;i2&&elem[2]!==null){path=itemPaths.has(elem[2])?itemPaths.get(elem[2]):lastPath;lastPath=path}let exactPath=elem.length>3&&elem[3]!==null?itemPaths.get(elem[3]):path;const unboxFlag=elem.length>4&&!!elem[4];if(path===undefined){path=null}if(exactPath===undefined){exactPath=null}lowercasePaths.push({ty,name:name.toLowerCase(),path,exactPath,unboxFlag});paths[i]={ty,name,path,exactPath,unboxFlag}}lastPath="";len=itemTypes.length;let lastName="";let lastWord="";for(let i=0;i=descShard.len&&!this.searchIndexEmptyDesc.get(crate).contains(bitIndex)){descShard={crate,shard:descShard.shard+1,start:descShard.start+descShard.len,len:itemDescShardDecoder.next(),promise:null,resolve:null,};descIndex=0;descShardList.push(descShard)}const name=itemNames[i]===""?lastName:itemNames[i];const word=itemNames[i]===""?lastWord:itemNames[i].toLowerCase();const path=itemPaths.has(i)?itemPaths.get(i):lastPath;const paramNames=itemParamNames.has(i)?itemParamNames.get(i).split(","):lastParamNames;const type=itemFunctionDecoder.next();if(type!==null){if(type){const fp=this.functionTypeFingerprint.subarray(id*4,(id+1)*4);for(const t of type.inputs){this.buildFunctionTypeFingerprint(t,fp)}for(const t of type.output){this.buildFunctionTypeFingerprint(t,fp)}for(const w of type.where_clause){for(const t of w){this.buildFunctionTypeFingerprint(t,fp)}}}}const itemParentIdx=itemParentIdxDecoder.next();normalizedName=word.indexOf("_")===-1?word:word.replace(/_/g,"");const row={crate,ty:itemTypes.charCodeAt(i)-65,name,path,descShard,descIndex,exactPath:itemReexports.has(i)?itemPaths.get(itemReexports.get(i)):path,parent:itemParentIdx>0?paths[itemParentIdx-1]:undefined,type,paramNames,id,word,normalizedName,bitIndex,implDisambiguator:implDisambiguator.has(i)?implDisambiguator.get(i):null,};this.nameTrie.insert(normalizedName,id,this.tailTable);id+=1;searchIndex.push(row);lastPath=row.path;lastParamNames=row.paramNames;if(!this.searchIndexEmptyDesc.get(crate).contains(bitIndex)){descIndex+=1}lastName=name;lastWord=word}if(aliases){const currentCrateAliases=new Map();this.ALIASES.set(crate,currentCrateAliases);for(const alias_name in aliases){if(!Object.prototype.hasOwnProperty.call(aliases,alias_name)){continue}let currentNameAliases;if(currentCrateAliases.has(alias_name)){currentNameAliases=currentCrateAliases.get(alias_name)}else{currentNameAliases=[];currentCrateAliases.set(alias_name,currentNameAliases)}for(const local_alias of aliases[alias_name]){currentNameAliases.push(local_alias+currentIndex)}}}currentIndex+=itemTypes.length;this.searchState.descShards.set(crate,descShardList)}this.TYPES_POOL=new Map();return searchIndex}static parseQuery(userQuery){function itemTypeFromName(typename){const index=itemTypes.findIndex(i=>i===typename);if(index<0){throw["Unknown type filter ",typename]}return index}function convertTypeFilterOnElem(elem){if(typeof elem.typeFilter==="string"){let typeFilter=elem.typeFilter;if(typeFilter==="const"){typeFilter="constant"}elem.typeFilter=itemTypeFromName(typeFilter)}else{elem.typeFilter=NO_TYPE_FILTER}for(const elem2 of elem.generics){convertTypeFilterOnElem(elem2)}for(const constraints of elem.bindings.values()){for(const constraint of constraints){convertTypeFilterOnElem(constraint)}}}function newParsedQuery(userQuery){return{userQuery,elems:[],returned:[],foundElems:0,totalElems:0,literalSearch:false,hasReturnArrow:false,error:null,correction:null,proposeCorrectionFrom:null,proposeCorrectionTo:null,typeFingerprint:new Uint32Array(4),}}function parseInput(query,parserState){let foundStopChar=true;while(parserState.pos"){if(isReturnArrow(parserState)){query.hasReturnArrow=true;break}throw["Unexpected ",c," (did you mean ","->","?)"]}else if(parserState.pos>0){throw["Unexpected ",c," after ",parserState.userQuery[parserState.pos-1]]}throw["Unexpected ",c]}else if(c===" "){skipWhitespace(parserState);continue}if(!foundStopChar){let extra=[];if(isLastElemGeneric(query.elems,parserState)){extra=[" after ",">"]}else if(prevIs(parserState,"\"")){throw["Cannot have more than one element if you use quotes"]}if(parserState.typeFilter!==null){throw["Expected ",","," or ","->",...extra,", found ",c,]}throw["Expected ",",",", ",":"," or ","->",...extra,", found ",c,]}const before=query.elems.length;getFilteredNextElem(query,parserState,query.elems,false);if(query.elems.length===before){parserState.pos+=1}foundStopChar=false}if(parserState.typeFilter!==null){throw["Unexpected ",":"," (expected path after type filter ",parserState.typeFilter+":",")",]}while(parserState.pos1}query.foundElems=query.elems.length+query.returned.length;query.totalElems=parserState.totalElems;return query}async execQuery(origParsedQuery,filterCrates,currentCrate){const results_others=new Map(),results_in_args=new Map(),results_returned=new Map();const parsedQuery=origParsedQuery;const queryLen=parsedQuery.elems.reduce((acc,next)=>acc+next.pathLast.length,0)+parsedQuery.returned.reduce((acc,next)=>acc+next.pathLast.length,0);const maxEditDistance=Math.floor(queryLen/3);const genericSymbols=new Map();const convertNameToId=(elem,isAssocType)=>{const loweredName=elem.pathLast.toLowerCase();if(this.typeNameIdMap.has(loweredName)&&(isAssocType||!this.typeNameIdMap.get(loweredName).assocOnly)){elem.id=this.typeNameIdMap.get(loweredName).id}else if(!parsedQuery.literalSearch){let match=null;let matchDist=maxEditDistance+1;let matchName="";for(const[name,{id,assocOnly}]of this.typeNameIdMap){const dist=Math.min(editDistance(name,loweredName,maxEditDistance),editDistance(name,elem.normalizedPathLast,maxEditDistance),);if(dist<=matchDist&&dist<=maxEditDistance&&(isAssocType||!assocOnly)){if(dist===matchDist&&matchName>name){continue}match=id;matchDist=dist;matchName=name}}if(match!==null){parsedQuery.correction=matchName}elem.id=match}if((elem.id===null&&parsedQuery.totalElems>1&&elem.typeFilter===-1&&elem.generics.length===0&&elem.bindings.size===0)||elem.typeFilter===TY_GENERIC){if(genericSymbols.has(elem.normalizedPathLast)){elem.id=genericSymbols.get(elem.normalizedPathLast)}else{elem.id=-(genericSymbols.size+1);genericSymbols.set(elem.normalizedPathLast,elem.id)}if(elem.typeFilter===-1&&elem.normalizedPathLast.length>=3){const maxPartDistance=Math.floor(elem.normalizedPathLast.length/3);let matchDist=maxPartDistance+1;let matchName="";for(const name of this.typeNameIdMap.keys()){const dist=editDistance(name,elem.normalizedPathLast,maxPartDistance,);if(dist<=matchDist&&dist<=maxPartDistance){if(dist===matchDist&&matchName>name){continue}matchDist=dist;matchName=name}}if(matchName!==""){parsedQuery.proposeCorrectionFrom=elem.name;parsedQuery.proposeCorrectionTo=matchName}}elem.typeFilter=TY_GENERIC}if(elem.generics.length>0&&elem.typeFilter===TY_GENERIC){parsedQuery.error=["Generic type parameter ",elem.name," does not accept generic parameters",]}for(const elem2 of elem.generics){convertNameToId(elem2)}elem.bindings=new Map(Array.from(elem.bindings.entries()).map(entry=>{const[name,constraints]=entry;if(!this.typeNameIdMap.has(name)){parsedQuery.error=["Type parameter ",name," does not exist",];return[0,[]]}for(const elem2 of constraints){convertNameToId(elem2,false)}return[this.typeNameIdMap.get(name).id,constraints]}),)};for(const elem of parsedQuery.elems){convertNameToId(elem,false);this.buildFunctionTypeFingerprint(elem,parsedQuery.typeFingerprint)}for(const elem of parsedQuery.returned){convertNameToId(elem,false);this.buildFunctionTypeFingerprint(elem,parsedQuery.typeFingerprint)}function createQueryResults(results_in_args,results_returned,results_others,parsedQuery){return{"in_args":results_in_args,"returned":results_returned,"others":results_others,"query":parsedQuery,}}const buildHrefAndPath=item=>{let displayPath;let href;const type=itemTypes[item.ty];const name=item.name;let path=item.path;let exactPath=item.exactPath;if(type==="mod"){displayPath=path+"::";href=this.rootPath+path.replace(/::/g,"/")+"/"+name+"/index.html"}else if(type==="import"){displayPath=item.path+"::";href=this.rootPath+item.path.replace(/::/g,"/")+"/index.html#reexport."+name}else if(type==="primitive"||type==="keyword"){displayPath="";exactPath="";href=this.rootPath+path.replace(/::/g,"/")+"/"+type+"."+name+".html"}else if(type==="externcrate"){displayPath="";href=this.rootPath+name+"/index.html"}else if(item.parent!==undefined){const myparent=item.parent;let anchor=type+"."+name;const parentType=itemTypes[myparent.ty];let pageType=parentType;let pageName=myparent.name;exactPath=`${myparent.exactPath}::${myparent.name}`;if(parentType==="primitive"){displayPath=myparent.name+"::";exactPath=myparent.name}else if(type==="structfield"&&parentType==="variant"){const enumNameIdx=item.path.lastIndexOf("::");const enumName=item.path.substr(enumNameIdx+2);path=item.path.substr(0,enumNameIdx);displayPath=path+"::"+enumName+"::"+myparent.name+"::";anchor="variant."+myparent.name+".field."+name;pageType="enum";pageName=enumName}else{displayPath=path+"::"+myparent.name+"::"}if(item.implDisambiguator!==null){anchor=item.implDisambiguator+"/"+anchor}href=this.rootPath+path.replace(/::/g,"/")+"/"+pageType+"."+pageName+".html#"+anchor}else{displayPath=item.path+"::";href=this.rootPath+item.path.replace(/::/g,"/")+"/"+type+"."+name+".html"}return[displayPath,href,`${exactPath}::${name}`]};function pathSplitter(path){const tmp=""+path.replace(/::/g,"::");if(tmp.endsWith("")){return tmp.slice(0,tmp.length-6)}return tmp}const transformResults=(results,typeInfo)=>{const duplicates=new Set();const out=[];for(const result of results){if(result.id!==-1){const res=buildHrefAndPath(this.searchIndex[result.id]);const obj=Object.assign({dist:result.dist,displayPath:pathSplitter(res[0]),},this.searchIndex[result.id]);obj.fullPath=res[2]+"|"+obj.ty;if(duplicates.has(obj.fullPath)){continue}if(obj.ty===TY_IMPORT&&duplicates.has(res[2])){continue}if(duplicates.has(res[2]+"|"+TY_IMPORT)){continue}duplicates.add(obj.fullPath);duplicates.add(res[2]);if(typeInfo!==null){obj.displayTypeSignature=this.formatDisplayTypeSignature(obj,typeInfo)}obj.href=res[1];out.push(obj);if(out.length>=MAX_RESULTS){break}}}return out};this.formatDisplayTypeSignature=async(obj,typeInfo)=>{const objType=obj.type;if(!objType){return{type:[],mappedNames:new Map(),whereClause:new Map()}}let fnInputs=null;let fnOutput=null;let mgens=null;if(typeInfo!=="elems"&&typeInfo!=="returned"){fnInputs=unifyFunctionTypes(objType.inputs,parsedQuery.elems,objType.where_clause,null,mgensScratch=>{fnOutput=unifyFunctionTypes(objType.output,parsedQuery.returned,objType.where_clause,mgensScratch,mgensOut=>{mgens=mgensOut;return true},0,);return!!fnOutput},0,)}else{const arr=typeInfo==="elems"?objType.inputs:objType.output;const highlighted=unifyFunctionTypes(arr,parsedQuery.elems,objType.where_clause,null,mgensOut=>{mgens=mgensOut;return true},0,);if(typeInfo==="elems"){fnInputs=highlighted}else{fnOutput=highlighted}}if(!fnInputs){fnInputs=objType.inputs}if(!fnOutput){fnOutput=objType.output}const mappedNames=new Map();const whereClause=new Map();const fnParamNames=obj.paramNames||[];const queryParamNames=[];const remapQuery=queryElem=>{if(queryElem.id!==null&&queryElem.id<0){queryParamNames[-1-queryElem.id]=queryElem.name}if(queryElem.generics.length>0){queryElem.generics.forEach(remapQuery)}if(queryElem.bindings.size>0){[...queryElem.bindings.values()].flat().forEach(remapQuery)}};parsedQuery.elems.forEach(remapQuery);parsedQuery.returned.forEach(remapQuery);const pushText=(fnType,result)=>{if(!!(result.length%2)===!!fnType.highlighted){result.push("")}else if(result.length===0&&!!fnType.highlighted){result.push("");result.push("")}result[result.length-1]+=fnType.name};const writeHof=(fnType,result)=>{const hofOutput=fnType.bindings.get(this.typeNameIdOfOutput)||[];const hofInputs=fnType.generics;pushText(fnType,result);pushText({name:" (",highlighted:false},result);let needsComma=false;for(const fnType of hofInputs){if(needsComma){pushText({name:", ",highlighted:false},result)}needsComma=true;writeFn(fnType,result)}pushText({name:hofOutput.length===0?")":") -> ",highlighted:false,},result);if(hofOutput.length>1){pushText({name:"(",highlighted:false},result)}needsComma=false;for(const fnType of hofOutput){if(needsComma){pushText({name:", ",highlighted:false},result)}needsComma=true;writeFn(fnType,result)}if(hofOutput.length>1){pushText({name:")",highlighted:false},result)}};const writeSpecialPrimitive=(fnType,result)=>{if(fnType.id===this.typeNameIdOfArray||fnType.id===this.typeNameIdOfSlice||fnType.id===this.typeNameIdOfTuple||fnType.id===this.typeNameIdOfUnit){const[ob,sb]=fnType.id===this.typeNameIdOfArray||fnType.id===this.typeNameIdOfSlice?["[","]"]:["(",")"];pushText({name:ob,highlighted:fnType.highlighted},result);onEachBtwn(fnType.generics,nested=>writeFn(nested,result),()=>pushText({name:", ",highlighted:false},result),);pushText({name:sb,highlighted:fnType.highlighted},result);return true}else if(fnType.id===this.typeNameIdOfReference){pushText({name:"&",highlighted:fnType.highlighted},result);let prevHighlighted=false;onEachBtwn(fnType.generics,value=>{prevHighlighted=!!value.highlighted;writeFn(value,result)},value=>pushText({name:" ",highlighted:prevHighlighted&&value.highlighted,},result),);return true}else if(fnType.id===this.typeNameIdOfFn){writeHof(fnType,result);return true}return false};const writeFn=(fnType,result)=>{if(fnType.id!==null&&fnType.id<0){if(fnParamNames[-1-fnType.id]===""){const generics=fnType.generics.length>0?fnType.generics:objType.where_clause[-1-fnType.id];for(const nested of generics){writeFn(nested,result)}return}else if(mgens){for(const[queryId,fnId]of mgens){if(fnId===fnType.id){mappedNames.set(queryParamNames[-1-queryId],fnParamNames[-1-fnType.id],)}}}pushText({name:fnParamNames[-1-fnType.id],highlighted:!!fnType.highlighted,},result);const where=[];onEachBtwn(fnType.generics,nested=>writeFn(nested,where),()=>pushText({name:" + ",highlighted:false},where),);if(where.length>0){whereClause.set(fnParamNames[-1-fnType.id],where)}}else{if(fnType.ty===TY_PRIMITIVE){if(writeSpecialPrimitive(fnType,result)){return}}else if(fnType.ty===TY_TRAIT&&(fnType.id===this.typeNameIdOfFn||fnType.id===this.typeNameIdOfFnMut||fnType.id===this.typeNameIdOfFnOnce)){writeHof(fnType,result);return}pushText(fnType,result);let hasBindings=false;if(fnType.bindings.size>0){onEachBtwn(fnType.bindings,([key,values])=>{const name=this.assocTypeIdNameMap.get(key);if(values.length===1&&values[0].id<0&&`${fnType.name}::${name}`===fnParamNames[-1-values[0].id]){for(const value of values){writeFn(value,[])}return true}if(!hasBindings){hasBindings=true;pushText({name:"<",highlighted:false},result)}pushText({name,highlighted:false},result);pushText({name:values.length!==1?"=(":"=",highlighted:false,},result);onEachBtwn(values||[],value=>writeFn(value,result),()=>pushText({name:" + ",highlighted:false},result),);if(values.length!==1){pushText({name:")",highlighted:false},result)}},()=>pushText({name:", ",highlighted:false},result),)}if(fnType.generics.length>0){pushText({name:hasBindings?", ":"<",highlighted:false},result)}onEachBtwn(fnType.generics,value=>writeFn(value,result),()=>pushText({name:", ",highlighted:false},result),);if(hasBindings||fnType.generics.length>0){pushText({name:">",highlighted:false},result)}}};const type=[];onEachBtwn(fnInputs,fnType=>writeFn(fnType,type),()=>pushText({name:", ",highlighted:false},type),);pushText({name:" -> ",highlighted:false},type);onEachBtwn(fnOutput,fnType=>writeFn(fnType,type),()=>pushText({name:", ",highlighted:false},type),);return{type,mappedNames,whereClause}};const sortResults=async(results,typeInfo,preferredCrate)=>{const userQuery=parsedQuery.userQuery;const normalizedUserQuery=parsedQuery.userQuery.toLowerCase();const isMixedCase=normalizedUserQuery!==userQuery;const result_list=[];const isReturnTypeQuery=parsedQuery.elems.length===0||typeInfo==="returned";for(const result of results.values()){result.item=this.searchIndex[result.id];result.word=this.searchIndex[result.id].word;if(isReturnTypeQuery){const resultItemType=result.item&&result.item.type;if(!resultItemType){continue}const inputs=resultItemType.inputs;const where_clause=resultItemType.where_clause;if(containsTypeFromQuery(inputs,where_clause)){result.path_dist*=100;result.dist*=100}}result_list.push(result)}result_list.sort((aaa,bbb)=>{let a;let b;if(isMixedCase){a=Number(aaa.item.name!==userQuery);b=Number(bbb.item.name!==userQuery);if(a!==b){return a-b}}a=Number(aaa.word!==normalizedUserQuery);b=Number(bbb.word!==normalizedUserQuery);if(a!==b){return a-b}a=Number(aaa.index<0);b=Number(bbb.index<0);if(a!==b){return a-b}if(parsedQuery.hasReturnArrow){a=Number(!isFnLikeTy(aaa.item.ty));b=Number(!isFnLikeTy(bbb.item.ty));if(a!==b){return a-b}}a=Number(aaa.path_dist);b=Number(bbb.path_dist);if(a!==b){return a-b}a=Number(aaa.index);b=Number(bbb.index);if(a!==b){return a-b}a=Number(aaa.dist);b=Number(bbb.dist);if(a!==b){return a-b}a=Number(this.searchIndexDeprecated.get(aaa.item.crate).contains(aaa.item.bitIndex),);b=Number(this.searchIndexDeprecated.get(bbb.item.crate).contains(bbb.item.bitIndex),);if(a!==b){return a-b}a=Number(aaa.item.crate!==preferredCrate);b=Number(bbb.item.crate!==preferredCrate);if(a!==b){return a-b}a=Number(aaa.word.length);b=Number(bbb.word.length);if(a!==b){return a-b}let aw=aaa.word;let bw=bbb.word;if(aw!==bw){return(aw>bw?+1:-1)}a=Number(this.searchIndexEmptyDesc.get(aaa.item.crate).contains(aaa.item.bitIndex),);b=Number(this.searchIndexEmptyDesc.get(bbb.item.crate).contains(bbb.item.bitIndex),);if(a!==b){return a-b}a=Number(aaa.item.ty);b=Number(bbb.item.ty);if(a!==b){return a-b}aw=aaa.item.path;bw=bbb.item.path;if(aw!==bw){return(aw>bw?+1:-1)}return 0});return transformResults(result_list,typeInfo)};function unifyFunctionTypes(fnTypesIn,queryElems,whereClause,mgensIn,solutionCb,unboxingDepth,){if(unboxingDepth>=UNBOXING_LIMIT){return null}const mgens=mgensIn===null?null:new Map(mgensIn);if(queryElems.length===0){return solutionCb(mgens)?fnTypesIn:null}if(!fnTypesIn||fnTypesIn.length===0){return null}const ql=queryElems.length;const fl=fnTypesIn.length;if(ql===1&&queryElems[0].generics.length===0&&queryElems[0].bindings.size===0){const queryElem=queryElems[0];for(const[i,fnType]of fnTypesIn.entries()){if(!unifyFunctionTypeIsMatchCandidate(fnType,queryElem,mgens)){continue}if(fnType.id!==null&&fnType.id<0&&queryElem.id!==null&&queryElem.id<0){if(mgens&&mgens.has(queryElem.id)&&mgens.get(queryElem.id)!==fnType.id){continue}const mgensScratch=new Map(mgens);mgensScratch.set(queryElem.id,fnType.id);if(!solutionCb||solutionCb(mgensScratch)){const highlighted=[...fnTypesIn];highlighted[i]=Object.assign({highlighted:true,},fnType,{generics:whereClause[-1-fnType.id],});return highlighted}}else if(solutionCb(mgens?new Map(mgens):null)){const highlighted=[...fnTypesIn];highlighted[i]=Object.assign({highlighted:true,},fnType,{generics:unifyGenericTypes(fnType.generics,queryElem.generics,whereClause,mgens?new Map(mgens):null,solutionCb,unboxingDepth,)||fnType.generics,});return highlighted}}for(const[i,fnType]of fnTypesIn.entries()){if(!unifyFunctionTypeIsUnboxCandidate(fnType,queryElem,whereClause,mgens,unboxingDepth+1,)){continue}if(fnType.id<0){const highlightedGenerics=unifyFunctionTypes(whereClause[(-fnType.id)-1],queryElems,whereClause,mgens,solutionCb,unboxingDepth+1,);if(highlightedGenerics){const highlighted=[...fnTypesIn];highlighted[i]=Object.assign({highlighted:true,},fnType,{generics:highlightedGenerics,});return highlighted}}else{const highlightedGenerics=unifyFunctionTypes([...Array.from(fnType.bindings.values()).flat(),...fnType.generics],queryElems,whereClause,mgens?new Map(mgens):null,solutionCb,unboxingDepth+1,);if(highlightedGenerics){const highlighted=[...fnTypesIn];highlighted[i]=Object.assign({},fnType,{generics:highlightedGenerics,bindings:new Map([...fnType.bindings.entries()].map(([k,v])=>{return[k,highlightedGenerics.splice(0,v.length)]})),});return highlighted}}}return false}const fnTypes=fnTypesIn.slice();const flast=fl-1;const qlast=ql-1;const queryElem=queryElems[qlast];let queryElemsTmp=null;for(let i=flast;i>=0;i-=1){const fnType=fnTypes[i];if(!unifyFunctionTypeIsMatchCandidate(fnType,queryElem,mgens)){continue}let mgensScratch;if(fnType.id!==null&&queryElem.id!==null&&fnType.id<0){mgensScratch=new Map(mgens);if(mgensScratch.has(queryElem.id)&&mgensScratch.get(queryElem.id)!==fnType.id){continue}mgensScratch.set(queryElem.id,fnType.id)}else{mgensScratch=mgens}fnTypes[i]=fnTypes[flast];fnTypes.length=flast;if(!queryElemsTmp){queryElemsTmp=queryElems.slice(0,qlast)}let unifiedGenerics=[];let unifiedGenericsMgens=null;const passesUnification=unifyFunctionTypes(fnTypes,queryElemsTmp,whereClause,mgensScratch,mgensScratch=>{if(fnType.generics.length===0&&queryElem.generics.length===0&&fnType.bindings.size===0&&queryElem.bindings.size===0){return solutionCb(mgensScratch)}const solution=unifyFunctionTypeCheckBindings(fnType,queryElem,whereClause,mgensScratch,unboxingDepth,);if(!solution){return false}const simplifiedGenerics=solution.simplifiedGenerics;for(const simplifiedMgens of solution.mgens){unifiedGenerics=unifyGenericTypes(simplifiedGenerics,queryElem.generics,whereClause,simplifiedMgens,solutionCb,unboxingDepth,);if(unifiedGenerics!==null){unifiedGenericsMgens=simplifiedMgens;return true}}return false},unboxingDepth,);if(passesUnification){passesUnification.length=fl;passesUnification[flast]=passesUnification[i];passesUnification[i]=Object.assign({},fnType,{highlighted:true,generics:unifiedGenerics,bindings:new Map([...fnType.bindings.entries()].map(([k,v])=>{return[k,queryElem.bindings.has(k)?unifyFunctionTypes(v,queryElem.bindings.get(k),whereClause,unifiedGenericsMgens,solutionCb,unboxingDepth,):unifiedGenerics.splice(0,v.length)]})),});return passesUnification}fnTypes[flast]=fnTypes[i];fnTypes[i]=fnType;fnTypes.length=fl}for(let i=flast;i>=0;i-=1){const fnType=fnTypes[i];if(!unifyFunctionTypeIsUnboxCandidate(fnType,queryElem,whereClause,mgens,unboxingDepth+1,)){continue}const generics=fnType.id!==null&&fnType.id<0?whereClause[(-fnType.id)-1]:fnType.generics;const bindings=fnType.bindings?Array.from(fnType.bindings.values()).flat():[];const passesUnification=unifyFunctionTypes(fnTypes.toSpliced(i,1,...bindings,...generics),queryElems,whereClause,mgens,solutionCb,unboxingDepth+1,);if(passesUnification){const highlightedGenerics=passesUnification.slice(i,i+generics.length+bindings.length,);const highlightedFnType=Object.assign({},fnType,{generics:highlightedGenerics,bindings:new Map([...fnType.bindings.entries()].map(([k,v])=>{return[k,highlightedGenerics.splice(0,v.length)]})),});return passesUnification.toSpliced(i,generics.length+bindings.length,highlightedFnType,)}}return null}function unifyGenericTypes(fnTypesIn,queryElems,whereClause,mgensIn,solutionCb,unboxingDepth,){if(unboxingDepth>=UNBOXING_LIMIT){return null}const mgens=mgensIn===null?null:new Map(mgensIn);if(queryElems.length===0){return solutionCb(mgens)?fnTypesIn:null}if(!fnTypesIn||fnTypesIn.length===0){return null}const fnType=fnTypesIn[0];const queryElem=queryElems[0];if(unifyFunctionTypeIsMatchCandidate(fnType,queryElem,mgens)){if(fnType.id!==null&&fnType.id<0&&queryElem.id!==null&&queryElem.id<0){if(!mgens||!mgens.has(queryElem.id)||mgens.get(queryElem.id)===fnType.id){const mgensScratch=new Map(mgens);mgensScratch.set(queryElem.id,fnType.id);const fnTypesRemaining=unifyGenericTypes(fnTypesIn.slice(1),queryElems.slice(1),whereClause,mgensScratch,solutionCb,unboxingDepth,);if(fnTypesRemaining){const highlighted=[fnType,...fnTypesRemaining];highlighted[0]=Object.assign({highlighted:true,},fnType,{generics:whereClause[-1-fnType.id],});return highlighted}}}else{let unifiedGenerics;const fnTypesRemaining=unifyGenericTypes(fnTypesIn.slice(1),queryElems.slice(1),whereClause,mgens,mgensScratch=>{const solution=unifyFunctionTypeCheckBindings(fnType,queryElem,whereClause,mgensScratch,unboxingDepth,);if(!solution){return false}const simplifiedGenerics=solution.simplifiedGenerics;for(const simplifiedMgens of solution.mgens){unifiedGenerics=unifyGenericTypes(simplifiedGenerics,queryElem.generics,whereClause,simplifiedMgens,solutionCb,unboxingDepth,);if(unifiedGenerics!==null){return true}}},unboxingDepth,);if(fnTypesRemaining){const highlighted=[fnType,...fnTypesRemaining];highlighted[0]=Object.assign({highlighted:true,},fnType,{generics:unifiedGenerics||fnType.generics,});return highlighted}}}if(unifyFunctionTypeIsUnboxCandidate(fnType,queryElem,whereClause,mgens,unboxingDepth+1,)){let highlightedRemaining;if(fnType.id!==null&&fnType.id<0){const highlightedGenerics=unifyFunctionTypes(whereClause[(-fnType.id)-1],[queryElem],whereClause,mgens,mgensScratch=>{const hl=unifyGenericTypes(fnTypesIn.slice(1),queryElems.slice(1),whereClause,mgensScratch,solutionCb,unboxingDepth,);if(hl){highlightedRemaining=hl}return hl},unboxingDepth+1,);if(highlightedGenerics){return[Object.assign({highlighted:true,},fnType,{generics:highlightedGenerics,}),...highlightedRemaining]}}else{const highlightedGenerics=unifyGenericTypes([...Array.from(fnType.bindings.values()).flat(),...fnType.generics,],[queryElem],whereClause,mgens,mgensScratch=>{const hl=unifyGenericTypes(fnTypesIn.slice(1),queryElems.slice(1),whereClause,mgensScratch,solutionCb,unboxingDepth,);if(hl){highlightedRemaining=hl}return hl},unboxingDepth+1,);if(highlightedGenerics){return[Object.assign({},fnType,{generics:highlightedGenerics,bindings:new Map([...fnType.bindings.entries()].map(([k,v])=>{return[k,highlightedGenerics.splice(0,v.length)]})),}),...highlightedRemaining]}}}return null}const unifyFunctionTypeIsMatchCandidate=(fnType,queryElem,mgensIn)=>{if(!typePassesFilter(queryElem.typeFilter,fnType.ty)){return false}if(fnType.id!==null&&fnType.id<0&&queryElem.id!==null&&queryElem.id<0){if(mgensIn&&mgensIn.has(queryElem.id)&&mgensIn.get(queryElem.id)!==fnType.id){return false}return true}else{if(queryElem.id===this.typeNameIdOfArrayOrSlice&&(fnType.id===this.typeNameIdOfSlice||fnType.id===this.typeNameIdOfArray)){}else if(queryElem.id===this.typeNameIdOfTupleOrUnit&&(fnType.id===this.typeNameIdOfTuple||fnType.id===this.typeNameIdOfUnit)){}else if(queryElem.id===this.typeNameIdOfHof&&(fnType.id===this.typeNameIdOfFn||fnType.id===this.typeNameIdOfFnMut||fnType.id===this.typeNameIdOfFnOnce)){}else if(fnType.id!==queryElem.id||queryElem.id===null){return false}if((fnType.generics.length+fnType.bindings.size)===0&&queryElem.generics.length!==0){return false}if(fnType.bindings.size0){const fnTypePath=fnType.path!==undefined&&fnType.path!==null?fnType.path.split("::"):[];if(queryElemPathLength>fnTypePath.length){return false}let i=0;for(const path of fnTypePath){if(path===queryElem.pathWithoutLast[i]){i+=1;if(i>=queryElemPathLength){break}}}if(i0){let mgensSolutionSet=[mgensIn];for(const[name,constraints]of queryElem.bindings.entries()){if(mgensSolutionSet.length===0){return false}if(!fnType.bindings.has(name)){return false}const fnTypeBindings=fnType.bindings.get(name);mgensSolutionSet=mgensSolutionSet.flatMap(mgens=>{const newSolutions=[];unifyFunctionTypes(fnTypeBindings,constraints,whereClause,mgens,newMgens=>{newSolutions.push(newMgens);return false},unboxingDepth,);return newSolutions})}if(mgensSolutionSet.length===0){return false}const binds=Array.from(fnType.bindings.entries()).flatMap(entry=>{const[name,constraints]=entry;if(queryElem.bindings.has(name)){return[]}else{return constraints}});if(simplifiedGenerics.length>0){simplifiedGenerics=[...binds,...simplifiedGenerics]}else{simplifiedGenerics=binds}return{simplifiedGenerics,mgens:mgensSolutionSet}}return{simplifiedGenerics,mgens:[mgensIn]}}function unifyFunctionTypeIsUnboxCandidate(fnType,queryElem,whereClause,mgens,unboxingDepth,){if(unboxingDepth>=UNBOXING_LIMIT){return false}if(fnType.id!==null&&fnType.id<0){if(!whereClause){return false}return checkIfInList(whereClause[(-fnType.id)-1],queryElem,whereClause,mgens,unboxingDepth,)}else if(fnType.unboxFlag&&(fnType.generics.length>0||fnType.bindings.size>0)){const simplifiedGenerics=[...fnType.generics,...Array.from(fnType.bindings.values()).flat(),];return checkIfInList(simplifiedGenerics,queryElem,whereClause,mgens,unboxingDepth,)}return false}function containsTypeFromQuery(list,where_clause){if(!list)return false;for(const ty of parsedQuery.returned){if(ty.id!==null&&ty.id<0){continue}if(checkIfInList(list,ty,where_clause,null,0)){return true}}for(const ty of parsedQuery.elems){if(ty.id!==null&&ty.id<0){continue}if(checkIfInList(list,ty,where_clause,null,0)){return true}}return false}function checkIfInList(list,elem,whereClause,mgens,unboxingDepth){for(const entry of list){if(checkType(entry,elem,whereClause,mgens,unboxingDepth)){return true}}return false}const checkType=(row,elem,whereClause,mgens,unboxingDepth)=>{if(unboxingDepth>=UNBOXING_LIMIT){return false}if(row.id!==null&&elem.id!==null&&row.id>0&&elem.id>0&&elem.pathWithoutLast.length===0&&row.generics.length===0&&elem.generics.length===0&&row.bindings.size===0&&elem.bindings.size===0&&elem.id!==this.typeNameIdOfArrayOrSlice&&elem.id!==this.typeNameIdOfHof&&elem.id!==this.typeNameIdOfTupleOrUnit){return row.id===elem.id&&typePassesFilter(elem.typeFilter,row.ty)}else{return unifyFunctionTypes([row],[elem],whereClause,mgens,()=>true,unboxingDepth,)}};const checkTypeMgensForConflict=mgens=>{if(!mgens){return true}const fnTypes=new Set();for(const[_qid,fid]of mgens){if(fnTypes.has(fid)){return false}fnTypes.add(fid)}return true};function checkPath(contains,ty){if(contains.length===0){return 0}const maxPathEditDistance=Math.floor(contains.reduce((acc,next)=>acc+next.length,0)/3,);let ret_dist=maxPathEditDistance+1;const path=ty.path.split("::");if(ty.parent&&ty.parent.name){path.push(ty.parent.name.toLowerCase())}const length=path.length;const clength=contains.length;pathiter:for(let i=length-clength;i>=0;i-=1){let dist_total=0;for(let x=0;xmaxPathEditDistance){continue pathiter}dist_total+=dist}}ret_dist=Math.min(ret_dist,Math.round(dist_total/clength))}return ret_dist>maxPathEditDistance?null:ret_dist}function typePassesFilter(filter,type){if(filter<=NO_TYPE_FILTER||filter===type)return true;const name=itemTypes[type];switch(itemTypes[filter]){case"constant":return name==="associatedconstant";case"fn":return name==="method"||name==="tymethod";case"type":return name==="primitive"||name==="associatedtype";case"trait":return name==="traitalias"}return false}function createAliasFromItem(item){return{crate:item.crate,name:item.name,path:item.path,descShard:item.descShard,descIndex:item.descIndex,exactPath:item.exactPath,ty:item.ty,parent:item.parent,type:item.type,is_alias:true,bitIndex:item.bitIndex,implDisambiguator:item.implDisambiguator,}}const handleAliases=async(ret,query,filterCrates,currentCrate)=>{const lowerQuery=query.toLowerCase();const aliases=[];const crateAliases=[];if(filterCrates!==null){if(this.ALIASES.has(filterCrates)&&this.ALIASES.get(filterCrates).has(lowerQuery)){const query_aliases=this.ALIASES.get(filterCrates).get(lowerQuery);for(const alias of query_aliases){aliases.push(createAliasFromItem(this.searchIndex[alias]))}}}else{for(const[crate,crateAliasesIndex]of this.ALIASES){if(crateAliasesIndex.has(lowerQuery)){const pushTo=crate===currentCrate?crateAliases:aliases;const query_aliases=crateAliasesIndex.get(lowerQuery);for(const alias of query_aliases){pushTo.push(createAliasFromItem(this.searchIndex[alias]))}}}}const sortFunc=(aaa,bbb)=>{if(aaa.path{return this.searchIndexEmptyDesc.get(alias.crate).contains(alias.bitIndex)?"":this.searchState.loadDesc(alias)};const[crateDescs,descs]=await Promise.all([Promise.all(crateAliases.map(fetchDesc)),Promise.all(aliases.map(fetchDesc)),]);const pushFunc=alias=>{alias.alias=query;const res=buildHrefAndPath(alias);alias.displayPath=pathSplitter(res[0]);alias.fullPath=alias.displayPath+alias.name;alias.href=res[1];ret.others.unshift(alias);if(ret.others.length>MAX_RESULTS){ret.others.pop()}};aliases.forEach((alias,i)=>{alias.desc=descs[i]});aliases.forEach(pushFunc);crateAliases.forEach((alias,i)=>{alias.desc=crateDescs[i]});crateAliases.forEach(pushFunc)};function addIntoResults(results,fullId,id,index,dist,path_dist,maxEditDistance){if(dist<=maxEditDistance||index!==-1){if(results.has(fullId)){const result=results.get(fullId);if(result.dontValidate||result.dist<=dist){return}}results.set(fullId,{id:id,index:index,dontValidate:parsedQuery.literalSearch,dist:dist,path_dist:path_dist,})}}function handleArgs(row,pos,results){if(!row||(filterCrates!==null&&row.crate!==filterCrates)){return}const rowType=row.type;if(!rowType){return}const tfpDist=compareTypeFingerprints(row.id,parsedQuery.typeFingerprint,);if(tfpDist===null){return}if(results.size>=MAX_RESULTS&&tfpDist>results.max_dist){return}if(!unifyFunctionTypes(rowType.inputs,parsedQuery.elems,rowType.where_clause,null,mgens=>{return unifyFunctionTypes(rowType.output,parsedQuery.returned,rowType.where_clause,mgens,checkTypeMgensForConflict,0,)},0,)){return}results.max_dist=Math.max(results.max_dist||0,tfpDist);addIntoResults(results,row.id.toString(),pos,0,tfpDist,0,Number.MAX_VALUE)}const compareTypeFingerprints=(fullId,queryFingerprint)=>{const fh0=this.functionTypeFingerprint[fullId*4];const fh1=this.functionTypeFingerprint[(fullId*4)+1];const fh2=this.functionTypeFingerprint[(fullId*4)+2];const[qh0,qh1,qh2]=queryFingerprint;const[in0,in1,in2]=[fh0&qh0,fh1&qh1,fh2&qh2];if((in0 ^ qh0)||(in1 ^ qh1)||(in2 ^ qh2)){return null}return this.functionTypeFingerprint[(fullId*4)+3]};const innerRunQuery=()=>{if(parsedQuery.foundElems===1&&!parsedQuery.hasReturnArrow){const elem=parsedQuery.elems[0];const handleNameSearch=id=>{const row=this.searchIndex[id];if(!typePassesFilter(elem.typeFilter,row.ty)||(filterCrates!==null&&row.crate!==filterCrates)){return}let pathDist=0;if(elem.fullPath.length>1){pathDist=checkPath(elem.pathWithoutLast,row);if(pathDist===null){return}}if(parsedQuery.literalSearch){if(row.word===elem.pathLast){addIntoResults(results_others,row.id,id,0,0,pathDist)}}else{addIntoResults(results_others,row.id,id,row.normalizedName.indexOf(elem.normalizedPathLast),editDistance(row.normalizedName,elem.normalizedPathLast,maxEditDistance,),pathDist,maxEditDistance,)}};if(elem.normalizedPathLast!==""){const last=elem.normalizedPathLast;for(const id of this.nameTrie.search(last,this.tailTable)){handleNameSearch(id)}}const length=this.searchIndex.length;for(let i=0,nSearchIndex=length;i0){const sortQ=(a,b)=>{const ag=a.generics.length===0&&a.bindings.size===0;const bg=b.generics.length===0&&b.bindings.size===0;if(ag!==bg){return ag-bg}const ai=a.id>0;const bi=b.id>0;return ai-bi};parsedQuery.elems.sort(sortQ);parsedQuery.returned.sort(sortQ);for(let i=0,nSearchIndex=this.searchIndex.length;i{const descs=await Promise.all(list.map(result=>{return this.searchIndexEmptyDesc.get(result.crate).contains(result.bitIndex)?"":this.searchState.loadDesc(result)}));for(const[i,result]of list.entries()){result.desc=descs[i]}}));if(parsedQuery.error!==null&&ret.others.length!==0){ret.query.error=null}return ret}}let rawSearchIndex;let docSearch;const longItemTypes=["keyword","primitive type","module","extern crate","re-export","struct","enum","function","type alias","static","trait","","trait method","method","struct field","enum variant","macro","assoc type","constant","assoc const","union","foreign type","existential type","attribute macro","derive macro","trait alias",];let currentResults;function printTab(nb){let iter=0;let foundCurrentTab=false;let foundCurrentResultSet=false;onEachLazy(document.getElementById("search-tabs").childNodes,elem=>{if(nb===iter){addClass(elem,"selected");foundCurrentTab=true}else{removeClass(elem,"selected")}iter+=1});const isTypeSearch=(nb>0||iter===1);iter=0;onEachLazy(document.getElementById("results").childNodes,elem=>{if(nb===iter){addClass(elem,"active");foundCurrentResultSet=true}else{removeClass(elem,"active")}iter+=1});if(foundCurrentTab&&foundCurrentResultSet){searchState.currentTab=nb;const correctionsElem=document.getElementsByClassName("search-corrections");if(isTypeSearch){removeClass(correctionsElem[0],"hidden")}else{addClass(correctionsElem[0],"hidden")}}else if(nb!==0){printTab(0)}}function buildUrl(search,filterCrates){let extra="?search="+encodeURIComponent(search);if(filterCrates!==null){extra+="&filter-crate="+encodeURIComponent(filterCrates)}return getNakedUrl()+extra+window.location.hash}function getFilterCrates(){const elem=document.getElementById("crate-search");if(elem&&elem.value!=="all crates"&&window.searchIndex.has(elem.value)){return elem.value}return null}function nextTab(direction){const next=(searchState.currentTab+direction+3)%searchState.focusedByTab.length;searchState.focusedByTab[searchState.currentTab]=document.activeElement;printTab(next);focusSearchResult()}function focusSearchResult(){const target=searchState.focusedByTab[searchState.currentTab]||document.querySelectorAll(".search-results.active a").item(0)||document.querySelectorAll("#search-tabs button").item(searchState.currentTab);searchState.focusedByTab[searchState.currentTab]=null;if(target){target.focus()}}async function addTab(array,query,display){const extraClass=display?" active":"";const output=document.createElement(array.length===0&&query.error===null?"div":"ul",);if(array.length>0){output.className="search-results "+extraClass;const lis=Promise.all(array.map(async item=>{const name=item.name;const type=itemTypes[item.ty];const longType=longItemTypes[item.ty];const typeName=longType.length!==0?`${longType}`:"?";const link=document.createElement("a");link.className="result-"+type;link.href=item.href;const resultName=document.createElement("span");resultName.className="result-name";resultName.insertAdjacentHTML("beforeend",`${typeName}`);link.appendChild(resultName);let alias=" ";if(item.is_alias){alias=`
\ +${item.alias} - see \ +
`}resultName.insertAdjacentHTML("beforeend",`
${alias}\ +${item.displayPath}${name}\ +
`);const description=document.createElement("div");description.className="desc";description.insertAdjacentHTML("beforeend",item.desc);if(item.displayTypeSignature){const{type,mappedNames,whereClause}=await item.displayTypeSignature;const displayType=document.createElement("div");type.forEach((value,index)=>{if(index%2!==0){const highlight=document.createElement("strong");highlight.appendChild(document.createTextNode(value));displayType.appendChild(highlight)}else{displayType.appendChild(document.createTextNode(value))}});if(mappedNames.size>0||whereClause.size>0){let addWhereLineFn=()=>{const line=document.createElement("div");line.className="where";line.appendChild(document.createTextNode("where"));displayType.appendChild(line);addWhereLineFn=()=>{}};for(const[qname,name]of mappedNames){if(name===qname){continue}addWhereLineFn();const line=document.createElement("div");line.className="where";line.appendChild(document.createTextNode(` ${qname} matches `));const lineStrong=document.createElement("strong");lineStrong.appendChild(document.createTextNode(name));line.appendChild(lineStrong);displayType.appendChild(line)}for(const[name,innerType]of whereClause){if(innerType.length<=1){continue}addWhereLineFn();const line=document.createElement("div");line.className="where";line.appendChild(document.createTextNode(` ${name}: `));innerType.forEach((value,index)=>{if(index%2!==0){const highlight=document.createElement("strong");highlight.appendChild(document.createTextNode(value));line.appendChild(highlight)}else{line.appendChild(document.createTextNode(value))}});displayType.appendChild(line)}}displayType.className="type-signature";link.appendChild(displayType)}link.appendChild(description);return link}));lis.then(lis=>{for(const li of lis){output.appendChild(li)}})}else if(query.error===null){const dlroChannel=`https://doc.rust-lang.org/${getVar("channel")}`;output.className="search-failed"+extraClass;output.innerHTML="No results :(
"+"Try on DuckDuckGo?

"+"Or try looking in one of these:"}return output}function makeTabHeader(tabNb,text,nbElems){const fmtNbElems=nbElems<10?`\u{2007}(${nbElems})\u{2007}\u{2007}`:nbElems<100?`\u{2007}(${nbElems})\u{2007}`:`\u{2007}(${nbElems})`;if(searchState.currentTab===tabNb){return""}return""}async function showResults(results,go_to_first,filterCrates){const search=searchState.outputElement();if(go_to_first||(results.others.length===1&&getSettingValue("go-to-only-result")==="true")){window.onunload=()=>{};searchState.removeQueryParameters();const elem=document.createElement("a");elem.href=results.others[0].href;removeClass(elem,"active");document.body.appendChild(elem);elem.click();return}if(results.query===undefined){results.query=DocSearch.parseQuery(searchState.input.value)}currentResults=results.query.userQuery;let currentTab=searchState.currentTab;if((currentTab===0&&results.others.length===0)||(currentTab===1&&results.in_args.length===0)||(currentTab===2&&results.returned.length===0)){if(results.others.length!==0){currentTab=0}else if(results.in_args.length){currentTab=1}else if(results.returned.length){currentTab=2}}let crates="";if(rawSearchIndex.size>1){crates="
in 
"+"
"}let output=`
\ +

Results

${crates}
`;if(results.query.error!==null){const error=results.query.error;error.forEach((value,index)=>{value=value.split("<").join("<").split(">").join(">");if(index%2!==0){error[index]=`${value.replaceAll(" ", " ")}`}else{error[index]=value}});output+=`

Query parser error: "${error.join("")}".

`;output+="
"+makeTabHeader(0,"In Names",results.others.length)+"
";currentTab=0}else if(results.query.foundElems<=1&&results.query.returned.length===0){output+="
"+makeTabHeader(0,"In Names",results.others.length)+makeTabHeader(1,"In Parameters",results.in_args.length)+makeTabHeader(2,"In Return Types",results.returned.length)+"
"}else{const signatureTabTitle=results.query.elems.length===0?"In Function Return Types":results.query.returned.length===0?"In Function Parameters":"In Function Signatures";output+="
"+makeTabHeader(0,signatureTabTitle,results.others.length)+"
";currentTab=0}if(results.query.correction!==null){const orig=results.query.returned.length>0?results.query.returned[0].name:results.query.elems[0].name;output+="

"+`Type "${orig}" not found. `+"Showing results for closest type name "+`"${results.query.correction}" instead.

`}if(results.query.proposeCorrectionFrom!==null){const orig=results.query.proposeCorrectionFrom;const targ=results.query.proposeCorrectionTo;output+="

"+`Type "${orig}" not found and used as generic parameter. `+`Consider searching for "${targ}" instead.

`}const[ret_others,ret_in_args,ret_returned]=await Promise.all([addTab(results.others,results.query,currentTab===0),addTab(results.in_args,results.query,currentTab===1),addTab(results.returned,results.query,currentTab===2),]);const resultsElem=document.createElement("div");resultsElem.id="results";resultsElem.appendChild(ret_others);resultsElem.appendChild(ret_in_args);resultsElem.appendChild(ret_returned);search.innerHTML=output;if(searchState.rustdocToolbar){search.querySelector(".main-heading").appendChild(searchState.rustdocToolbar)}const crateSearch=document.getElementById("crate-search");if(crateSearch){crateSearch.addEventListener("input",updateCrate)}search.appendChild(resultsElem);searchState.showResults(search);const elems=document.getElementById("search-tabs").childNodes;searchState.focusedByTab=[];let i=0;for(const elem of elems){const j=i;elem.onclick=()=>printTab(j);searchState.focusedByTab.push(null);i+=1}printTab(currentTab)}function updateSearchHistory(url){if(!browserSupportsHistoryApi()){return}const params=searchState.getQueryStringParams();if(!history.state&&!params.search){history.pushState(null,"",url)}else{history.replaceState(null,"",url)}}async function search(forced){const query=DocSearch.parseQuery(searchState.input.value.trim());let filterCrates=getFilterCrates();if(!forced&&query.userQuery===currentResults){if(query.userQuery.length>0){putBackSearch()}return}searchState.setLoadingSearch();const params=searchState.getQueryStringParams();if(filterCrates===null&¶ms["filter-crate"]!==undefined){filterCrates=params["filter-crate"]}searchState.title="\""+query.userQuery+"\" Search - Rust";updateSearchHistory(buildUrl(query.userQuery,filterCrates));await showResults(await docSearch.execQuery(query,filterCrates,window.currentCrate),params.go_to_first,filterCrates)}function onSearchSubmit(e){e.preventDefault();searchState.clearInputTimeout();search()}function putBackSearch(){const search_input=searchState.input;if(!searchState.input){return}if(search_input.value!==""&&!searchState.isDisplayed()){searchState.showResults();if(browserSupportsHistoryApi()){history.replaceState(null,"",buildUrl(search_input.value,getFilterCrates()))}document.title=searchState.title}}function registerSearchEvents(){const params=searchState.getQueryStringParams();if(searchState.input.value===""){searchState.input.value=params.search||""}const searchAfter500ms=()=>{searchState.clearInputTimeout();if(searchState.input.value.length===0){searchState.hideResults()}else{searchState.timeout=setTimeout(search,500)}};searchState.input.onkeyup=searchAfter500ms;searchState.input.oninput=searchAfter500ms;document.getElementsByClassName("search-form")[0].onsubmit=onSearchSubmit;searchState.input.onchange=e=>{if(e.target!==document.activeElement){return}searchState.clearInputTimeout();setTimeout(search,0)};searchState.input.onpaste=searchState.input.onchange;searchState.outputElement().addEventListener("keydown",e=>{if(e.altKey||e.ctrlKey||e.shiftKey||e.metaKey){return}if(e.which===38){const previous=document.activeElement.previousElementSibling;if(previous){previous.focus()}else{searchState.focus()}e.preventDefault()}else if(e.which===40){const next=document.activeElement.nextElementSibling;if(next){next.focus()}const rect=document.activeElement.getBoundingClientRect();if(window.innerHeight-rect.bottom{if(e.which===40){focusSearchResult();e.preventDefault()}});searchState.input.addEventListener("focus",()=>{putBackSearch()});searchState.input.addEventListener("blur",()=>{if(window.searchState.input){window.searchState.input.placeholder=window.searchState.origPlaceholder}});if(browserSupportsHistoryApi()){const previousTitle=document.title;window.addEventListener("popstate",e=>{const params=searchState.getQueryStringParams();document.title=previousTitle;currentResults=null;if(params.search&¶ms.search.length>0){searchState.input.value=params.search;e.preventDefault();search()}else{searchState.input.value="";searchState.hideResults()}})}window.onpageshow=()=>{const qSearch=searchState.getQueryStringParams().search;if(searchState.input.value===""&&qSearch){searchState.input.value=qSearch}search()}}function updateCrate(ev){if(ev.target.value==="all crates"){const query=searchState.input.value.trim();updateSearchHistory(buildUrl(query,null))}currentResults=null;search(true)}function initSearch(searchIndx){rawSearchIndex=searchIndx;if(typeof window!=="undefined"){docSearch=new DocSearch(rawSearchIndex,ROOT_PATH,searchState);registerSearchEvents();if(window.searchState.getQueryStringParams().search){search()}}else if(typeof exports!=="undefined"){docSearch=new DocSearch(rawSearchIndex,ROOT_PATH,searchState);exports.docSearch=docSearch;exports.parseQuery=DocSearch.parseQuery}}if(typeof exports!=="undefined"){exports.initSearch=initSearch}if(typeof window!=="undefined"){window.initSearch=initSearch;if(window.searchIndex!==undefined){initSearch(window.searchIndex)}}else{initSearch(new Map())}class ParametricDescription{constructor(w,n,minErrors){this.w=w;this.n=n;this.minErrors=minErrors}isAccept(absState){const state=Math.floor(absState/(this.w+1));const offset=absState%(this.w+1);return this.w-offset+this.minErrors[state]<=this.n}getPosition(absState){return absState%(this.w+1)}getVector(name,charCode,pos,end){let vector=0;for(let i=pos;i>5;const bitStart=bitLoc&31;if(bitStart+bitsPerValue<=32){return((data[dataLoc]>>bitStart)&this.MASKS[bitsPerValue-1])}else{const part=32-bitStart;return ~~(((data[dataLoc]>>bitStart)&this.MASKS[part-1])+((data[1+dataLoc]&this.MASKS[bitsPerValue-part-1])<{const settingId=toggle.id;const settingValue=getSettingValue(settingId);if(settingValue!==null){toggle.checked=settingValue==="true"}toggle.onchange=()=>{changeSetting(toggle.id,toggle.checked)}});onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"),elem=>{const settingId=elem.name;let settingValue=getSettingValue(settingId);if(settingId==="theme"){const useSystem=getSettingValue("use-system-theme");if(useSystem==="true"||settingValue===null){settingValue=useSystem==="false"?"light":"system preference"}}if(settingValue!==null&&settingValue!=="null"){elem.checked=settingValue===elem.value}elem.addEventListener("change",ev=>{changeSetting(ev.target.name,ev.target.value)})})}function buildSettingsPageSections(settings){let output="";for(const setting of settings){if(setting==="hr"){output+="
";continue}const js_data_name=setting["js_name"];const setting_name=setting["name"];if(setting["options"]!==undefined){output+=`\ +
+
${setting_name}
+
`;onEach(setting["options"],option=>{const checked=option===setting["default"]?" checked":"";const full=`${js_data_name}-${option.replace(/ /g,"-")}`;output+=`\ + `});output+=`\ +
+
`}else{const checked=setting["default"]===true?" checked":"";output+=`\ +
\ + \ +
`}}return output}function buildSettingsPage(){const theme_names=getVar("themes").split(",").filter(t=>t);theme_names.push("light","dark","ayu");const settings=[{"name":"Theme","js_name":"theme","default":"system preference","options":theme_names.concat("system preference"),},{"name":"Preferred light theme","js_name":"preferred-light-theme","default":"light","options":theme_names,},{"name":"Preferred dark theme","js_name":"preferred-dark-theme","default":"dark","options":theme_names,},{"name":"Auto-hide item contents for large items","js_name":"auto-hide-large-items","default":true,},{"name":"Auto-hide item methods' documentation","js_name":"auto-hide-method-docs","default":false,},{"name":"Auto-hide trait implementation documentation","js_name":"auto-hide-trait-implementations","default":false,},{"name":"Directly go to item in search if there is only one result","js_name":"go-to-only-result","default":false,},{"name":"Show line numbers on code examples","js_name":"line-numbers","default":false,},{"name":"Hide persistent navigation bar","js_name":"hide-sidebar","default":false,},{"name":"Hide table of contents","js_name":"hide-toc","default":false,},{"name":"Hide module navigation","js_name":"hide-modnav","default":false,},{"name":"Disable keyboard shortcuts","js_name":"disable-shortcuts","default":false,},{"name":"Use sans serif fonts","js_name":"sans-serif-fonts","default":false,},{"name":"Word wrap source code","js_name":"word-wrap-source-code","default":false,},];const elementKind=isSettingsPage?"section":"div";const innerHTML=`
${buildSettingsPageSections(settings)}
`;const el=document.createElement(elementKind);el.id="settings";if(!isSettingsPage){el.className="popover"}el.innerHTML=innerHTML;if(isSettingsPage){document.getElementById(MAIN_ID).appendChild(el)}else{el.setAttribute("tabindex","-1");getSettingsButton().appendChild(el)}return el}const settingsMenu=buildSettingsPage();function displaySettings(){settingsMenu.style.display="";onEachLazy(settingsMenu.querySelectorAll("input[type='checkbox']"),el=>{const val=getSettingValue(el.id);const checked=val==="true";if(checked!==el.checked&&val!==null){el.checked=checked}})}function settingsBlurHandler(event){if(!getHelpButton().contains(document.activeElement)&&!getHelpButton().contains(event.relatedTarget)&&!getSettingsButton().contains(document.activeElement)&&!getSettingsButton().contains(event.relatedTarget)){window.hidePopoverMenus()}}if(!isSettingsPage){const settingsButton=getSettingsButton();const settingsMenu=document.getElementById("settings");settingsButton.onclick=event=>{if(settingsMenu.contains(event.target)){return}event.preventDefault();const shouldDisplaySettings=settingsMenu.style.display==="none";window.hideAllModals();if(shouldDisplaySettings){displaySettings()}};settingsButton.onblur=settingsBlurHandler;settingsButton.querySelector("a").onblur=settingsBlurHandler;onEachLazy(settingsMenu.querySelectorAll("input"),el=>{el.onblur=settingsBlurHandler});settingsMenu.onblur=settingsBlurHandler}setTimeout(()=>{setEvents(settingsMenu);if(!isSettingsPage){displaySettings()}removeClass(getSettingsButton(),"rotate")},0)})() \ No newline at end of file diff --git a/static.files/src-script-63605ae7.js b/static.files/src-script-63605ae7.js new file mode 100644 index 00000000..98cebcaa --- /dev/null +++ b/static.files/src-script-63605ae7.js @@ -0,0 +1 @@ +"use strict";(function(){const rootPath=getVar("root-path");const NAME_OFFSET=0;const DIRS_OFFSET=1;const FILES_OFFSET=2;const RUSTDOC_MOBILE_BREAKPOINT=700;function closeSidebarIfMobile(){if(window.innerWidth{removeClass(document.documentElement,"src-sidebar-expanded");updateLocalStorage("source-sidebar-show","false")};window.rustdocShowSourceSidebar=()=>{addClass(document.documentElement,"src-sidebar-expanded");updateLocalStorage("source-sidebar-show","true")};window.rustdocToggleSrcSidebar=()=>{if(document.documentElement.classList.contains("src-sidebar-expanded")){window.rustdocCloseSourceSidebar()}else{window.rustdocShowSourceSidebar()}};function createSrcSidebar(){const container=nonnull(document.querySelector("nav.sidebar"));const sidebar=document.createElement("div");sidebar.id="src-sidebar";let hasFoundFile=false;for(const[key,source]of srcIndex){source[NAME_OFFSET]=key;hasFoundFile=createDirEntry(source,sidebar,"",hasFoundFile)}container.appendChild(sidebar);const selected_elem=sidebar.getElementsByClassName("selected")[0];if(typeof selected_elem!=="undefined"){selected_elem.focus()}}function highlightSrcLines(){const match=window.location.hash.match(/^#?(\d+)(?:-(\d+))?$/);if(!match){return}let from=parseInt(match[1],10);let to=from;if(typeof match[2]!=="undefined"){to=parseInt(match[2],10)}if(to{removeClass(e,"line-highlighted")});for(let i=from;i<=to;++i){elem=document.getElementById(""+i);if(!elem){break}addClass(elem,"line-highlighted")}}const handleSrcHighlight=(function(){let prev_line_id=0;const set_fragment=name=>{const x=window.scrollX,y=window.scrollY;if(browserSupportsHistoryApi()){history.replaceState(null,"","#"+name);highlightSrcLines()}else{location.replace("#"+name)}window.scrollTo(x,y)};return ev=>{let cur_line_id=parseInt(ev.target.id,10);if(isNaN(cur_line_id)||ev.ctrlKey||ev.altKey||ev.metaKey){return}ev.preventDefault();if(ev.shiftKey&&prev_line_id){if(prev_line_id>cur_line_id){const tmp=prev_line_id;prev_line_id=cur_line_id;cur_line_id=tmp}set_fragment(prev_line_id+"-"+cur_line_id)}else{prev_line_id=cur_line_id;set_fragment(""+cur_line_id)}}}());window.addEventListener("hashchange",highlightSrcLines);onEachLazy(document.querySelectorAll("a[data-nosnippet]"),el=>{el.addEventListener("click",handleSrcHighlight)});highlightSrcLines();window.createSrcSidebar=createSrcSidebar})() \ No newline at end of file diff --git a/static.files/storage-82c7156e.js b/static.files/storage-82c7156e.js new file mode 100644 index 00000000..dd769fbf --- /dev/null +++ b/static.files/storage-82c7156e.js @@ -0,0 +1,23 @@ +"use strict";const builtinThemes=["light","dark","ayu"];const darkThemes=["dark","ayu"];window.currentTheme=(function(){const currentTheme=document.getElementById("themeStyle");return currentTheme instanceof HTMLLinkElement?currentTheme:null})();const settingsDataset=(function(){const settingsElement=document.getElementById("default-settings");return settingsElement&&settingsElement.dataset?settingsElement.dataset:null})();function nonnull(x,msg){if(x===null){throw(msg||"unexpected null value!")}else{return x}}function getSettingValue(settingName){const current=getCurrentValue(settingName);if(current===null&&settingsDataset!==null){const def=settingsDataset[settingName.replace(/-/g,"_")];if(def!==undefined){return def}}return current}const localStoredTheme=getSettingValue("theme");function hasClass(elem,className){return!!elem&&!!elem.classList&&elem.classList.contains(className)}function addClass(elem,className){if(elem&&elem.classList){elem.classList.add(className)}}function removeClass(elem,className){if(elem&&elem.classList){elem.classList.remove(className)}}function onEach(arr,func){for(const elem of arr){if(func(elem)){return true}}return false}function onEachLazy(lazyArray,func){return onEach(Array.prototype.slice.call(lazyArray),func)}function updateLocalStorage(name,value){try{if(value===null){window.localStorage.removeItem("rustdoc-"+name)}else{window.localStorage.setItem("rustdoc-"+name,value)}}catch(e){}}function getCurrentValue(name){try{return window.localStorage.getItem("rustdoc-"+name)}catch(e){return null}}function getVar(name){const el=document.querySelector("head > meta[name='rustdoc-vars']");return el?el.getAttribute("data-"+name):null}function switchTheme(newThemeName,saveTheme){const themeNames=(getVar("themes")||"").split(",").filter(t=>t);themeNames.push(...builtinThemes);if(newThemeName===null||themeNames.indexOf(newThemeName)===-1){return}if(saveTheme){updateLocalStorage("theme",newThemeName)}document.documentElement.setAttribute("data-theme",newThemeName);if(builtinThemes.indexOf(newThemeName)!==-1){if(window.currentTheme&&window.currentTheme.parentNode){window.currentTheme.parentNode.removeChild(window.currentTheme);window.currentTheme=null}}else{const newHref=getVar("root-path")+encodeURIComponent(newThemeName)+getVar("resource-suffix")+".css";if(!window.currentTheme){if(document.readyState==="loading"){document.write(``);window.currentTheme=(function(){const currentTheme=document.getElementById("themeStyle");return currentTheme instanceof HTMLLinkElement?currentTheme:null})()}else{window.currentTheme=document.createElement("link");window.currentTheme.rel="stylesheet";window.currentTheme.id="themeStyle";window.currentTheme.href=newHref;document.documentElement.appendChild(window.currentTheme)}}else if(newHref!==window.currentTheme.href){window.currentTheme.href=newHref}}}const updateTheme=(function(){const mql=window.matchMedia("(prefers-color-scheme: dark)");function updateTheme(){if(getSettingValue("use-system-theme")!=="false"){const lightTheme=getSettingValue("preferred-light-theme")||"light";const darkTheme=getSettingValue("preferred-dark-theme")||"dark";updateLocalStorage("use-system-theme","true");switchTheme(mql.matches?darkTheme:lightTheme,true)}else{switchTheme(getSettingValue("theme"),false)}}mql.addEventListener("change",updateTheme);return updateTheme})();if(getSettingValue("use-system-theme")!=="false"&&window.matchMedia){if(getSettingValue("use-system-theme")===null&&getSettingValue("preferred-dark-theme")===null&&localStoredTheme!==null&&darkThemes.indexOf(localStoredTheme)>=0){updateLocalStorage("preferred-dark-theme",localStoredTheme)}}updateTheme();if(getSettingValue("source-sidebar-show")==="true"){addClass(document.documentElement,"src-sidebar-expanded")}if(getSettingValue("hide-sidebar")==="true"){addClass(document.documentElement,"hide-sidebar")}if(getSettingValue("hide-toc")==="true"){addClass(document.documentElement,"hide-toc")}if(getSettingValue("hide-modnav")==="true"){addClass(document.documentElement,"hide-modnav")}if(getSettingValue("sans-serif-fonts")==="true"){addClass(document.documentElement,"sans-serif")}if(getSettingValue("word-wrap-source-code")==="true"){addClass(document.documentElement,"word-wrap-source-code")}function updateSidebarWidth(){const desktopSidebarWidth=getSettingValue("desktop-sidebar-width");if(desktopSidebarWidth&&desktopSidebarWidth!=="null"){document.documentElement.style.setProperty("--desktop-sidebar-width",desktopSidebarWidth+"px",)}const srcSidebarWidth=getSettingValue("src-sidebar-width");if(srcSidebarWidth&&srcSidebarWidth!=="null"){document.documentElement.style.setProperty("--src-sidebar-width",srcSidebarWidth+"px",)}}updateSidebarWidth();window.addEventListener("pageshow",ev=>{if(ev.persisted){setTimeout(updateTheme,0);setTimeout(updateSidebarWidth,0)}});class RustdocSearchElement extends HTMLElement{constructor(){super()}connectedCallback(){const rootPath=getVar("root-path");const currentCrate=getVar("current-crate");this.innerHTML=``}}window.customElements.define("rustdoc-search",RustdocSearchElement);class RustdocToolbarElement extends HTMLElement{constructor(){super()}connectedCallback(){if(this.firstElementChild){return}const rootPath=getVar("root-path");this.innerHTML=` +
+ Settings +
+
+ Help +
+ `}}window.customElements.define("rustdoc-toolbar",RustdocToolbarElement) \ No newline at end of file diff --git a/trait.impl/clap_builder/derive/trait.Args.js b/trait.impl/clap_builder/derive/trait.Args.js new file mode 100644 index 00000000..5d13de52 --- /dev/null +++ b/trait.impl/clap_builder/derive/trait.Args.js @@ -0,0 +1,9 @@ +(function() { + var implementors = Object.fromEntries([["cli",[["impl Args for Cli"]]],["server",[["impl Args for Config"]]]]); + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } +})() +//{"start":57,"fragment_lengths":[110,129]} \ No newline at end of file diff --git a/trait.impl/clap_builder/derive/trait.CommandFactory.js b/trait.impl/clap_builder/derive/trait.CommandFactory.js new file mode 100644 index 00000000..f3e5b25d --- /dev/null +++ b/trait.impl/clap_builder/derive/trait.CommandFactory.js @@ -0,0 +1,9 @@ +(function() { + var implementors = Object.fromEntries([["cli",[["impl CommandFactory for Cli"]]],["server",[["impl CommandFactory for Config"]]]]); + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } +})() +//{"start":57,"fragment_lengths":[120,139]} \ No newline at end of file diff --git a/trait.impl/clap_builder/derive/trait.FromArgMatches.js b/trait.impl/clap_builder/derive/trait.FromArgMatches.js new file mode 100644 index 00000000..2ccb9464 --- /dev/null +++ b/trait.impl/clap_builder/derive/trait.FromArgMatches.js @@ -0,0 +1,9 @@ +(function() { + var implementors = Object.fromEntries([["cli",[["impl FromArgMatches for CommandOptions"],["impl FromArgMatches for Cli"]]],["server",[["impl FromArgMatches for Config"]]]]); + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } +})() +//{"start":57,"fragment_lengths":[258,139]} \ No newline at end of file diff --git a/trait.impl/clap_builder/derive/trait.Parser.js b/trait.impl/clap_builder/derive/trait.Parser.js new file mode 100644 index 00000000..f9b28f08 --- /dev/null +++ b/trait.impl/clap_builder/derive/trait.Parser.js @@ -0,0 +1,9 @@ +(function() { + var implementors = Object.fromEntries([["cli",[["impl Parser for Cli"]]],["server",[["impl Parser for Config"]]]]); + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } +})() +//{"start":57,"fragment_lengths":[112,131]} \ No newline at end of file diff --git a/trait.impl/clap_builder/derive/trait.Subcommand.js b/trait.impl/clap_builder/derive/trait.Subcommand.js new file mode 100644 index 00000000..d0e3fa8a --- /dev/null +++ b/trait.impl/clap_builder/derive/trait.Subcommand.js @@ -0,0 +1,9 @@ +(function() { + var implementors = Object.fromEntries([["cli",[["impl Subcommand for CommandOptions"]]]]); + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } +})() +//{"start":57,"fragment_lengths":[143]} \ No newline at end of file diff --git a/trait.impl/core/fmt/trait.Debug.js b/trait.impl/core/fmt/trait.Debug.js new file mode 100644 index 00000000..ce817d75 --- /dev/null +++ b/trait.impl/core/fmt/trait.Debug.js @@ -0,0 +1,9 @@ +(function() { + var implementors = Object.fromEntries([["mrc",[["impl Debug for MpvCommand"]]]]); + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } +})() +//{"start":57,"fragment_lengths":[250]} \ No newline at end of file diff --git a/trait.impl/core/marker/trait.Freeze.js b/trait.impl/core/marker/trait.Freeze.js new file mode 100644 index 00000000..0eec0165 --- /dev/null +++ b/trait.impl/core/marker/trait.Freeze.js @@ -0,0 +1,9 @@ +(function() { + var implementors = Object.fromEntries([["cli",[["impl Freeze for CommandOptions",1,["cli::CommandOptions"]],["impl Freeze for Cli",1,["cli::Cli"]]]],["mrc",[["impl Freeze for MpvCommand",1,["mrc::MpvCommand"]]]],["server",[["impl Freeze for Config",1,["server::Config"]]]]]); + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } +})() +//{"start":57,"fragment_lengths":[547,282,284]} \ No newline at end of file diff --git a/trait.impl/core/marker/trait.Send.js b/trait.impl/core/marker/trait.Send.js new file mode 100644 index 00000000..bff30d75 --- /dev/null +++ b/trait.impl/core/marker/trait.Send.js @@ -0,0 +1,9 @@ +(function() { + var implementors = Object.fromEntries([["cli",[["impl Send for CommandOptions",1,["cli::CommandOptions"]],["impl Send for Cli",1,["cli::Cli"]]]],["mrc",[["impl Send for MpvCommand",1,["mrc::MpvCommand"]]]],["server",[["impl Send for Config",1,["server::Config"]]]]]); + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } +})() +//{"start":57,"fragment_lengths":[535,276,278]} \ No newline at end of file diff --git a/trait.impl/core/marker/trait.Sync.js b/trait.impl/core/marker/trait.Sync.js new file mode 100644 index 00000000..dfb06c17 --- /dev/null +++ b/trait.impl/core/marker/trait.Sync.js @@ -0,0 +1,9 @@ +(function() { + var implementors = Object.fromEntries([["cli",[["impl Sync for CommandOptions",1,["cli::CommandOptions"]],["impl Sync for Cli",1,["cli::Cli"]]]],["mrc",[["impl Sync for MpvCommand",1,["mrc::MpvCommand"]]]],["server",[["impl Sync for Config",1,["server::Config"]]]]]); + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } +})() +//{"start":57,"fragment_lengths":[535,276,278]} \ No newline at end of file diff --git a/trait.impl/core/marker/trait.Unpin.js b/trait.impl/core/marker/trait.Unpin.js new file mode 100644 index 00000000..17133d7e --- /dev/null +++ b/trait.impl/core/marker/trait.Unpin.js @@ -0,0 +1,9 @@ +(function() { + var implementors = Object.fromEntries([["cli",[["impl Unpin for CommandOptions",1,["cli::CommandOptions"]],["impl Unpin for Cli",1,["cli::Cli"]]]],["mrc",[["impl Unpin for MpvCommand",1,["mrc::MpvCommand"]]]],["server",[["impl Unpin for Config",1,["server::Config"]]]]]); + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } +})() +//{"start":57,"fragment_lengths":[541,279,281]} \ No newline at end of file diff --git a/trait.impl/core/panic/unwind_safe/trait.RefUnwindSafe.js b/trait.impl/core/panic/unwind_safe/trait.RefUnwindSafe.js new file mode 100644 index 00000000..152c8267 --- /dev/null +++ b/trait.impl/core/panic/unwind_safe/trait.RefUnwindSafe.js @@ -0,0 +1,9 @@ +(function() { + var implementors = Object.fromEntries([["cli",[["impl RefUnwindSafe for CommandOptions",1,["cli::CommandOptions"]],["impl RefUnwindSafe for Cli",1,["cli::Cli"]]]],["mrc",[["impl RefUnwindSafe for MpvCommand",1,["mrc::MpvCommand"]]]],["server",[["impl RefUnwindSafe for Config",1,["server::Config"]]]]]); + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } +})() +//{"start":57,"fragment_lengths":[635,326,328]} \ No newline at end of file diff --git a/trait.impl/core/panic/unwind_safe/trait.UnwindSafe.js b/trait.impl/core/panic/unwind_safe/trait.UnwindSafe.js new file mode 100644 index 00000000..76064153 --- /dev/null +++ b/trait.impl/core/panic/unwind_safe/trait.UnwindSafe.js @@ -0,0 +1,9 @@ +(function() { + var implementors = Object.fromEntries([["cli",[["impl UnwindSafe for CommandOptions",1,["cli::CommandOptions"]],["impl UnwindSafe for Cli",1,["cli::Cli"]]]],["mrc",[["impl UnwindSafe for MpvCommand",1,["mrc::MpvCommand"]]]],["server",[["impl UnwindSafe for Config",1,["server::Config"]]]]]); + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } +})() +//{"start":57,"fragment_lengths":[617,317,319]} \ No newline at end of file